Translate Skill
Manages translation files in apps/frontend/src/i18n/languages/.
Translation Files
- 15 languages: en (source), de, es, fr, hi, it, ja, ko, nl, pt, sv, tr, tw, vi, zh
- Format: flat JSON key-value pairs (keys = English phrases)
- Interpolation:
{{variableName}}
- Library:
react-i18next configured in apps/frontend/src/i18n/index.tsx
- Language list defined in
apps/frontend/src/i18n/index.tsx (languages array)
When Adding New Translation Keys
- Add the new key to
en.json with the English value
- Add the same key to ALL other language files with the correct translation for the language of the file
- After adding to all files, sort ALL translation files alphabetically by key (case-insensitive)
When Removing Translation Keys
- Remove the key from ALL 15 language files
- Files should remain sorted after removal
Sorting Rules
- All translation JSON files MUST have keys sorted alphabetically (case-insensitive)
- Sorting applies to ALL language files, not just
en.json
- After any modification, verify keys are sorted
Sort Procedure
For each .json file in apps/frontend/src/i18n/languages/:
- Parse the JSON
- Get all keys and sort them case-insensitively
- Rebuild the object with sorted keys
- Write back with 2-space indentation and trailing newline
Use a Node.js script or jq to sort. Example with Node.js:
node -e "
const fs = require('fs');
const glob = require('glob');
const files = glob.sync('apps/frontend/src/i18n/languages/*.json');
files.forEach(f => {
const obj = JSON.parse(fs.readFileSync(f, 'utf8'));
const sorted = Object.keys(obj)
.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }))
.reduce((acc, key) => { acc[key] = obj[key]; return acc; }, {});
fs.writeFileSync(f, JSON.stringify(sorted, null, 2) + '\n');
});
"
Sync Check
After any translation change, verify:
en.json has all keys that exist in code (search for t("...") usage)
- All non-English files have the EXACT same keys as
en.json
- Missing keys in non-English files get the correct translation for the language of the file
- Extra keys in non-English files (not in
en.json) should be removed
- All files are sorted alphabetically by key
Fixed Words
See apps/frontend/src/i18n/fixedWords.json. Grouped by language code ("all" applies to every language).
Two use cases:
- Untranslated words — value equals the English word (e.g.
"round": "round" keeps "round" in English for Italian)
- Fixed translations — value is the mandatory translation for that concept (e.g.
"endorsement": "supporto" means always use "supporto" for endorsement in Italian)
When translating, ALWAYS check this file first. If a word has a fixed translation for the target language, use it consistently in every sentence.
1---2name: translate3description: Translate Skill4---5# Translate Skill67Manages translation files in `apps/frontend/src/i18n/languages/`.89## Translation Files1011- 15 languages: en (source), de, es, fr, hi, it, ja, ko, nl, pt, sv, tr, tw, vi, zh12- Format: flat JSON key-value pairs (keys = English phrases)13- Interpolation: `{{variableName}}`14- Library: `react-i18next` configured in `apps/frontend/src/i18n/index.tsx`15- Language list defined in `apps/frontend/src/i18n/index.tsx` (`languages` array)1617## When Adding New Translation Keys18191. Add the new key to `en.json` with the English value202. Add the same key to ALL other language files with the correct translation for the language of the file213. After adding to all files, sort ALL translation files alphabetically by key (case-insensitive)2223## When Removing Translation Keys24251. Remove the key from ALL 15 language files262. Files should remain sorted after removal2728## Sorting Rules2930- All translation JSON files MUST have keys sorted alphabetically (case-insensitive)31- Sorting applies to ALL language files, not just `en.json`32- After any modification, verify keys are sorted3334## Sort Procedure3536For each `.json` file in `apps/frontend/src/i18n/languages/`:37381. Parse the JSON392. Get all keys and sort them case-insensitively403. Rebuild the object with sorted keys414. Write back with 2-space indentation and trailing newline4243Use a Node.js script or jq to sort. Example with Node.js:4445```bash46node -e "47const fs = require('fs');48const glob = require('glob');49const files = glob.sync('apps/frontend/src/i18n/languages/*.json');50files.forEach(f => {51 const obj = JSON.parse(fs.readFileSync(f, 'utf8'));52 const sorted = Object.keys(obj)53 .sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }))54 .reduce((acc, key) => { acc[key] = obj[key]; return acc; }, {});55 fs.writeFileSync(f, JSON.stringify(sorted, null, 2) + '\n');56});57"58```5960## Sync Check6162After any translation change, verify:6364- `en.json` has all keys that exist in code (search for `t("..."`) usage)65- All non-English files have the EXACT same keys as `en.json`66- Missing keys in non-English files get the correct translation for the language of the file67- Extra keys in non-English files (not in `en.json`) should be removed68- All files are sorted alphabetically by key6970## Fixed Words7172See `apps/frontend/src/i18n/fixedWords.json`. Grouped by language code (`"all"` applies to every language).7374Two use cases:751. **Untranslated words** — value equals the English word (e.g. `"round": "round"` keeps "round" in English for Italian)762. **Fixed translations** — value is the mandatory translation for that concept (e.g. `"endorsement": "supporto"` means always use "supporto" for endorsement in Italian)7778When translating, ALWAYS check this file first. If a word has a fixed translation for the target language, use it consistently in every sentence.