// Language tiers: automatic choices ("follow the site", "follow system") resolve only to supported // languages through the fallback chain; a language picked explicitly applies whatever its tier; // Settings → Language lists supported languages first and community translations apart. import assert from 'node:assert/strict'; import test from 'node:test'; import { communitySuggestion, resolveLocale } from '../src/frame/language.ts'; import { groupLanguages } from '../src/panel/languageModel.ts'; import type { PanelLanguage } from '../src/panel/site.ts'; const available = ['en', 'en-GB', 'de', 'pt', 'zh-Hans', 'zh-Hant', 'fr', 'ar', 'ar-x-fm', 'sv', 'pl']; const supported = ['en', 'en-GB', 'de', 'pt', 'zh-Hant', 'fr', 'ar']; test('automatic choices resolve only to supported languages, through the fallback chain', () => { const auto = (system: string[]) => resolveLocale('system', null, system, available, supported); assert.equal(auto(['pt-BR']), 'pt'); assert.equal(auto(['en-US']), 'en'); assert.equal(auto(['en-GB']), 'en-GB'); assert.equal(auto(['de-AT', 'en']), 'de'); assert.equal(resolveLocale('site', 'pt-BR', ['de'], available, supported), 'pt'); // A community language stays on English: system, site and the site's own tag alike. assert.equal(auto(['sv-SE']), 'en'); assert.equal(auto(['pl']), 'en'); assert.equal(resolveLocale('site', 'sv', ['de'], available, supported), 'en', 'the site is Swedish (community): English, not the system language'); assert.equal(resolveLocale('site', null, ['sv'], available, supported), 'en'); // The next preference wins over English when it is supported. assert.equal(auto(['sv', 'fr']), 'fr'); // Private-use variants and scripts fall back within the supported set. assert.equal(auto(['ar-x-fm']), 'ar'); assert.equal(auto(['zh-Hant']), 'zh-Hant'); assert.equal(auto(['zh-Hans']), 'en', 'Simplified Chinese is community here'); }); test('with every language supported (the default) nothing changes', () => { assert.equal(resolveLocale('system', null, ['sv-SE'], available), 'sv'); assert.equal(resolveLocale('site', 'pl', ['de'], available), 'pl'); }); test('an explicit pick always applies, whatever its tier', () => { for (const code of available) assert.equal(resolveLocale(code, 'de', ['fr'], available, supported), code, code); assert.equal(resolveLocale('sv-SE', null, ['fr'], available, supported), 'sv', 'a regional tag of a community language'); assert.equal(resolveLocale('xx', null, ['fr'], available, supported), 'fr', 'unknown: the system language'); }); test('a community language the site or system uses is suggested, never applied', () => { assert.equal(communitySuggestion('site', 'sv', ['de'], available, supported), 'sv'); assert.equal(communitySuggestion('site', null, ['pl-PL'], available, supported), 'pl'); assert.equal(communitySuggestion('system', null, ['sv'], available, supported), 'sv'); assert.equal(communitySuggestion('site', 'pt-BR', ['sv'], available, supported), null, 'supported: nothing to suggest'); assert.equal(communitySuggestion('site', 'xx', ['de'], available, supported), null, 'not offered at all'); assert.equal(communitySuggestion('sv', 'sv', ['sv'], available, supported), null, 'an explicit pick needs no hint'); assert.equal(communitySuggestion('system', null, ['sv'], available), null, 'no tiers'); }); test('Settings groups supported languages first and community ones apart, order kept', () => { const row = (code: string, tier: PanelLanguage['tier']): PanelLanguage => ({ code, name: code, englishName: code, dir: 'ltr', status: 'machine', tier, coverage: 1 }); const list = [row('en', 'supported'), row('sv', 'community'), row('de', 'supported'), row('pl', 'community')]; const groups = groupLanguages(list); assert.deepEqual(groups.supported.map(language => language.code), ['en', 'de']); assert.deepEqual(groups.community.map(language => language.code), ['sv', 'pl']); assert.deepEqual(groupLanguages([row('en', 'supported')]).community, []); });