🌙 i18n Quick Reference Guide
🌙 Quick Start
🌙 1. Using in Components (Hook)
import { useTranslation } from 'react-i18next';
const MyComponent = () => {
const { t } = useTranslation();
return <div>{t('key')}</div>;
};
1
2
3
4
5
6
2
3
4
5
6
🌙 2. Using in Non-Component Code
import i18n from 'i18next';
const label = i18n.t('key');
1
2
3
2
3
🌙 3. Using with HTML Content
import { Trans } from 'react-i18next';
<Trans i18nKey="key_with_html" />
1
2
3
2
3
🌙 File Structure
web/libs/editor/src/i18n/
├── index.ts # i18n initialization
├── LanguageSwitcher.tsx # Language selector component
├── react-i18next.d.ts # TypeScript types
└── locales/
├── en/
│ └── translations.ts # English translations
└── zh/
└── translations.ts # Chinese translations
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
🌙 Adding New Translations
🌙 Step 1: Add to Translation Files
English (locales/en/translations.ts):
const EN_TRANSLATIONS = {
my_new_key: "My New Text",
// ... other keys
};
1
2
3
4
2
3
4
Chinese (locales/zh/translations.ts):
const ZH_TRANSLATIONS = {
my_new_key: "我的新文本",
// ... other keys
};
1
2
3
4
2
3
4
🌙 Step 2: Use in Components
const { t } = useTranslation();
<div>{t('my_new_key')}</div>
1
2
2
🌙 Common Patterns
🌙 With Variables (Interpolation)
Translation:
{
welcome: "Welcome, {name}!"
}
1
2
3
2
3
Usage:
t('welcome', { name: 'John' })
// Output: "Welcome, John!"
1
2
2
🌙 Conditional Text
const message = isActive
? i18n.t('active_message')
: i18n.t('inactive_message');
1
2
3
2
3
🌙 In Modal/Confirm
confirm({
title: i18n.t('confirm_title'),
content: i18n.t('confirm_message'),
okText: i18n.t('ok'),
cancelText: i18n.t('cancel'),
});
1
2
3
4
5
6
2
3
4
5
6
🌙 In Tooltips
<Tooltip title={i18n.t('tooltip_text')}>
<Button />
</Tooltip>
1
2
3
2
3
🌙 Best Practices
🌙 ✅ DO
// Use semantic key names
t('delete_annotation')
// Organize by feature
const SETTINGS = {
enable_hotkeys: "Enable Hotkeys",
show_labels: "Show Labels"
};
// Use variables for dynamic content
t('time_ago', { time: '5 minutes' })
// Use Trans for HTML content
<Trans i18nKey="message_with_html" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
🌙 ❌ DON'T
// Don't use meaningless keys
t('text1')
// Don't hard-code text
<button>Delete</button>
// Don't forget to handle both languages
// Always add translations to both en and zh files
// Don't use t() for HTML content
t('message_with_html') // HTML tags will be escaped
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🌙 Translation Key Naming Conventions
🌙 Pattern: feature_action_context
{
// Feature: annotation, action: delete, context: title
annotation_delete_title: "Delete Annotation",
// Feature: annotation, action: delete, context: description
annotation_delete_desc: "Are you sure?",
// Feature: region, action: show, context: all
region_show_all: "Show All Regions",
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
🌙 Common Prefixes
enable_*- Settings/togglesshow_*- Display options*_title- Dialog/modal titles*_desc- Descriptions*_info- Information messages*_error- Error messages
🌙 Adding a New Language
🌙 1. Create Translation File
mkdir -p web/libs/editor/src/i18n/locales/fr
touch web/libs/editor/src/i18n/locales/fr/translations.ts
1
2
2
🌙 2. Add Translations
// locales/fr/translations.ts
const FR_TRANSLATIONS = {
settings: "Paramètres",
delete: "Supprimer",
// ... copy all keys from EN
};
export default FR_TRANSLATIONS;
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
🌙 3. Update Configuration
// i18n/index.ts
import FR from './locales/fr/translations';
i18n.init({
supportedLngs: ['en', 'zh', 'fr'],
resources: {
en: { translation: EN },
zh: { translation: ZH },
fr: { translation: FR },
},
});
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🌙 4. Update Language Switcher
// LanguageSwitcher.tsx
const languages = [
{ code: 'en', lang: 'English' },
{ code: 'zh', lang: '简体中文' },
{ code: 'fr', lang: 'Français' },
];
1
2
3
4
5
6
2
3
4
5
6
🌙 Troubleshooting
🌙 Issue: Translation key shows instead of text
Check:
- Key exists in translation file
- Current language matches file
- No typos in key name
Debug:
console.log(i18n.t('your_key'));
console.log(i18n.language);
1
2
2
🌙 Issue: Language switch doesn't update UI
Solution: Use useTranslation() hook instead of direct i18n.t()
// ❌ Won't update
const Component = () => {
const label = i18n.t('label');
return <div>{label}</div>;
};
// ✅ Will update
const Component = () => {
const { t } = useTranslation();
return <div>{t('label')}</div>;
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🌙 Issue: HTML tags display as text
Solution: Use <Trans> component
// ❌ HTML escaped
<div>{t('message_with_html')}</div>
// ✅ HTML rendered
<div><Trans i18nKey="message_with_html" /></div>
1
2
3
4
5
2
3
4
5
🌙 Translation Checklist
Before committing translation changes:
- [ ] All keys exist in both
enandzhtranslation files - [ ] Key names are semantic and descriptive
- [ ] Variables (like
{name}) are consistent across languages - [ ] HTML tags are consistent across languages
- [ ] No hard-coded text strings in components
- [ ] Tested language switching
- [ ] Translation is accurate and natural
- [ ] Length doesn't break UI layout
🌙 Common Translation Keys Reference
🌙 Actions
delete, cancel, submit, update, save, reset,
undo, redo, skip, edit, add, create, copy
1
2
2
🌙 Status
draft, submitted, saved, skipped, accepted,
rejected, updated, created, started
1
2
2
🌙 UI Elements
settings, general, hotkeys, layout, regions,
labels, comments, annotations, relations
1
2
2
🌙 Messages
pls_confirm_del, no_changes_made, are_sure,
yes, no, confirm, proceed, cancel_edit
1
2
2
🌙 Time/User
time_ago, by_name, created, started, updated
1
🌙 API Quick Reference
🌙 useTranslation Hook
const { t, i18n } = useTranslation();
t(key: string, options?: object): string
i18n.language: string
i18n.changeLanguage(lng: string): Promise
1
2
3
4
5
2
3
4
5
🌙 Trans Component
<Trans
i18nKey="translation_key"
values={{ variable: value }}
components={{ bold: <strong /> }}
/>
1
2
3
4
5
2
3
4
5
🌙 Direct i18n Access
i18n.t(key: string, options?: object): string
i18n.changeLanguage(lng: string): Promise
i18n.language: string
i18n.languages: string[]
1
2
3
4
2
3
4
🌙 Configuration Overview
// i18n/index.ts
i18n.init({
supportedLngs: ['en', 'zh'], // Supported languages
fallbackLng: 'en', // Default language
defaultNS: 'translation', // Default namespace
detection: {
order: [ // Detection order
'queryString', // ?lng=en
'cookie', // Cookie
'localStorage', // localStorage
'navigator', // Browser setting
'htmlTag' // <html lang="">
],
caches: ['cookie'], // Cache location
},
react: {
useSuspense: true, // Use React Suspense
},
interpolation: {
escapeValue: false, // React handles XSS
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
🌙 Examples by Use Case
🌙 Button Labels
<Button>{t('delete')}</Button>
<Button>{t('submit')}</Button>
<Button>{t('cancel')}</Button>
1
2
3
2
3
🌙 Form Labels
<label>{t('start')}</label>
<label>{t('end')}</label>
<label>{t('duration')}</label>
1
2
3
2
3
🌙 Tooltips
<Tooltip title={t('delete_annotation')}>
<IconButton />
</Tooltip>
1
2
3
2
3
🌙 Modal Dialogs
Modal.confirm({
title: i18n.t('confirm_title'),
content: i18n.t('confirm_message'),
okText: i18n.t('ok'),
cancelText: i18n.t('cancel'),
});
1
2
3
4
5
6
2
3
4
5
6
🌙 Error Messages
{error && <div className="error">{t('error_message')}</div>}
1
🌙 Dynamic Lists
const items = [
{ key: 'option1', label: t('option1') },
{ key: 'option2', label: t('option2') },
];
1
2
3
4
2
3
4
🌙 With Variables
// Simple variable
t('welcome', { name: username })
// Multiple variables
t('region_selected', { num: count })
// Time formatting
t('time_ago', { time: formatTime(date) })
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
🌙 Resources
- Full Documentation: I18N_IMPLEMENTATION_GUIDE.md
- i18next Docs: https://www.i18next.com/
- react-i18next Docs: https://react.i18next.com/
- Source Code:
web/libs/editor/src/i18n/
For detailed information, examples, and best practices, see the complete i18n guide.