Files
fluxer/packages/locale/src/tests/LocaleService.test.tsx
2026-02-17 12:22:36 +00:00

194 lines
6.6 KiB
TypeScript

/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {AllLocales, type LocaleCode, Locales} from '@fluxer/constants/src/Locales';
import {
getFlagCode,
getLocaleCode,
getLocaleFromCode,
getLocaleMetadata,
getLocaleName,
parseAcceptLanguage,
} from '@fluxer/locale/src/LocaleService';
import {describe, expect, it} from 'vitest';
interface LocaleLookupCase {
input: string;
expected: LocaleCode | null;
}
interface AcceptLanguageCase {
header: string | null | undefined;
expected: LocaleCode;
}
const localeNameCases: Array<{locale: LocaleCode; expected: string}> = [
{locale: Locales.EN_US, expected: 'English (US)'},
{locale: Locales.EN_GB, expected: 'English'},
{locale: Locales.DE, expected: 'Deutsch'},
{locale: Locales.JA, expected: '日本語'},
{locale: Locales.ZH_CN, expected: '简体中文'},
{locale: Locales.ZH_TW, expected: '繁體中文'},
{locale: Locales.ES_419, expected: 'Español (Latinoamérica)'},
{locale: Locales.PT_BR, expected: 'Português (Brasil)'},
];
const flagCodeCases: Array<{locale: LocaleCode; expected: string}> = [
{locale: Locales.EN_US, expected: '1f1fa-1f1f8'},
{locale: Locales.EN_GB, expected: '1f1ec-1f1e7'},
{locale: Locales.DE, expected: '1f1e9-1f1ea'},
{locale: Locales.JA, expected: '1f1ef-1f1f5'},
{locale: Locales.ZH_CN, expected: '1f1e8-1f1f3'},
{locale: Locales.ES_419, expected: '1f30e'},
{locale: Locales.PT_BR, expected: '1f1e7-1f1f7'},
];
const localeLookupCases: Array<LocaleLookupCase> = [
{input: 'en', expected: Locales.EN_US},
{input: 'en-US', expected: Locales.EN_US},
{input: 'en-us', expected: Locales.EN_US},
{input: 'en_GB', expected: Locales.EN_GB},
{input: 'en-gb', expected: Locales.EN_GB},
{input: 'de', expected: Locales.DE},
{input: 'ja', expected: Locales.JA},
{input: 'zh-CN', expected: Locales.ZH_CN},
{input: 'zh-cn', expected: Locales.ZH_CN},
{input: 'zh-TW', expected: Locales.ZH_TW},
{input: 'zh-tw', expected: Locales.ZH_TW},
{input: 'es-419', expected: Locales.ES_419},
{input: 'pt-br', expected: Locales.PT_BR},
{input: 'sv', expected: Locales.SV_SE},
{input: 'sv-se', expected: Locales.SV_SE},
{input: 'xx', expected: null},
{input: '', expected: null},
{input: 'en-AU', expected: null},
];
const localeCodeCases: Array<{locale: LocaleCode; expected: string}> = [
{locale: Locales.EN_US, expected: 'en'},
{locale: Locales.EN_GB, expected: 'en'},
{locale: Locales.DE, expected: 'de'},
{locale: Locales.ZH_CN, expected: 'zh'},
{locale: Locales.ZH_TW, expected: 'zh'},
{locale: Locales.ES_ES, expected: 'es'},
{locale: Locales.ES_419, expected: 'es'},
{locale: Locales.PT_BR, expected: 'pt'},
{locale: Locales.SV_SE, expected: 'sv'},
{locale: Locales.JA, expected: 'ja'},
];
const acceptLanguageCases: Array<AcceptLanguageCase> = [
{header: null, expected: Locales.EN_US},
{header: undefined, expected: Locales.EN_US},
{header: '', expected: Locales.EN_US},
{header: 'de', expected: Locales.DE},
{header: 'en-GB', expected: Locales.EN_GB},
{header: 'en-gb', expected: Locales.EN_GB},
{header: 'de;q=0.9, fr;q=1.0', expected: Locales.FR},
{header: 'en-US,en;q=0.9,de;q=0.8', expected: Locales.EN_US},
{header: 'en-AU', expected: Locales.EN_US},
{header: 'es', expected: Locales.ES_ES},
{header: 'pt', expected: Locales.PT_BR},
{header: 'zh', expected: Locales.ZH_CN},
{header: 'sv', expected: Locales.SV_SE},
{header: 'de;q=0.5, ja;q=0.9, fr;q=0.7', expected: Locales.JA},
{header: 'de, fr;q=0.5', expected: Locales.DE},
{header: 'xx-YY', expected: Locales.EN_US},
{header: 'fr-CA', expected: Locales.EN_US},
{header: ' de , fr ', expected: Locales.DE},
{header: 'zh-TW', expected: Locales.ZH_TW},
{header: 'zh-CN', expected: Locales.ZH_CN},
{header: 'es-419', expected: Locales.ES_419},
{header: 'pt-BR', expected: Locales.PT_BR},
{header: 'sv-SE', expected: Locales.SV_SE},
{header: 'xx-YY, zz-AA, qq-BB', expected: Locales.EN_US},
{header: 'zh-TW, zh;q=0.9', expected: Locales.ZH_TW},
{header: 'en-US,en;q=0.9,ja;q=0.8,de;q=0.7,fr;q=0.6', expected: Locales.EN_US},
{header: 'de;q=0.999, fr;q=0.998', expected: Locales.DE},
{header: 'de;q=0, fr;q=1', expected: Locales.FR},
];
describe('LocaleService', () => {
describe('getLocaleMetadata', () => {
it('returns consolidated metadata for a locale', () => {
expect(getLocaleMetadata(Locales.EN_US)).toEqual({
code: Locales.EN_US,
languageCode: 'en',
name: 'English (US)',
flagCode: '1f1fa-1f1f8',
});
});
it('returns metadata for every supported locale', () => {
for (const locale of AllLocales) {
const metadata = getLocaleMetadata(locale);
expect(metadata.code).toBe(locale);
expect(metadata.name.length).toBeGreaterThan(0);
expect(metadata.flagCode.length).toBeGreaterThan(0);
}
});
});
describe('getLocaleName', () => {
for (const {locale, expected} of localeNameCases) {
it(`returns ${expected} for ${locale}`, () => {
expect(getLocaleName(locale)).toBe(expected);
});
}
});
describe('getFlagCode', () => {
for (const {locale, expected} of flagCodeCases) {
it(`returns ${expected} for ${locale}`, () => {
expect(getFlagCode(locale)).toBe(expected);
});
}
});
describe('getLocaleFromCode', () => {
for (const {input, expected} of localeLookupCases) {
it(`resolves ${input || 'empty'} to ${expected ?? 'null'}`, () => {
expect(getLocaleFromCode(input)).toBe(expected);
});
}
it('resolves canonical locale codes for all supported locales', () => {
for (const locale of AllLocales) {
expect(getLocaleFromCode(locale)).toBe(locale);
}
});
});
describe('getLocaleCode', () => {
for (const {locale, expected} of localeCodeCases) {
it(`returns ${expected} for ${locale}`, () => {
expect(getLocaleCode(locale)).toBe(expected);
});
}
});
describe('parseAcceptLanguage', () => {
for (const {header, expected} of acceptLanguageCases) {
it(`selects ${expected} for ${header ?? 'nullish header'}`, () => {
expect(parseAcceptLanguage(header)).toBe(expected);
});
}
});
});