feat(i18n): add multi-language internationalization support (zh/en)#1561
feat(i18n): add multi-language internationalization support (zh/en)#15617723qqq wants to merge 4 commits into
Conversation
- Add i18n engine with Chinese (zh) and English (en) locales - Add locale selector dialog for runtime language switching (/locale command) - Replace all hardcoded English strings with t() calls across CLI, TUI, and Web UI - Add comprehensive i18n test coverage - Add changeset for i18n-coverage
🦋 Changeset detectedLatest commit: 5a83265 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8a69993056
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| outputWriter.writeStatus( | ||
| `Retrying (${event.nextAttempt}/${event.maxAttempts}) in ${Math.ceil(event.delayMs / 1000)}s — ${event.errorName}`, | ||
| ); |
There was a problem hiding this comment.
Preserve retry metadata for stream-json
When a retry occurs under kimi -p --output-format=stream-json, this now calls the generic status writer, so the JSONL output becomes {"role":"meta","type":"status","content":"Retrying ..."} and drops failed_attempt, delay_ms, error_message, and status_code. The stream-json contract/tests already expose retries as type: "turn.step.retrying" with structured fields, so consumers can no longer distinguish or handle provider retries; keep the structured JSON path and only localize the text writer.
Useful? React with 👍 / 👎.
| return new Promise((resolve) => { | ||
| const picker = new ChoicePickerComponent({ | ||
| title: 'Select a provider to log out', | ||
| title: t('tui.statusMessages.selectProviderToLogout'), |
There was a problem hiding this comment.
Add missing translations for prompt/provider keys
This and the other new tui.statusMessages.* keys in prompts.ts/provider.ts (for feedback attachment choices, API-key subtitle, catalog/provider add/remove statuses, etc.) are not present in either apps/kimi-code/src/i18n/locales/en.ts or zh.ts; because t() falls back to the key, opening these flows shows strings like tui.statusMessages.selectProviderToLogout instead of user text. Add the missing locale entries or point these calls at existing keys.
Useful? React with 👍 / 👎.
| v-if="goal.status !== 'paused'" | ||
| size="sm" | ||
| variant="secondary" | ||
| class="goal-action" | ||
| @click.stop="emit('controlGoal', 'pause')" |
There was a problem hiding this comment.
Resume blocked goals from the strip
In the blocked-goal state, this condition renders the Pause action and hides Resume, but the rest of the web UI treats blocked goals as resumable (goalCanResume is true for paused || blocked in Composer). Users who expand the goal strip after a goal blocks can only send goalControl: 'pause', which does not unblock or resume it; render Resume for blocked and Pause only for active.
Useful? React with 👍 / 👎.
| goalTurns: '{{count}} turns', | ||
| goalTokens: '{{count}} tokens', | ||
| goalTokenBudget: '{{pct}}% token budget', |
There was a problem hiding this comment.
Use vue-i18n placeholder syntax
Vue-i18n in the web app uses single-brace named interpolation ({count}), and GoalStrip passes { count }/{ pct } to these keys. With {{count}}/{{pct}}, the message compiler will not substitute the values, so expanded goal stats render literal placeholders instead of numbers; change these new web locale strings (and the zh mirrors) to {count} and {pct}.
Useful? React with 👍 / 👎.
…issing locale keys, fix GoalStrip blocked state, fix vue-i18n placeholder syntax
- Restore writeRetrying with structured JSON meta for stream-json consumers; t() only for text output
- Add missing i18n keys for prompts.ts and provider.ts (selectProviderToLogout, feedback*, catalog*, addProvider*, etc.)
- Fix GoalStrip.vue: blocked goals now show Resume instead of Pause (paused || blocked → resume, active → pause)
- Fix vue-i18n placeholder syntax: {{count}} → {count}, {{pct}} → {pct}
Signed-off-by: 7723qqq <65469696+7723qqq@users.noreply.github.com>
Signed-off-by: 7723qqq <65469696+7723qqq@users.noreply.github.com>
Summary
This PR adds comprehensive multi-language internationalization (i18n) support across the CLI, TUI, and Web UI.
Changes
apps/kimi-code/src/i18n/) — lightweight i18n core with Chinese (zh) and English (en) localesapps/kimi-code/src/tui/components/dialogs/locale-selector.ts) — runtime language switching dialog via/localecommandt()calls across:apps/kimi-code/test/i18n/index.test.ts) — i18n engine unit testsapps/kimi-web/src/i18n/locales/for both en and zhHow it works
Locale detection:
localeconfig option →KIMI_LOCALEenv var →zh(default).Screenshots
(TBD — locale selector dialog, Chinese TUI, Chinese Web UI)
Checklist
zh