Complete Cantonese Wu and Macau browser language fallbacks

Resolve yue and wuu to their existing registered variants, and zh-MO to Traditional Chinese. Exercise actual startup autoruns, delayed profile preference, browser languagechange and absence of profile writes. Browser-language checks pass. Arabic Uzbek vocabulary/script remains a separate translation review.

Thanks to xet7 !
This commit is contained in:
Lauri Ojansivu committed 2026-09-13 18:37:41 +03:00
1 parent 57651f1281
commit 37ae64fa8c
2 files changed
+34 -2

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@ const aliases = {
vep: 've-PP', vec: 've-CC', vls: 'vl-SS', war: 'wa-RR',
'es-419': 'es-LA', 'be-by': 'be-BE', 'ca-valencia': 'ca-valencia',
'uz-arab': 'uz-AR', 'uz-latn': 'uz-LA', iw: 'he', ji: 'yi', in: 'id',
no: 'nb',
no: 'nb', yue: 'yue_CN', wuu: 'wuu-Hans', 'zh-mo': 'zh-Hant',
};
function matchBrowserLanguage(value, resolveTag) {
if (typeof value !== 'string' || !value.trim()) return undefined;
+33 -1
View File
@@ -12,7 +12,7 @@ for (const row of rows) {
const browserTag = row[2].replace(/_/g, '-');
assert.equal(normalize(matchBrowserLanguage(browserTag.toLowerCase(), resolve)), normalize(row[2]));
}
for (const [browser, expected] of Object.entries({vep:'ve-PP', vec:'ve-CC', vls:'vl-SS', war:'wa-RR', 'es-419':'es-LA', 'be-BY':'be-BE', 'uz-Arab-UZ':'uz-AR', 'uz-Latn-UZ':'uz-LA', 'zh-Hant-TW':'zh-Hant', 'fr-CA-u-ca-gregory':'fr-CA', 'en-AU':'en_AU', iw:'he', in:'id', no:'nb'})) {
for (const [browser, expected] of Object.entries({vep:'ve-PP', vec:'ve-CC', vls:'vl-SS', war:'wa-RR', 'es-419':'es-LA', 'be-BY':'be-BE', 'uz-Arab-UZ':'uz-AR', 'uz-Latn-UZ':'uz-LA', 'zh-Hant-TW':'zh-Hant', 'fr-CA-u-ca-gregory':'fr-CA', 'en-AU':'en_AU', iw:'he', in:'id', no:'nb', yue:'yue_CN', 'yue-HK':'yue_CN', wuu:'wuu-Hans', 'zh-MO':'zh-Hant'})) {
assert.equal(matchBrowserLanguage(browser, resolve), expected, browser);
}
assert.equal(preferredLanguage(undefined, {languages:['zz-ZZ','fr-CA','de']}, resolve), 'fr-CA');
@@ -24,3 +24,35 @@ assert.equal(preferredLanguage(undefined, {userLanguage:'fi-FI'}, resolve), 'fi'
assert.equal(matchBrowserLanguage(null, resolve), undefined);
assert.notEqual(matchBrowserLanguage('vep', resolve), 've');
console.log(`browserLanguageFallback: ${rows.length} registry locales, standard aliases, ordered preferences and saved-profile precedence passed`);
// Exercise the actual startup autorun with controlled profile/browser inputs.
const vm = require('node:vm');
let profile;
let browser = {languages:['zz-ZZ','fr-CA']};
const callbacks = [];
const startup = [];
const selections = [];
let languageChange;
const client = fs.readFileSync(path.join(__dirname, '../client/lib/i18n.js'), 'utf8').replace(/^import .*;$/gm, '');
vm.runInNewContext(client, {
require: () => ({preferredLanguage}),
Meteor: {startup(callback) {startup.push(callback);}},
Tracker: {autorun(callback) {callbacks.push(callback); callback();}},
ReactiveCache: {getCurrentUser: () => profile},
TAPi18n: {resolveTag:resolve, setLanguage: language => selections.push(language), getLanguage:()=>'en', getLanguageDirection:()=>'ltr'},
navigator:browser, window:{addEventListener(name, callback) {assert.equal(name,'languagechange'); languageChange=callback;}},
console,
});
startup.forEach(callback => callback());
assert.equal(selections.at(-1), 'fr-CA');
profile = {profile:{language:'de'}};
callbacks.at(-1)();
assert.equal(selections.at(-1), 'de');
browser.languages = ['vep'];
languageChange();
assert.equal(selections.at(-1), 'de');
profile = {profile:{}};
callbacks.at(-1)();
assert.equal(selections.at(-1), 've-PP');
assert.equal(profile.profile.language, undefined, 'browser detection never saves a preference');
console.log('browserLanguageFallback: actual startup, resumed profile and languagechange checks passed');