Files
veilix.app/src/core/routing/locale.test.ts
T
andreypr207andClaude Opus 5.5 7e331c2c9d Этап 1a: фундамент
- Next 16.4 и Payload 3.91 в одном приложении, PostgreSQL с UUID,
  TypeScript 6, ESLint 9, Prettier, Vitest
- Payload: администраторы с ролями, multi-tenant по сайтам, локализация
  en/ru/de/fr/es, интерфейс админки ru/en, языки сайта (sites.locales)
- Коллекции sites, domains, currencies, countries, locations, tags,
  tariffs, payment-systems (manual), media и начальные данные (pnpm seed)
- Proxy: хост → домен, язык и валюта, внутренние маршруты по хосту;
  /admin и /api закрыты на доменах брендов
- Токены и темы брендов, оболочки сайта и кабинета, переключатели языка,
  валюты и темы, заглушки страниц
- /svc/health, юнит systemd veilix-dev.service
- Документация: решения D-022…D-024, команды в CLAUDE.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 05:08:05 +02:00

70 lines
2.4 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type { Locale } from '@/i18n/locales'
import { detectLocale, localeForCountry, matchAcceptLanguage, parseAcceptLanguage } from './locale'
const all: Locale[] = ['en', 'ru', 'de', 'fr', 'es']
describe('parseAcceptLanguage', () => {
it('сортирует по весу, при равном весе сохраняет порядок', () => {
expect(parseAcceptLanguage('de;q=0.5, ru-RU, en;q=0.9, fr')).toEqual([
'ru-ru',
'fr',
'en',
'de',
])
})
it('отбрасывает *, нулевой и битый вес', () => {
expect(parseAcceptLanguage('*, es;q=0, de;q=abc, fr;q=0.1')).toEqual(['fr'])
})
it('пустой заголовок — пустой список', () => {
expect(parseAcceptLanguage(null)).toEqual([])
expect(parseAcceptLanguage('')).toEqual([])
})
})
describe('matchAcceptLanguage', () => {
it('берёт основной подтег', () => {
expect(matchAcceptLanguage('es-419,es;q=0.9', all)).toBe('es')
})
it('пропускает языки, которых нет на домене', () => {
expect(matchAcceptLanguage('zh-CN, de;q=0.8', ['en', 'ru'])).toBeNull()
expect(matchAcceptLanguage('pt-BR, ru;q=0.7', all)).toBe('ru')
})
})
describe('localeForCountry', () => {
it('сопоставляет страны по 06-i18n', () => {
expect(localeForCountry('KZ', all)).toBe('ru')
expect(localeForCountry('at', all)).toBe('de')
expect(localeForCountry('MX', all)).toBe('es')
expect(localeForCountry('BR', all)).toBeNull()
expect(localeForCountry('NL', all)).toBeNull()
})
it('учитывает языки домена', () => {
expect(localeForCountry('DE', ['en', 'ru'])).toBeNull()
})
})
describe('detectLocale', () => {
it('язык браузера важнее страны', () => {
expect(
detectLocale({ acceptLanguage: 'en-US', country: 'RU', enabled: all, fallback: 'en' }),
).toBe('en')
})
it('без подходящего языка браузера — страна, затем язык по умолчанию', () => {
expect(
detectLocale({ acceptLanguage: 'zh', country: 'RU', enabled: all, fallback: 'en' }),
).toBe('ru')
expect(
detectLocale({ acceptLanguage: null, country: null, enabled: all, fallback: 'en' }),
).toBe('en')
})
})