- 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>
70 lines
2.4 KiB
TypeScript
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')
|
|
})
|
|
})
|