Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

175
gaia/shared/js/language_list.js Executable file
View file

@ -0,0 +1,175 @@
'use strict';
/**
* Helper object to find all supported languages;
*
* (Needs l10n.js or l20n.js, and the settings permission)
*/
(function(exports) {
var LOCALES_FILE = '/shared/resources/languages.json';
function readFile(file, callback) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function loadFile() {
if (xhr.readyState === 4) {
if (xhr.status === 0 || xhr.status === 200) {
resolve(xhr.response);
} else {
reject(xhr.statusText);
}
}
};
xhr.open('GET', file, true); // async
xhr.responseType = 'json';
xhr.send();
});
}
function onError(name) {
console.error('Error checking setting ' + name);
}
function readSetting(name, callback) {
var settings = window.navigator.mozSettings;
if (!settings || !settings.createLock) {
return callback(null);
}
return settings.createLock().get(name).then(function(res) {
return res[name];
}, onError.bind(null, name));
}
exports.LanguageList = {
_languages: null,
// for stubbing in tests
_readFile: readFile,
_readSetting: readSetting,
_extendPseudo: function(languages, currentLang, pseudoEnabled) {
// 1. remove buildtime pseudolocales is pseudo is disabled
if (!pseudoEnabled) {
for (var code in languages) {
var isCurrent = (code === currentLang);
if (code.indexOf('-x-ps') > -1 && !isCurrent) {
delete languages[code];
}
}
}
if (!document.l10n) {
return Promise.resolve(languages);
}
// 2. add the remaining runtime pseudolocales if pseudo enabled
var runtimePseudoCodes = Object.keys(document.l10n.pseudo).filter(
code => !(code in languages) && (code === currentLang || pseudoEnabled));
function obj(arr1, arr2) {
const zipped = [];
arr1.forEach(x => {
arr2.forEach(y => {
zipped.push([x, y]);
});
});
return zipped.reduce(
(obj, [x, y]) => Object.assign(obj, { [x]: y }), {});
/* jshint ignore: end */
}
return Promise.all(
runtimePseudoCodes.map(
code => document.l10n.pseudo[code].getName())).then(
names => Object.assign(languages, obj(runtimePseudoCodes, names)));
},
_extendAdditional: function(languages, ver, additional) {
/* jshint boss:true */
for (var lang in additional) {
for (var i = 0, locale; locale = additional[lang][i]; i++) {
if (locale.target === ver) {
languages[lang] = locale.name;
break;
}
}
}
},
_removeWithNoSpeech: function(languages, srEnabled) {
if (srEnabled) {
var speechLangs = new Set(
window.speechSynthesis.getVoices().map(v => v.lang.split('-')[0]));
for (var langName in languages) {
if (!speechLangs.has(langName.split('-')[0])) {
delete languages[langName];
}
}
}
},
_copyObj: function(obj) {
var copy = Object.create(null);
for (var prop in obj) {
copy[prop] = obj[prop];
}
return copy;
},
_parseVersion: function(ver) {
return ver.split('.').slice(0, 2).join('.');
},
_build: function() {
return Promise.all([
this._languages || (this._languages = this._readFile(LOCALES_FILE)),
this._readSetting('language.current'),
this._readSetting('devtools.pseudolocalization.enabled')
]).then(([langsFromFile, current, pseudoEnabled]) => {
var langs = this._copyObj(langsFromFile);
return Promise.all([
this._extendPseudo(langs, current, pseudoEnabled),
this._readSetting('langpack.channel'),
current,
this._readSetting('accessibility.screenreader'),
navigator.mozApps.getAdditionalLanguages()
]);
}).then(([langs, ver, current, srEnabled, addl]) => {
this._extendAdditional(langs, this._parseVersion(ver), addl);
this._removeWithNoSpeech(langs, srEnabled);
return [langs, current];
});
},
get: function(callback) {
if (!callback) {
return;
}
this._build().then(Function.prototype.apply.bind(callback, null));
},
wrapBidi: function(langCode, langName) {
// Right-to-Left (RTL) languages:
// (http://www.w3.org/International/questions/qa-scripts)
// Arabic, Hebrew, Farsi, Pashto, Bidi English (pseudo), Urdu
var rtlList = ['ar', 'he', 'fa', 'ps', 'ar-x-psbidi', 'ur'];
// Use script direction control-characters to wrap the text labels
// since markup (i.e. <bdo>) does not work inside <option> tags
// http://www.w3.org/International/tutorials/bidi-xhtml/#nomarkup
var lEmbedBegin =
(rtlList.indexOf(langCode) >= 0) ? '\u202b' : '\u202a';
var lEmbedEnd = '\u202c';
// The control-characters enforce the language-specific script
// direction to correctly display the text label (Bug #851457)
return lEmbedBegin + langName + lEmbedEnd;
}
};
}(window));