feat(installer): add --locale flag for translated docs installation

Adds `--locale <code>` support to the ECC installer so users can install
localized reference docs (agents, commands, skills, rules) into
`~/.claude/docs/<locale>/` alongside the existing English installation.

Changes:
- manifests/install-modules.json: add 8 locale doc modules (docs-ja-JP,
  docs-zh-CN, docs-ko-KR, docs-pt-BR, docs-ru, docs-tr, docs-vi-VN,
  docs-zh-TW), each with kind="docs" and defaultInstall=false
- manifests/install-components.json: add 8 locale: components mapping to
  the new modules
- scripts/lib/install-manifests.js: add locale: family prefix,
  SUPPORTED_LOCALES, LOCALE_ALIAS_TO_COMPONENT_ID (with aliases like
  ja=ja-JP, zh=zh-CN, ko=ko-KR), and listSupportedLocales()
- scripts/lib/install/request.js: add --locale flag to parseInstallArgs(),
  resolve locale alias → component ID in normalizeInstallRequest(), throw
  on unsupported locale codes
- scripts/lib/install-targets/claude-home.js: map docs/<locale>/ source
  paths to ~/.claude/docs/<locale>/ destination (side-by-side, no overwrite
  of English files)
- scripts/install-apply.js: import listSupportedLocales, add --locale
  usage line and available locales list to --help output

Usage examples:
  ./install.sh --locale ja                    # Japanese docs only
  ./install.sh --profile core --locale zh-CN  # core profile + zh-CN docs
  ./install.sh typescript --locale ja         # legacy + locale (errors)
This commit is contained in:
Claude
2026-05-18 07:57:10 +09:00
committed by Affaan Mustafa
parent 519c592a12
commit 71aedad889
6 changed files with 234 additions and 2 deletions

View File

@@ -525,6 +525,70 @@
"modules": [ "modules": [
"machine-learning" "machine-learning"
] ]
},
{
"id": "locale:ja",
"family": "locale",
"description": "Japanese (ja-JP) translated reference docs installed to ~/.claude/docs/ja-JP/.",
"modules": [
"docs-ja-JP"
]
},
{
"id": "locale:zh-CN",
"family": "locale",
"description": "Simplified Chinese (zh-CN) translated reference docs installed to ~/.claude/docs/zh-CN/.",
"modules": [
"docs-zh-CN"
]
},
{
"id": "locale:ko-KR",
"family": "locale",
"description": "Korean (ko-KR) translated reference docs installed to ~/.claude/docs/ko-KR/.",
"modules": [
"docs-ko-KR"
]
},
{
"id": "locale:pt-BR",
"family": "locale",
"description": "Brazilian Portuguese (pt-BR) translated reference docs installed to ~/.claude/docs/pt-BR/.",
"modules": [
"docs-pt-BR"
]
},
{
"id": "locale:ru",
"family": "locale",
"description": "Russian (ru) translated reference docs installed to ~/.claude/docs/ru/.",
"modules": [
"docs-ru"
]
},
{
"id": "locale:tr",
"family": "locale",
"description": "Turkish (tr) translated reference docs installed to ~/.claude/docs/tr/.",
"modules": [
"docs-tr"
]
},
{
"id": "locale:vi-VN",
"family": "locale",
"description": "Vietnamese (vi-VN) translated reference docs installed to ~/.claude/docs/vi-VN/.",
"modules": [
"docs-vi-VN"
]
},
{
"id": "locale:zh-TW",
"family": "locale",
"description": "Traditional Chinese (zh-TW) translated reference docs installed to ~/.claude/docs/zh-TW/.",
"modules": [
"docs-zh-TW"
]
} }
] ]
} }

View File

@@ -693,6 +693,126 @@
"defaultInstall": false, "defaultInstall": false,
"cost": "medium", "cost": "medium",
"stability": "stable" "stability": "stable"
},
{
"id": "docs-ja-JP",
"kind": "docs",
"description": "Japanese (ja-JP) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/ja-JP"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-zh-CN",
"kind": "docs",
"description": "Simplified Chinese (zh-CN) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/zh-CN"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-ko-KR",
"kind": "docs",
"description": "Korean (ko-KR) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/ko-KR"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-pt-BR",
"kind": "docs",
"description": "Brazilian Portuguese (pt-BR) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/pt-BR"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-ru",
"kind": "docs",
"description": "Russian (ru) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/ru"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-tr",
"kind": "docs",
"description": "Turkish (tr) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/tr"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-vi-VN",
"kind": "docs",
"description": "Vietnamese (vi-VN) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/vi-VN"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
},
{
"id": "docs-zh-TW",
"kind": "docs",
"description": "Traditional Chinese (zh-TW) translated reference docs for agents, commands, skills, and rules.",
"paths": [
"docs/zh-TW"
],
"targets": [
"claude"
],
"dependencies": [],
"defaultInstall": false,
"cost": "heavy",
"stability": "stable"
} }
] ]
} }

View File

@@ -10,6 +10,7 @@ const os = require('os');
const { const {
SUPPORTED_INSTALL_TARGETS, SUPPORTED_INSTALL_TARGETS,
listLegacyCompatibilityLanguages, listLegacyCompatibilityLanguages,
listSupportedLocales,
} = require('./lib/install-manifests'); } = require('./lib/install-manifests');
const { const {
LEGACY_INSTALL_TARGETS, LEGACY_INSTALL_TARGETS,
@@ -19,12 +20,14 @@ const {
function getHelpText() { function getHelpText() {
const languages = listLegacyCompatibilityLanguages(); const languages = listLegacyCompatibilityLanguages();
const locales = listSupportedLocales();
return ` return `
Usage: install.sh [--target <${LEGACY_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] <language> [<language> ...] Usage: install.sh [--target <${LEGACY_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] <language> [<language> ...]
install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --profile <name> [--with <component>]... [--without <component>]... install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --profile <name> [--with <component>]... [--without <component>]...
install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --modules <id,id,...> [--with <component>]... [--without <component>]... install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --modules <id,id,...> [--with <component>]... [--without <component>]...
install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --skills <skill-id[,skill-id...]> install.sh [--target <${SUPPORTED_INSTALL_TARGETS.join('|')}>] [--dry-run] [--json] --skills <skill-id[,skill-id...]>
install.sh [--target claude] [--dry-run] [--json] --locale <locale-code>
install.sh [--dry-run] [--json] --config <path> install.sh [--dry-run] [--json] --config <path>
Targets: Targets:
@@ -46,6 +49,8 @@ Options:
--skills <ids> Install one or more skill directories by ID, e.g. continuous-learning-v2 --skills <ids> Install one or more skill directories by ID, e.g. continuous-learning-v2
--without <component> --without <component>
Exclude a user-facing install component Exclude a user-facing install component
--locale <code> Install translated docs to ~/.claude/docs/<locale>/
(claude target only; can be combined with --profile or --with)
--config <path> Load install intent from ecc-install.json --config <path> Load install intent from ecc-install.json
--dry-run Show the install plan without copying files --dry-run Show the install plan without copying files
--json Emit machine-readable plan/result JSON --json Emit machine-readable plan/result JSON
@@ -53,6 +58,9 @@ Options:
Available languages: Available languages:
${languages.map(language => ` - ${language}`).join('\n')} ${languages.map(language => ` - ${language}`).join('\n')}
Available locales (--locale):
${locales.map(locale => ` - ${locale}`).join('\n')}
`; `;
} }

View File

@@ -12,7 +12,28 @@ const COMPONENT_FAMILY_PREFIXES = {
capability: 'capability:', capability: 'capability:',
agent: 'agent:', agent: 'agent:',
skill: 'skill:', skill: 'skill:',
locale: 'locale:',
}; };
const SUPPORTED_LOCALES = Object.freeze(['ja', 'zh-CN', 'ko-KR', 'pt-BR', 'ru', 'tr', 'vi-VN', 'zh-TW']);
const LOCALE_ALIAS_TO_COMPONENT_ID = Object.freeze({
'ja': 'locale:ja',
'ja-JP': 'locale:ja',
'zh-CN': 'locale:zh-CN',
'zh': 'locale:zh-CN',
'ko-KR': 'locale:ko-KR',
'ko': 'locale:ko-KR',
'pt-BR': 'locale:pt-BR',
'pt': 'locale:pt-BR',
'ru': 'locale:ru',
'tr': 'locale:tr',
'vi-VN': 'locale:vi-VN',
'vi': 'locale:vi-VN',
'zh-TW': 'locale:zh-TW',
});
function listSupportedLocales() {
return [...SUPPORTED_LOCALES];
}
const LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET = Object.freeze({ const LEGACY_COMPAT_BASE_MODULE_IDS_BY_TARGET = Object.freeze({
claude: [ claude: [
'rules-core', 'rules-core',
@@ -607,11 +628,14 @@ function resolveInstallPlan(options = {}) {
module.exports = { module.exports = {
DEFAULT_REPO_ROOT, DEFAULT_REPO_ROOT,
SUPPORTED_INSTALL_TARGETS, SUPPORTED_INSTALL_TARGETS,
SUPPORTED_LOCALES,
LOCALE_ALIAS_TO_COMPONENT_ID,
getManifestPaths, getManifestPaths,
loadInstallManifests, loadInstallManifests,
getInstallComponent, getInstallComponent,
listInstallComponents, listInstallComponents,
listLegacyCompatibilityLanguages, listLegacyCompatibilityLanguages,
listSupportedLocales,
listInstallModules, listInstallModules,
listInstallProfiles, listInstallProfiles,
resolveInstallPlan, resolveInstallPlan,

View File

@@ -39,6 +39,10 @@ function getClaudeManagedDestinationPath(adapter, sourceRelativePath, input) {
); );
} }
if (normalizedSourcePath === 'docs' || normalizedSourcePath.startsWith('docs/')) {
return path.join(targetRoot, normalizedSourcePath);
}
return null; return null;
} }

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const { validateInstallModuleIds } = require('../install-manifests'); const { validateInstallModuleIds, LOCALE_ALIAS_TO_COMPONENT_ID, listSupportedLocales } = require('../install-manifests');
const LEGACY_INSTALL_TARGETS = ['claude', 'cursor', 'antigravity']; const LEGACY_INSTALL_TARGETS = ['claude', 'cursor', 'antigravity'];
@@ -27,6 +27,7 @@ function parseInstallArgs(argv) {
includeComponentIds: [], includeComponentIds: [],
excludeComponentIds: [], excludeComponentIds: [],
languages: [], languages: [],
locale: null,
}; };
for (let index = 0; index < args.length; index += 1) { for (let index = 0; index < args.length; index += 1) {
@@ -60,6 +61,9 @@ function parseInstallArgs(argv) {
parsed.excludeComponentIds.push(componentId.trim()); parsed.excludeComponentIds.push(componentId.trim());
} }
index += 1; index += 1;
} else if (arg === '--locale') {
parsed.locale = args[index + 1] || null;
index += 1;
} else if (arg === '--dry-run') { } else if (arg === '--dry-run') {
parsed.dryRun = true; parsed.dryRun = true;
} else if (arg === '--json') { } else if (arg === '--json') {
@@ -84,9 +88,17 @@ function normalizeInstallRequest(options = {}) {
const moduleIds = validateInstallModuleIds( const moduleIds = validateInstallModuleIds(
dedupeStrings([...(config?.moduleIds || []), ...(options.moduleIds || [])]) dedupeStrings([...(config?.moduleIds || []), ...(options.moduleIds || [])])
); );
const locale = options.locale || config?.locale || null;
const localeComponentId = locale ? LOCALE_ALIAS_TO_COMPONENT_ID[locale] : null;
if (locale && !localeComponentId) {
throw new Error(
`Unsupported locale: "${locale}". Supported locales: ${listSupportedLocales().join(', ')}`
);
}
const includeComponentIds = dedupeStrings([ const includeComponentIds = dedupeStrings([
...(config?.includeComponentIds || []), ...(config?.includeComponentIds || []),
...(options.includeComponentIds || []), ...(options.includeComponentIds || []),
...(localeComponentId ? [localeComponentId] : []),
]); ]);
const excludeComponentIds = dedupeStrings([ const excludeComponentIds = dedupeStrings([
...(config?.excludeComponentIds || []), ...(config?.excludeComponentIds || []),
@@ -102,7 +114,7 @@ function normalizeInstallRequest(options = {}) {
if (usingManifestMode && legacyLanguages.length > 0) { if (usingManifestMode && legacyLanguages.length > 0) {
throw new Error( throw new Error(
'Legacy language arguments cannot be combined with --profile, --modules, --with, --without, or manifest config selections' 'Legacy language arguments cannot be combined with --profile, --modules, --with, --without, --locale, or manifest config selections'
); );
} }