DEV: add translation fallback option for i18n

Allow for a default translation string to be returned when a translation cannot
be found.

Useful in contexts where there is a known fallback, such as custom emoji group
strings.
This commit is contained in:
Jeff Wong 2022-06-07 12:02:09 -07:00
parent 532935043c
commit 9a656e18e9
2 changed files with 34 additions and 24 deletions

View File

@ -279,4 +279,13 @@ module("Unit | Utility | i18n", function (hooks) {
"Hi $& $&" "Hi $& $&"
); );
}); });
test("Customized missing translation string", function (assert) {
assert.strictEqual(
I18n.t("emoji_picker.customtest", {
translatedFallback: "customtest",
}),
"customtest"
);
});
}); });

View File

@ -8,7 +8,7 @@ I18n.defaultLocale = "en";
I18n.pluralizationRules = { I18n.pluralizationRules = {
en(n) { en(n) {
return n === 0 ? ["zero", "none", "other"] : n === 1 ? "one" : "other"; return n === 0 ? ["zero", "none", "other"] : n === 1 ? "one" : "other";
} },
}; };
// Set current locale to null // Set current locale to null
@ -22,11 +22,11 @@ I18n.SEPARATOR = ".";
I18n.noFallbacks = false; I18n.noFallbacks = false;
I18n.isValidNode = function(obj, node, undefined) { I18n.isValidNode = function (obj, node, undefined) {
return obj[node] !== null && obj[node] !== undefined; return obj[node] !== null && obj[node] !== undefined;
}; };
I18n.lookup = function(scope, options) { I18n.lookup = function (scope, options) {
options = options || {}; options = options || {};
var translations = this.prepareOptions(I18n.translations), var translations = this.prepareOptions(I18n.translations),
@ -79,7 +79,7 @@ I18n.lookup = function(scope, options) {
// I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"}); // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
// #=> {name: "John Doe", role: "user"} // #=> {name: "John Doe", role: "user"}
// //
I18n.prepareOptions = function() { I18n.prepareOptions = function () {
var options = {}, var options = {},
opts, opts,
count = arguments.length; count = arguments.length;
@ -101,7 +101,7 @@ I18n.prepareOptions = function() {
return options; return options;
}; };
I18n.interpolate = function(message, options) { I18n.interpolate = function (message, options) {
options = this.prepareOptions(options); options = this.prepareOptions(options);
var matches = message.match(this.PLACEHOLDER), var matches = message.match(this.PLACEHOLDER),
@ -139,7 +139,7 @@ I18n.interpolate = function(message, options) {
return message; return message;
}; };
I18n.translate = function(scope, options) { I18n.translate = function (scope, options) {
options = this.prepareOptions(options); options = this.prepareOptions(options);
options.needsPluralization = typeof options.count === "number"; options.needsPluralization = typeof options.count === "number";
options.ignoreMissing = !this.noFallbacks; options.ignoreMissing = !this.noFallbacks;
@ -168,11 +168,14 @@ I18n.translate = function(scope, options) {
try { try {
return this.interpolate(translation, options); return this.interpolate(translation, options);
} catch (error) { } catch (error) {
return this.missingTranslation(scope, null, options); return (
options.translatedFallback ||
this.missingTranslation(scope, null, options)
);
} }
}; };
I18n.findTranslation = function(scope, options) { I18n.findTranslation = function (scope, options) {
var translation = this.lookup(scope, options); var translation = this.lookup(scope, options);
if (translation && options.needsPluralization) { if (translation && options.needsPluralization) {
@ -182,18 +185,16 @@ I18n.findTranslation = function(scope, options) {
return translation; return translation;
}; };
I18n.toNumber = function(number, options) { I18n.toNumber = function (number, options) {
options = this.prepareOptions(options, this.lookup("number.format"), { options = this.prepareOptions(options, this.lookup("number.format"), {
precision: 3, precision: 3,
separator: this.SEPARATOR, separator: this.SEPARATOR,
delimiter: ",", delimiter: ",",
strip_insignificant_zeros: false strip_insignificant_zeros: false,
}); });
var negative = number < 0, var negative = number < 0,
string = Math.abs(number) string = Math.abs(number).toFixed(options.precision).toString(),
.toFixed(options.precision)
.toString(),
parts = string.split(this.SEPARATOR), parts = string.split(this.SEPARATOR),
buffer = [], buffer = [],
formattedNumber; formattedNumber;
@ -219,7 +220,7 @@ I18n.toNumber = function(number, options) {
if (options.strip_insignificant_zeros) { if (options.strip_insignificant_zeros) {
var regex = { var regex = {
separator: new RegExp(options.separator.replace(/\./, "\\.") + "$"), separator: new RegExp(options.separator.replace(/\./, "\\.") + "$"),
zeros: /0+$/ zeros: /0+$/,
}; };
formattedNumber = formattedNumber formattedNumber = formattedNumber
@ -230,7 +231,7 @@ I18n.toNumber = function(number, options) {
return formattedNumber; return formattedNumber;
}; };
I18n.toHumanSize = function(number, options) { I18n.toHumanSize = function (number, options) {
var kb = 1024, var kb = 1024,
size = number, size = number,
iterations = 0, iterations = 0,
@ -256,7 +257,7 @@ I18n.toHumanSize = function(number, options) {
options = this.prepareOptions(options, { options = this.prepareOptions(options, {
precision: precision, precision: precision,
format: this.t("number.human.storage_units.format"), format: this.t("number.human.storage_units.format"),
delimiter: "" delimiter: "",
}); });
number = this.toNumber(size, options); number = this.toNumber(size, options);
@ -265,13 +266,13 @@ I18n.toHumanSize = function(number, options) {
return number; return number;
}; };
I18n.pluralizer = function(locale) { I18n.pluralizer = function (locale) {
var pluralizer = this.pluralizationRules[locale]; var pluralizer = this.pluralizationRules[locale];
if (pluralizer !== undefined) return pluralizer; if (pluralizer !== undefined) return pluralizer;
return this.pluralizationRules["en"]; return this.pluralizationRules["en"];
}; };
I18n.findAndTranslateValidNode = function(keys, translation) { I18n.findAndTranslateValidNode = function (keys, translation) {
for (var i = 0; i < keys.length; i++) { for (var i = 0; i < keys.length; i++) {
var key = keys[i]; var key = keys[i];
if (this.isValidNode(translation, key)) return translation[key]; if (this.isValidNode(translation, key)) return translation[key];
@ -279,7 +280,7 @@ I18n.findAndTranslateValidNode = function(keys, translation) {
return null; return null;
}; };
I18n.pluralize = function(translation, scope, options) { I18n.pluralize = function (translation, scope, options) {
if (typeof translation !== "object") return translation; if (typeof translation !== "object") return translation;
options = this.prepareOptions(options); options = this.prepareOptions(options);
@ -298,7 +299,7 @@ I18n.pluralize = function(translation, scope, options) {
return this.missingTranslation(scope, keys[0]); return this.missingTranslation(scope, keys[0]);
}; };
I18n.missingTranslation = function(scope, key, options) { I18n.missingTranslation = function (scope, key, options) {
var message = "[" + this.currentLocale() + this.SEPARATOR + scope; var message = "[" + this.currentLocale() + this.SEPARATOR + scope;
if (key) { if (key) {
@ -312,18 +313,18 @@ I18n.missingTranslation = function(scope, key, options) {
return message + "]"; return message + "]";
}; };
I18n.currentLocale = function() { I18n.currentLocale = function () {
return I18n.locale || I18n.defaultLocale; return I18n.locale || I18n.defaultLocale;
}; };
I18n.enableVerboseLocalization = function() { I18n.enableVerboseLocalization = function () {
var counter = 0; var counter = 0;
var keys = {}; var keys = {};
var t = I18n.t; var t = I18n.t;
I18n.noFallbacks = true; I18n.noFallbacks = true;
I18n.t = I18n.translate = function(scope, value) { I18n.t = I18n.translate = function (scope, value) {
var current = keys[scope]; var current = keys[scope];
if (!current) { if (!current) {
current = keys[scope] = ++counter; current = keys[scope] = ++counter;
@ -338,7 +339,7 @@ I18n.enableVerboseLocalization = function() {
}; };
}; };
I18n.enableVerboseLocalizationSession = function() { I18n.enableVerboseLocalizationSession = function () {
sessionStorage.setItem("verbose_localization", "true"); sessionStorage.setItem("verbose_localization", "true");
I18n.enableVerboseLocalization(); I18n.enableVerboseLocalization();