cherry-studio/docs/technical/how-to-i18n-en.md
icarus e5232b1fbb docs(i18n): update i18n documentation to reflect english as source language
- Change source language from Chinese to English in both docs
- Update script names from check:i18n/sync:i18n/auto:i18n to i18n:check/i18n:sync/i18n:auto
- Remove deprecated update:i18n script references
- Clarify base locale behavior and environment variable usage
2025-10-23 21:49:16 +08:00

170 lines
5.4 KiB
Markdown

# How to Do i18n Gracefully
> [!WARNING]
> This document is machine translated from Chinese. While we strive for accuracy, there may be some imperfections in the translation.
## Enhance Development Experience with the i18n Ally Plugin
i18n Ally is a powerful VSCode extension that provides real-time feedback during development, helping developers detect missing or incorrect translations earlier.
The plugin has already been configured in the project — simply install it to get started.
### Advantages During Development
- **Real-time Preview**: Translated texts are displayed directly in the editor.
- **Error Detection**: Automatically tracks and highlights missing translations or unused keys.
- **Quick Navigation**: Jump to key definitions with Ctrl/Cmd + click.
- **Auto-completion**: Provides suggestions when typing i18n keys.
### Demo
![demo-1](./.assets.how-to-i18n/demo-1.png)
![demo-2](./.assets.how-to-i18n/demo-2.png)
![demo-3](./.assets.how-to-i18n/demo-3.png)
## i18n Conventions
### **Avoid Flat Structure at All Costs**
Never use flat structures like `"add.button.tip": "Add"`. Instead, adopt a clear nested structure:
```json
// Wrong - Flat structure
{
"add.button.tip": "Add",
"delete.button.tip": "Delete"
}
// Correct - Nested structure
{
"add": {
"button": {
"tip": "Add"
}
},
"delete": {
"button": {
"tip": "Delete"
}
}
}
```
#### Why Use Nested Structure?
1. **Natural Grouping**: Related texts are logically grouped by their context through object nesting.
2. **Plugin Requirement**: Tools like i18n Ally require either flat or nested format to properly analyze translation files.
### **Avoid Template Strings in `t()`**
**We strongly advise against using template strings for dynamic interpolation.** While convenient in general JavaScript development, they cause several issues in i18n scenarios.
#### 1. **Plugin Cannot Track Dynamic Keys**
Tools like i18n Ally cannot parse dynamic content within template strings, resulting in:
- No real-time preview
- No detection of missing translations
- No navigation to key definitions
```javascript
// Not recommended - Plugin cannot resolve
const message = t(`fruits.${fruit}`)
```
#### 2. **No Real-time Rendering in Editor**
Template strings appear as raw code instead of the final translated text in IDEs, degrading the development experience.
#### 3. **Harder to Maintain**
Since the plugin cannot track such usages, developers must manually verify the existence of corresponding keys in language files.
### Recommended Approach
To avoid missing keys, all dynamically translated texts should first maintain a `FooKeyMap`, then retrieve the translation text through a function.
For example:
```ts
// src/renderer/src/i18n/label.ts
const themeModeKeyMap = {
dark: 'settings.theme.dark',
light: 'settings.theme.light',
system: 'settings.theme.system'
} as const
export const getThemeModeLabel = (key: string): string => {
return themeModeKeyMap[key] ? t(themeModeKeyMap[key]) : key
}
```
By avoiding template strings, you gain better developer experience, more reliable translation checks, and a more maintainable codebase.
## Automation Scripts
The project includes several scripts to automate i18n-related tasks:
### `i18n:check` - Validate i18n Structure
This script checks:
- Whether all language files use nested structure
- For missing or unused keys
- Whether keys are properly sorted
```bash
yarn i18n:check
```
### `i18n:sync` - Synchronize JSON Structure and Sort Order
By default, this script uses `en-us.json` as the source of truth to sync structure across all language files, including:
1. Adding missing keys, with placeholder `[to be translated]`
2. Removing obsolete keys
3. Sorting keys automatically
You can override this behavior by setting the `BASE_LOCALE` environment variable.
```bash
yarn i18n:sync
```
### `i18n:auto` - Automatically Translate Pending Texts
This script automatically translates texts marked as `[to be translated]` using machine translation. Similar to `i18n:sync`, it defaults to using `en-us.json` as the base, but you can override this behavior by setting the `BASE_LOCALE` environment variable.
Typically, after adding required texts to `en-us.json`, running `i18n:sync && i18n:auto` will automatically complete the translations.
Before using this script, you need to configure environment variables, for example:
```bash
API_KEY="sk-xxx"
BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1/"
MODEL="qwen-plus-latest"
```
You can also add environment variables by directly editing the `.env` file.
```bash
yarn i18n:auto
```
### Workflow
1. During development, first add the required text in `en-us.json`. You can use the quick fix functionality provided by the i18n-ally plugin to easily accomplish this.
2. Confirm the text displays correctly in the UI
3. Use `yarn i18n:sync` to sync the text to other language files
4. Use `yarn i18n:auto` to perform automatic translation
5. Grab a coffee and wait for the translation to complete!
## Best Practices
1. **Use English as Source Language**: All development starts in English, then translates to other languages.
2. **Run Check Script Before Commit**: Use `yarn i18n:check` to catch i18n issues early.
3. **Translate in Small Increments**: Avoid accumulating a large backlog of untranslated content.
4. **Keep Keys Semantically Clear**: Keys should clearly express their purpose, e.g., `user.profile.avatar.upload.error`