Skip to content
Development
Skill

/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.

From plugin
aionui
34k4 skills1 command

Claude Code

$ npx -y skills add iOfficeAI/AionUi --skill i18n --agent claude-code

SKILL.md

i18n.SKILL.md
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

packages/desktop/src/common/config/i18n-config.json   # Single source of truth: languages, modules
packages/desktop/src/renderer/services/i18n/
├── index.ts                             # i18next configuration
├── i18n-keys.d.ts                       # AUTO-GENERATED — do not edit manually
├── direction.ts                         # RTL/LTR resolution
├── format.ts                            # Formatting helpers
├── list.ts                              # Language list for the UI
└── 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.json

Key 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" packages/desktop/src/renderer/services/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

{
  "taskC
Read more
@iofficeai
Ships withaionui

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!

Stars on GitHub

Momentum

stars in total
34.0k
Star history of iOfficeAI/AionUi on GitHub, a chart by star-history.com

Other skills on aionui.

architecture

architecture

Project architecture and file structure conventions for all process types. Use when: (1) Creating new files or modules, (2)…

@iofficeai@iofficeaiInstall Skill
bump-version

bump-version

Use when bumping the AionUi version: query AionCore release, verify artifacts, update package.json, generate CHANGELOG, branch,…

@iofficeai@iofficeaiInstall Skill
testing

testing

Testing workflow and quality standards for writing and running tests. Use when: (1) Writing new tests, (2) Adding a new feature…

@iofficeai@iofficeaiInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills11d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about i18n.

Which coding agents can use i18n?
i18n installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.