gecko-dev/devtools/client/shared/l10n.js
2016-05-19 08:35:45 -06:00

134 lines
4.0 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { Ci } = require("chrome");
const Services = require("Services");
/**
* Localization convenience methods.
*
* @param string stringBundleName
* The desired string bundle's name.
*/
function LocalizationHelper(stringBundleName) {
loader.lazyGetter(this, "stringBundle", () =>
Services.strings.createBundle(stringBundleName));
loader.lazyGetter(this, "ellipsis", () =>
Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString)
.data);
}
LocalizationHelper.prototype = {
/**
* L10N shortcut function.
*
* @param string name
* @return string
*/
getStr: function (name) {
return this.stringBundle.GetStringFromName(name);
},
/**
* L10N shortcut function.
*
* @param string name
* @param array args
* @return string
*/
getFormatStr: function (name, ...args) {
return this.stringBundle.formatStringFromName(name, args, args.length);
},
/**
* L10N shortcut function for numeric arguments that need to be formatted.
* All numeric arguments will be fixed to 2 decimals and given a localized
* decimal separator. Other arguments will be left alone.
*
* @param string name
* @param array args
* @return string
*/
getFormatStrWithNumbers: function (name, ...args) {
let newArgs = args.map(x => {
return typeof x == "number" ? this.numberWithDecimals(x, 2) : x;
});
return this.stringBundle.formatStringFromName(name,
newArgs,
newArgs.length);
},
/**
* Converts a number to a locale-aware string format and keeps a certain
* number of decimals.
*
* @param number number
* The number to convert.
* @param number decimals [optional]
* Total decimals to keep.
* @return string
* The localized number as a string.
*/
numberWithDecimals: function (number, decimals = 0) {
// If this is an integer, don't do anything special.
if (number === (number|0)) {
return number;
}
// If this isn't a number (and yes, `isNaN(null)` is false), return zero.
if (isNaN(number) || number === null) {
return "0";
}
let localized = number.toLocaleString();
// If no grouping or decimal separators are available, bail out, because
// padding with zeros at the end of the string won't make sense anymore.
if (!localized.match(/[^\d]/)) {
return localized;
}
return number.toLocaleString(undefined, {
maximumFractionDigits: decimals,
minimumFractionDigits: decimals
});
}
};
/**
* A helper for having the same interface as LocalizationHelper, but for more
* than one file. Useful for abstracting l10n string locations.
*/
function MultiLocalizationHelper(...stringBundleNames) {
let instances = stringBundleNames.map(bundle => {
return new LocalizationHelper(bundle);
});
// Get all function members of the LocalizationHelper class, making sure we're
// not executing any potential getters while doing so, and wrap all the
// methods we've found to work on all given string bundles.
Object.getOwnPropertyNames(LocalizationHelper.prototype)
.map(name => ({
name: name,
descriptor: Object.getOwnPropertyDescriptor(LocalizationHelper.prototype,
name)
}))
.filter(({ descriptor }) => descriptor.value instanceof Function)
.forEach(method => {
this[method.name] = (...args) => {
for (let l10n of instances) {
try {
return method.descriptor.value.apply(l10n, args);
} catch (e) {
// Do nothing
}
}
return null;
};
});
}
exports.LocalizationHelper = LocalizationHelper;
exports.MultiLocalizationHelper = MultiLocalizationHelper;