i18n
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesei18n Skill
i18n 技能指南
Standards and workflow for internationalization. All user-visible text must use i18n.
Announce at start: "I'm using i18n skill to ensure proper internationalization."
国际化的标准与工作流。所有用户可见的文本都必须使用i18n。
开始时声明: "我正在使用i18n技能来确保正确的国际化。"
File Structure
文件结构
src/renderer/i18n/
├── index.ts # i18next configuration
└── locales/
├── en-US.json # English (primary)
├── zh-CN.json # Simplified Chinese
├── zh-TW.json # Traditional Chinese
├── ja-JP.json # Japanese
└── ko-KR.json # Koreansrc/renderer/i18n/
├── index.ts # i18next 配置
└── locales/
├── en-US.json # 英文(主语言)
├── zh-CN.json # 简体中文
├── zh-TW.json # 繁体中文
├── ja-JP.json # 日语
└── ko-KR.json # 韩语Key Naming Convention
键命名规范
IMPORTANT: New i18n keys MUST use flat dot-notation format.
Format:
<module>.<feature>.<detail>重要提示:新的i18n键必须使用扁平化的点符号格式。
格式:
<模块>.<功能>.<细节>Rules
规则
| Level | Description | Examples |
|---|---|---|
| Module | Page or major feature | |
| Feature | Specific functionality | |
| Detail | Specific text purpose | |
| 层级 | 描述 | 示例 |
|---|---|---|
| 模块 | 页面或主要功能 | |
| 功能 | 具体功能 | |
| 细节 | 具体文本用途 | |
Examples
示例
✓ cron.form.title
✓ cron.form.namePlaceholder
✓ cron.list.emptyState
✓ settings.llm.apiKeyRequired
✗ cronFormTitle (missing dots)
✗ CRON.FORM.TITLE (wrong case)✓ cron.form.title
✓ cron.form.namePlaceholder
✓ cron.list.emptyState
✓ settings.llm.apiKeyRequired
✗ cronFormTitle (缺少点符号)
✗ CRON.FORM.TITLE (大小写错误)Flat vs Nested Structure
扁平化 vs 嵌套结构
json
// ✅ GOOD - flat structure (use for NEW keys)
{
"cron.form.title": "Create Scheduled Task",
"cron.form.nameLabel": "Task Name",
"cron.list.empty": "No scheduled tasks"
}
// ❌ AVOID - nested structure (legacy only, do not add new)
{
"cron": {
"form": {
"title": "..."
}
}
}Rationale:
- Flat keys are searchable in codebase (see , search directly)
t('cron.form.title') - Easier to verify sync across locale files
- Avoids deep nesting confusion
json
// ✅ 推荐 - 扁平化结构(用于新增键)
{
"cron.form.title": "Create Scheduled Task",
"cron.form.nameLabel": "Task Name",
"cron.list.empty": "No scheduled tasks"
}
// ❌ 避免 - 嵌套结构(仅用于遗留代码,请勿新增)
{
"cron": {
"form": {
"title": "..."
}
}
}理由:
- 扁平化键可在代码库中直接搜索(例如,可直接搜索)
t('cron.form.title') - 更易验证各语言文件间的同步性
- 避免深层嵌套带来的混淆
Common Suffixes
常见后缀
| Suffix | Usage |
|---|---|
| Section/page titles |
| Input placeholders |
| Form labels |
| Button text |
| Status messages |
| Confirmation dialogs |
| Empty state messages |
| Loading states |
| Tooltip text |
| 后缀 | 用途 |
|---|---|
| 章节/页面标题 |
| 输入框占位符 |
| 表单标签 |
| 按钮文本 |
| 状态消息 |
| 确认对话框 |
| 空状态消息 |
| 加载状态 |
| 提示框文本 |
Shared Keys
共享键
Use for reusable text:
common.*json
{
"common.save": "Save",
"common.cancel": "Cancel",
"common.confirm": "Confirm",
"common.delete": "Delete",
"common.loading": "Loading..."
}使用定义可复用文本:
common.*json
{
"common.save": "Save",
"common.cancel": "Cancel",
"common.confirm": "Confirm",
"common.delete": "Delete",
"common.loading": "Loading..."
}Adding New Text Workflow
添加新文本的工作流
Step 1: Check Existing Keys
步骤1:检查现有键
Before adding new key, search for similar existing keys:
bash
grep -r "keyword" src/renderer/i18n/locales/添加新键前,先搜索是否存在类似的现有键:
bash
grep -r "keyword" src/renderer/i18n/locales/Step 2: Add to ALL Locale Files
步骤2:添加至所有语言文件
CRITICAL: Must add to all 5 files simultaneously.
bash
undefined关键要求:必须同时添加至全部5个文件。
bash
undefinedFiles to update:
需要更新的文件:
src/renderer/i18n/locales/en-US.json # English text
src/renderer/i18n/locales/zh-CN.json # Simplified Chinese
src/renderer/i18n/locales/zh-TW.json # Traditional Chinese
src/renderer/i18n/locales/ja-JP.json # Japanese
src/renderer/i18n/locales/ko-KR.json # Korean
undefinedsrc/renderer/i18n/locales/en-US.json # 英文文本
src/renderer/i18n/locales/zh-CN.json # 简体中文
src/renderer/i18n/locales/zh-TW.json # 繁体中文
src/renderer/i18n/locales/ja-JP.json # 日语
src/renderer/i18n/locales/ko-KR.json # 韩语
undefinedStep 3: Use in Component
步骤3:在组件中使用
tsx
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return <button>{t('module.feature.action')}</button>;
}tsx
import { useTranslation } from 'react-i18next';
function MyComponent() {
const { t } = useTranslation();
return <button>{t('module.feature.action')}</button>;
}Step 4: Verify Sync
步骤4:验证同步性
After adding, verify all files have the new keys.
添加完成后,验证所有文件都包含新键。
Sync Checking
同步检查
Before Commit
提交前检查
Always verify key sync across all locale files:
bash
undefined请始终验证所有语言文件间的键是否同步:
bash
undefinedQuick check - compare line counts (rough indicator)
快速检查 - 比较行数(大致指标)
wc -l src/renderer/i18n/locales/*.json
wc -l src/renderer/i18n/locales/*.json
Check for flat keys diff between en-US and zh-CN
检查en-US与zh-CN之间的扁平化键差异
diff <(grep -oE '"[a-zA-Z0-9_.]+":' src/renderer/i18n/locales/en-US.json | sort -u)
<(grep -oE '"[a-zA-Z0-9_.]+":' src/renderer/i18n/locales/zh-CN.json | sort -u)
<(grep -oE '"[a-zA-Z0-9_.]+":' src/renderer/i18n/locales/zh-CN.json | sort -u)
undefineddiff <(grep -oE '"[a-zA-Z0-9_.]+":' src/renderer/i18n/locales/en-US.json | sort -u)
<(grep -oE '"[a-zA-Z0-9_.]+":' src/renderer/i18n/locales/zh-CN.json | sort -u)
<(grep -oE '"[a-zA-Z0-9_.]+":' src/renderer/i18n/locales/zh-CN.json | sort -u)
undefinedFix Sync Issues
修复同步问题
If keys are out of sync:
- Identify missing keys from diff output
- Add missing keys to appropriate files
- Re-run diff to verify
如果键不同步:
- 从差异输出中找出缺失的键
- 将缺失的键添加至对应文件
- 重新运行diff验证
Hardcoded String Detection
硬编码字符串检测
Prohibited Patterns
禁止模式
Never use hardcoded Chinese/English text in JSX:
tsx
// ❌ BAD
<span>重命名</span>
<span>Delete</span>
<button title="更多操作">...</button>
{name || '新对话'}
// ✅ GOOD
<span>{t('common.rename')}</span>
<span>{t('common.delete')}</span>
<button title={t('common.moreActions')}>...</button>
{name || t('chat.newConversation')}请勿在JSX中使用硬编码的中文/英文文本:
tsx
// ❌ 错误示例
<span>重命名</span>
<span>Delete</span>
<button title="更多操作">...</button>
{name || '新对话'}
// ✅ 正确示例
<span>{t('common.rename')}</span>
<span>{t('common.delete')}</span>
<button title={t('common.moreActions')}>...</button>
{name || t('chat.newConversation')}Exceptions
例外情况
Comments and internal logs are allowed:
tsx
// This is a comment, Chinese is OK
console.log('Debug info'); // OK for logs注释和内部日志允许使用硬编码文本:
tsx
// 这是一条注释,可使用中文
console.log('Debug info'); // 日志中使用英文没问题zh-TW Maintenance
繁体中文(zh-TW)维护
Auto-conversion Safe
可安全自动转换的术语
Most terms can be auto-converted from zh-CN:
- 设置 → 設置
- 删除 → 刪除
- 确认 → 確認
大部分术语可从简体中文自动转换:
- 设置 → 設置
- 删除 → 刪除
- 确认 → 確認
Manual Adjustment Required
需要手动调整的术语
Some terms need manual review:
| zh-CN | zh-TW | Notes |
|---|---|---|
| 视频 | 影片 | Different term |
| 软件 | 軟體 | Different term |
| 信息 | 訊息 | Different term |
| 默认 | 預設 | Different term |
部分术语需要手动检查调整:
| 简体中文 | 繁体中文 | 说明 |
|---|---|---|
| 视频 | 影片 | 术语不同 |
| 软件 | 軟體 | 术语不同 |
| 信息 | 訊息 | 术语不同 |
| 默认 | 預設 | 术语不同 |
Interpolation
插值语法
Variables
变量
json
{
"greeting": "Hello, {{name}}!",
"itemCount": "{{count}} items"
}tsx
t('greeting', { name: 'User' });
t('itemCount', { count: 5 });json
{
"greeting": "Hello, {{name}}!",
"itemCount": "{{count}} items"
}tsx
t('greeting', { name: 'User' });
t('itemCount', { count: 5 });HTML in Translations
翻译中的HTML
Use Trans component for complex markup:
tsx
import { Trans } from 'react-i18next';
<Trans i18nKey='cron.countdown'>
Task <strong>{{ taskName }}</strong> in <span>{{ countdown }}</span>
</Trans>;对于复杂标记,使用Trans组件:
tsx
import { Trans } from 'react-i18next';
<Trans i18nKey='cron.countdown'>
Task <strong>{{ taskName }}</strong> in <span>{{ countdown }}</span>
</Trans>;Quick Checklist
快速检查清单
Before submitting code with new text:
- All user-visible text uses function
t() - New keys use flat format
module.feature.detail - New keys added to ALL 5 locale files
- No hardcoded Chinese/English in JSX
- zh-TW reviewed for term differences
- ja-JP and ko-KR translations added (or marked TODO)
提交包含新文本的代码前,请确认:
- 所有用户可见文本均使用函数
t() - 新键使用扁平化的格式
module.feature.detail - 新键已添加至全部5个语言文件
- JSX中无硬编码的中文/英文文本
- 繁体中文(zh-TW)术语已检查差异
- 日语(ja-JP)和韩语(ko-KR)翻译已添加(或标记为TODO)
Common Mistakes
常见错误
| Mistake | Correct |
|---|---|
| Adding key to only one file | Add to all 5 files |
| Using nested structure for new | Use flat |
Using | Define key: |
| Inline Chinese in JSX | Use |
| Forgetting interpolation | Use |
| 错误 | 修正方案 |
|---|---|
| 仅在一个文件中添加键 | 添加至全部5个文件 |
| 新增键使用嵌套结构 | 使用扁平化的 |
使用 | 定义键后使用: |
| JSX中直接写中文 | 使用 |
| 忘记使用插值语法 | 使用 |