How to refer to locale-specific file?

I have a number of localised help files; how can I refer to the correct one?

I don’t think I can simply use the current locale within the URL as I may not have a set of translations for the current locale, so there’d be no fall-back. I can see no way to check whether my extension has that file in advance.

The single i18n example for this suggests (for CSS) using the extension name as a distinguisher within the URL (…/MSG_extensionName/…), but that could never work as it assumes all translations have a unique translation, but that won’t be true all the time (e.g., UK/US English, or Portuguese/Brazilian Portuguese).

Can I check in advance for a file or chrome URL being valid, or get a list of locales my extension supports?

I suppose I can manually create a list – I guess I’ll have to do that for new :frowning:

What i do in a similar scenario, is that i define in messages.json a string matching the locale name:

"__localeName": {
    "message": "fr"
}

To know which locale is being picked by the i18n system, i just request a translation for this string browser.i18n.getMessage("__localeName").

1 Like

Note that the locale name for various versions of some languages is different en-GB is British English and en-US is… pt-BR is Brazilian Portugese
in the locale folder of your extension you have folders for all the languages that you support and the files of the same name in each folder. In mine I have a file - singledomain.properties in every localisation folder.

As regards the issue of languages you don’t support… I have this code which I found which somehow knows to use the en-US folder if the locale of the machine in use is not present.
The unload function is included because it’s used in the getString function.
Run getString.init in your start up function and getString(name); to get the actual value.
function getString(name) {
// Use the cached bundle to retrieve the string
var str;
try {
str = getString.bundle.GetStringFromName(name);
}
// Use the fallback in-case the string isn’t localized
catch(ex) {
console.log(name);
//str = getString.fallback.GetStringFromName(name);
}

return str;
}

/**

  • Initialize getString() for the provided add-on.
  • @usage getString.init(addon): Load properties file for the add-on.
  • @param [object] addon: Add-on object from AddonManager
  • @usage getString.init(addon, getAlternate): Load properties with alternate.
  • @param [object] addon: Add-on object from AddonManager
  • @param [function] getAlternate: Convert a locale to an alternate locale
    */
    getString.init = function(addon, getAlternate) {

// Set a default get alternate function if it doesn’t exist
if (typeof getAlternate != “function”)
getAlternate = function() “en-US”;

// Get the bundled properties file for the app’s locale
function getBundle(locale) {

let propertyPath = "locale/" + locale + "/singledomain.properties";

let propertyFile = addon.getResourceURI(propertyPath);

// Get a bundle and test if it's able to do simple things

try {
var bundle = Services.strings.createBundle(propertyFile.spec);
bundle.getSimpleEnumeration();

     return bundle;

}
catch(ex) {}

// The locale must not exist, so give nothing
return null;

}

// Use the current locale or the alternate as the primary bundle
let locale = Cc["@mozilla.org/chrome/chrome-registry;1"].
getService(Ci.nsIXULChromeRegistry).getSelectedLocale(“global”);

getString.bundle = getBundle(locale) || getBundle(getAlternate(locale));

// Create a fallback in-case a string is missing
getString.fallback = getBundle(“en-US”);

// Clear out the strings cache when cleaning up so new ones load
unload(function() Services.strings.flushBundles());
}

/**

  • Save callbacks to run when unloading. Optionally scope the callback to a
  • container, e.g., window. Provide a way to run all the callbacks.
  • @usage unload(): Run all callbacks and release them.
  • @usage unload(callback): Add a callback to run on unload.
  • @param [function] callback: 0-parameter function to call on unload.
  • @return [function]: A 0-parameter function that undoes adding the callback.
  • @usage unload(callback, container) Add a scoped callback to run on unload.
  • @param [function] callback: 0-parameter function to call on unload.
  • @param [node] container: Remove the callback when this container unloads.
  • @return [function]: A 0-parameter function that undoes adding the callback.
    */
    function unload(callback, container) {
    // Initialize the array of unloaders on the first usage
    let unloaders = unload.unloaders;
    if (unloaders == null)
    unloaders = unload.unloaders = [];

// Calling with no arguments runs all the unloader callbacks
if (callback == null) {
unloaders.slice().forEach(function(unloader) unloader());
unloaders.length = 0;
return true;
}

// The callback is bound to the lifetime of the container if we have one
if (container != null) {
// Remove the unloader when the container unloads
container.addEventListener(“unload”, removeUnloader, false);

// Wrap the callback to additionally remove the unload listener
let origCallback = callback;
callback = function() {
  container.removeEventListener("unload", removeUnloader, false);
  origCallback();
}

}

// Wrap the callback in a function that ignores failures
function unloader() {
try {
callback();
}
catch(ex) {}
}
unloaders.push(unloader);

// Provide a way to remove the unloader
function removeUnloader() {
let index = unloaders.indexOf(unloader);
if (index != -1)
unloaders.splice(index, 1);
return true;
}
return removeUnloader;

}