fix(web): externalize copy the jsx-only i18n guard cannot see, and gate it (#2711)

Co-authored-by: Kandev Agent <agent@kandev.dev>
This commit is contained in:
João Salavisa
2026-08-16 12:08:59 +01:00
committed by GitHub
parent 38c94e7d00
commit 63c21686ff
140 changed files with 1534 additions and 233 deletions
@@ -52,6 +52,7 @@ function actionPromptPlaceholders(t: TFunction): ScriptPlaceholder[] {
// preset seeded in one locale and saved unedited would keep that locale's text
// forever. Same contract as DEFAULT_PR_PRESETS in my-github/action-presets.ts.
function newPreset(): GitHubActionPreset {
// i18n-exempt: persisted, editable preset label. See the comment above.
return {
id: `preset_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`,
label: "New action",
@@ -26,6 +26,7 @@ import { useTranslation } from "react-i18next";
// and is editable in the row below, so it must stay locale-neutral — see
// `newPreset` in action-presets-section.tsx for the same contract.
function newPreset(): StoredQueryPreset {
// i18n-exempt: persisted, editable preset label. See the comment above.
return {
value: `q_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`,
label: "New query",
@@ -74,7 +74,9 @@ type FormState = {
cleanupPolicy: CleanupPolicy;
};
// i18n-exempt: GitHub search syntax and label ids, shown as examples.
const DEFAULT_QUERY = "type:issue state:open";
// i18n-exempt: GitHub label ids, shown as examples.
const ISSUE_LABEL_EXAMPLES = "bug, enhancement, priority:high";
function makeDefaultForm(workspaceId: string): FormState {
@@ -56,6 +56,7 @@ export function issueWatchPlaceholders(t: TFunction): ScriptPlaceholder[] {
* Seeded into the prompt field, then persisted and sent to the agent verbatim.
* Deliberately NOT translated — see `DEFAULT_REVIEW_WATCH_PROMPT`.
*/
// i18n-exempt: default watch prompt, persisted and sent verbatim to the agent.
export const DEFAULT_ISSUE_WATCH_PROMPT = `You have been assigned a GitHub issue to work on.
**Issue:** {{issue.link}}
@@ -68,6 +68,7 @@ export function toTaskPreset(stored: GitHubActionPreset): TaskPreset {
// into a user's saved presets and leave them there after a locale switch.
// `prompt_template` is additionally sent to the agent verbatim. Localizing these
// needs a key/persisted-value split, the same open item as PR_PRESETS.
// i18n-exempt: persisted preset seed. Localizing needs a key/value split in the preset type.
export const DEFAULT_PR_PRESETS: GitHubActionPreset[] = [
{
id: "review",
@@ -95,6 +96,7 @@ export const DEFAULT_PR_PRESETS: GitHubActionPreset[] = [
},
];
// i18n-exempt: persisted preset seed. Localizing needs a key/value split in the preset type.
export const DEFAULT_ISSUE_PRESETS: GitHubActionPreset[] = [
{
id: "implement",
@@ -27,6 +27,7 @@ export type PresetOption = {
// them there after a locale switch. Localizing these needs a key/persisted-value
// split in this module, the same open item as the built-in layout profile names.
// `value`, `filter` and `group` are wire values and a GitHub search query.
// i18n-exempt: persisted saved-search seed, and the query beside it is GitHub search syntax.
export const PR_PRESETS: PresetOption[] = [
{
value: "review_requested",
@@ -65,6 +66,7 @@ export const PR_PRESETS: PresetOption[] = [
},
];
// i18n-exempt: persisted saved-search seed, and the query beside it is GitHub search syntax.
export const ISSUE_PRESETS: PresetOption[] = [
{
value: "assigned",
@@ -4,6 +4,7 @@ import type { PRComment } from "@/lib/types/github";
import { CollapsibleSection, AddToContextButton, FeedbackItemRow } from "./pr-shared";
import { useTranslation } from "react-i18next";
// i18n-exempt: builds the message body sent to the agent, not UI copy.
function buildCommentMessage(comment: PRComment, prUrl: string): string {
const location = comment.path
? `\`${comment.path}${comment.line > 0 ? `:${comment.line}` : ""}\``
+9 -8
View File
@@ -7,22 +7,23 @@ import { Button } from "@kandev/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@kandev/ui/tooltip";
import { markdownComponents, remarkPlugins } from "@/components/shared/markdown-components";
import { useTranslation } from "react-i18next";
import { t } from "@/lib/i18n";
export function formatTimeAgo(dateStr: string): string {
const date = new Date(dateStr);
if (isNaN(date.getTime())) return "";
const diff = Date.now() - date.getTime();
if (diff < 0) return "just now";
if (diff < 0) return t("github:timeAgoJustNow");
const minutes = Math.floor(diff / 60000);
if (minutes < 1) return "just now";
if (minutes < 60) return `${minutes}m ago`;
if (minutes < 1) return t("github:timeAgoJustNow");
if (minutes < 60) return t("github:timeAgoMinutes", { count: minutes });
const hours = Math.floor(minutes / 60);
if (hours < 24) return `${hours}h ago`;
if (hours < 24) return t("github:timeAgoHours", { count: hours });
const days = Math.floor(hours / 24);
if (days < 7) return `${days}d ago`;
if (days < 30) return `${Math.floor(days / 7)}w ago`;
if (days < 365) return `${Math.floor(days / 30)}mo ago`;
return `${Math.floor(days / 365)}y ago`;
if (days < 7) return t("github:timeAgoDays", { count: days });
if (days < 30) return t("github:timeAgoWeeks", { count: Math.floor(days / 7) });
if (days < 365) return t("github:timeAgoMonths", { count: Math.floor(days / 30) });
return t("github:timeAgoYears", { count: Math.floor(days / 365) });
}
function formatMs(ms: number): string {
@@ -61,6 +61,7 @@ export function reviewWatchPlaceholders(t: TFunction): ScriptPlaceholder[] {
* Deliberately NOT translated: it is agent instructions and stored data, so
* translating it would write locale-dependent text into a user's saved watch.
*/
// i18n-exempt: default watch prompt, persisted and sent verbatim to the agent.
export const DEFAULT_REVIEW_WATCH_PROMPT = `Review Pull Request #{{pr.number}}: {{pr.title}}
Repository: {{pr.repo}}
PR: {{pr.link}}
@@ -16,7 +16,9 @@ import { useMemo } from "react";
// than written into the catalog: they contain a literal `{{task_prompt}}` token,
// which i18next would read as an interpolation and substitute away, and the
// pseudo-locale would transliterate the URL.
// i18n-exempt: example prompt text, shown as a sample of what is sent verbatim to the agent.
const STEP_PROMPT_EXAMPLE = "Analyze the task: {{task_prompt}}";
// i18n-exempt: example prompt text, shown as a sample of what is sent verbatim to the agent.
const FINAL_PROMPT_EXAMPLE = "Analyze the task: Pull Request ready for review: https://...";
// Pulled out of review-watch-dialog.tsx to keep that file under the 600-line