From ef36af0e55d814dc80893af923886ccff40f46e5 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 20 Jan 2026 11:27:32 -0600 Subject: [PATCH] wip(app): i18n --- packages/ui/package.json | 1 + packages/ui/src/context/i18n.tsx | 39 ++++++++++++++++++++++++++++++++ packages/ui/src/context/index.ts | 1 + packages/ui/src/i18n/en.ts | 33 +++++++++++++++++++++++++++ packages/ui/src/i18n/zh.ts | 37 ++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+) create mode 100644 packages/ui/src/context/i18n.tsx create mode 100644 packages/ui/src/i18n/en.ts create mode 100644 packages/ui/src/i18n/zh.ts diff --git a/packages/ui/package.json b/packages/ui/package.json index be9f8b923..47257e750 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -5,6 +5,7 @@ "license": "MIT", "exports": { "./*": "./src/components/*.tsx", + "./i18n/*": "./src/i18n/*.ts", "./pierre": "./src/pierre/index.ts", "./pierre/*": "./src/pierre/*.ts", "./hooks": "./src/hooks/index.ts", diff --git a/packages/ui/src/context/i18n.tsx b/packages/ui/src/context/i18n.tsx new file mode 100644 index 000000000..fd8b05d3c --- /dev/null +++ b/packages/ui/src/context/i18n.tsx @@ -0,0 +1,39 @@ +import { createContext, useContext, type Accessor, type ParentProps } from "solid-js" +import { dict as en } from "../i18n/en" + +export type UiI18nKey = keyof typeof en + +export type UiI18nParams = Record + +export type UiI18n = { + locale: Accessor + t: (key: UiI18nKey, params?: UiI18nParams) => string +} + +function resolveTemplate(text: string, params?: UiI18nParams) { + if (!params) return text + return text.replace(/{{\s*([^}]+?)\s*}}/g, (_, rawKey) => { + const key = String(rawKey) + const value = params[key] + if (value === undefined || value === null) return "" + return String(value) + }) +} + +const fallback: UiI18n = { + locale: () => "en", + t: (key, params) => { + const value = en[key] ?? String(key) + return resolveTemplate(value, params) + }, +} + +const Context = createContext(fallback) + +export function I18nProvider(props: ParentProps<{ value: UiI18n }>) { + return {props.children} +} + +export function useI18n() { + return useContext(Context) +} diff --git a/packages/ui/src/context/index.ts b/packages/ui/src/context/index.ts index 499cb74d4..5615dd0ec 100644 --- a/packages/ui/src/context/index.ts +++ b/packages/ui/src/context/index.ts @@ -2,3 +2,4 @@ export * from "./helper" export * from "./data" export * from "./diff" export * from "./dialog" +export * from "./i18n" diff --git a/packages/ui/src/i18n/en.ts b/packages/ui/src/i18n/en.ts new file mode 100644 index 000000000..caee7e536 --- /dev/null +++ b/packages/ui/src/i18n/en.ts @@ -0,0 +1,33 @@ +export const dict = { + "ui.sessionReview.title": "Session changes", + "ui.sessionReview.diffStyle.unified": "Unified", + "ui.sessionReview.diffStyle.split": "Split", + "ui.sessionReview.expandAll": "Expand all", + "ui.sessionReview.collapseAll": "Collapse all", + + "ui.sessionTurn.steps.show": "Show steps", + "ui.sessionTurn.steps.hide": "Hide steps", + "ui.sessionTurn.summary.response": "Response", + "ui.sessionTurn.diff.showMore": "Show more changes ({{count}})", + + "ui.sessionTurn.retry.retrying": "retrying", + "ui.sessionTurn.retry.inSeconds": "in {{seconds}}s", + + "ui.sessionTurn.status.delegating": "Delegating work", + "ui.sessionTurn.status.planning": "Planning next steps", + "ui.sessionTurn.status.gatheringContext": "Gathering context", + "ui.sessionTurn.status.searchingCodebase": "Searching the codebase", + "ui.sessionTurn.status.searchingWeb": "Searching the web", + "ui.sessionTurn.status.makingEdits": "Making edits", + "ui.sessionTurn.status.runningCommands": "Running commands", + "ui.sessionTurn.status.thinking": "Thinking", + "ui.sessionTurn.status.thinkingWithTopic": "Thinking - {{topic}}", + "ui.sessionTurn.status.gatheringThoughts": "Gathering thoughts", + "ui.sessionTurn.status.consideringNextSteps": "Considering next steps", + + "ui.messagePart.diagnostic.error": "Error", + "ui.messagePart.title.edit": "Edit", + "ui.messagePart.title.write": "Write", + "ui.messagePart.option.typeOwnAnswer": "Type your own answer", + "ui.messagePart.review.title": "Review your answers", +} diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts new file mode 100644 index 000000000..59cbe6e27 --- /dev/null +++ b/packages/ui/src/i18n/zh.ts @@ -0,0 +1,37 @@ +import { dict as en } from "./en" + +type Keys = keyof typeof en + +export const dict = { + "ui.sessionReview.title": "会话变更", + "ui.sessionReview.diffStyle.unified": "统一", + "ui.sessionReview.diffStyle.split": "拆分", + "ui.sessionReview.expandAll": "全部展开", + "ui.sessionReview.collapseAll": "全部收起", + + "ui.sessionTurn.steps.show": "显示步骤", + "ui.sessionTurn.steps.hide": "隐藏步骤", + "ui.sessionTurn.summary.response": "回复", + "ui.sessionTurn.diff.showMore": "显示更多更改 ({{count}})", + + "ui.sessionTurn.retry.retrying": "重试中", + "ui.sessionTurn.retry.inSeconds": "{{seconds}} 秒后", + + "ui.sessionTurn.status.delegating": "正在委派工作", + "ui.sessionTurn.status.planning": "正在规划下一步", + "ui.sessionTurn.status.gatheringContext": "正在收集上下文", + "ui.sessionTurn.status.searchingCodebase": "正在搜索代码库", + "ui.sessionTurn.status.searchingWeb": "正在搜索网页", + "ui.sessionTurn.status.makingEdits": "正在修改", + "ui.sessionTurn.status.runningCommands": "正在运行命令", + "ui.sessionTurn.status.thinking": "思考中", + "ui.sessionTurn.status.thinkingWithTopic": "思考 - {{topic}}", + "ui.sessionTurn.status.gatheringThoughts": "正在整理思路", + "ui.sessionTurn.status.consideringNextSteps": "正在考虑下一步", + + "ui.messagePart.diagnostic.error": "错误", + "ui.messagePart.title.edit": "编辑", + "ui.messagePart.title.write": "写入", + "ui.messagePart.option.typeOwnAnswer": "输入自己的答案", + "ui.messagePart.review.title": "检查你的答案", +} satisfies Partial>