mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
fix(#646): translate the Pin tab names row and list it in the Settings reference
The new App Settings row had no zh-CN entry, so it read in English in a Chinese UI, and docs/wiki/Settings-Reference.md did not list it. Adds the label and description to i18n.js, a row in the Agents & CLIs table, and a JSDOM test that runs the real translator over the real index.html. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
76479fdc96
commit
8870cfc7dc
3 files changed
+70
No files matched your search
@@ -150,6 +150,7 @@ instead of its native cloud backend. See [Custom Model Endpoints](Custom-Model-E
|
|||||||
| Allowed Tools | The list used by the explicit mode. |
|
| Allowed Tools | The list used by the explicit mode. |
|
||||||
| Ralph / Todo Tracker | Enables the Ralph loop surfaces. |
|
| Ralph / Todo Tracker | Enables the Ralph loop surfaces. |
|
||||||
| Agent Teams | Experimental teams. Also needs the CLI's own environment flag. |
|
| Agent Teams | Experimental teams. Also needs the CLI's own environment flag. |
|
||||||
|
| Pin tab names on the CLI | Launches every Claude session with `--name` set to its tab name, so Claude Code's prompt label and `/resume` list match your tabs. Claude then stops generating its own titles for those sessions, and a rename in Codeman holds only until the next turn. Synced, off by default; applies from the next session start or respawn. |
|
||||||
| Codeman Agent Skill | Under **All agent CLIs**. Injects the agent skill into each new session's case, where that session's CLI looks for skills (every CLI except Pi and a plain shell). Off by default. See [The Codeman Skill](Codeman-Skill). |
|
| Codeman Agent Skill | Under **All agent CLIs**. Injects the agent skill into each new session's case, where that session's CLI looks for skills (every CLI except Pi and a plain shell). Off by default. See [The Codeman Skill](Codeman-Skill). |
|
||||||
| Remote auto-reconnect | Reattaches dropped remote SSH sessions. On by default. |
|
| Remote auto-reconnect | Reattaches dropped remote SSH sessions. On by default. |
|
||||||
| Nice priority / value | Runs agent processes at a lower CPU priority. |
|
| Nice priority / value | Runs agent processes at a lower CPU priority. |
|
||||||
|
|||||||
@@ -678,6 +678,9 @@
|
|||||||
'Claude Model': 'Claude 模型',
|
'Claude Model': 'Claude 模型',
|
||||||
'1M Opus Context': 'Opus 100 万上下文',
|
'1M Opus Context': 'Opus 100 万上下文',
|
||||||
'Remote auto-reconnect': '远程自动重连',
|
'Remote auto-reconnect': '远程自动重连',
|
||||||
|
'Pin tab names on the CLI': '在 CLI 上固定标签名',
|
||||||
|
"Launch every Claude session with its tab name, so the CLI's prompt label and /resume list match your tabs. Claude then stops generating its own titles for those sessions, and a rename in Codeman holds only until the next turn. Applies from the next session start or respawn, no server restart needed.":
|
||||||
|
'以标签名启动每个 Claude 会话,让 CLI 的提示框标签和 /resume 列表与你的标签一致。Claude 随后不再为这些会话生成自己的标题,在 Codeman 中的重命名也只保留到下一轮。从下一次会话启动或重新生成时生效,无需重启服务器。',
|
||||||
'Thinking Effort': '思考强度',
|
'Thinking Effort': '思考强度',
|
||||||
Low: '低',
|
Low: '低',
|
||||||
Medium: '中',
|
Medium: '中',
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview The "Pin tab names on the CLI" App Settings row (#646) in Chinese (zh-CN):
|
||||||
|
* its label and description run through the real translator over the real index.html in
|
||||||
|
* JSDOM, read in Chinese with no English left beyond `CLI`, `Claude`, `Codeman` and
|
||||||
|
* `/resume`, and each key is in the dictionary once (a repeated key in the object literal
|
||||||
|
* silently replaces the first).
|
||||||
|
*
|
||||||
|
* Port: N/A.
|
||||||
|
*/
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
import vm from 'node:vm';
|
||||||
|
import { JSDOM } from 'jsdom';
|
||||||
|
import { afterAll, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
const PUBLIC = resolve(import.meta.dirname, '../src/web/public');
|
||||||
|
const I18N = readFileSync(resolve(PUBLIC, 'i18n.js'), 'utf8');
|
||||||
|
const INDEX = readFileSync(resolve(PUBLIC, 'index.html'), 'utf8');
|
||||||
|
|
||||||
|
type Api = { configure(o: Record<string, string>): void; start(): void };
|
||||||
|
|
||||||
|
/** What may stay Latin: the product and CLI names and the slash command. */
|
||||||
|
const leftover = (text: string) => text.replace(/\/resume|\b(CLI|Claude|Codeman)\b/g, '').match(/[A-Za-z]+/g) ?? [];
|
||||||
|
|
||||||
|
function rowStrings(doc: Document): { label: string; description: string } {
|
||||||
|
const row = doc.getElementById('appSettingsPinCliSessionName')!.closest('.set-row')!;
|
||||||
|
return {
|
||||||
|
label: row.querySelector('.set-row-label')!.textContent!.trim(),
|
||||||
|
description: row.querySelector('.set-row-desc')!.textContent!.trim(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = new JSDOM(INDEX);
|
||||||
|
const english = rowStrings(source.window.document);
|
||||||
|
|
||||||
|
const dom = new JSDOM(INDEX, { runScripts: 'outside-only', url: 'http://localhost/' });
|
||||||
|
vm.runInContext(I18N, dom.getInternalVMContext(), { filename: 'i18n.js' });
|
||||||
|
const api = (dom.window as unknown as { CodemanI18n: Api }).CodemanI18n;
|
||||||
|
api.start();
|
||||||
|
api.configure({ language: 'zh-CN' });
|
||||||
|
const chinese = rowStrings(dom.window.document);
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
source.window.close();
|
||||||
|
dom.window.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('the Pin tab names on the CLI row in zh-CN', () => {
|
||||||
|
it('finds the row (the check is not vacuous)', () => {
|
||||||
|
expect(english.label).toBe('Pin tab names on the CLI');
|
||||||
|
expect(english.description).toMatch(/^Launch every Claude session with its tab name/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('translates the label and the description, with no English left', () => {
|
||||||
|
for (const key of ['label', 'description'] as const) {
|
||||||
|
expect(chinese[key]).not.toBe(english[key]);
|
||||||
|
expect(leftover(chinese[key])).toEqual([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds each key to the dictionary once', () => {
|
||||||
|
for (const text of [english.label, english.description]) {
|
||||||
|
expect(I18N.split(`'${text}'`).length + I18N.split(`"${text}"`).length - 2).toBe(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user