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.
100 lines
2.7 KiB
100 lines
2.7 KiB
/**
|
|
* i18n.ts 国际化模块单元测试
|
|
*/
|
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { t, setLocale, getLocale } from '../src/i18n';
|
|
|
|
describe('setLocale / getLocale', () => {
|
|
beforeEach(() => {
|
|
setLocale('zh-CN');
|
|
});
|
|
|
|
it('默认语言为 zh-CN', () => {
|
|
expect(getLocale()).toBe('zh-CN');
|
|
});
|
|
|
|
it('切换为英文', () => {
|
|
setLocale('en');
|
|
expect(getLocale()).toBe('en');
|
|
});
|
|
|
|
it('匹配语言前缀(zh → zh-CN)', () => {
|
|
setLocale('zh');
|
|
expect(getLocale()).toBe('zh-CN');
|
|
});
|
|
|
|
it('未知语言保持默认 zh-CN', () => {
|
|
setLocale('fr');
|
|
expect(getLocale()).toBe('zh-CN');
|
|
});
|
|
});
|
|
|
|
describe('t()', () => {
|
|
beforeEach(() => {
|
|
setLocale('zh-CN');
|
|
});
|
|
|
|
it('返回中文翻译', () => {
|
|
expect(t('send')).toBe('发送');
|
|
expect(t('close')).toBe('关闭');
|
|
});
|
|
|
|
it('切换英文后返回英文翻译', () => {
|
|
setLocale('en');
|
|
expect(t('send')).toBe('Send');
|
|
expect(t('close')).toBe('Close');
|
|
});
|
|
|
|
it('未知 key 返回 key 本身', () => {
|
|
expect(t('nonexistent_key')).toBe('nonexistent_key');
|
|
});
|
|
|
|
it('支持插值参数替换', () => {
|
|
setLocale('zh-CN');
|
|
expect(t('source_count', { n: 3 })).toBe('3 条参考来源');
|
|
});
|
|
|
|
it('英文插值参数替换', () => {
|
|
setLocale('en');
|
|
expect(t('source_count', { n: 5 })).toBe('5 source(s)');
|
|
});
|
|
|
|
it('中英文字典 key 数量一致', () => {
|
|
// 验证中英文字典完整性:所有中文 key 在英文中都有对应
|
|
setLocale('zh-CN');
|
|
const zhKeys = Object.keys(getAllKeys('zh-CN'));
|
|
setLocale('en');
|
|
const enKeys = Object.keys(getAllKeys('en'));
|
|
|
|
// 每个中文 key 在英文字典中也应存在
|
|
for (const key of zhKeys) {
|
|
setLocale('en');
|
|
const translated = t(key);
|
|
expect(translated).not.toBe(key); // 不应回退到 key 本身
|
|
}
|
|
});
|
|
});
|
|
|
|
/** 辅助函数:获取指定语言的所有 key(通过遍历测试已知 key) */
|
|
function getAllKeys(_locale: string): Record<string, string> {
|
|
const knownKeys = [
|
|
'title', 'minimize', 'close', 'status_online',
|
|
'welcome_title', 'welcome_desc',
|
|
'placeholder', 'send', 'stop', 'new_message',
|
|
'copy', 'copied', 'retry',
|
|
'loading', 'stream_interrupted',
|
|
'category_all', 'source_count',
|
|
'clear', 'clear_confirm',
|
|
'history_title', 'history_empty', 'history_search',
|
|
'feedback_up', 'feedback_down',
|
|
'teaser_text', 'new_msg_announce',
|
|
'error_network', 'error_timeout', 'error_send',
|
|
'history_group_today', 'history_group_yesterday',
|
|
'history_group_week', 'history_group_earlier',
|
|
];
|
|
const result: Record<string, string> = {};
|
|
for (const key of knownKeys) {
|
|
result[key] = t(key);
|
|
}
|
|
return result;
|
|
}
|