/i18n
Internationalization (i18n) workflow and standards for managing translations. Use when: (1) Adding new user-facing text, (2) Creating new components with user-facing text, (3) Reviewing code for i18n compliance, (4) Adding a new translation module.
$ npx -y skills add iOfficeAI/AionUi --skill i18n --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/i18n
Context preview
The summary Claude sees to decide when to auto-load this skill.
Internationalization (i18n) workflow and standards for managing translations. Use when: (1) Adding new user-facing text, (2) Creating new components with user-facing text, (3) Reviewing code for i18n compliance, (4) Adding a new translation module.
SKILL.md
i18n.SKILL.mdname: i18n
description: |
Internationalization (i18n) workflow and standards for managing translations.
Use when: (1) Adding new user-facing text, (2) Creating new components with user-facing text,
(3) Reviewing code for i18n compliance, (4) Adding a new translation module.
i18n Skill
Standards and workflow for internationalization. All user-visible text must use i18n.
**Announce at start:** "I'm using i18n skill to ensure proper internationalization."
IMPORTANT: Read Config First
Before doing any i18n work, **always read `src/common/config/i18n-config.json`** to get the current list of supported languages and modules. Never assume a fixed number — languages and modules may have been added or removed since this skill was written.
cat src/common/config/i18n-config.json
This file is the **single source of truth**. All scripts, runtime code, and this workflow depend on it.
File Structure
src/common/config/i18n-config.json # Single source of truth: languages, modules
src/renderer/i18n/
├── index.ts # i18next configuration
├── i18n-keys.d.ts # AUTO-GENERATED — do not edit manually
└── locales/
├── <lang>/ # One directory per language in i18n-config.json
│ ├── index.ts # Barrel import for all modules
│ ├── common.json # One JSON per module in i18n-config.json
│ ├── conversation.json
│ └── ...
└── ...Key Facts
- **Reference language**: defined by `referenceLanguage` in `i18n-config.json` (currently `en-US`)
- **Supported languages**: defined by `supportedLanguages` array — read the file to get the current list
- **Modules**: defined by `modules` array — read the file to get the current list
Key Structure
Keys use **namespaced dot notation** in code: `t('module.key')` or `t('module.nested.key')`.
Inside each module JSON file, keys can be **flat or nested**:
// common.json — flat keys
{
"send": "Send",
"cancel": "Cancel",
"copySuccess": "Copied"
}
// cron.json — nested keys
{
"scheduledTasks": "Scheduled Tasks",
"status": {
"active": "Active",
"paused": "Paused"
}
}In code:
t('common.send'); // flat key in common.json
t('cron.status.active'); // nested key in cron.jsonKey Naming Rules
- Use **camelCase** for key names: `copySuccess`, `scheduledTasks`
- Group related keys with nesting: `status.active`, `actions.pause`
- Reusable text goes in `common.json`: save, cancel, delete, confirm, etc.
- Feature-specific text goes in the corresponding module
Common Suffixes
| Suffix | Usage | | ------------------- | -------------------- | | `title` | Section/page titles | | `placeholder` | Input placeholders | | `label` | Form labels | | `success` / `error` | Status messages | | `confirm` | Confirmation dialogs | | `empty` | Empty state messages | | `tooltip` | Tooltip text |
Adding New Text — Workflow
Step 1: Read `src/common/config/i18n-config.json`
Get the current language list and module list. Do not skip this step.
Step 2: Check Existing Keys
Before adding a new key, search for similar existing keys:
grep -r "keyword" src/renderer/i18n/locales/en-US/
Reuse `common.*` keys when possible.
Step 3: Choose the Right Module
Match the module to the feature area. If no module fits, consider whether a new module is needed (see "Adding a New Module" below).
Step 4: Add to ALL Locale Directories
**CRITICAL:** Every new key must be added to **every** locale in `supportedLanguages`. Use this checklist for each key:
- [ ] `en-US/<module>.json` — reference language (added in Step 3)
- [ ] `zh-CN/<module>.json` — added
- [ ] `zh-TW/<module>.json` — added
- [ ] Any other language listed in `src/common/config/i18n-config.json` → `supportedLanguages` — added
A key missing from even one locale will cause `node scripts/check-i18n.js` to fail in CI.
Step 5: Use in Component
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return <button>{t('common.save')}</button>;
}Step 6: Regenerate Types and Validate
Run these two commands **in order** — both must pass before committing:
bun run i18n:types # Step A: regenerate i18n-keys.d.ts from reference locale
node scripts/check-i18n.js # Step B: validate structure, keys, and type sync
- `i18n:types` must be run **before** `check-i18n.js` — the check validates the generated file
- If `check-i18n.js` exits with errors (❌), fix them before proceeding
- If `check-i18n.js` exits with warnings only (⚠️), review but may proceed
- **Never commit with a stale `i18n-keys.d.ts`**
Adding a New Module
1. Add module name to `src/common/config/i18n-config.json` → `modules` array 2. Create `<module>.json` in **every** locale directory (read `supportedLanguages` to know which) 3. Add import + export in each locale's `index.ts` 4. Run `bun run i18n:types` to regenerate type definitions 5. Run `node scripts/check-i18n.js` to validate
Hardcoded String Detection
Prohibited Patterns
Never use hardcoded Chinese/English text in JSX:
// Bad
<span>重命名</span>
<span>Delete</span>
{name || '新对话'}
// Good
<span>{t('common.rename')}</span>
<span>{t('common.delete')}</span>
{name || t('conversation.newConversation')}Exceptions
- Code comments (any language OK)
- `console.log()` / debug output
- Internal string constants not shown to users
Interpolation
Variables
{
"taskCount": "{{count}} task(s)",
"greeting": "Hello, {{name}}!"
}t('cron.taskCount', { count: 5 });HTML in Translations
Use Trans component for complex markup:
import { Trans } from 'react-i18next';
<Trans i18nKey='cron.Read more
name: i18n description: | Internationalization (i18n) workflow and standards for managing translations. Use when: (1) Adding new user-facing text, (2) Creating new components with user-facing text, (3) Reviewing code for i18n compliance, (4) Adding a new translation module.
i18n Skill
Standards and workflow for internationalization. All user-visible text must use i18n.
**Announce at start:** "I'm using i18n skill to ensure proper internationalization."
IMPORTANT: Read Config First
Before doing any i18n work, **always read `src/common/config/i18n-config.json`** to get the current list of supported languages and modules. Never assume a fixed number — languages and modules may have been added or removed since this skill was written.
cat src/common/config/i18n-config.json
This file is the **single source of truth**. All scripts, runtime code, and this workflow depend on it.
File Structure
src/common/config/i18n-config.json # Single source of truth: languages, modules
src/renderer/i18n/
├── index.ts # i18next configuration
├── i18n-keys.d.ts # AUTO-GENERATED — do not edit manually
└── locales/
├── <lang>/ # One directory per language in i18n-config.json
│ ├── index.ts # Barrel import for all modules
│ ├── common.json # One JSON per module in i18n-config.json
│ ├── conversation.json
│ └── ...
└── ...Key Facts
- **Reference language**: defined by `referenceLanguage` in `i18n-config.json` (currently `en-US`)
- **Supported languages**: defined by `supportedLanguages` array — read the file to get the current list
- **Modules**: defined by `modules` array — read the file to get the current list
Key Structure
Keys use **namespaced dot notation** in code: `t('module.key')` or `t('module.nested.key')`.
Inside each module JSON file, keys can be **flat or nested**:
// common.json — flat keys
{
"send": "Send",
"cancel": "Cancel",
"copySuccess": "Copied"
}
// cron.json — nested keys
{
"scheduledTasks": "Scheduled Tasks",
"status": {
"active": "Active",
"paused": "Paused"
}
}In code:
t('common.send'); // flat key in common.json
t('cron.status.active'); // nested key in cron.jsonKey Naming Rules
- Use **camelCase** for key names: `copySuccess`, `scheduledTasks`
- Group related keys with nesting: `status.active`, `actions.pause`
- Reusable text goes in `common.json`: save, cancel, delete, confirm, etc.
- Feature-specific text goes in the corresponding module
Common Suffixes
| Suffix | Usage | | ------------------- | -------------------- | | `title` | Section/page titles | | `placeholder` | Input placeholders | | `label` | Form labels | | `success` / `error` | Status messages | | `confirm` | Confirmation dialogs | | `empty` | Empty state messages | | `tooltip` | Tooltip text |
Adding New Text — Workflow
Step 1: Read `src/common/config/i18n-config.json`
Get the current language list and module list. Do not skip this step.
Step 2: Check Existing Keys
Before adding a new key, search for similar existing keys:
grep -r "keyword" src/renderer/i18n/locales/en-US/
Reuse `common.*` keys when possible.
Step 3: Choose the Right Module
Match the module to the feature area. If no module fits, consider whether a new module is needed (see "Adding a New Module" below).
Step 4: Add to ALL Locale Directories
**CRITICAL:** Every new key must be added to **every** locale in `supportedLanguages`. Use this checklist for each key:
- [ ] `en-US/<module>.json` — reference language (added in Step 3)
- [ ] `zh-CN/<module>.json` — added
- [ ] `zh-TW/<module>.json` — added
- [ ] Any other language listed in `src/common/config/i18n-config.json` → `supportedLanguages` — added
A key missing from even one locale will cause `node scripts/check-i18n.js` to fail in CI.
Step 5: Use in Component
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return <button>{t('common.save')}</button>;
}Step 6: Regenerate Types and Validate
Run these two commands **in order** — both must pass before committing:
bun run i18n:types # Step A: regenerate i18n-keys.d.ts from reference locale node scripts/check-i18n.js # Step B: validate structure, keys, and type sync
- `i18n:types` must be run **before** `check-i18n.js` — the check validates the generated file
- If `check-i18n.js` exits with errors (❌), fix them before proceeding
- If `check-i18n.js` exits with warnings only (⚠️), review but may proceed
- **Never commit with a stale `i18n-keys.d.ts`**
Adding a New Module
1. Add module name to `src/common/config/i18n-config.json` → `modules` array 2. Create `<module>.json` in **every** locale directory (read `supportedLanguages` to know which) 3. Add import + export in each locale's `index.ts` 4. Run `bun run i18n:types` to regenerate type definitions 5. Run `node scripts/check-i18n.js` to validate
Hardcoded String Detection
Prohibited Patterns
Never use hardcoded Chinese/English text in JSX:
// Bad
<span>重命名</span>
<span>Delete</span>
{name || '新对话'}
// Good
<span>{t('common.rename')}</span>
<span>{t('common.delete')}</span>
{name || t('conversation.newConversation')}Exceptions
- Code comments (any language OK)
- `console.log()` / debug output
- Internal string constants not shown to users
Interpolation
Variables
{
"taskCount": "{{count}} task(s)",
"greeting": "Hello, {{name}}!"
}t('cron.taskCount', { count: 5 });HTML in Translations
Use Trans component for complex markup:
import { Trans } from 'react-i18next';
<Trans i18nKey='cron.Open-source 24/7 Cowork app for OpenClaw, Hermes, Claude Code, Codex, OpenCode and 20+ more CLI Agent | Customize your assistants | Team them up|Star if you like it!
Repo: iOfficeAI/AionUi
Other skills on aionui.
- /architecture
Project architecture and file structure conventions for all process types. Use when: (1) Creating new files or modules, (2) Deciding where code should go, (3) Converting single-file components to directories, (4) Reviewing code for structure compliance, (5) Adding new bridges,
Open skill - /bump-version
Use when bumping the AionUi version: query AionCore release, verify artifacts, update package.json, generate CHANGELOG, branch, commit, push, create PR, auto-merge, tag release.
Open skill - /testing
Testing workflow and quality standards for writing and running tests. Use when: (1) Writing new tests, (2) Adding a new feature that needs tests, (3) Modifying logic that has existing tests, (4) Before claiming a task is complete.
Open skill

