mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
fix: translate the Allow network access warning into Chinese (release review)
That description is the only warning that the switch weakens Codex's sandbox, and it had no zh-CN entry. The test runs the real translator over the real index.html. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
029378eb98
commit
20b62d68b8
2 files changed
+71
No files matched your search
@@ -55,6 +55,9 @@
|
||||
'应用于新本地会话;可用强度取决于模型和 Codex 版本。自定义端点、Docker 和远程会话保留自己的设置。',
|
||||
'Default Codex model may only contain letters, digits, ".", "_", "-" and "/"':
|
||||
'Codex 默认模型只能包含字母、数字、"."、"_"、"-" 和 "/"',
|
||||
'Allow network access': '允许网络访问',
|
||||
"Lets commands in Codex's workspace-write sandbox use the network, which the Codeman skill needs to reach this server. Those commands can then call Codeman's API, which can start a session outside the sandbox with no approval prompt, even when a password is set. So with this on, Codex's sandbox does not contain a prompt-injected command: treat it as close to Bypass. Applies to every new local Codex session, not scheduled jobs. It does not change Codex's sandbox mode: a folder Codex runs read-only (one it does not trust) keeps the network closed and asks per command.":
|
||||
'允许 Codex 的 workspace-write 沙箱中的命令使用网络,Codeman 技能需要网络才能连接到此服务器。这些命令随后可以调用 Codeman 的 API,而该 API 可以在沙箱之外启动会话且不弹出审批提示,即使设置了密码也是如此。因此开启后,Codex 的沙箱无法约束被提示注入的命令:请把它视为接近“绕过审批与沙箱”。应用于所有新的本地 Codex 会话,不包括定时任务。它不会改变 Codex 的沙箱模式:Codex 以只读方式运行的文件夹(即它不信任的文件夹)仍会保持网络关闭,并逐条命令询问。',
|
||||
'Skip to terminal': '跳转到终端',
|
||||
'Go to main page': '返回主页',
|
||||
'Session tabs': '会话标签页',
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @fileoverview The Codex "Allow network access" row (App Settings → Codex) in Chinese (zh-CN).
|
||||
* That description is the only warning a user gets that the switch weakens Codex's sandbox, so
|
||||
* it must read in Chinese, through the real translator over the real index.html in JSDOM, with
|
||||
* no English left beyond product names and the `workspace-write` mode name, and each key must be
|
||||
* in the dictionary exactly 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');
|
||||
const ROW_INPUT = 'appSettingsCodexNetworkAccess';
|
||||
|
||||
type Api = { configure(o: Record<string, string>): void; start(): void };
|
||||
|
||||
/** What may stay Latin: the product names, the API acronym and codex's own sandbox mode name. */
|
||||
const leftover = (text: string) =>
|
||||
text.replace(/workspace-write|\b(Codex|Codeman|API)\b/g, '').match(/[A-Za-z]+/g) ?? [];
|
||||
|
||||
function rowStrings(doc: Document): { label: string; description: string } {
|
||||
const row = doc.getElementById(ROW_INPUT)!.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 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' });
|
||||
|
||||
afterAll(() => {
|
||||
source.window.close();
|
||||
dom.window.close();
|
||||
});
|
||||
|
||||
describe('the Allow network access row in zh-CN', () => {
|
||||
const english = rowStrings(source.window.document);
|
||||
const chinese = rowStrings(dom.window.document);
|
||||
|
||||
it.each(['label', 'description'] as const)('translates the %s, with no English left', (key) => {
|
||||
expect(english[key].length).toBeGreaterThan(0);
|
||||
expect(chinese[key]).not.toBe(english[key]);
|
||||
expect(leftover(chinese[key])).toEqual([]);
|
||||
});
|
||||
|
||||
it('keeps the warning that the setting is close to Bypass', () => {
|
||||
expect(chinese.description).toContain('绕过审批与沙箱');
|
||||
});
|
||||
|
||||
it('adds each key to the dictionary once', () => {
|
||||
for (const text of Object.values(english)) {
|
||||
const quoted = text.includes("'") ? JSON.stringify(text) : `'${text}'`;
|
||||
expect(I18N.split(`${quoted}:`).length - 1).toBe(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user