Skip to content

Commit 98d361e

Browse files
committed
feat: add i18n
1 parent 65b8313 commit 98d361e

39 files changed

Lines changed: 1759 additions & 217 deletions

File tree

frontend/electron-builder.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ extraResources:
1717
filter:
1818
- 'main*'
1919
- 'config/**/*'
20+
- from: src/locales
21+
to: locales
22+
filter:
23+
- '**/*'
2024
asarUnpack:
2125
- resources/**
2226
win:

frontend/i18next-parser.config.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// i18next-parser.config.js
2+
module.exports = {
3+
// 1. 上下文与键值分隔符
4+
contextSeparator: '_',
5+
// 如果你的 Key 包含 '.' (例如 "error.message") 且你希望它在 JSON 中嵌套,请保持默认 '.'
6+
// 如果你使用自然语言作为 Key (例如 "Hello World"),建议设为 false 以避免意外分割
7+
keySeparator: '.',
8+
namespaceSeparator: ':',
9+
10+
// 2. 备份与恢复
11+
// 设为 false,因为如果不慎覆盖,Git 才是最好的备份工具。生成 _old.json 文件通常会弄脏目录
12+
createOldCatalogs: false,
13+
14+
// 3. 默认值策略 (高阶用法)
15+
// 最佳实践:对于源语言 (en-US),默认值就是 Key 本身(如果 Key 是自然语言)
16+
// 对于其他语言 (zh-CN),留空以便翻译人员识别
17+
defaultValue: (locale, namespace, key, value) => {
18+
console.log('Found Key:', key, locale, namespace, value)
19+
if (locale === 'en-US') {
20+
// 如果代码中已经有默认值 (t('key', 'default')),使用代码中的值
21+
return value || key
22+
}
23+
return '' // 中文等其他语言留空,表示待翻译
24+
},
25+
26+
// 4. 代码格式化
27+
indentation: 2,
28+
keepRemoved: true, // 保持 true 以防止代码临时注释导致翻译丢失
29+
30+
// 5. 词法分析器 (Lexers)
31+
// 明确配置 jsx/tsx 的解析选项,确保能够提取组件属性中的翻译
32+
lexers: {
33+
ts: ['JavascriptLexer'],
34+
tsx: [
35+
{
36+
lexer: 'JsxLexer',
37+
functions: ['t', 'Trans'], // 提取 t() 函数和 <Trans> 组件
38+
attr: 'i18nKey' // 提取组件属性中的 Key
39+
}
40+
],
41+
js: ['JavascriptLexer'],
42+
jsx: [
43+
{
44+
lexer: 'JsxLexer',
45+
functions: ['t', 'Trans'],
46+
attr: 'i18nKey'
47+
}
48+
],
49+
default: ['JavascriptLexer']
50+
},
51+
52+
// 6. 语言与过滤
53+
locales: ['zh-CN', 'en-US'],
54+
// 这里的 defaultNamespace 主要是指未指定 ns 时的归宿
55+
defaultNamespace: 'translation',
56+
57+
// 7. 输出配置
58+
output: 'src/locales/$LOCALE/$NAMESPACE.json',
59+
60+
// 8. 输入源 (保持你原有的 Monorepo 结构)
61+
input: [
62+
'src/renderer/**/*.{js,jsx,ts,tsx}',
63+
'src/main/**/*.{js,ts}',
64+
'src/preload/**/*.{js,ts}',
65+
'packages/**/*.{js,ts}',
66+
'!src/**/*.d.ts',
67+
'!**/node_modules/**'
68+
],
69+
70+
// 9. 排序 (对 Git 协作至关重要)
71+
sort: true,
72+
73+
// 10. 日志
74+
verbose: true,
75+
76+
// [新增] 如果 key 已经存在于 json 中,是否更新其默认值?
77+
// 通常设为 false,避免代码中的临时修改覆盖了翻译人员已经校对好的文案
78+
resetDefaultValueLocale: false
79+
}

frontend/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
"publish": "npm run copy-backend && npm run build && electron-builder --mac --win -p always",
3535
"rebuild": "electron-rebuild -f -w better-sqlite3",
3636
"copy-backend": "node scripts/copy-prebuilt-backend.js",
37-
"electron-pack": "npm run build && electron-builder --mac"
37+
"electron-pack": "npm run build && electron-builder --mac",
38+
"i18n:extract": "pnpm dlx i18next-parser --config i18next-parser.config.js",
39+
"i18n:validate": "i18next-parser --validate --config i18next-parser.config.js"
3840
},
3941
"dependencies": {
4042
"@ai-sdk/openai-compatible": "^1.0.14",
@@ -64,6 +66,8 @@
6466
"electron-updater": "^6.3.9",
6567
"embla-carousel-react": "^8.6.0",
6668
"express": "^5.1.0",
69+
"i18next": "^25.6.3",
70+
"i18next-fs-backend": "^2.6.1",
6771
"jotai": "^2.14.0",
6872
"lucide-react": "^0.542.0",
6973
"mitt": "^3.0.1",
@@ -117,6 +121,7 @@
117121
"eslint-plugin-react-refresh": "^0.4.20",
118122
"fetch-socks": "1.3.2",
119123
"highlight.js": "^11.11.1",
124+
"i18next-parser": "^9.3.0",
120125
"iconv-lite": "^0.6.3",
121126
"less": "^4.4.0",
122127
"lodash": "^4.17.21",

0 commit comments

Comments
 (0)