# 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/images/i18n/demo-1.png)

![demo-2](../../assets/images/i18n/demo-2.png)

![demo-3](../../assets/images/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
pnpm i18n:check
```

### `i18n:sync` - Synchronize JSON Structure and Sort Order

This script uses `zh-cn.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

```bash
pnpm i18n:sync
```

### `i18n:translate` - Automatically Translate Pending Texts

This script fills in texts marked as `[to be translated]` using machine translation.

Typically, after adding new texts in `zh-cn.json`, run `i18n:sync`, then `i18n:translate` to complete translations.

Before using this script, set the required environment variables:

```bash
API_KEY="sk-xxx"
BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1/"
MODEL="qwen-plus-latest"
```

Alternatively, add these variables directly to your `.env` file.

```bash
pnpm i18n:translate
```

### Workflow

1. During development, first add the required text in `zh-cn.json`
2. Confirm it displays correctly in the Chinese environment
3. Run `pnpm i18n:sync` to propagate the keys to other language files
4. Run `pnpm i18n:translate` to perform machine translation
5. Grab a coffee and let the magic happen!

## Best Practices

1. **Use Chinese as Source Language**: All development starts in Chinese, then translates to other languages.
2. **Run Check Script Before Commit**: Use `pnpm 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`
