172 lines
4.1 KiB
TypeScript
172 lines
4.1 KiB
TypeScript
// Copyright 2021 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { assert } from 'chai';
|
|
import { stub } from 'sinon';
|
|
import * as LocaleMatcher from '@formatjs/intl-localematcher';
|
|
import { load, _getAvailableLocales } from '../../../app/locale';
|
|
import { FAKE_DEFAULT_LOCALE } from '../../../app/spell_check';
|
|
import { HourCyclePreference } from '../../types/I18N';
|
|
|
|
describe('locale', async () => {
|
|
describe('load', () => {
|
|
it('resolves expected locales correctly', async () => {
|
|
const logger = {
|
|
fatal: stub().throwsArg(0),
|
|
error: stub().throwsArg(0),
|
|
warn: stub().throwsArg(0),
|
|
info: stub(),
|
|
debug: stub(),
|
|
trace: stub(),
|
|
};
|
|
|
|
async function testCase(
|
|
preferredSystemLocales: Array<string>,
|
|
expectedLocale: string
|
|
) {
|
|
const actualLocale = await load({
|
|
preferredSystemLocales,
|
|
hourCyclePreference: HourCyclePreference.UnknownPreference,
|
|
logger,
|
|
});
|
|
assert.strictEqual(actualLocale.name, expectedLocale);
|
|
}
|
|
|
|
// Basic tests
|
|
await testCase(['en'], 'en');
|
|
await testCase(['es'], 'es');
|
|
await testCase(['fr', 'hk'], 'fr');
|
|
await testCase(['fr-FR', 'hk'], 'fr');
|
|
await testCase(['fa-UK'], 'fa-IR');
|
|
await testCase(['an', 'fr-FR'], 'fr'); // If we ever add support for Aragonese, this test will fail.
|
|
|
|
// Specific cases we want to ensure work as expected
|
|
await testCase(['zh-TW'], 'zh-Hant');
|
|
await testCase(['zh-Hant-TW'], 'zh-Hant');
|
|
await testCase(['zh-Hant-CA'], 'zh-Hant');
|
|
await testCase(['zh-Hant-HK'], 'zh-HK');
|
|
await testCase(['zh'], 'zh-CN');
|
|
await testCase(['yue'], 'yue');
|
|
await testCase(['ug'], 'ug');
|
|
await testCase(['nn', 'nb'], 'nb');
|
|
await testCase(['es-419'], 'es');
|
|
await testCase(['sr-RO', 'sr'], 'sr');
|
|
await testCase(['sr-RS', 'sr'], 'sr');
|
|
});
|
|
});
|
|
|
|
describe('Intl.LocaleMatcher', () => {
|
|
it('should work for single locales outside of their region', () => {
|
|
// Our supported locales where we only have a single region for a language
|
|
const SINGLE_REGION_LOCALES = [
|
|
'af-ZA',
|
|
'az-AZ',
|
|
'bg-BG',
|
|
'bn-BD',
|
|
'bs-BA',
|
|
'et-EE',
|
|
'fa-IR',
|
|
'ga-IE',
|
|
'gl-ES',
|
|
'gu-IN',
|
|
'hi-IN',
|
|
'hr-HR',
|
|
'ka-GE',
|
|
'kk-KZ',
|
|
'km-KH',
|
|
'kn-IN',
|
|
'ky-KG',
|
|
'lt-LT',
|
|
'lv-LV',
|
|
'mk-MK',
|
|
'ml-IN',
|
|
'mr-IN',
|
|
'pa-IN',
|
|
'ro-RO',
|
|
'sk-SK',
|
|
'sl-SI',
|
|
'sq-AL',
|
|
'ta-IN',
|
|
'te-IN',
|
|
'tl-PH',
|
|
'uk-UA',
|
|
];
|
|
|
|
// Just a whole bunch of common regions
|
|
const TEST_REGIONS = [
|
|
'AE',
|
|
'AR',
|
|
'AT',
|
|
'AU',
|
|
'BE',
|
|
'CA',
|
|
'CH',
|
|
'CL',
|
|
'CN',
|
|
'CO',
|
|
'CR',
|
|
'CZ',
|
|
'DE',
|
|
'DK',
|
|
'DO',
|
|
'EC',
|
|
'EG',
|
|
'ES',
|
|
'FI',
|
|
'FR',
|
|
'GB',
|
|
'GR',
|
|
'GT',
|
|
'HK',
|
|
'IE',
|
|
'IL',
|
|
'IN',
|
|
'IT',
|
|
'JP',
|
|
'KR',
|
|
'MY',
|
|
'NL',
|
|
'NO',
|
|
'PA',
|
|
'PE',
|
|
'PH',
|
|
'PL',
|
|
'PT',
|
|
'RO',
|
|
'RS',
|
|
'RU',
|
|
'SA',
|
|
'SE',
|
|
'SG',
|
|
'SK',
|
|
'TH',
|
|
'TR',
|
|
'UA',
|
|
'US',
|
|
'VE',
|
|
];
|
|
|
|
const availableLocales = _getAvailableLocales();
|
|
|
|
for (const locale of SINGLE_REGION_LOCALES) {
|
|
const { language } = new Intl.Locale(locale);
|
|
for (const region of TEST_REGIONS) {
|
|
const newLocale = new Intl.Locale(language, { region });
|
|
|
|
const matched = LocaleMatcher.match(
|
|
[newLocale.baseName],
|
|
availableLocales,
|
|
FAKE_DEFAULT_LOCALE,
|
|
{ algorithm: 'best fit' }
|
|
);
|
|
|
|
assert.strictEqual(
|
|
matched,
|
|
locale,
|
|
`${locale} -> ${language} -> ${region} -> ${newLocale.baseName} -> ${matched}`
|
|
);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|