diff --git a/claude-plugin/skills/academy-terms/data/terms.ja.json b/claude-plugin/skills/academy-terms/data/terms.ja.json index aaab603..fe3cd91 100644 --- a/claude-plugin/skills/academy-terms/data/terms.ja.json +++ b/claude-plugin/skills/academy-terms/data/terms.ja.json @@ -15,11 +15,7 @@ "クロード" ], "Anthropic": [ - "アンスロピック", - "人間", - "人間的", - "人為的", - "人類の" + "アンスロピック" ], "Anthropic Academy": [ "Anthropic Academy" @@ -27,9 +23,6 @@ "Enterprise": [ "エンタープライズ" ], - "Personal": [ - "個人" - ], "Plugin": [ "プラグイン" ], @@ -70,15 +63,12 @@ "フック" ], "Cowork": [ - "コワーク", - "共同作業" + "コワーク" ], "Dispatch": [ - "ディスパッチ", - "派遣" + "ディスパッチ" ], "Computer Use": [ - "コンピュータ使用", "コンピュータユース" ] }, diff --git a/claude-plugin/skills/academy-terms/data/terms.ko.json b/claude-plugin/skills/academy-terms/data/terms.ko.json index fe023f9..918645c 100644 --- a/claude-plugin/skills/academy-terms/data/terms.ko.json +++ b/claude-plugin/skills/academy-terms/data/terms.ko.json @@ -11,28 +11,21 @@ "Claude Code": [ "클로드 코드", "클로드 Code", - "클로우드 코드", - "클라우드 코드" + "클로우드 코드" ], "Claude": [ "클로드", - "클로우드", - "클라우드" + "클로우드" ], "Anthropic Academy": [ "앤스로픽 아카데미", "앤트로픽 아카데미", - "안트로픽 아카데미", - "인류학적 아카데미" + "안트로픽 아카데미" ], "Anthropic": [ "앤스로픽", "앤트로픽", - "안트로픽", - "인류학적", - "인간적인", - "인류", - "인간적" + "안트로픽" ], "Enterprise > Personal > Project > Plugins": [ "기업 > 개인 > 프로젝트 > 플러그인", @@ -42,12 +35,6 @@ "기업 → 개인 → 프로젝트 → 플러그인", "엔터프라이즈 → 개인 → 프로젝트 → 플러그인" ], - "Enterprise": [ - "기업" - ], - "Personal": [ - "개인적인" - ], "Plugin": [ "플러그인" ], @@ -55,26 +42,20 @@ "플러그인들" ], "skill": [ - "기술", "스킬" ], "skills": [ - "기술들", - "스킬들", - "기술" + "스킬들" ], "Skills": [ - "스킬들", - "기술들" + "스킬들" ], "SKILL.md": [ "스킬.md", "기술.md" ], "frontmatter": [ - "프론트매터", - "앞부분", - "서문" + "프론트매터" ], "CLAUDE.md": [ "클로드.md" @@ -97,16 +78,12 @@ "후크" ], "Cowork": [ - "코워크", - "공동작업", - "협업" + "코워크" ], "Dispatch": [ - "디스패치", - "발송" + "디스패치" ], "Computer Use": [ - "컴퓨터 사용", "컴퓨터 유즈" ] }, diff --git a/claude-plugin/skills/academy-terms/data/terms.zh-CN.json b/claude-plugin/skills/academy-terms/data/terms.zh-CN.json index 98b392f..102e448 100644 --- a/claude-plugin/skills/academy-terms/data/terms.zh-CN.json +++ b/claude-plugin/skills/academy-terms/data/terms.zh-CN.json @@ -16,22 +16,11 @@ "克劳德" ], "Anthropic": [ - "人类学", - "安特罗皮克", - "人为的", - "人类的", - "人为", - "拟人" + "安特罗皮克" ], "Anthropic Academy": [ "Anthropic Academy" ], - "Enterprise": [ - "企业" - ], - "Personal": [ - "个人" - ], "Plugin": [ "插件" ], @@ -50,9 +39,6 @@ "SKILL.md": [ "SKILL.md" ], - "frontmatter": [ - "前言" - ], "CLAUDE.md": [ "CLAUDE.md" ], @@ -72,18 +58,6 @@ "hooks": [ "钩子", "挂钩" - ], - "Cowork": [ - "协作", - "共同工作" - ], - "Dispatch": [ - "调度", - "分派" - ], - "Computer Use": [ - "电脑使用", - "计算机使用" ] }, "terms": { diff --git a/claude-plugin/skills/academy-terms/data/terms.zh-TW.json b/claude-plugin/skills/academy-terms/data/terms.zh-TW.json index cadf7f5..ef9fce1 100644 --- a/claude-plugin/skills/academy-terms/data/terms.zh-TW.json +++ b/claude-plugin/skills/academy-terms/data/terms.zh-TW.json @@ -16,22 +16,11 @@ "克洛德" ], "Anthropic": [ - "人類學", - "安特羅皮克", - "人為的", - "人類的", - "人為", - "擬人" + "安特羅皮克" ], "Anthropic Academy": [ "Anthropic Academy" ], - "Enterprise": [ - "企業" - ], - "Personal": [ - "個人" - ], "Plugin": [ "外掛程式" ], @@ -50,9 +39,6 @@ "SKILL.md": [ "SKILL.md" ], - "frontmatter": [ - "前言" - ], "CLAUDE.md": [ "CLAUDE.md" ], @@ -72,18 +58,6 @@ "hooks": [ "鉤子", "掛鉤" - ], - "Cowork": [ - "協作", - "共同工作" - ], - "Dispatch": [ - "調度", - "分派" - ], - "Computer Use": [ - "電腦使用", - "計算機使用" ] }, "terms": { diff --git a/src/data/ja.json b/src/data/ja.json index 591b5ac..c97631f 100644 --- a/src/data/ja.json +++ b/src/data/ja.json @@ -1131,66 +1131,27 @@ "Peer learning strategies": "ピアラーニング戦略" }, "_protected": { - "Claude Code": [ - "クロードコード" - ], - "Claude": [ - "クロード" - ], - "Anthropic": [ - "アンスロピック", "人間", "人間的", "人為的", "人類の" - ], - "Anthropic Academy": [ - "Anthropic Academy" - ], - "Enterprise": [ - "エンタープライズ" - ], - "Personal": [ - "個人" - ], - "Plugin": [ - "プラグイン" - ], - "Plugins": [ - "プラグイン" - ], - "skill": [ - "スキル" - ], - "skills": [ - "スキル" - ], - "Skills": [ - "スキル" - ], - "SKILL.md": [ - "SKILL.md" - ], - "frontmatter": [ - "フロントマター" - ], - "CLAUDE.md": [ - "CLAUDE.md" - ], - "YAML": [ - "YAML" - ], - "slash command": [ - "スラッシュコマンド" - ], - "subagent": [ - "サブエージェント" - ], - "hook": [ - "フック" - ], - "hooks": [ - "フック" - ], - "Cowork": ["コワーク", "共同作業"], - "Dispatch": ["ディスパッチ", "派遣"], - "Computer Use": ["コンピュータ使用", "コンピュータユース"] + "Claude Code": ["クロードコード"], + "Claude": ["クロード"], + "Anthropic": ["アンスロピック"], + "Anthropic Academy": ["Anthropic Academy"], + "Enterprise": ["エンタープライズ"], + "Plugin": ["プラグイン"], + "Plugins": ["プラグイン"], + "skill": ["スキル"], + "skills": ["スキル"], + "Skills": ["スキル"], + "SKILL.md": ["SKILL.md"], + "frontmatter": ["フロントマター"], + "CLAUDE.md": ["CLAUDE.md"], + "YAML": ["YAML"], + "slash command": ["スラッシュコマンド"], + "subagent": ["サブエージェント"], + "hook": ["フック"], + "hooks": ["フック"], + "Cowork": ["コワーク"], + "Dispatch": ["ディスパッチ"], + "Computer Use": ["コンピュータユース"] }, "exam_ui": { "Pass": "合格", diff --git a/src/data/ko.json b/src/data/ko.json index 4319cde..fde0031 100644 --- a/src/data/ko.json +++ b/src/data/ko.json @@ -1131,30 +1131,28 @@ "Peer learning strategies": "동료 학습 전략" }, "_protected": { - "Claude Code": ["클로드 코드", "클로드 Code", "클로우드 코드", "클라우드 코드"], - "Claude": ["클로드", "클로우드", "클라우드"], - "Anthropic Academy": ["앤스로픽 아카데미", "앤트로픽 아카데미", "안트로픽 아카데미", "인류학적 아카데미"], - "Anthropic": ["앤스로픽", "앤트로픽", "안트로픽", "인류학적", "인간적인", "인류", "인간적"], + "Claude Code": ["클로드 코드", "클로드 Code", "클로우드 코드"], + "Claude": ["클로드", "클로우드"], + "Anthropic Academy": ["앤스로픽 아카데미", "앤트로픽 아카데미", "안트로픽 아카데미"], + "Anthropic": ["앤스로픽", "앤트로픽", "안트로픽"], "Enterprise > Personal > Project > Plugins": ["기업 > 개인 > 프로젝트 > 플러그인", "엔터프라이즈 > 개인 > 프로젝트 > 플러그인"], "Enterprise → Personal → Project → Plugins": ["기업 → 개인 → 프로젝트 → 플러그인", "엔터프라이즈 → 개인 → 프로젝트 → 플러그인"], - "Enterprise": ["기업"], - "Personal": ["개인적인"], "Plugin": ["플러그인"], "Plugins": ["플러그인들"], - "skill": ["기술", "스킬"], - "skills": ["기술들", "스킬들", "기술"], - "Skills": ["스킬들", "기술들"], + "skill": ["스킬"], + "skills": ["스킬들"], + "Skills": ["스킬들"], "SKILL.md": ["스킬.md", "기술.md"], - "frontmatter": ["프론트매터", "앞부분", "서문"], + "frontmatter": ["프론트매터"], "CLAUDE.md": ["클로드.md"], "YAML": ["야멜"], "slash command": ["슬래시 명령"], "subagent": ["하위 에이전트", "서브에이전트"], "hook": ["후크"], "hooks": ["후크들", "후크"], - "Cowork": ["코워크", "공동작업", "협업"], - "Dispatch": ["디스패치", "발송"], - "Computer Use": ["컴퓨터 사용", "컴퓨터 유즈"] + "Cowork": ["코워크"], + "Dispatch": ["디스패치"], + "Computer Use": ["컴퓨터 유즈"] }, "exam_ui": { "Pass": "합격", diff --git a/src/data/zh-CN.json b/src/data/zh-CN.json index a9183da..9495309 100644 --- a/src/data/zh-CN.json +++ b/src/data/zh-CN.json @@ -1131,69 +1131,22 @@ "Peer learning strategies": "同伴学习策略" }, "_protected": { - "Claude Code": [ - "克洛德代码" - ], - "Claude": [ - "克洛德", - "克劳德" - ], - "Anthropic": [ - "人类学", "安特罗皮克", "人为的", "人类的", "人为", "拟人" - ], - "Anthropic Academy": [ - "Anthropic Academy" - ], - "Enterprise": [ - "企业" - ], - "Personal": [ - "个人" - ], - "Plugin": [ - "插件" - ], - "Plugins": [ - "插件" - ], - "skill": [ - "技能" - ], - "skills": [ - "技能" - ], - "Skills": [ - "技能" - ], - "SKILL.md": [ - "SKILL.md" - ], - "frontmatter": [ - "前言" - ], - "CLAUDE.md": [ - "CLAUDE.md" - ], - "YAML": [ - "YAML" - ], - "slash command": [ - "斜杠命令" - ], - "subagent": [ - "子代理" - ], - "hook": [ - "钩子", - "挂钩" - ], - "hooks": [ - "钩子", - "挂钩" - ], - "Cowork": ["协作", "共同工作"], - "Dispatch": ["调度", "分派"], - "Computer Use": ["电脑使用", "计算机使用"] + "Claude Code": ["克洛德代码"], + "Claude": ["克洛德", "克劳德"], + "Anthropic": ["安特罗皮克"], + "Anthropic Academy": ["Anthropic Academy"], + "Plugin": ["插件"], + "Plugins": ["插件"], + "skill": ["技能"], + "skills": ["技能"], + "Skills": ["技能"], + "SKILL.md": ["SKILL.md"], + "CLAUDE.md": ["CLAUDE.md"], + "YAML": ["YAML"], + "slash command": ["斜杠命令"], + "subagent": ["子代理"], + "hook": ["钩子", "挂钩"], + "hooks": ["钩子", "挂钩"] }, "exam_ui": { "Pass": "通过", diff --git a/src/data/zh-TW.json b/src/data/zh-TW.json index a876f10..768bfa8 100644 --- a/src/data/zh-TW.json +++ b/src/data/zh-TW.json @@ -1131,69 +1131,22 @@ "Peer learning strategies": "同儕學習策略" }, "_protected": { - "Claude Code": [ - "克勞德代碼" - ], - "Claude": [ - "克勞德", - "克洛德" - ], - "Anthropic": [ - "人類學", "安特羅皮克", "人為的", "人類的", "人為", "擬人" - ], - "Anthropic Academy": [ - "Anthropic Academy" - ], - "Enterprise": [ - "企業" - ], - "Personal": [ - "個人" - ], - "Plugin": [ - "外掛程式" - ], - "Plugins": [ - "外掛程式" - ], - "skill": [ - "技能" - ], - "skills": [ - "技能" - ], - "Skills": [ - "技能" - ], - "SKILL.md": [ - "SKILL.md" - ], - "frontmatter": [ - "前言" - ], - "CLAUDE.md": [ - "CLAUDE.md" - ], - "YAML": [ - "YAML" - ], - "slash command": [ - "斜線命令" - ], - "subagent": [ - "子代理" - ], - "hook": [ - "鉤子", - "掛鉤" - ], - "hooks": [ - "鉤子", - "掛鉤" - ], - "Cowork": ["協作", "共同工作"], - "Dispatch": ["調度", "分派"], - "Computer Use": ["電腦使用", "計算機使用"] + "Claude Code": ["克勞德代碼"], + "Claude": ["克勞德", "克洛德"], + "Anthropic": ["安特羅皮克"], + "Anthropic Academy": ["Anthropic Academy"], + "Plugin": ["外掛程式"], + "Plugins": ["外掛程式"], + "skill": ["技能"], + "skills": ["技能"], + "Skills": ["技能"], + "SKILL.md": ["SKILL.md"], + "CLAUDE.md": ["CLAUDE.md"], + "YAML": ["YAML"], + "slash command": ["斜線命令"], + "subagent": ["子代理"], + "hook": ["鉤子", "掛鉤"], + "hooks": ["鉤子", "掛鉤"] }, "exam_ui": { "Pass": "通過", diff --git a/tests/e2e/helpers/network-stubs.js b/tests/e2e/helpers/network-stubs.js index 7dd3777..8dd9fd8 100644 --- a/tests/e2e/helpers/network-stubs.js +++ b/tests/e2e/helpers/network-stubs.js @@ -88,14 +88,16 @@ const GT_KO = { 'Key concepts': '핵심 개념', 'A prompt is the input you give to Claude. Better prompts produce better responses.': '프롬프트는 Claude에게 주는 입력입니다. 더 나은 프롬프트는 더 나은 응답을 만듭니다.', - // DELIBERATELY mistranslated entry. "Anthropic" → "인류학적" and + // DELIBERATELY mistranslated entry. "Anthropic" → "앤스로픽" and // "Claude" → "클로드" are exactly the GT mistakes the // src/data/ko.json `_protected` map exists to fix. protected-terms.js // runs `restoreProtectedTerms()` on every GT batch result before it // reaches the DOM, so the user should see "Anthropic" + "Claude" — NOT // the wrong forms below. tests/e2e/protected-terms.spec.js asserts - // exactly that. - 'Anthropic released Claude as a frontier model.': '인류학적은 클로드를 프런티어 모델로 출시했습니다.', + // exactly that. (NB: 앤스로픽 is a transliteration, not a real word — the + // ambiguous common-word wrong-forms like 인류학적/인류 were removed from the + // dictionary because they corrupt correct prose; see protected-terms.test.js.) + 'Anthropic released Claude as a frontier model.': '앤스로픽은 클로드를 프런티어 모델로 출시했습니다.', // Code-comment fixture (tests/e2e/code-comments.spec.js). The Python // `# This is a Claude prompt example` comment gets translated by // translateCodeComments — the line's leading `# ` is preserved diff --git a/tests/e2e/protected-terms.spec.js b/tests/e2e/protected-terms.spec.js index 791bacb..72943ce 100644 --- a/tests/e2e/protected-terms.spec.js +++ b/tests/e2e/protected-terms.spec.js @@ -3,8 +3,8 @@ * * `protected-terms.js` is the post-processing pass that fixes Google * Translate's brand-name / technical-term mistakes ("Anthropic" → - * "인류학적" gets restored back to "Anthropic", "Claude" → "클로드" gets - * restored back to "Claude", etc). The 24 unit tests in + * "앤스로픽" gets restored back to "Anthropic", "Claude" → "클로드" gets + * restored back to "Claude", etc). The unit tests in * `tests/protected-terms.test.js` cover the function in isolation. But * the function only matters if `gt-queue.js` actually invokes it on every * GT result before the DOM write — and there's been no end-to-end proof @@ -19,7 +19,7 @@ * mistranslation. * * Three assertions, ranked by importance: - * 1. Wrong forms ("인류학적", "클로드") are NOT in the DOM. + * 1. Wrong forms ("앤스로픽", "클로드") are NOT in the DOM. * 2. Correct forms ("Anthropic", "Claude") ARE in the DOM. * 3. The surrounding Korean translation is intact (proving we didn't * accidentally revert the WHOLE GT result). @@ -81,7 +81,7 @@ test.describe('SkillBridge — protected terms restoration', () => { // 1. The wrong forms the GT stub deliberately returned must NOT make it // to the user. If protected-terms.js's `restoreProtectedTerms` was // bypassed or no longer hooked into gt-queue.js, these would land. - expect.soft(pt.pProtected, '인류학적 (anthropological) wrong form').not.toContain('인류학적'); + expect.soft(pt.pProtected, '앤스로픽 (Anthropic transliteration) wrong form').not.toContain('앤스로픽'); expect.soft(pt.pProtected, '클로드 wrong form').not.toContain('클로드'); // 2. The English brand names must appear in their correct form, restored diff --git a/tests/protected-terms.test.js b/tests/protected-terms.test.js index e950ddd..d26e91b 100644 --- a/tests/protected-terms.test.js +++ b/tests/protected-terms.test.js @@ -191,3 +191,56 @@ describe('Protected Terms System (real production code)', () => { }); }); }); + +// Regression guard for the corruption class documented in protected-terms.js: +// restoreProtectedTerms does an unanchored replaceAll with no CJK word boundary, +// so any _protected wrong-form that is itself a common standalone word silently +// corrupts correct prose (e.g. 클라우드 "Cloud" -> Claude, 인류 "humanity" -> +// Anthropic, 大型企业 "large enterprise" -> 大型Enterprise). This runs against the +// REAL shipped src/data/*.json (not a fixture), so it fails if a dangerous +// wrong-form is ever (re-)introduced into a CJK dictionary's _protected section. +describe('no corruption of correct CJK prose (real shipped dictionaries)', () => { + // Each sentence is ordinary target-language prose containing a word that used + // to be a dangerous wrong-form. After the fix it must pass through untouched. + const cases = { + ko: [ + '클라우드 컴퓨팅은 확장 가능합니다', // Cloud (was -> Claude) + '인류의 미래를 생각합니다', // humanity (was -> Anthropic) + '대기업 환경에서 일합니다', // large enterprise (was -> 대Enterprise) + '기술자가 필요합니다', // technician (was -> skill자) + '우리는 협업합니다', // collaborate (was -> Cowork) + '문서의 앞부분을 읽으세요', // front part (was -> frontmatter) + '개인적인 의견입니다', // personal opinion (was -> Personal) + ], + ja: [ + '人類の未来を考える', // humanity (was -> Anthropic) + '個人的な意見です', // personal (was -> Personal) + '共同作業のスペース', // joint work (was -> Cowork) + ], + 'zh-CN': [ + '人类的未来', // humanity (was -> Anthropic) + '大型企业环境', // large enterprise (was -> Enterprise) + '任务调度系统', // task scheduling (was -> Dispatch) + '个人观点', // personal view (was -> Personal) + '团队协作', // team collaboration (was -> Cowork) + ], + 'zh-TW': [ + '人類的未來', // humanity (was -> Anthropic) + '大型企業環境', // large enterprise (was -> Enterprise) + '任務調度系統', // task scheduling (was -> Dispatch) + '個人觀點', // personal view (was -> Personal) + '團隊協作', // team collaboration (was -> Cowork) + ], + }; + + for (const [lang, sentences] of Object.entries(cases)) { + test(`${lang}: correct prose is not corrupted by protected-term restoration`, () => { + const dict = require(`../src/data/${lang}.json`); + resetProtectedTerms(); + buildProtectedTermsMap(lang, fakeTranslator(dict._protected)); + for (const sentence of sentences) { + expect(restoreProtectedTerms(sentence)).toBe(sentence); + } + }); + } +});