Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions apps/kimi-code/src/cli/v2/run-v2-print.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,14 @@ async function resolveNativeSession(
throw new Error(t('tui.statusMessages.sessionNotFound', { sessionId: opts.session! }));
}
if (target.cwd !== undefined && resolve(target.cwd) !== resolve(workDir)) {
stderr.write(
// The session exists but belongs to another directory — say so in the
// thrown error instead of the contradictory "session not found".
throw new Error(
t('tui.statusMessages.sessionDifferentDir', {
sessionId: opts.session!,
cwd: target.cwd,
}),
}).trimEnd(),
);
throw new Error(t('tui.statusMessages.sessionNotFound', { sessionId: opts.session! }));
}
const session = await resumeById(opts.session);
const agent = await ensureMainAgent(session);
Expand Down
13 changes: 8 additions & 5 deletions apps/kimi-code/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,13 @@ export interface CreateI18nOptions {
*
* @example
* const { t, setLocale } = createI18n();
* console.log(t('errors.sessionNotFound'));
* console.log(t('cli.errors.promptEmpty'));
*/
export function createI18n(options: CreateI18nOptions = {}): I18nInstance {
let currentLocale: Locale = options.noDetect
? 'en'
: (options.initialLocale ?? detectLocaleNode());
// An explicit initialLocale always wins; noDetect only suppresses
// env-based detection (falling back to 'en') when no locale was given.
let currentLocale: Locale = options.initialLocale
?? (options.noDetect ? 'en' : detectLocaleNode());

let localeCurrentJson = JSON.stringify(messages[currentLocale]);

Expand Down Expand Up @@ -237,4 +238,6 @@ const defaultI18n = createI18n();
export const t = defaultI18n.t.bind(defaultI18n);
export const setLocale = defaultI18n.setLocale.bind(defaultI18n);
export const getLocale = defaultI18n.getLocale.bind(defaultI18n);
export const getEngine = defaultI18n.getEngine.bind(defaultI18n);
export const getEngine = defaultI18n.getEngine.bind(defaultI18n);
export const getMessages = defaultI18n.getMessages.bind(defaultI18n);
export const translateBatch = defaultI18n.translateBatch.bind(defaultI18n);
1 change: 1 addition & 0 deletions apps/kimi-code/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
"yolo": "yolo",
"plan": "plan",
"swarm": "swarm",
"swarmPlan": "swarm-plan",
"turn": "turn",
"turns": "turns"
},
Expand Down
19 changes: 19 additions & 0 deletions apps/kimi-code/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,24 @@ export default {
usageDesc: 'Show session tokens, context window, and plan quotas.',
githubToken: 'GitHub Token',
githubTokenDesc: 'Set the GitHub personal access token for built-in GitHub tools.',
astron: 'Astron',
astronDesc: 'Configure the Astron model parameters.',
},
astronSettings: {
title: 'Astron Settings',
hintNavigate: '↑↓ navigate',
hintEnter: 'Enter edit/toggle',
hintSave: 'Ctrl+S save',
hintCancel: 'Esc cancel',
hintBackspace: 'Backspace delete',
saveButton: '[ Save ]',
saved: 'Saved',
statusEnabled: 'enabled',
statusDisabled: 'disabled',
fieldStream: 'Stream',
fieldTemperature: 'Temperature',
fieldMaxTokens: 'Max Tokens',
fieldSearchDisable: 'Search Disable',
},
permissionSelector: {
title: 'Select permission mode',
Expand Down Expand Up @@ -1683,6 +1701,7 @@ export default {
configGithubTokenInput: 'Enter your GitHub personal access token (classic).',
configGithubTokenSaved: 'GitHub token saved.',
configGithubTokenSaveFailed: 'Failed to save GitHub token: {{error}}',
configAstronSaveFailed: 'Failed to save Astron settings: {{error}}',
// tui/commands/dispatch.ts
configInvalidSlashCommand: 'Invalid slash command: /{{name}}',
configVersionDisplay: 'Kimi Code v{{version}}',
Expand Down
3 changes: 2 additions & 1 deletion apps/kimi-code/src/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
"yolo": "yolo",
"plan": "plan",
"swarm": "swarm",
"swarmPlan": "swarm-plan",
"turn": "turn",
"turns": "turns"
},
Expand Down Expand Up @@ -893,7 +894,7 @@
"noModelSelected": "未选择模型。请运行 /model 选择模型。",
"unknownTheme": "未知主题:{{theme}}",
"unknownModelAlias": "未知模型别名:{{alias}}",
"unsupportedEffort": "{{alias}} 不支持的思考强度 \"{{arg}\"。可用:{{segments}}",
"unsupportedEffort": "{{alias}} 不支持的思考强度 \"{{arg}}\"。可用:{{segments}}",
"switchModelFailed": "切换模型失败:{{msg}}",
"switchSavedButDefaultFailed": "已切换到 {{name}},但保存默认设置失败:{{msg}}",
"loadExperimentsFailed": "加载实验性功能失败:{{error}}",
Expand Down
21 changes: 20 additions & 1 deletion apps/kimi-code/src/i18n/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,24 @@ export default {
usageDesc: '查看会话令牌数、上下文窗口和计划配额。',
githubToken: 'GitHub Token',
githubTokenDesc: '设置内置 GitHub 工具的 Personal Access Token。',
astron: 'Astron',
astronDesc: '配置 Astron 模型参数。',
},
astronSettings: {
title: 'Astron 设置',
hintNavigate: '↑↓ 导航',
hintEnter: 'Enter 编辑/切换',
hintSave: 'Ctrl+S 保存',
hintCancel: 'Esc 取消',
hintBackspace: 'Backspace 删除',
saveButton: '[ 保存 ]',
saved: '已保存',
statusEnabled: '已启用',
statusDisabled: '已禁用',
fieldStream: '流式输出',
fieldTemperature: '温度',
fieldMaxTokens: '最大 Token 数',
fieldSearchDisable: '禁用搜索',
},
permissionSelector: {
title: '选择权限模式',
Expand Down Expand Up @@ -882,7 +900,7 @@ export default {
noModelSelected: '未选择模型。请运行 /model 选择模型。',
unknownTheme: '未知主题:{{theme}}',
unknownModelAlias: '未知模型别名:{{alias}}',
unsupportedEffort: '{{alias}} 不支持的思考强度 "{{arg}"。可用:{{segments}}',
unsupportedEffort: '{{alias}} 不支持的思考强度 "{{arg}}"。可用:{{segments}}',
switchModelFailed: '切换模型失败:{{msg}}',
switchSavedButDefaultFailed: '已切换到 {{name}},但保存默认设置失败:{{msg}}',
loadExperimentsFailed: '加载实验性功能失败:{{error}}',
Expand Down Expand Up @@ -1678,6 +1696,7 @@ export default {
configGithubTokenInput: '输入你的 GitHub Personal Access Token(经典版)。',
configGithubTokenSaved: 'GitHub Token 已保存。',
configGithubTokenSaveFailed: '保存 GitHub Token 失败:{{error}}',
configAstronSaveFailed: '保存 Astron 设置失败:{{error}}',
// tui/commands/dispatch.ts
configInvalidSlashCommand: '无效的斜杠命令:/{{name}}',
configVersionDisplay: 'Kimi Code v{{version}}',
Expand Down
2 changes: 1 addition & 1 deletion apps/kimi-code/src/migration/badge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { t } from '#/i18n';

export function formatImportedBadge(): string {
return t('migration.badgeImported');
return t('tui.migration.badgeImported');
}

export interface SessionLabelInput {
Expand Down
76 changes: 38 additions & 38 deletions apps/kimi-code/src/migration/migration-screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ const SPINNER_INTERVAL_MS = 80;

function stepLabels(): ReadonlyArray<readonly [string, string]> {
return [
['config', t('migration.stepLabelConfig')],
['mcp', t('migration.stepLabelMcp')],
['user-history', t('migration.stepLabelReplHistory')],
['sessions', t('migration.stepLabelSessions')],
['config', t('tui.migration.stepLabelConfig')],
['mcp', t('tui.migration.stepLabelMcp')],
['user-history', t('tui.migration.stepLabelReplHistory')],
['sessions', t('tui.migration.stepLabelSessions')],
];
}

Expand Down Expand Up @@ -285,26 +285,26 @@ export class MigrationScreenComponent extends Container implements Focusable {
const colors = this.opts.colors ?? currentTheme.palette;
const lines: string[] = [chalk.hex(colors.primary)('─'.repeat(width))];
if (this.migrationFailed) {
lines.push(chalk.hex(colors.error).bold(t('migration.failed')));
lines.push(chalk.hex(colors.error).bold(t('tui.migration.failed')));
if (this.migrationFailureReason !== undefined) {
lines.push('');
lines.push(chalk.hex(colors.text)(t('migration.reason', { reason: this.migrationFailureReason })));
lines.push(chalk.hex(colors.text)(t('tui.migration.reason', { reason: this.migrationFailureReason })));
}
lines.push('');
lines.push(chalk.hex(colors.text)(t('migration.retryHint')));
lines.push(chalk.hex(colors.text)(t('tui.migration.retryHint')));
lines.push('');
lines.push(chalk.hex(colors.textMuted)(t('migration.continueHint')));
lines.push(chalk.hex(colors.textMuted)(t('tui.migration.continueHint')));
lines.push(chalk.hex(colors.primary)('─'.repeat(width)));
return lines.map((l) => truncateToWidth(l, width));
}
const r = this.report;
lines.push(chalk.hex(colors.primary).bold(t('migration.complete')));
lines.push(chalk.hex(colors.primary).bold(t('tui.migration.complete')));
lines.push('');
if (r !== undefined) {
const sum = r.summary;
if (sum.sessions.sessionsMigrated > 0) {
lines.push(
chalk.hex(colors.success)(t('migration.sessionsMigrated', { count: String(sum.sessions.sessionsMigrated) })),
chalk.hex(colors.success)(t('tui.migration.sessionsMigrated', { count: String(sum.sessions.sessionsMigrated) })),
);
}
// Only claim a data class was migrated when the summary says it was —
Expand All @@ -316,36 +316,36 @@ export class MigrationScreenComponent extends Container implements Focusable {
if (sum.userHistory.copied > 0) migratedKinds.push('REPL history');
if (sum.skills.copied > 0) migratedKinds.push('skills');
if (migratedKinds.length > 0) {
lines.push(chalk.hex(colors.success)(t('migration.kindsMigrated', { kinds: migratedKinds.join(' · ') })));
lines.push(chalk.hex(colors.success)(t('tui.migration.kindsMigrated', { kinds: migratedKinds.join(' · ') })));
}
if (sum.sessions.sessionsMigrated === 0 && migratedKinds.length === 0) {
lines.push(chalk.hex(colors.textMuted)(t('migration.skipped')));
lines.push(chalk.hex(colors.textMuted)(t('tui.migration.skipped')));
}
if (r.notices.detectedPlugins.length > 0) {
lines.push(
chalk.hex(colors.warning)(
t('migration.pluginsNotSupported', { count: String(r.notices.detectedPlugins.length) }),
t('tui.migration.pluginsNotSupported', { count: String(r.notices.detectedPlugins.length) }),
),
);
}
if (sum.config.droppedHooks > 0) {
lines.push(
chalk.hex(colors.warning)(
t('migration.hooksDropped', { count: String(sum.config.droppedHooks) }),
t('tui.migration.hooksDropped', { count: String(sum.config.droppedHooks) }),
),
);
}
if (sum.config.configConflicts.length > 0) {
lines.push(
chalk.hex(colors.warning)(
t('migration.configConflicts', { count: String(sum.config.configConflicts.length), keys: sum.config.configConflicts.join(' · ') }),
t('tui.migration.configConflicts', { count: String(sum.config.configConflicts.length), keys: sum.config.configConflicts.join(' · ') }),
),
);
}
if (sum.config.wroteSiblingDueToConflict) {
lines.push(
chalk.hex(colors.warning)(
t('migration.configParseError'),
t('tui.migration.configParseError'),
),
);
const sc = sum.config.siblingContents;
Expand All @@ -360,41 +360,41 @@ export class MigrationScreenComponent extends Container implements Focusable {
items.push(`${sc.hooks} hook${sc.hooks === 1 ? '' : 's'}`);
}
if (items.length > 0) {
lines.push(chalk.hex(colors.warning)(t('migration.contains', { items: items.join(', ') })));
lines.push(chalk.hex(colors.warning)(t('tui.migration.contains', { items: items.join(', ') })));
}
}
if (sum.config.wroteTuiSibling) {
lines.push(
chalk.hex(colors.warning)(
t('migration.tuiConflict'),
t('tui.migration.tuiConflict'),
),
);
}
if (sum.mcp.wroteSiblingDueToConflict) {
lines.push(
chalk.hex(colors.warning)(
t('migration.mcpUnreadable'),
t('tui.migration.mcpUnreadable'),
),
);
}
if (r.notices.mcpOauthServersRequiringReauth.length > 0) {
lines.push(
chalk.hex(colors.warning)(
t('migration.mcpNeedsAuth', { count: String(r.notices.mcpOauthServersRequiringReauth.length) }),
t('tui.migration.mcpNeedsAuth', { count: String(r.notices.mcpOauthServersRequiringReauth.length) }),
),
);
}
if (sum.sessions.sessionsFailed.length > 0) {
lines.push(
chalk.hex(colors.warning)(
t('migration.sessionsFailed', { count: String(sum.sessions.sessionsFailed.length) }),
t('tui.migration.sessionsFailed', { count: String(sum.sessions.sessionsFailed.length) }),
),
);
}
if (sum.sessions.sessionsConflicts.length > 0) {
lines.push(
chalk.hex(colors.warning)(
t('migration.sessionsSkipped', { count: String(sum.sessions.sessionsConflicts.length) }),
t('tui.migration.sessionsSkipped', { count: String(sum.sessions.sessionsConflicts.length) }),
),
);
}
Expand All @@ -403,17 +403,17 @@ export class MigrationScreenComponent extends Container implements Focusable {
if (sum.sessions.sessionsSkippedEmpty > 0) {
lines.push(
chalk.hex(colors.textMuted)(
t('migration.emptySessionsSkipped', { count: String(sum.sessions.sessionsSkippedEmpty) }),
t('tui.migration.emptySessionsSkipped', { count: String(sum.sessions.sessionsSkippedEmpty) }),
),
);
}
lines.push('');
lines.push(
chalk.hex(colors.textMuted)(t('migration.oldDataKept')),
chalk.hex(colors.textMuted)(t('tui.migration.oldDataKept')),
);
}
lines.push('');
lines.push(chalk.hex(colors.textMuted)(t('migration.continueHint')));
lines.push(chalk.hex(colors.textMuted)(t('tui.migration.continueHint')));
lines.push(chalk.hex(colors.primary)('─'.repeat(width)));
return lines.map((l) => truncateToWidth(l, width));
}
Expand All @@ -423,14 +423,14 @@ export class MigrationScreenComponent extends Container implements Focusable {
const spinner = SPINNER_FRAMES[this.spinnerFrame] ?? SPINNER_FRAMES[0];
const lines: string[] = [
chalk.hex(colors.primary)('─'.repeat(width)),
chalk.hex(colors.primary).bold(t('migration.progressTitle')),
chalk.hex(colors.primary).bold(t('tui.migration.progressTitle')),
'',
];
if (this.progressTotal > 0) {
lines.push(
chalk.hex(colors.accent)(` ${spinner} `) +
chalk.hex(colors.text)(
t('migration.progressTranslating', { done: String(this.progressDone), total: String(this.progressTotal) }),
t('tui.migration.progressTranslating', { done: String(this.progressDone), total: String(this.progressTotal) }),
),
);
lines.push('');
Expand All @@ -453,11 +453,11 @@ export class MigrationScreenComponent extends Container implements Focusable {
const step = this.currentStep();
const lines: string[] = [
chalk.hex(colors.primary)('─'.repeat(width)),
chalk.hex(colors.primary).bold(t('migration.title')),
chalk.hex(colors.primary).bold(t('tui.migration.title')),
'',
];
if (this.phase === 'ask1') {
lines.push(chalk.hex(colors.text)(t('migration.foundExisting')));
lines.push(chalk.hex(colors.text)(t('tui.migration.foundExisting')));
lines.push(chalk.hex(colors.textMuted)(` ${summarizePlan(this.opts.plan)}`));
lines.push('');
}
Expand All @@ -476,7 +476,7 @@ export class MigrationScreenComponent extends Container implements Focusable {
lines.push('');
lines.push(
chalk.hex(colors.textMuted)(
t('migration.navHintAsk', { action: this.opts.skipDecisionStep === true ? 'cancel' : 'later' }),
t('tui.migration.navHintAsk', { action: this.opts.skipDecisionStep === true ? 'cancel' : 'later' }),
),
);
lines.push(chalk.hex(colors.primary)('─'.repeat(width)));
Expand Down Expand Up @@ -535,11 +535,11 @@ function summarizePlan(plan: MigrationPlan): string {
function stepFor(phase: Phase, plan: MigrationPlan): StepDef {
if (phase === 'ask1') {
return {
title: t('migration.ask1Title'),
title: t('tui.migration.ask1Title'),
options: [
{ label: t('migration.migrateNow'), value: 'now' satisfies Prompt1Choice },
{ label: t('migration.askLater'), value: 'later' satisfies Prompt1Choice },
{ label: t('migration.neverAgain'), value: 'never' satisfies Prompt1Choice },
{ label: t('tui.migration.migrateNow'), value: 'now' satisfies Prompt1Choice },
{ label: t('tui.migration.askLater'), value: 'later' satisfies Prompt1Choice },
{ label: t('tui.migration.neverAgain'), value: 'never' satisfies Prompt1Choice },
],
};
}
Expand All @@ -548,12 +548,12 @@ function stepFor(phase: Phase, plan: MigrationPlan): StepDef {
// word only (no count) when no sessions were detected.
const sessionsLabel =
plan.totalSessions > 0
? t('migration.configPlusSessions', { count: String(plan.totalSessions) })
: t('migration.configPlusAllSessions');
? t('tui.migration.configPlusSessions', { count: String(plan.totalSessions) })
: t('tui.migration.configPlusAllSessions');
return {
title: t('migration.ask2Title'),
title: t('tui.migration.ask2Title'),
options: [
{ label: t('migration.configOnly'), value: 'config-only' satisfies Prompt2Choice },
{ label: t('tui.migration.configOnly'), value: 'config-only' satisfies Prompt2Choice },
{ label: sessionsLabel, value: 'all-sessions' satisfies Prompt2Choice },
],
};
Expand Down
Loading