Skip to content

Commit a1eeb1a

Browse files
committed
feat(i18n): add missing translations and fix Semi Design locale mapping
Add missing translation keys for all non-English languages: - zh-TW: 27 keys (plurals, cache, recharge) - fr: 98 keys (disk cache, OAuth, preferences, performance monitor) - ru: 98 keys (disk cache, OAuth, preferences, performance monitor) - ja: 103 keys (disk cache, OAuth, preferences, performance monitor) - vi: 99 keys (disk cache, OAuth, preferences, performance monitor) Fix SemiLocaleWrapper to map all supported languages (zh-TW, fr, ru, ja, vi) to their Semi Design locale counterparts instead of only zh/en, which caused UI components like pagination to show Chinese labels for non-Chinese/English users. fix(i18n): remove duplicate English-keyed translations Remove English keys (Recharge Quota, GC execution failed, Cache Directory, Available) that duplicate existing Chinese source keys, violating the project's Chinese-source-key convention for i18n lookups. fix(i18n): translate Vietnamese _other plural forms from English The _other plural variants for filtering, models, logs, and token deletion were left as English strings, causing English fallback text for count > 1 in Vietnamese locale. fix(i18n): remove duplicate English keys from en.json Remove English-keyed duplicates (GC execution failed, Cache Directory, Available) that duplicate existing Chinese-keyed entries in en.json.
1 parent c5365e4 commit a1eeb1a

109 files changed

Lines changed: 5718 additions & 2321 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

web/i18next.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { defineConfig } from 'i18next-cli';
2121

2222
/** @type {import('i18next-cli').I18nextToolkitConfig} */
2323
export default defineConfig({
24-
locales: ['zh', 'en', 'fr', 'ru', 'ja', 'vi'],
24+
locales: ['zh-CN', 'zh-TW', 'en', 'fr', 'ru', 'ja', 'vi'],
2525
extract: {
2626
input: ['src/**/*.{js,jsx,ts,tsx}'],
2727
ignore: ['src/i18n/**/*'],

web/src/components/auth/LoginForm.jsx

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ const LoginForm = () => {
7171
let navigate = useNavigate();
7272
const { t } = useTranslation();
7373
const githubButtonTextKeyByState = {
74-
idle: '使用 GitHub 继续',
75-
redirecting: '正在跳转 GitHub...',
76-
timeout: '请求超时,请刷新页面后重新发起 GitHub 登录',
74+
idle: t('使用 GitHub 继续'),
75+
redirecting: t('正在跳转 GitHub...'),
76+
timeout: t('请求超时,请刷新页面后重新发起 GitHub 登录'),
7777
};
7878
const [inputs, setInputs] = useState({
7979
username: '',
@@ -110,7 +110,7 @@ const LoginForm = () => {
110110
const [githubButtonState, setGithubButtonState] = useState('idle');
111111
const [githubButtonDisabled, setGithubButtonDisabled] = useState(false);
112112
const githubTimeoutRef = useRef(null);
113-
const githubButtonText = t(githubButtonTextKeyByState[githubButtonState]);
113+
const githubButtonText = githubButtonTextKeyByState[githubButtonState];
114114
const [customOAuthLoading, setCustomOAuthLoading] = useState({});
115115

116116
const logo = getLogo();
@@ -184,7 +184,7 @@ const LoginForm = () => {
184184

185185
const onSubmitWeChatVerificationCode = async () => {
186186
if (turnstileEnabled && turnstileToken === '') {
187-
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
187+
showInfo(t('请稍后几秒重试,Turnstile 正在检查用户环境!'));
188188
return;
189189
}
190190
setWechatCodeSubmitLoading(true);
@@ -199,13 +199,13 @@ const LoginForm = () => {
199199
setUserData(data);
200200
updateAPI();
201201
navigate('/');
202-
showSuccess('登录成功!');
202+
showSuccess(t('登录成功!'));
203203
setShowWeChatLoginModal(false);
204204
} else {
205205
showError(message);
206206
}
207207
} catch (error) {
208-
showError('登录失败,请重试');
208+
showError(t('登录失败,请重试'));
209209
} finally {
210210
setWechatCodeSubmitLoading(false);
211211
}
@@ -221,7 +221,7 @@ const LoginForm = () => {
221221
return;
222222
}
223223
if (turnstileEnabled && turnstileToken === '') {
224-
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
224+
showInfo(t('请稍后几秒重试,Turnstile 正在检查用户环境!'));
225225
return;
226226
}
227227
setSubmitted(true);
@@ -247,11 +247,11 @@ const LoginForm = () => {
247247
userDispatch({ type: 'login', payload: data });
248248
setUserData(data);
249249
updateAPI();
250-
showSuccess('登录成功!');
250+
showSuccess(t('登录成功!'));
251251
if (username === 'root' && password === '123456') {
252252
Modal.error({
253-
title: '您正在使用默认密码!',
254-
content: '请立刻修改默认密码!',
253+
title: t('您正在使用默认密码!'),
254+
content: t('请立刻修改默认密码!'),
255255
centered: true,
256256
});
257257
}
@@ -260,10 +260,10 @@ const LoginForm = () => {
260260
showError(message);
261261
}
262262
} else {
263-
showError('请输入用户名和密码!');
263+
showError(t('请输入用户名和密码!'));
264264
}
265265
} catch (error) {
266-
showError('登录失败,请重试');
266+
showError(t('登录失败,请重试'));
267267
} finally {
268268
setLoginLoading(false);
269269
}
@@ -297,15 +297,15 @@ const LoginForm = () => {
297297
if (success) {
298298
userDispatch({ type: 'login', payload: data });
299299
localStorage.setItem('user', JSON.stringify(data));
300-
showSuccess('登录成功!');
300+
showSuccess(t('登录成功!'));
301301
setUserData(data);
302302
updateAPI();
303303
navigate('/');
304304
} else {
305305
showError(message);
306306
}
307307
} catch (error) {
308-
showError('登录失败,请重试');
308+
showError(t('登录失败,请重试'));
309309
}
310310
};
311311

@@ -417,11 +417,11 @@ const LoginForm = () => {
417417
return;
418418
}
419419
if (!passkeySupported) {
420-
showInfo('当前环境无法使用 Passkey 登录');
420+
showInfo(t('当前环境无法使用 Passkey 登录'));
421421
return;
422422
}
423423
if (!window.PublicKeyCredential) {
424-
showInfo('当前浏览器不支持 Passkey');
424+
showInfo(t('当前浏览器不支持 Passkey'));
425425
return;
426426
}
427427

@@ -430,7 +430,7 @@ const LoginForm = () => {
430430
const beginRes = await API.post('/api/user/passkey/login/begin');
431431
const { success, message, data } = beginRes.data;
432432
if (!success) {
433-
showError(message || '无法发起 Passkey 登录');
433+
showError(message || t('无法发起 Passkey 登录'));
434434
return;
435435
}
436436

@@ -442,7 +442,7 @@ const LoginForm = () => {
442442
});
443443
const payload = buildAssertionResult(assertion);
444444
if (!payload) {
445-
showError('Passkey 验证失败,请重试');
445+
showError(t('Passkey 验证失败,请重试'));
446446
return;
447447
}
448448

@@ -455,16 +455,16 @@ const LoginForm = () => {
455455
userDispatch({ type: 'login', payload: finish.data });
456456
setUserData(finish.data);
457457
updateAPI();
458-
showSuccess('登录成功!');
458+
showSuccess(t('登录成功!'));
459459
navigate('/console');
460460
} else {
461-
showError(finish.message || 'Passkey 登录失败,请重试');
461+
showError(finish.message || t('Passkey 登录失败,请重试'));
462462
}
463463
} catch (error) {
464464
if (error?.name === 'AbortError') {
465-
showInfo('已取消 Passkey 登录');
465+
showInfo(t('已取消 Passkey 登录'));
466466
} else {
467-
showError('Passkey 登录失败,请重试');
467+
showError(t('Passkey 登录失败,请重试'));
468468
}
469469
} finally {
470470
setPasskeyLoading(false);
@@ -490,7 +490,7 @@ const LoginForm = () => {
490490
userDispatch({ type: 'login', payload: data });
491491
setUserData(data);
492492
updateAPI();
493-
showSuccess('登录成功!');
493+
showSuccess(t('登录成功!'));
494494
navigate('/console');
495495
};
496496

@@ -885,7 +885,11 @@ const LoginForm = () => {
885885
}}
886886
>
887887
<div className='flex flex-col items-center'>
888-
<img src={status.wechat_qrcode} alt='微信二维码' className='mb-4' />
888+
<img
889+
src={status.wechat_qrcode}
890+
alt={t('微信二维码')}
891+
className='mb-4'
892+
/>
889893
</div>
890894

891895
<div className='text-center mb-4'>
@@ -928,7 +932,7 @@ const LoginForm = () => {
928932
/>
929933
</svg>
930934
</div>
931-
两步验证
935+
{t('两步验证')}
932936
</div>
933937
}
934938
visible={showTwoFA}
@@ -958,8 +962,7 @@ const LoginForm = () => {
958962
style={{ top: '50%', left: '-120px' }}
959963
/>
960964
<div className='w-full max-w-sm mt-[60px]'>
961-
{showEmailLogin ||
962-
!hasOAuthLoginOptions
965+
{showEmailLogin || !hasOAuthLoginOptions
963966
? renderEmailLoginForm()
964967
: renderOAuthOptions()}
965968
{renderWeChatLoginModal()}

web/src/components/auth/OAuth2Callback.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const OAuth2Callback = (props) => {
3535
const [searchParams] = useSearchParams();
3636
const [, userDispatch] = useContext(UserContext);
3737
const navigate = useNavigate();
38-
38+
3939
// 防止 React 18 Strict Mode 下重复执行
4040
const hasExecuted = useRef(false);
4141

web/src/components/auth/RegisterForm.jsx

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ const RegisterForm = () => {
6969
let navigate = useNavigate();
7070
const { t } = useTranslation();
7171
const githubButtonTextKeyByState = {
72-
idle: '使用 GitHub 继续',
73-
redirecting: '正在跳转 GitHub...',
74-
timeout: '请求超时,请刷新页面后重新发起 GitHub 登录',
72+
idle: t('使用 GitHub 继续'),
73+
redirecting: t('正在跳转 GitHub...'),
74+
timeout: t('请求超时,请刷新页面后重新发起 GitHub 登录'),
7575
};
7676
const [inputs, setInputs] = useState({
7777
username: '',
@@ -109,7 +109,7 @@ const RegisterForm = () => {
109109
const [githubButtonState, setGithubButtonState] = useState('idle');
110110
const [githubButtonDisabled, setGithubButtonDisabled] = useState(false);
111111
const githubTimeoutRef = useRef(null);
112-
const githubButtonText = t(githubButtonTextKeyByState[githubButtonState]);
112+
const githubButtonText = githubButtonTextKeyByState[githubButtonState];
113113

114114
const logo = getLogo();
115115
const systemName = getSystemName();
@@ -184,7 +184,7 @@ const RegisterForm = () => {
184184

185185
const onSubmitWeChatVerificationCode = async () => {
186186
if (turnstileEnabled && turnstileToken === '') {
187-
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
187+
showInfo(t('请稍后几秒重试,Turnstile 正在检查用户环境!'));
188188
return;
189189
}
190190
setWechatCodeSubmitLoading(true);
@@ -199,13 +199,13 @@ const RegisterForm = () => {
199199
setUserData(data);
200200
updateAPI();
201201
navigate('/');
202-
showSuccess('登录成功!');
202+
showSuccess(t('登录成功!'));
203203
setShowWeChatLoginModal(false);
204204
} else {
205205
showError(message);
206206
}
207207
} catch (error) {
208-
showError('登录失败,请重试');
208+
showError(t('登录失败,请重试'));
209209
} finally {
210210
setWechatCodeSubmitLoading(false);
211211
}
@@ -217,16 +217,16 @@ const RegisterForm = () => {
217217

218218
async function handleSubmit(e) {
219219
if (password.length < 8) {
220-
showInfo('密码长度不得小于 8 位!');
220+
showInfo(t('密码长度不得小于 8 位!'));
221221
return;
222222
}
223223
if (password !== password2) {
224-
showInfo('两次输入的密码不一致');
224+
showInfo(t('两次输入的密码不一致'));
225225
return;
226226
}
227227
if (username && password) {
228228
if (turnstileEnabled && turnstileToken === '') {
229-
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
229+
showInfo(t('请稍后几秒重试,Turnstile 正在检查用户环境!'));
230230
return;
231231
}
232232
setRegisterLoading(true);
@@ -242,12 +242,12 @@ const RegisterForm = () => {
242242
const { success, message } = res.data;
243243
if (success) {
244244
navigate('/login');
245-
showSuccess('注册成功!');
245+
showSuccess(t('注册成功!'));
246246
} else {
247247
showError(message);
248248
}
249249
} catch (error) {
250-
showError('注册失败,请重试');
250+
showError(t('注册失败,请重试'));
251251
} finally {
252252
setRegisterLoading(false);
253253
}
@@ -257,7 +257,7 @@ const RegisterForm = () => {
257257
const sendVerificationCode = async () => {
258258
if (inputs.email === '') return;
259259
if (turnstileEnabled && turnstileToken === '') {
260-
showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
260+
showInfo(t('请稍后几秒重试,Turnstile 正在检查用户环境!'));
261261
return;
262262
}
263263
setVerificationCodeLoading(true);
@@ -267,13 +267,13 @@ const RegisterForm = () => {
267267
);
268268
const { success, message } = res.data;
269269
if (success) {
270-
showSuccess('验证码发送成功,请检查你的邮箱!');
270+
showSuccess(t('验证码发送成功,请检查你的邮箱!'));
271271
setDisableButton(true); // 发送成功后禁用按钮,开始倒计时
272272
} else {
273273
showError(message);
274274
}
275275
} catch (error) {
276-
showError('发送验证码失败,请重试');
276+
showError(t('发送验证码失败,请重试'));
277277
} finally {
278278
setVerificationCodeLoading(false);
279279
}
@@ -379,15 +379,15 @@ const RegisterForm = () => {
379379
if (success) {
380380
userDispatch({ type: 'login', payload: data });
381381
localStorage.setItem('user', JSON.stringify(data));
382-
showSuccess('登录成功!');
382+
showSuccess(t('登录成功!'));
383383
setUserData(data);
384384
updateAPI();
385385
navigate('/');
386386
} else {
387387
showError(message);
388388
}
389389
} catch (error) {
390-
showError('登录失败,请重试');
390+
showError(t('登录失败,请重试'));
391391
}
392392
};
393393

@@ -745,7 +745,11 @@ const RegisterForm = () => {
745745
}}
746746
>
747747
<div className='flex flex-col items-center'>
748-
<img src={status.wechat_qrcode} alt='微信二维码' className='mb-4' />
748+
<img
749+
src={status.wechat_qrcode}
750+
alt={t('微信二维码')}
751+
className='mb-4'
752+
/>
749753
</div>
750754

751755
<div className='text-center mb-4'>
@@ -781,8 +785,7 @@ const RegisterForm = () => {
781785
style={{ top: '50%', left: '-120px' }}
782786
/>
783787
<div className='w-full max-w-sm mt-[60px]'>
784-
{showEmailRegister ||
785-
!hasOAuthRegisterOptions
788+
{showEmailRegister || !hasOAuthRegisterOptions
786789
? renderEmailRegisterForm()
787790
: renderOAuthOptions()}
788791
{renderWeChatLoginModal()}

0 commit comments

Comments
 (0)