295 lines
8.1 KiB
Markdown
295 lines
8.1 KiB
Markdown
---
|
|
name: frontend-admin-i18n
|
|
description: Generate frontend i18n translation files for madong plugin module. Creates JSON translation files with proper key patterns for both zh-cn and en languages.
|
|
---
|
|
|
|
# Step 9: Generate Frontend i18n
|
|
|
|
Generate JSON translation files for plugin module frontend.
|
|
|
|
## File Locations
|
|
|
|
### Plugin Mode (插件模式)
|
|
|
|
```
|
|
frontend/admin/src/apps/{plugin}/lang/zh-cn/{module}.{feature}.json
|
|
frontend/admin/src/apps/{plugin}/lang/en/{module}.{feature}.json
|
|
```
|
|
|
|
**Key prefix**: `{plugin}.{module}.{feature}`
|
|
- Example: `official/lang/zh-cn/rich_text.template.json` → key prefix is `official.rich_text.template`
|
|
|
|
### Built-in Mode (内置模式)
|
|
|
|
```
|
|
frontend/admin/src/lang/zh-cn/{module}.{feature}.json
|
|
frontend/admin/src/lang/en/{module}.{feature}.json
|
|
```
|
|
|
|
**Key prefix**: `{module}.{feature}` (NO plugin prefix)
|
|
- Example: `admin/src/lang/zh-cn/rich_text.template.json` → key prefix is `rich_text.template`
|
|
|
|
**Important**:
|
|
- File path itself defines the key prefix
|
|
- Inside the JSON file, do NOT include the prefix again
|
|
- Use nested object structure, NOT dot notation in keys
|
|
|
|
## Translation File Template (zh-cn)
|
|
|
|
```json
|
|
{
|
|
"dialog_title": "富文本模板",
|
|
"table": {
|
|
"columns": {
|
|
"sort": "排序",
|
|
"title": "标题",
|
|
"template": "模板类型",
|
|
"is_show": "显示状态",
|
|
"status": "状态",
|
|
"created_at": "创建时间"
|
|
}
|
|
},
|
|
"search_form": {
|
|
"title": "标题",
|
|
"template": "模板类型"
|
|
},
|
|
"form": {
|
|
"title": "标题",
|
|
"template": "模板类型",
|
|
"sort": "排序",
|
|
"is_show": "显示状态",
|
|
"enabled": "启用状态",
|
|
"content": "内容",
|
|
"meta": "元数据",
|
|
"extra": "扩展数据"
|
|
},
|
|
"validate": {
|
|
"title_required": "请输入标题",
|
|
"content_required": "请输入内容"
|
|
},
|
|
"tips": {
|
|
"add_success": "添加成功",
|
|
"edit_success": "编辑成功",
|
|
"delete_confirm": "确认删除吗?",
|
|
"delete_success": "删除成功"
|
|
},
|
|
"actions": {
|
|
"add": "新增",
|
|
"edit": "编辑",
|
|
"delete": "删除",
|
|
"detail": "详情",
|
|
"submit": "提交",
|
|
"cancel": "取消",
|
|
"confirm": "确定"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Translation File Template (en)
|
|
|
|
```json
|
|
{
|
|
"dialog_title": "Rich Text Template",
|
|
"table": {
|
|
"columns": {
|
|
"sort": "Sort",
|
|
"title": "Title",
|
|
"template": "Template Type",
|
|
"is_show": "Show Status",
|
|
"status": "Status",
|
|
"created_at": "Created At"
|
|
}
|
|
},
|
|
"search_form": {
|
|
"title": "Title",
|
|
"template": "Template Type"
|
|
},
|
|
"form": {
|
|
"title": "Title",
|
|
"template": "Template Type",
|
|
"sort": "Sort",
|
|
"is_show": "Show Status",
|
|
"enabled": "Enabled Status",
|
|
"content": "Content",
|
|
"meta": "Meta Data",
|
|
"extra": "Extra Data"
|
|
},
|
|
"validate": {
|
|
"title_required": "Please enter title",
|
|
"content_required": "Please enter content"
|
|
},
|
|
"tips": {
|
|
"add_success": "Added successfully",
|
|
"edit_success": "Edited successfully",
|
|
"delete_confirm": "Are you sure to delete?",
|
|
"delete_success": "Deleted successfully"
|
|
},
|
|
"actions": {
|
|
"add": "Add",
|
|
"edit": "Edit",
|
|
"delete": "Delete",
|
|
"detail": "Detail",
|
|
"submit": "Submit",
|
|
"cancel": "Cancel",
|
|
"confirm": "Confirm"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Usage in Frontend Code
|
|
|
|
### Plugin Mode
|
|
|
|
```typescript
|
|
import { $t } from '@/locales'
|
|
|
|
// File: official/lang/zh-cn/rich_text.template.json
|
|
// Key in file: "dialog_title"
|
|
// Full key: official.rich_text.template.dialog_title
|
|
const title = $t('official.rich_text.template.dialog_title')
|
|
const columnLabel = $t('official.rich_text.template.table.columns.title')
|
|
|
|
// In Vue component
|
|
<el-button>{{ $t('official.rich_text.template.actions.add') }}</el-button>
|
|
```
|
|
|
|
### Built-in Mode
|
|
|
|
```typescript
|
|
import { $t } from '@/locales'
|
|
|
|
// File: admin/src/lang/zh-cn/rich_text.template.json
|
|
// Key in file: "dialog_title"
|
|
// Full key: rich_text.template.dialog_title (NO plugin prefix)
|
|
const title = $t('rich_text.template.dialog_title')
|
|
const columnLabel = $t('rich_text.template.table.columns.title')
|
|
|
|
// In Vue component
|
|
<el-button>{{ $t('rich_text.template.actions.add') }}</el-button>
|
|
```
|
|
|
|
## Auto-generation Checklist
|
|
|
|
When generating frontend i18n:
|
|
- [ ] Create lang directory structure if not exists: `lang/zh-cn/` and `lang/en/`
|
|
- [ ] Filename format: `{module}.{feature}.json` (e.g., `rich_text.template.json`)
|
|
- [ ] Generate `zh-cn/{module}.{feature}.json` with nested object structure
|
|
- [ ] Generate `en/{module}.{feature}.json` with nested object structure
|
|
- [ ] Do NOT include key prefix in JSON content (prefix comes from filename)
|
|
- [ ] Add all column labels, placeholders, and validation messages
|
|
|
|
## Key Naming Convention
|
|
|
|
### Plugin Mode
|
|
|
|
| Type | File Location | Key in JSON | Full Key Used in Code |
|
|
|------|---------------|-------------|----------------------|
|
|
| Title | `apps/official/lang/zh-cn/rich_text.template.json` | `"dialog_title"` | `official.rich_text.template.dialog_title` |
|
|
| Column | `apps/official/lang/zh-cn/rich_text.template.json` | `"table.columns.title"` (nested) | `official.rich_text.template.table.columns.title` |
|
|
| Search | `apps/official/lang/zh-cn/rich_text.template.json` | `"search_form.title"` (nested) | `official.rich_text.template.search_form.title` |
|
|
| Form | `apps/official/lang/zh-cn/rich_text.template.json` | `"form.title"` (nested) | `official.rich_text.template.form.title` |
|
|
| Action | `apps/official/lang/zh-cn/rich_text.template.json` | `"actions.add"` (nested) | `official.rich_text.template.actions.add` |
|
|
|
|
### Built-in Mode
|
|
|
|
| Type | File Location | Key in JSON | Full Key Used in Code |
|
|
|------|---------------|-------------|----------------------|
|
|
| Title | `admin/src/lang/zh-cn/rich_text.template.json` | `"dialog_title"` | `rich_text.template.dialog_title` |
|
|
| Column | `admin/src/lang/zh-cn/rich_text.template.json` | `"table.columns.title"` (nested) | `rich_text.template.table.columns.title` |
|
|
| Search | `admin/src/lang/zh-cn/rich_text.template.json` | `"search_form.title"` (nested) | `rich_text.template.search_form.title` |
|
|
| Form | `admin/src/lang/zh-cn/rich_text.template.json` | `"form.title"` (nested) | `rich_text.template.form.title` |
|
|
| Action | `admin/src/lang/zh-cn/rich_text.template.json` | `"actions.add"` (nested) | `rich_text.template.actions.add` |
|
|
|
|
## File Naming Rules
|
|
|
|
1. **Module name in filename uses underscore**: `rich_text.template.json` (NOT `rich-text.template.json`)
|
|
2. **Feature name in filename uses lowercase**: `template` (NOT `Template`)
|
|
3. **File extension**: `.json`
|
|
4. **Directory structure**: `lang/{locale}/{module}.{feature}.json`
|
|
|
|
## Integration with Frontend Code
|
|
|
|
The generated i18n keys should match the schemas/index.tsx:
|
|
|
|
```typescript
|
|
// schemas/index.tsx
|
|
import { $t } from '@/locales'
|
|
|
|
export const crudSchema = (): CrudSchema => {
|
|
return {
|
|
// File: official/lang/zh-cn/rich_text.template.json
|
|
// Key: "dialog_title"
|
|
dialogTitle: $t('official.rich_text.template.dialog_title'),
|
|
columns: [
|
|
{
|
|
prop: 'title',
|
|
// Key: "table.columns.title"
|
|
label: $t('official.rich_text.template.table.columns.title'),
|
|
},
|
|
],
|
|
searchFormSchema: {
|
|
schema: [
|
|
{
|
|
// Key: "search_form.title"
|
|
label: $t('official.rich_text.template.search_form.title'),
|
|
prop: 'title',
|
|
},
|
|
],
|
|
},
|
|
formSchema: {
|
|
schema: [
|
|
{
|
|
// Key: "form.title"
|
|
label: $t('official.rich_text.template.form.title'),
|
|
prop: 'title',
|
|
},
|
|
],
|
|
},
|
|
}
|
|
}
|
|
```
|
|
|
|
## Common Mistakes to Avoid
|
|
|
|
1. ❌ **Wrong**: Including prefix in JSON keys
|
|
```json
|
|
{
|
|
"official.rich_text.template.dialog_title": "富文本模板"
|
|
}
|
|
```
|
|
|
|
2. ✅ **Correct**: Nested object without prefix
|
|
```json
|
|
{
|
|
"dialog_title": "富文本模板"
|
|
}
|
|
```
|
|
|
|
3. ❌ **Wrong**: Using hyphen in filename
|
|
```
|
|
lang/zh-cn/rich-text.template.json
|
|
```
|
|
|
|
4. ✅ **Correct**: Using underscore in filename
|
|
```
|
|
lang/zh-cn/rich_text.template.json
|
|
```
|
|
|
|
5. ❌ **Wrong**: Flat keys with dots
|
|
```json
|
|
{
|
|
"table.columns.sort": "排序"
|
|
}
|
|
```
|
|
|
|
6. ✅ **Correct**: Nested objects
|
|
```json
|
|
{
|
|
"table": {
|
|
"columns": {
|
|
"sort": "排序"
|
|
}
|
|
}
|
|
}
|
|
```
|