forked from mengyxu/noob-components
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
7.4 KiB
355 lines
7.4 KiB
|
3 months ago
|
# I18n
|
||
|
|
|
||
|
|
> Internationalization using vue3-i18n with class-based translation modules.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The i18n system uses `vue3-i18n` with class-based translation modules for English and Chinese. Translations are organized by domain into flat object structures.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Architecture
|
||
|
|
|
||
|
|
```
|
||
|
|
I18n Module
|
||
|
|
├── vue3-i18n instance (i18n)
|
||
|
|
├── Zh class (Chinese translations)
|
||
|
|
├── En class (English translations)
|
||
|
|
├── registerLang() - dynamic language registration
|
||
|
|
└── createt() - namespace suffix helper
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## I18n Setup
|
||
|
|
|
||
|
|
**File**: `/home/hechang27/Documents/sprt/noob-components/plugs/i18n/index.ts`
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import { createI18n } from 'vue3-i18n';
|
||
|
|
import Zh from './zh';
|
||
|
|
import En from './en';
|
||
|
|
|
||
|
|
const messages = {
|
||
|
|
zh: new Zh(),
|
||
|
|
en: new En(),
|
||
|
|
};
|
||
|
|
|
||
|
|
const i18n = createI18n({
|
||
|
|
locale: 'zh',
|
||
|
|
messages,
|
||
|
|
});
|
||
|
|
|
||
|
|
const registerLang = (name, data) => {
|
||
|
|
messages[name] = data;
|
||
|
|
};
|
||
|
|
|
||
|
|
export { i18n, Zh, En, registerLang };
|
||
|
|
|
||
|
|
export const createt = (sufix: string) => {
|
||
|
|
return (key: string): string => {
|
||
|
|
key = sufix + key;
|
||
|
|
return i18n.t(key);
|
||
|
|
};
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Key Exports
|
||
|
|
|
||
|
|
| Export | Type | Description |
|
||
|
|
|--------|------|-------------|
|
||
|
|
| `i18n` | VueI18n | Main i18n instance |
|
||
|
|
| `Zh` | class | Chinese translation class |
|
||
|
|
| `En` | class | English translation class |
|
||
|
|
| `registerLang` | function | Dynamically register new language |
|
||
|
|
| `createt` | function | Creates namespace-prefixed translator |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Translation Structure
|
||
|
|
|
||
|
|
Translations are organized by domain with flat object keys:
|
||
|
|
|
||
|
|
### Base Translations (common actions)
|
||
|
|
|
||
|
|
**English** (`plugs/i18n/en.ts`):
|
||
|
|
```typescript
|
||
|
|
base = {
|
||
|
|
color: 'Color',
|
||
|
|
add: 'Add',
|
||
|
|
delete: 'Delete',
|
||
|
|
modify: 'Modify',
|
||
|
|
stop: 'Stop',
|
||
|
|
select: 'Select',
|
||
|
|
refresh: 'Refresh',
|
||
|
|
save: 'Save',
|
||
|
|
confirm: 'Confirm',
|
||
|
|
cancel: 'Cancel',
|
||
|
|
loading: 'Loading...',
|
||
|
|
active: 'Active',
|
||
|
|
inactive: 'Inactive',
|
||
|
|
key: 'Key',
|
||
|
|
value: 'Value',
|
||
|
|
import: 'Import',
|
||
|
|
export: 'Export',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
**Chinese** (`plugs/i18n/zh.ts`):
|
||
|
|
```typescript
|
||
|
|
base = {
|
||
|
|
color: '颜色',
|
||
|
|
add: '添加',
|
||
|
|
delete: '删除',
|
||
|
|
modify: '修改',
|
||
|
|
stop: '停止',
|
||
|
|
select: '查询',
|
||
|
|
refresh: '刷新',
|
||
|
|
save: '保存',
|
||
|
|
confirm: '确认',
|
||
|
|
cancel: '取消',
|
||
|
|
loading: '加载中...',
|
||
|
|
active: '生效',
|
||
|
|
inactive: '无效',
|
||
|
|
key: '键',
|
||
|
|
value: '值',
|
||
|
|
import: '导入',
|
||
|
|
export: '导出',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Domain Keys
|
||
|
|
|
||
|
|
### Styles
|
||
|
|
|
||
|
|
**English**:
|
||
|
|
```typescript
|
||
|
|
styles = ['Default', 'Lignt', 'Dark', 'DefaultB', 'zhuBeiDong'];
|
||
|
|
```
|
||
|
|
|
||
|
|
**Chinese**:
|
||
|
|
```typescript
|
||
|
|
styles = ['青', '明亮', '黑夜', '蓝', '主被动'];
|
||
|
|
```
|
||
|
|
|
||
|
|
### Head/Menu
|
||
|
|
|
||
|
|
**English**:
|
||
|
|
```typescript
|
||
|
|
head = {
|
||
|
|
center: 'Personal center',
|
||
|
|
logout: 'Logout',
|
||
|
|
fullScreen: 'Toggle full screen',
|
||
|
|
changeStyle: 'Switch themes',
|
||
|
|
language: 'Language',
|
||
|
|
zh: 'Chinese',
|
||
|
|
en: 'English',
|
||
|
|
size: 'Size',
|
||
|
|
normal: 'Normal',
|
||
|
|
small: 'Small',
|
||
|
|
large: 'Large',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
**Chinese**:
|
||
|
|
```typescript
|
||
|
|
head = {
|
||
|
|
center: '个人中心',
|
||
|
|
logout: '退出登录',
|
||
|
|
fullScreen: '切换全屏',
|
||
|
|
changeStyle: '切换主题',
|
||
|
|
language: '语言',
|
||
|
|
zh: '中文',
|
||
|
|
en: '英文',
|
||
|
|
size: '尺寸',
|
||
|
|
normal: '正常',
|
||
|
|
small: '小',
|
||
|
|
large: '大',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### Validation Rules
|
||
|
|
|
||
|
|
**English**:
|
||
|
|
```typescript
|
||
|
|
rule = {
|
||
|
|
pleaseEnter: 'Please enter ',
|
||
|
|
notNull: 'There cannot be empty',
|
||
|
|
pleaseSelect: 'Please select',
|
||
|
|
formatErr: 'The input format is incorrect',
|
||
|
|
int: 'Number',
|
||
|
|
max: 'The max value is {0}',
|
||
|
|
min: 'The min value is {0}',
|
||
|
|
maxLen: 'Enter up to {0} character',
|
||
|
|
minLen: 'Enter a minimum of {0} character',
|
||
|
|
hexadecimal: 'Please enter hexadecimal digits',
|
||
|
|
idCard: {
|
||
|
|
format: 'The ID card is wrong in length or format',
|
||
|
|
area: 'The ID area is illegal',
|
||
|
|
birth: 'The date of birth on the ID card is illegal',
|
||
|
|
error: 'The ID number is illegal',
|
||
|
|
},
|
||
|
|
username: [
|
||
|
|
'The username consists of letters, numbers, and is between 4-16 in length',
|
||
|
|
"Usernames cannot be underscored '_'",
|
||
|
|
'Usernames cannot contain spaces',
|
||
|
|
],
|
||
|
|
name: 'The name consists of Chinese characters or letters and is no more than 10 in length',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### HTTP Errors
|
||
|
|
|
||
|
|
**English**:
|
||
|
|
```typescript
|
||
|
|
http = {
|
||
|
|
unPermission: 'You do not have access yet, please contact your administrator to add it',
|
||
|
|
noPermission: 'This permission is not yet open, do not access without permission',
|
||
|
|
error: 'Network error',
|
||
|
|
downFail: 'Download failed with network abnormality!',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
**Chinese**:
|
||
|
|
```typescript
|
||
|
|
http = {
|
||
|
|
unPermission: '您暂无权访问,请联系管理员添加',
|
||
|
|
noPermission: '此权限尚未开放,请勿越权访问',
|
||
|
|
error: '网络错误',
|
||
|
|
downFail: '下载失败,网络异常!',
|
||
|
|
unLogin: '请先登录系统',
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### WebSocket Messages
|
||
|
|
|
||
|
|
**English**:
|
||
|
|
```typescript
|
||
|
|
ws = {
|
||
|
|
status: {
|
||
|
|
connected: 'Connected',
|
||
|
|
connecting: 'Connecting...',
|
||
|
|
disconnected: 'Disconnected',
|
||
|
|
error: 'Error',
|
||
|
|
},
|
||
|
|
autorefresh: {
|
||
|
|
enabled: 'Autorefresh enabled',
|
||
|
|
enabling: 'Enabling...',
|
||
|
|
disabled: 'Autorefresh disabled',
|
||
|
|
error: 'Autorefresh error',
|
||
|
|
},
|
||
|
|
tooltip: {
|
||
|
|
required: 'Required',
|
||
|
|
subscribed: 'Subscribed',
|
||
|
|
error: 'Error',
|
||
|
|
retry: 'Retry attempt',
|
||
|
|
clickToToggle: 'Click to enable/disable autorefresh',
|
||
|
|
retrying: 'Retrying',
|
||
|
|
errorOccurred: 'An error occurred',
|
||
|
|
},
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
**Chinese**:
|
||
|
|
```typescript
|
||
|
|
ws = {
|
||
|
|
status: {
|
||
|
|
connected: '已连接',
|
||
|
|
connecting: '连接中...',
|
||
|
|
disconnected: '未连接',
|
||
|
|
error: '错误',
|
||
|
|
},
|
||
|
|
autorefresh: {
|
||
|
|
enabled: '自动刷新已启用',
|
||
|
|
enabling: '正在启用...',
|
||
|
|
disabled: '自动刷新已禁用',
|
||
|
|
error: '自动刷新错误',
|
||
|
|
},
|
||
|
|
tooltip: {
|
||
|
|
required: '需要',
|
||
|
|
subscribed: '已订阅',
|
||
|
|
error: '错误',
|
||
|
|
retry: '重试次数',
|
||
|
|
clickToToggle: '点击启用/禁用自动刷新',
|
||
|
|
retrying: '正在重试',
|
||
|
|
errorOccurred: '发生错误',
|
||
|
|
},
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Domain Organization
|
||
|
|
|
||
|
|
| Domain | Description |
|
||
|
|
|--------|-------------|
|
||
|
|
| `base` | Common actions (add, delete, save, etc.) |
|
||
|
|
| `pwd` | Password and login related |
|
||
|
|
| `styles` | Theme style names |
|
||
|
|
| `head` | Header/menu labels |
|
||
|
|
| `tool` | Tool labels |
|
||
|
|
| `rule` | Validation rules |
|
||
|
|
| `http` | HTTP error messages |
|
||
|
|
| `preMenu` | Predefined menu items |
|
||
|
|
| `log` | Log management |
|
||
|
|
| `dict` | Dictionary management |
|
||
|
|
| `permission` | Permission management |
|
||
|
|
| `role` | Role management |
|
||
|
|
| `user` | User management |
|
||
|
|
| `buffer` | Cache management |
|
||
|
|
| `config` | Configuration management |
|
||
|
|
| `ws` | WebSocket messages |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Usage Patterns
|
||
|
|
|
||
|
|
### Direct i18n Usage
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import { i18n } from './i18n';
|
||
|
|
|
||
|
|
// Simple key
|
||
|
|
i18n.t('base.add'); // 'Add' or '添加'
|
||
|
|
|
||
|
|
// With interpolation
|
||
|
|
i18n.t('rule.max', { 0: 100 }); // 'The max value is 100'
|
||
|
|
i18n.t('rule.max', 100); // 'The max value is 100'
|
||
|
|
```
|
||
|
|
|
||
|
|
### Namespace-prefixed Translator
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import { createt } from './i18n';
|
||
|
|
|
||
|
|
const t = createt('user.'); // Creates translator with 'user.' prefix
|
||
|
|
t('.title'); // Resolves to 'user.title'
|
||
|
|
t('.delete'); // Resolves to 'user.delete'
|
||
|
|
```
|
||
|
|
|
||
|
|
### Dynamic Language Registration
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
import { registerLang } from './i18n';
|
||
|
|
|
||
|
|
registerLang('jp', new JapaneseClass());
|
||
|
|
i18n.locale = 'jp';
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Anti-Patterns
|
||
|
|
|
||
|
|
1. **Do not use flat keys for complex hierarchies** - Nested objects are fine, but avoid deeply nested structures
|
||
|
|
2. **Do not mix languages in one translation class** - Each class should contain only one language
|
||
|
|
3. **Do not use translation keys as literal strings** - Use the dot notation path consistently
|
||
|
|
4. **Do not forget to include all translation domains** - Missing domains will cause runtime errors
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Language**: English
|