83 lines
3.0 KiB
TypeScript
83 lines
3.0 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
import { setLocale } from './locale.svelte';
|
|
import { t } from './t';
|
|
import { LOCALE_TAGS } from './dict';
|
|
import { normalizeForSearch, scoreDoc } from './matching';
|
|
import { toolSearchDoc } from './tool-strings';
|
|
import { TOOLS } from '../registry';
|
|
|
|
afterEach(() => {
|
|
setLocale('ru');
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
describe('Смоук §6 i18n', () => {
|
|
it('1. html lang следует за локалью', () => {
|
|
const doc = { documentElement: { lang: '' } };
|
|
vi.stubGlobal('document', doc);
|
|
setLocale('en');
|
|
expect(doc.documentElement.lang).toBe('en');
|
|
setLocale('ru');
|
|
expect(doc.documentElement.lang).toBe('ru');
|
|
});
|
|
|
|
it('3. Ключевые секции переведены без смеси языков', () => {
|
|
const samples: Array<[string, string, string]> = [
|
|
['header.workspace', 'Рабочая область', 'Workspace'],
|
|
['catalog.heading', 'Каталог инструментов', 'Tool catalog'],
|
|
['home.heroTitle', 'Что делаем с изображением?', 'What do you want to do'],
|
|
['chain.inputLegend', 'Вход', 'Input'],
|
|
['resultCard.nextTool', 'Следующий инструмент', 'Next tool'],
|
|
['download.busy', 'Готовим файл', 'Preparing file']
|
|
];
|
|
for (const [key, ruPart, enPart] of samples) {
|
|
setLocale('ru');
|
|
expect(t(key), key + ' @ru').toContain(ruPart);
|
|
setLocale('en');
|
|
expect(t(key), key + ' @en').toContain(enPart);
|
|
}
|
|
});
|
|
|
|
it('5. Ошибки с vars локализуются на оба языка', () => {
|
|
setLocale('ru');
|
|
expect(t('errors.badHex', { value: '#zz' })).toBe('Некорректный HEX-цвет: "#zz"');
|
|
expect(t('errors.toolNotFound', { id: 'x' })).toContain('не найден');
|
|
setLocale('en');
|
|
expect(t('errors.badHex', { value: '#zz' })).toBe('Invalid HEX color: "#zz"');
|
|
});
|
|
|
|
it('6. Поиск кросс-языковой в обе стороны', () => {
|
|
const ids = (q: string) =>
|
|
TOOLS.filter((tool) => {
|
|
const s = scoreDoc(toolSearchDoc(tool), normalizeForSearch(q));
|
|
return s !== null && s > 0;
|
|
}).map((tool) => tool.id);
|
|
|
|
setLocale('ru');
|
|
let hits = ids('rotate');
|
|
expect(hits).toContain('rotate-png');
|
|
hits = ids('повер');
|
|
expect(hits).toContain('rotate-png');
|
|
|
|
setLocale('en');
|
|
hits = ids('пово');
|
|
expect(hits).toContain('rotate-free-png');
|
|
hits = ids('rotate');
|
|
expect(hits).toContain('rotate-png');
|
|
});
|
|
|
|
it('6b. Ё не мешает совпадению', () => {
|
|
const blackWhite = TOOLS.find((tool) => tool.id === 'black-and-white-png')!;
|
|
setLocale('ru');
|
|
const hit = scoreDoc(toolSearchDoc(blackWhite), normalizeForSearch('ЧЁРНО'));
|
|
expect(hit).not.toBeNull();
|
|
const withoutYo = scoreDoc(toolSearchDoc(blackWhite), normalizeForSearch('черно'));
|
|
expect(withoutYo).not.toBeNull();
|
|
});
|
|
|
|
it('7. Теги локалей для форматирования чисел корректны', () => {
|
|
expect(LOCALE_TAGS.ru).toBe('ru-RU');
|
|
expect(LOCALE_TAGS.en).toBe('en-US');
|
|
});
|
|
});
|