Skip to content

Commit e96af1a

Browse files
author
weilei
committed
feat(core): 添加国际化支持,构建多语言包并更新组件以支持语言切换
1 parent 49b18b3 commit e96af1a

File tree

20 files changed

+607
-16
lines changed

20 files changed

+607
-16
lines changed
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
console.log('开始构建国际化语言包...\n');
5+
6+
// 确保目标目录存在
7+
const libDir = path.join(__dirname, '../lib');
8+
const localeDir = path.join(libDir, 'locale');
9+
const langDir = path.join(localeDir, 'lang');
10+
11+
// 创建目录
12+
[libDir, localeDir, langDir].forEach(dir => {
13+
if (!fs.existsSync(dir)) {
14+
fs.mkdirSync(dir, { recursive: true });
15+
}
16+
});
17+
18+
// 源目录
19+
const srcLocaleDir = path.join(__dirname, '../src/locale');
20+
const srcLangDir = path.join(srcLocaleDir, 'lang');
21+
22+
// 将 ES6 模块转换为 CommonJS
23+
function transformToCommonJS(code) {
24+
return code
25+
.replace(/export default\s+/, 'module.exports = ')
26+
.replace(/import\s+(.+?)\s+from\s+['"](.+?)['"];?/g, 'const $1 = require("$2");');
27+
}
28+
29+
// 构建单个文件
30+
function buildFile(srcPath, destPath) {
31+
try {
32+
const code = fs.readFileSync(srcPath, 'utf8');
33+
const transformedCode = transformToCommonJS(code);
34+
35+
fs.writeFileSync(destPath, transformedCode);
36+
console.log(`✅ 构建成功: ${path.relative(process.cwd(), destPath)}`);
37+
return true;
38+
} catch (error) {
39+
console.error(`❌ 构建失败: ${path.relative(process.cwd(), srcPath)}`);
40+
console.error(error.message);
41+
return false;
42+
}
43+
}
44+
45+
// 构建主 locale/index.js
46+
const localeIndexSrc = path.join(srcLocaleDir, 'index.js');
47+
const localeIndexDest = path.join(localeDir, 'index.js');
48+
if (fs.existsSync(localeIndexSrc)) {
49+
buildFile(localeIndexSrc, localeIndexDest);
50+
}
51+
52+
// 构建 locale/mixin.js
53+
const mixinSrc = path.join(srcLocaleDir, 'mixin.js');
54+
const mixinDest = path.join(localeDir, 'mixin.js');
55+
if (fs.existsSync(mixinSrc)) {
56+
buildFile(mixinSrc, mixinDest);
57+
}
58+
59+
// 构建所有语言包
60+
if (fs.existsSync(srcLangDir)) {
61+
const langFiles = fs.readdirSync(srcLangDir);
62+
63+
langFiles.forEach(file => {
64+
if (file.endsWith('.js')) {
65+
const srcPath = path.join(srcLangDir, file);
66+
const destPath = path.join(langDir, file);
67+
buildFile(srcPath, destPath);
68+
}
69+
});
70+
}
71+
72+
// 创建语言包入口文件 lib/locale/lang/index.js
73+
const langIndexContent = `// 语言包入口文件
74+
module.exports = {
75+
// 中文
76+
'zh-CN': require('./zh-CN'),
77+
'zh-cn': require('./zh-CN'),
78+
'zh-TW': require('./zh-TW'),
79+
'zh-tw': require('./zh-TW'),
80+
81+
// 英文
82+
'en': require('./en'),
83+
'en-US': require('./en'),
84+
'en-GB': require('./en'),
85+
86+
// 日语
87+
'ja-JP': require('./ja'),
88+
'ja': require('./ja'),
89+
90+
// 韩语
91+
'ko-KR': require('./ko'),
92+
'ko': require('./ko'),
93+
94+
// 法语
95+
'fr-FR': require('./fr'),
96+
'fr': require('./fr'),
97+
98+
// 德语
99+
'de-DE': require('./de'),
100+
'de': require('./de'),
101+
102+
// 西班牙语
103+
'es-ES': require('./es'),
104+
'es': require('./es'),
105+
106+
// 俄语
107+
'ru-RU': require('./ru-RU'),
108+
'ru': require('./ru-RU'),
109+
110+
// 葡萄牙语
111+
'pt-BR': require('./pt-br'),
112+
'pt-br': require('./pt-br'),
113+
'pt': require('./pt-br'),
114+
115+
// 意大利语
116+
'it-IT': require('./it'),
117+
'it': require('./it'),
118+
119+
// 阿拉伯语
120+
'ar-SA': require('./ar'),
121+
'ar': require('./ar')
122+
};
123+
`;
124+
125+
fs.writeFileSync(path.join(langDir, 'index.js'), langIndexContent);
126+
console.log(`✅ 构建成功: lib/locale/lang/index.js`);
127+
128+
// 创建便于 CDN 使用的 UMD 格式语言包
129+
const createUMDLang = (langName, langCode) => {
130+
const srcPath = path.join(srcLangDir, `${langCode}.js`);
131+
if (fs.existsSync(srcPath)) {
132+
const langContent = fs.readFileSync(srcPath, 'utf8');
133+
// 提取语言数据对象
134+
const langDataMatch = langContent.match(/export default\s+(\{[\s\S]*\});?\s*$/);
135+
if (langDataMatch) {
136+
const langData = langDataMatch[1];
137+
138+
const umdContent = `(function (global, factory) {
139+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
140+
typeof define === 'function' && define.amd ? define(factory) :
141+
(global = global || self, (global.ELEMENT_UI_X = global.ELEMENT_UI_X || {}, global.ELEMENT_UI_X.lang = global.ELEMENT_UI_X.lang || {}, global.ELEMENT_UI_X.lang.${langName} = factory()));
142+
}(this, function () { 'use strict';
143+
144+
return ${langData};
145+
146+
}));
147+
`;
148+
149+
const umdPath = path.join(langDir, `${langCode}.umd.js`);
150+
fs.writeFileSync(umdPath, umdContent);
151+
console.log(`✅ 构建成功: lib/locale/lang/${langCode}.umd.js (UMD格式)`);
152+
}
153+
}
154+
};
155+
156+
// 构建 UMD 格式的语言包
157+
const umdLanguages = [
158+
{ name: 'zhCN', code: 'zh-CN' },
159+
{ name: 'zhTW', code: 'zh-TW' },
160+
{ name: 'en', code: 'en' },
161+
{ name: 'ja', code: 'ja' },
162+
{ name: 'ko', code: 'ko' },
163+
{ name: 'fr', code: 'fr' },
164+
{ name: 'de', code: 'de' },
165+
{ name: 'es', code: 'es' },
166+
{ name: 'ru', code: 'ru-RU' },
167+
{ name: 'ptBr', code: 'pt-br' },
168+
{ name: 'it', code: 'it' },
169+
{ name: 'ar', code: 'ar' },
170+
];
171+
172+
umdLanguages.forEach(({ name, code }) => {
173+
createUMDLang(name, code);
174+
});
175+
176+
console.log('\n🎉 国际化语言包构建完成!');

packages/element-ui-x/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@
2020
"keywords": [
2121
"element-ui",
2222
"vue",
23-
"ai"
23+
"ai",
24+
"i18n"
2425
],
2526
"bugs": {
2627
"url": "https://github.com/worryzyy/element-ui-x/issues"
2728
},
2829
"scripts": {
29-
"build": "npm run build:common && npm run build:esm && npm run build:umd && npm run build:components",
30+
"build": "npm run build:common && npm run build:esm && npm run build:umd && npm run build:components && npm run build:locale",
3031
"build:common": "webpack --config build/webpack.common.conf.js",
3132
"build:esm": "webpack --config build/webpack.esm.conf.js",
3233
"build:umd": "webpack --config build/webpack.umd.conf.js",
33-
"build:components": "node build/build-components.js"
34+
"build:components": "node build/build-components.js",
35+
"build:locale": "node build/build-locale.js"
3436
},
3537
"peerDependencies": {
3638
"element-ui": "2.15.14",

packages/element-ui-x/src/components/Sender/src/main.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
:autosize="computedAutoSize"
5757
type="textarea"
5858
:validate-event="false"
59-
:placeholder="placeholder"
59+
:placeholder="computedPlaceholder"
6060
:readonly="readOnly || disabled"
6161
:disabled="disabled"
6262
@keydown.native="handleKeyDown"
@@ -185,6 +185,7 @@
185185
</template>
186186

187187
<script>
188+
import Locale from '../../../locale/mixin';
188189
import ClearButton from './components/ClearButton.vue';
189190
import LoadingButton from './components/LoadingButton.vue';
190191
import SendButton from './components/SendButton.vue';
@@ -193,6 +194,7 @@
193194
194195
export default {
195196
name: 'ElXSender',
197+
mixins: [Locale],
196198
197199
components: {
198200
ClearButton,
@@ -209,7 +211,7 @@
209211
},
210212
placeholder: {
211213
type: String,
212-
default: '请输入内容',
214+
default: '',
213215
},
214216
autoSize: {
215217
type: Object,
@@ -344,6 +346,11 @@
344346
maxRows: 6,
345347
};
346348
},
349+
350+
// 计算 placeholder
351+
computedPlaceholder() {
352+
return this.placeholder || this.elXt('el_x.sender.placeholder');
353+
},
347354
},
348355
349356
watch: {

packages/element-ui-x/src/components/Thinking/src/main.vue

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@
4646
>
4747
{{
4848
localStatus === 'thinking'
49-
? '思考中...'
49+
? elXt('el_x.thinking.processing')
5050
: localStatus === 'error'
51-
? '思考遇到问题'
51+
? elXt('el_x.thinking.error')
5252
: localStatus === 'end'
53-
? '思考完成'
54-
: '开始思考'
53+
? elXt('el_x.thinking.completed')
54+
: elXt('el_x.thinking.start')
5555
}}
5656
</slot>
5757
</span>
@@ -99,8 +99,11 @@
9999
</template>
100100

101101
<script>
102+
import Locale from '../../../locale/mixin';
103+
102104
export default {
103105
name: 'ElXThinking',
106+
mixins: [Locale],
104107
props: {
105108
content: {
106109
type: String,
@@ -154,7 +157,9 @@
154157
},
155158
computed: {
156159
displayedContent() {
157-
return this.localStatus === 'error' ? '思考过程中出现错误' : this.content;
160+
return this.localStatus === 'error'
161+
? this.elXt('el_x.thinking.errorContent')
162+
: this.content;
158163
},
159164
},
160165
watch: {

packages/element-ui-x/src/index.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import {
2020
XRequest,
2121
XStream,
2222
} from './mixins';
23+
// 导入国际化功能
24+
import locale from './locale';
25+
import lang from './locale/lang';
2326

2427
const components = [
2528
ElXTypewriter,
@@ -35,14 +38,26 @@ const components = [
3538
ElXWelcome,
3639
];
3740

38-
const install = function (Vue) {
41+
const install = function (Vue, opts = {}) {
42+
// 处理国际化配置
43+
if (opts.locale) {
44+
locale.use(opts.locale);
45+
}
46+
if (opts.i18n) {
47+
locale.i18n(opts.i18n);
48+
}
49+
3950
components.forEach(component => {
4051
Vue.component(component.name, component);
4152
});
4253
};
4354

4455
// 具名导出(按需引入)- 组件和Mixins
4556
export {
57+
// Mixins
58+
createSendUtils,
59+
createStreamUtils,
60+
customMixins,
4661
// 组件
4762
ElXAttachments,
4863
ElXBubble,
@@ -55,20 +70,22 @@ export {
5570
ElXThoughtChain,
5671
ElXTypewriter,
5772
ElXWelcome,
58-
// Mixins
59-
createSendUtils,
60-
createStreamUtils,
61-
customMixins,
73+
lang,
74+
// 国际化
75+
locale,
6276
recordMixin,
6377
sendMixin,
6478
streamMixin,
6579
XRequest,
6680
XStream,
6781
};
82+
6883
// 默认导出(完整引入)
6984
const ElementUIX = {
70-
version: '1.0.0',
85+
version: '0.2.2',
7186
install,
87+
locale,
88+
lang,
7289
};
7390

7491
// 将组件添加到默认导出对象中

0 commit comments

Comments
 (0)