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:
@@ -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}` : ""}\``
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user