@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
151 lines (123 loc) • 4.3 kB
text/typescript
// @vitest-environment node
import { cookies } from 'next/headers';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { DEFAULT_LANG } from '@/const/locale';
import { normalizeLocale } from '@/locales/resources';
import { getLocale, translation } from './translation';
// Mock external dependencies
vi.mock('next/headers', () => ({
cookies: vi.fn(),
}));
vi.mock('@/const/locale', () => ({
DEFAULT_LANG: 'en-US',
LOBE_LOCALE_COOKIE: 'LOBE_LOCALE',
}));
vi.mock('@/locales/resources', () => ({
normalizeLocale: vi.fn((locale) => locale),
}));
vi.mock('@/utils/env', () => ({
isDev: false,
}));
// 模拟动态导入结果
const mockTranslations = {
key1: 'Value 1',
key2: 'Value 2 with {{param}}',
nested: { key: 'Nested value' },
};
const mockDefaultTranslations = {
key1: '默认值 1',
key2: '默认值 2 带 {{param}}',
nested: { key: '默认嵌套值' },
};
// 重写导入函数
vi.mock('@/../locales/en-US/common.json', async () => {
return mockTranslations;
});
vi.mock('@/locales/default/common', async () => {
return mockDefaultTranslations;
});
describe('getLocale', () => {
const mockCookieStore = {
get: vi.fn(),
};
beforeEach(() => {
vi.clearAllMocks();
(cookies as any).mockReturnValue(mockCookieStore);
});
it('should return the provided locale if hl is specified', async () => {
const result = await getLocale('fr-FR');
expect(result).toBe('fr-FR');
expect(normalizeLocale).toHaveBeenCalledWith('fr-FR');
});
it('should return DEFAULT_LANG if no cookie is set', async () => {
mockCookieStore.get.mockReturnValue(undefined);
const result = await getLocale();
expect(result).toBe(DEFAULT_LANG);
});
});
describe('translation', () => {
beforeEach(() => {
vi.clearAllMocks();
// 重置 import 模拟
vi.doMock('@/../locales/en-US/common.json', async () => {
return mockTranslations;
});
});
it('should return correct translation object', async () => {
const result = await translation('common', 'en-US');
expect(result).toHaveProperty('locale', 'en-US');
expect(result).toHaveProperty('t');
expect(typeof result.t).toBe('function');
});
it('should translate keys correctly', async () => {
const { t } = await translation('common', 'en-US');
expect(t('key1')).toBe('Value 1');
expect(t('key2', { param: 'test' })).toBe('Value 2 with test');
expect(t('nested.key')).toBe('Nested value');
});
it('should handle multiple parameters in translation string', async () => {
// 模拟多参数翻译
vi.doMock('@/../locales/en-US/common.json', async () => ({
multiParam: 'Hello {{name}}, you have {{count}} messages',
}));
const { t } = await translation('common', 'en-US');
expect(t('multiParam', { name: 'John', count: '5' })).toBe('Hello John, you have 5 messages');
});
it('should handle different namespaces', async () => {
// 模拟另一个命名空间
vi.doMock('@/../locales/en-US/chat.json', async () => ({
welcome: 'Welcome to the chat',
}));
const { t } = await translation('chat', 'en-US');
expect(t('welcome')).toBe('Welcome to the chat');
});
it('should handle deep nested objects in translations', async () => {
// 模拟深层嵌套对象
vi.doMock('@/../locales/en-US/common.json', async () => ({
very: {
deeply: {
nested: {
key: 'Found the nested value',
},
},
},
}));
const { t } = await translation('common', 'en-US');
expect(t('very.deeply.nested.key')).toBe('Found the nested value');
});
it('should handle empty parameters object', async () => {
vi.doMock('@/../locales/en-US/common.json', async () => ({
simpleText: 'Just a simple text',
}));
const { t } = await translation('common', 'en-US');
expect(t('simpleText', {})).toBe('Just a simple text');
});
it('should handle missing parameters in translation string', async () => {
vi.doMock('@/../locales/en-US/common.json', async () => ({
withParam: 'Text with {{param}}',
}));
const { t } = await translation('common', 'en-US');
// 当缺少参数时应保留占位符
expect(t('withParam')).toBe('Text with {{param}}');
});
});