mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
59097b207f
Over the years we accrued many spelling mistakes in the code base. This PR attempts to fix spelling mistakes and typos in all areas of the code that are extremely safe to change - comments - test descriptions - other low risk areas
343 lines
8.6 KiB
JavaScript
343 lines
8.6 KiB
JavaScript
// Instantiate the object
|
|
var I18n = I18n || {};
|
|
|
|
// Set default locale to english
|
|
I18n.defaultLocale = "en";
|
|
|
|
// Set default pluralization rule
|
|
I18n.pluralizationRules = {
|
|
en: function(n) {
|
|
return n === 0 ? ["zero", "none", "other"] : n === 1 ? "one" : "other";
|
|
}
|
|
};
|
|
|
|
// Set current locale to null
|
|
I18n.locale = null;
|
|
I18n.fallbackLocale = null;
|
|
|
|
// Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
|
|
I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
|
|
|
|
I18n.SEPARATOR = ".";
|
|
|
|
I18n.noFallbacks = false;
|
|
|
|
I18n.isValidNode = function(obj, node, undefined) {
|
|
return obj[node] !== null && obj[node] !== undefined;
|
|
};
|
|
|
|
I18n.lookup = function(scope, options) {
|
|
options = options || {};
|
|
|
|
var translations = this.prepareOptions(I18n.translations),
|
|
locale = options.locale || I18n.currentLocale(),
|
|
messages = translations[locale] || {},
|
|
currentScope;
|
|
|
|
options = this.prepareOptions(options);
|
|
|
|
if (typeof scope === "object") {
|
|
scope = scope.join(this.SEPARATOR);
|
|
}
|
|
|
|
if (options.scope) {
|
|
scope = options.scope.toString() + this.SEPARATOR + scope;
|
|
}
|
|
|
|
var originalScope = scope;
|
|
scope = scope.split(this.SEPARATOR);
|
|
|
|
if (scope.length > 0 && scope[0] !== "js") {
|
|
scope.unshift("js");
|
|
}
|
|
|
|
while (messages && scope.length > 0) {
|
|
currentScope = scope.shift();
|
|
messages = messages[currentScope];
|
|
}
|
|
|
|
if (messages === undefined && this.extras && this.extras[locale]) {
|
|
messages = this.extras[locale];
|
|
scope = originalScope.split(this.SEPARATOR);
|
|
|
|
while (messages && scope.length > 0) {
|
|
currentScope = scope.shift();
|
|
messages = messages[currentScope];
|
|
}
|
|
}
|
|
|
|
if (messages === undefined) {
|
|
messages = options.defaultValue;
|
|
}
|
|
|
|
return messages;
|
|
};
|
|
|
|
// Merge several hash options, checking if value is set before
|
|
// overwriting any value. The precedence is from left to right.
|
|
//
|
|
// I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
|
|
// #=> {name: "John Doe", role: "user"}
|
|
//
|
|
I18n.prepareOptions = function() {
|
|
var options = {},
|
|
opts,
|
|
count = arguments.length;
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
opts = arguments[i];
|
|
|
|
if (!opts) {
|
|
continue;
|
|
}
|
|
|
|
for (var key in opts) {
|
|
if (!this.isValidNode(options, key)) {
|
|
options[key] = opts[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return options;
|
|
};
|
|
|
|
I18n.interpolate = function(message, options) {
|
|
options = this.prepareOptions(options);
|
|
|
|
var matches = message.match(this.PLACEHOLDER),
|
|
placeholder,
|
|
value,
|
|
name;
|
|
|
|
if (!matches) {
|
|
return message;
|
|
}
|
|
|
|
for (var i = 0; (placeholder = matches[i]); i++) {
|
|
name = placeholder.replace(this.PLACEHOLDER, "$1");
|
|
|
|
if (typeof options[name] === "string") {
|
|
// The dollar sign (`$`) is a special replace pattern, and `$&` inserts
|
|
// the matched string. Thus dollars signs need to be escaped with the
|
|
// special pattern `$$`, which inserts a single `$`.
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
|
|
value = options[name].replace(/\$/g, "$$$$");
|
|
} else {
|
|
value = options[name];
|
|
}
|
|
|
|
if (!this.isValidNode(options, name)) {
|
|
value = "[missing " + placeholder + " value]";
|
|
}
|
|
|
|
var regex = new RegExp(
|
|
placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}")
|
|
);
|
|
message = message.replace(regex, value);
|
|
}
|
|
|
|
return message;
|
|
};
|
|
|
|
I18n.translate = function(scope, options) {
|
|
options = this.prepareOptions(options);
|
|
options.needsPluralization = typeof options.count === "number";
|
|
options.ignoreMissing = !this.noFallbacks;
|
|
|
|
var translation = this.findTranslation(scope, options);
|
|
|
|
if (!this.noFallbacks) {
|
|
if (!translation && this.fallbackLocale) {
|
|
options.locale = this.fallbackLocale;
|
|
translation = this.findTranslation(scope, options);
|
|
}
|
|
|
|
options.ignoreMissing = false;
|
|
|
|
if (!translation && this.currentLocale() !== this.defaultLocale) {
|
|
options.locale = this.defaultLocale;
|
|
translation = this.findTranslation(scope, options);
|
|
}
|
|
|
|
if (!translation && this.currentLocale() !== "en") {
|
|
options.locale = "en";
|
|
translation = this.findTranslation(scope, options);
|
|
}
|
|
}
|
|
|
|
try {
|
|
return this.interpolate(translation, options);
|
|
} catch (error) {
|
|
return this.missingTranslation(scope);
|
|
}
|
|
};
|
|
|
|
I18n.findTranslation = function(scope, options) {
|
|
var translation = this.lookup(scope, options);
|
|
|
|
if (translation && options.needsPluralization) {
|
|
translation = this.pluralize(translation, scope, options);
|
|
}
|
|
|
|
return translation;
|
|
};
|
|
|
|
I18n.toNumber = function(number, options) {
|
|
options = this.prepareOptions(options, this.lookup("number.format"), {
|
|
precision: 3,
|
|
separator: this.SEPARATOR,
|
|
delimiter: ",",
|
|
strip_insignificant_zeros: false
|
|
});
|
|
|
|
var negative = number < 0,
|
|
string = Math.abs(number)
|
|
.toFixed(options.precision)
|
|
.toString(),
|
|
parts = string.split(this.SEPARATOR),
|
|
buffer = [],
|
|
formattedNumber;
|
|
|
|
number = parts[0];
|
|
|
|
while (number.length > 0) {
|
|
buffer.unshift(number.substr(Math.max(0, number.length - 3), 3));
|
|
number = number.substr(0, number.length - 3);
|
|
}
|
|
|
|
formattedNumber = buffer.join(options.delimiter);
|
|
|
|
if (options.precision > 0) {
|
|
formattedNumber += options.separator + parts[1];
|
|
}
|
|
|
|
if (negative) {
|
|
formattedNumber = "-" + formattedNumber;
|
|
}
|
|
|
|
if (options.strip_insignificant_zeros) {
|
|
var regex = {
|
|
separator: new RegExp(options.separator.replace(/\./, "\\.") + "$"),
|
|
zeros: /0+$/
|
|
};
|
|
|
|
formattedNumber = formattedNumber
|
|
.replace(regex.zeros, "")
|
|
.replace(regex.separator, "");
|
|
}
|
|
|
|
return formattedNumber;
|
|
};
|
|
|
|
I18n.toHumanSize = function(number, options) {
|
|
var kb = 1024,
|
|
size = number,
|
|
iterations = 0,
|
|
unit,
|
|
precision;
|
|
|
|
while (size >= kb && iterations < 4) {
|
|
size = size / kb;
|
|
iterations += 1;
|
|
}
|
|
|
|
if (iterations === 0) {
|
|
unit = this.t("number.human.storage_units.units.byte", { count: size });
|
|
precision = 0;
|
|
} else {
|
|
unit = this.t(
|
|
"number.human.storage_units.units." +
|
|
[null, "kb", "mb", "gb", "tb"][iterations]
|
|
);
|
|
precision = size - Math.floor(size) === 0 ? 0 : 1;
|
|
}
|
|
|
|
options = this.prepareOptions(options, {
|
|
precision: precision,
|
|
format: this.t("number.human.storage_units.format"),
|
|
delimiter: ""
|
|
});
|
|
|
|
number = this.toNumber(size, options);
|
|
number = options.format.replace("%u", unit).replace("%n", number);
|
|
|
|
return number;
|
|
};
|
|
|
|
I18n.pluralizer = function(locale) {
|
|
var pluralizer = this.pluralizationRules[locale];
|
|
if (pluralizer !== undefined) return pluralizer;
|
|
return this.pluralizationRules["en"];
|
|
};
|
|
|
|
I18n.findAndTranslateValidNode = function(keys, translation) {
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
if (this.isValidNode(translation, key)) return translation[key];
|
|
}
|
|
return null;
|
|
};
|
|
|
|
I18n.pluralize = function(translation, scope, options) {
|
|
if (typeof translation !== "object") return translation;
|
|
|
|
options = this.prepareOptions(options);
|
|
var count = options.count.toString();
|
|
|
|
var pluralizer = this.pluralizer(options.locale || this.currentLocale());
|
|
var key = pluralizer(Math.abs(count));
|
|
var keys = typeof key === "object" && key instanceof Array ? key : [key];
|
|
|
|
var message = this.findAndTranslateValidNode(keys, translation);
|
|
|
|
if (message !== null || options.ignoreMissing) {
|
|
return message;
|
|
}
|
|
|
|
return this.missingTranslation(scope, keys[0]);
|
|
};
|
|
|
|
I18n.missingTranslation = function(scope, key) {
|
|
var message = "[" + this.currentLocale() + this.SEPARATOR + scope;
|
|
if (key) {
|
|
message += this.SEPARATOR + key;
|
|
}
|
|
return message + "]";
|
|
};
|
|
|
|
I18n.currentLocale = function() {
|
|
return I18n.locale || I18n.defaultLocale;
|
|
};
|
|
|
|
I18n.enableVerboseLocalization = function() {
|
|
var counter = 0;
|
|
var keys = {};
|
|
var t = I18n.t;
|
|
|
|
I18n.noFallbacks = true;
|
|
|
|
I18n.t = I18n.translate = function(scope, value) {
|
|
var current = keys[scope];
|
|
if (!current) {
|
|
current = keys[scope] = ++counter;
|
|
var message = "Translation #" + current + ": " + scope;
|
|
if (value && Object.keys(value).length > 0) {
|
|
message += ", parameters: " + JSON.stringify(value);
|
|
}
|
|
// eslint-disable-next-line no-console
|
|
console.info(message);
|
|
}
|
|
return t.apply(I18n, [scope, value]) + " (#" + current + ")";
|
|
};
|
|
};
|
|
|
|
I18n.enableVerboseLocalizationSession = function() {
|
|
sessionStorage.setItem("verbose_localization", "true");
|
|
I18n.enableVerboseLocalization();
|
|
|
|
return "Verbose localization is enabled. Close the browser tab to turn it off. Reload the page to see the translation keys.";
|
|
};
|
|
|
|
// shortcuts
|
|
I18n.t = I18n.translate;
|