This commit is contained in:
462
node_modules/node-polyglot/index.js
generated
vendored
Normal file
462
node_modules/node-polyglot/index.js
generated
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
// (c) 2012-2018 Airbnb, Inc.
|
||||
//
|
||||
// polyglot.js may be freely distributed under the terms of the BSD
|
||||
// license. For all licensing information, details, and documentation:
|
||||
// http://airbnb.github.com/polyglot.js
|
||||
//
|
||||
//
|
||||
// Polyglot.js is an I18n helper library written in JavaScript, made to
|
||||
// work both in the browser and in Node. It provides a simple solution for
|
||||
// interpolation and pluralization, based off of Airbnb's
|
||||
// experience adding I18n functionality to its Backbone.js and Node apps.
|
||||
//
|
||||
// Polylglot is agnostic to your translation backend. It doesn't perform any
|
||||
// translation; it simply gives you a way to manage translated phrases from
|
||||
// your client- or server-side JavaScript application.
|
||||
//
|
||||
|
||||
'use strict';
|
||||
|
||||
var entries = require('object.entries');
|
||||
var warning = require('warning');
|
||||
var has = require('hasown');
|
||||
|
||||
var warn = function warn(message) {
|
||||
warning(false, message);
|
||||
};
|
||||
|
||||
var defaultReplace = String.prototype.replace;
|
||||
var split = String.prototype.split;
|
||||
|
||||
// #### Pluralization methods
|
||||
// The string that separates the different phrase possibilities.
|
||||
var delimiter = '||||';
|
||||
|
||||
var russianPluralGroups = function (n) {
|
||||
var lastTwo = n % 100;
|
||||
var end = lastTwo % 10;
|
||||
if (lastTwo !== 11 && end === 1) {
|
||||
return 0;
|
||||
}
|
||||
if (2 <= end && end <= 4 && !(lastTwo >= 12 && lastTwo <= 14)) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
};
|
||||
|
||||
var defaultPluralRules = {
|
||||
// Mapping from pluralization group plural logic.
|
||||
pluralTypes: {
|
||||
arabic: function (n) {
|
||||
// http://www.arabeyes.org/Plural_Forms
|
||||
if (n < 3) { return n; }
|
||||
var lastTwo = n % 100;
|
||||
if (lastTwo >= 3 && lastTwo <= 10) return 3;
|
||||
return lastTwo >= 11 ? 4 : 5;
|
||||
},
|
||||
bosnian_serbian: russianPluralGroups,
|
||||
chinese: function () { return 0; },
|
||||
croatian: russianPluralGroups,
|
||||
french: function (n) { return n >= 2 ? 1 : 0; },
|
||||
german: function (n) { return n !== 1 ? 1 : 0; },
|
||||
russian: russianPluralGroups,
|
||||
lithuanian: function (n) {
|
||||
if (n % 10 === 1 && n % 100 !== 11) { return 0; }
|
||||
return n % 10 >= 2 && n % 10 <= 9 && (n % 100 < 11 || n % 100 > 19) ? 1 : 2;
|
||||
},
|
||||
czech: function (n) {
|
||||
if (n === 1) { return 0; }
|
||||
return (n >= 2 && n <= 4) ? 1 : 2;
|
||||
},
|
||||
polish: function (n) {
|
||||
if (n === 1) { return 0; }
|
||||
var end = n % 10;
|
||||
return 2 <= end && end <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
|
||||
},
|
||||
icelandic: function (n) { return (n % 10 !== 1 || n % 100 === 11) ? 1 : 0; },
|
||||
slovenian: function (n) {
|
||||
var lastTwo = n % 100;
|
||||
if (lastTwo === 1) {
|
||||
return 0;
|
||||
}
|
||||
if (lastTwo === 2) {
|
||||
return 1;
|
||||
}
|
||||
if (lastTwo === 3 || lastTwo === 4) {
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
},
|
||||
romanian: function (n) {
|
||||
if (n === 1) { return 0; }
|
||||
var lastTwo = n % 100;
|
||||
if (n === 0 || (lastTwo >= 2 && lastTwo <= 19)) { return 1; }
|
||||
return 2;
|
||||
},
|
||||
ukrainian: russianPluralGroups
|
||||
},
|
||||
|
||||
// Mapping from pluralization group to individual language codes/locales.
|
||||
// Will look up based on exact match, if not found and it's a locale will parse the locale
|
||||
// for language code, and if that does not exist will default to 'en'
|
||||
pluralTypeToLanguages: {
|
||||
arabic: ['ar'],
|
||||
bosnian_serbian: ['bs-Latn-BA', 'bs-Cyrl-BA', 'srl-RS', 'sr-RS'],
|
||||
chinese: ['id', 'id-ID', 'ja', 'ko', 'ko-KR', 'lo', 'ms', 'th', 'th-TH', 'zh'],
|
||||
croatian: ['hr', 'hr-HR'],
|
||||
german: ['fa', 'da', 'de', 'en', 'es', 'fi', 'el', 'he', 'hi-IN', 'hu', 'hu-HU', 'it', 'nl', 'no', 'pt', 'sv', 'tr'],
|
||||
french: ['fr', 'tl', 'pt-br'],
|
||||
russian: ['ru', 'ru-RU'],
|
||||
lithuanian: ['lt'],
|
||||
czech: ['cs', 'cs-CZ', 'sk'],
|
||||
polish: ['pl'],
|
||||
icelandic: ['is', 'mk'],
|
||||
slovenian: ['sl-SL'],
|
||||
romanian: ['ro'],
|
||||
ukrainian: ['uk', 'ua']
|
||||
}
|
||||
};
|
||||
|
||||
function langToTypeMap(mapping) {
|
||||
var ret = {};
|
||||
var mappingEntries = entries(mapping);
|
||||
for (var i = 0; i < mappingEntries.length; i += 1) {
|
||||
var type = mappingEntries[i][0];
|
||||
var langs = mappingEntries[i][1];
|
||||
for (var j = 0; j < langs.length; j += 1) {
|
||||
ret[langs[j]] = type;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function pluralTypeName(pluralRules, locale) {
|
||||
var langToPluralType = langToTypeMap(pluralRules.pluralTypeToLanguages);
|
||||
return langToPluralType[locale]
|
||||
|| langToPluralType[split.call(locale, /-/, 1)[0]]
|
||||
|| langToPluralType.en;
|
||||
}
|
||||
|
||||
function pluralTypeIndex(pluralRules, pluralType, count) {
|
||||
return pluralRules.pluralTypes[pluralType](count);
|
||||
}
|
||||
|
||||
function createMemoizedPluralTypeNameSelector() {
|
||||
var localePluralTypeStorage = {};
|
||||
|
||||
return function (pluralRules, locale) {
|
||||
var pluralType = localePluralTypeStorage[locale];
|
||||
|
||||
if (pluralType && !pluralRules.pluralTypes[pluralType]) {
|
||||
pluralType = null;
|
||||
localePluralTypeStorage[locale] = pluralType;
|
||||
}
|
||||
|
||||
if (!pluralType) {
|
||||
pluralType = pluralTypeName(pluralRules, locale);
|
||||
|
||||
if (pluralType) {
|
||||
localePluralTypeStorage[locale] = pluralType;
|
||||
}
|
||||
}
|
||||
|
||||
return pluralType;
|
||||
};
|
||||
}
|
||||
|
||||
function escape(token) {
|
||||
return token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function constructTokenRegex(opts) {
|
||||
var prefix = (opts && opts.prefix) || '%{';
|
||||
var suffix = (opts && opts.suffix) || '}';
|
||||
|
||||
if (prefix === delimiter || suffix === delimiter) {
|
||||
throw new RangeError('"' + delimiter + '" token is reserved for pluralization');
|
||||
}
|
||||
|
||||
return new RegExp(escape(prefix) + '(.*?)' + escape(suffix), 'g');
|
||||
}
|
||||
|
||||
var memoizedPluralTypeName = createMemoizedPluralTypeNameSelector();
|
||||
|
||||
var defaultTokenRegex = /%\{(.*?)\}/g;
|
||||
|
||||
// ### transformPhrase(phrase, substitutions, locale)
|
||||
//
|
||||
// Takes a phrase string and transforms it by choosing the correct
|
||||
// plural form and interpolating it.
|
||||
//
|
||||
// transformPhrase('Hello, %{name}!', {name: 'Spike'});
|
||||
// // "Hello, Spike!"
|
||||
//
|
||||
// The correct plural form is selected if substitutions.smart_count
|
||||
// is set. You can pass in a number instead of an Object as `substitutions`
|
||||
// as a shortcut for `smart_count`.
|
||||
//
|
||||
// transformPhrase('%{smart_count} new messages |||| 1 new message', {smart_count: 1}, 'en');
|
||||
// // "1 new message"
|
||||
//
|
||||
// transformPhrase('%{smart_count} new messages |||| 1 new message', {smart_count: 2}, 'en');
|
||||
// // "2 new messages"
|
||||
//
|
||||
// transformPhrase('%{smart_count} new messages |||| 1 new message', 5, 'en');
|
||||
// // "5 new messages"
|
||||
//
|
||||
// You should pass in a third argument, the locale, to specify the correct plural type.
|
||||
// It defaults to `'en'` with 2 plural forms.
|
||||
function transformPhrase(
|
||||
phrase,
|
||||
substitutions,
|
||||
locale,
|
||||
tokenRegex,
|
||||
pluralRules,
|
||||
replaceImplementation
|
||||
) {
|
||||
if (typeof phrase !== 'string') {
|
||||
throw new TypeError('Polyglot.transformPhrase expects argument #1 to be string');
|
||||
}
|
||||
|
||||
if (substitutions == null) {
|
||||
return phrase;
|
||||
}
|
||||
|
||||
var result = phrase;
|
||||
var interpolationRegex = tokenRegex || defaultTokenRegex;
|
||||
var replace = replaceImplementation || defaultReplace;
|
||||
|
||||
// allow number as a pluralization shortcut
|
||||
var options = typeof substitutions === 'number' ? { smart_count: substitutions } : substitutions;
|
||||
|
||||
// Select plural form: based on a phrase text that contains `n`
|
||||
// plural forms separated by `delimiter`, a `locale`, and a `substitutions.smart_count`,
|
||||
// choose the correct plural form. This is only done if `count` is set.
|
||||
if (options.smart_count != null && phrase) {
|
||||
var pluralRulesOrDefault = pluralRules || defaultPluralRules;
|
||||
var texts = split.call(phrase, delimiter);
|
||||
var bestLocale = locale || 'en';
|
||||
var pluralType = memoizedPluralTypeName(pluralRulesOrDefault, bestLocale);
|
||||
var pluralTypeWithCount = pluralTypeIndex(
|
||||
pluralRulesOrDefault,
|
||||
pluralType,
|
||||
options.smart_count
|
||||
);
|
||||
|
||||
result = defaultReplace.call(texts[pluralTypeWithCount] || texts[0], /^[^\S]*|[^\S]*$/g, '');
|
||||
}
|
||||
|
||||
// Interpolate: Creates a `RegExp` object for each interpolation placeholder.
|
||||
result = replace.call(result, interpolationRegex, function (expression, argument) {
|
||||
if (!has(options, argument) || options[argument] == null) { return expression; }
|
||||
return options[argument];
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ### Polyglot class constructor
|
||||
function Polyglot(options) {
|
||||
var opts = options || {};
|
||||
this.phrases = {};
|
||||
this.extend(opts.phrases || {});
|
||||
this.currentLocale = opts.locale || 'en';
|
||||
var allowMissing = opts.allowMissing ? transformPhrase : null;
|
||||
this.onMissingKey = typeof opts.onMissingKey === 'function' ? opts.onMissingKey : allowMissing;
|
||||
this.warn = opts.warn || warn;
|
||||
this.replaceImplementation = opts.replace || defaultReplace;
|
||||
this.tokenRegex = constructTokenRegex(opts.interpolation);
|
||||
this.pluralRules = opts.pluralRules || defaultPluralRules;
|
||||
}
|
||||
|
||||
// ### polyglot.locale([locale])
|
||||
//
|
||||
// Get or set locale. Internally, Polyglot only uses locale for pluralization.
|
||||
Polyglot.prototype.locale = function (newLocale) {
|
||||
if (newLocale) this.currentLocale = newLocale;
|
||||
return this.currentLocale;
|
||||
};
|
||||
|
||||
// ### polyglot.extend(phrases)
|
||||
//
|
||||
// Use `extend` to tell Polyglot how to translate a given key.
|
||||
//
|
||||
// polyglot.extend({
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}"
|
||||
// });
|
||||
//
|
||||
// The key can be any string. Feel free to call `extend` multiple times;
|
||||
// it will override any phrases with the same key, but leave existing phrases
|
||||
// untouched.
|
||||
//
|
||||
// It is also possible to pass nested phrase objects, which get flattened
|
||||
// into an object with the nested keys concatenated using dot notation.
|
||||
//
|
||||
// polyglot.extend({
|
||||
// "nav": {
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}",
|
||||
// "sidebar": {
|
||||
// "welcome": "Welcome"
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// console.log(polyglot.phrases);
|
||||
// // {
|
||||
// // 'nav.hello': 'Hello',
|
||||
// // 'nav.hello_name': 'Hello, %{name}',
|
||||
// // 'nav.sidebar.welcome': 'Welcome'
|
||||
// // }
|
||||
//
|
||||
// `extend` accepts an optional second argument, `prefix`, which can be used
|
||||
// to prefix every key in the phrases object with some string, using dot
|
||||
// notation.
|
||||
//
|
||||
// polyglot.extend({
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}"
|
||||
// }, "nav");
|
||||
//
|
||||
// console.log(polyglot.phrases);
|
||||
// // {
|
||||
// // 'nav.hello': 'Hello',
|
||||
// // 'nav.hello_name': 'Hello, %{name}'
|
||||
// // }
|
||||
//
|
||||
// This feature is used internally to support nested phrase objects.
|
||||
Polyglot.prototype.extend = function (morePhrases, prefix) {
|
||||
var phraseEntries = entries(morePhrases || {});
|
||||
for (var i = 0; i < phraseEntries.length; i += 1) {
|
||||
var key = phraseEntries[i][0];
|
||||
var phrase = phraseEntries[i][1];
|
||||
var prefixedKey = prefix ? prefix + '.' + key : key;
|
||||
if (typeof phrase === 'object') {
|
||||
this.extend(phrase, prefixedKey);
|
||||
} else {
|
||||
this.phrases[prefixedKey] = phrase;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ### polyglot.unset(phrases)
|
||||
// Use `unset` to selectively remove keys from a polyglot instance.
|
||||
//
|
||||
// polyglot.unset("some_key");
|
||||
// polyglot.unset({
|
||||
// "hello": "Hello",
|
||||
// "hello_name": "Hello, %{name}"
|
||||
// });
|
||||
//
|
||||
// The unset method can take either a string (for the key), or an object hash with
|
||||
// the keys that you would like to unset.
|
||||
Polyglot.prototype.unset = function (morePhrases, prefix) {
|
||||
if (typeof morePhrases === 'string') {
|
||||
delete this.phrases[morePhrases];
|
||||
} else {
|
||||
var phraseEntries = entries(morePhrases || {});
|
||||
for (var i = 0; i < phraseEntries.length; i += 1) {
|
||||
var key = phraseEntries[i][0];
|
||||
var phrase = phraseEntries[i][1];
|
||||
var prefixedKey = prefix ? prefix + '.' + key : key;
|
||||
if (typeof phrase === 'object') {
|
||||
this.unset(phrase, prefixedKey);
|
||||
} else {
|
||||
delete this.phrases[prefixedKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ### polyglot.clear()
|
||||
//
|
||||
// Clears all phrases. Useful for special cases, such as freeing
|
||||
// up memory if you have lots of phrases but no longer need to
|
||||
// perform any translation. Also used internally by `replace`.
|
||||
Polyglot.prototype.clear = function () {
|
||||
this.phrases = {};
|
||||
};
|
||||
|
||||
// ### polyglot.replace(phrases)
|
||||
//
|
||||
// Completely replace the existing phrases with a new set of phrases.
|
||||
// Normally, just use `extend` to add more phrases, but under certain
|
||||
// circumstances, you may want to make sure no old phrases are lying around.
|
||||
Polyglot.prototype.replace = function (newPhrases) {
|
||||
this.clear();
|
||||
this.extend(newPhrases);
|
||||
};
|
||||
|
||||
// ### polyglot.t(key, options)
|
||||
//
|
||||
// The most-used method. Provide a key, and `t` will return the
|
||||
// phrase.
|
||||
//
|
||||
// polyglot.t("hello");
|
||||
// => "Hello"
|
||||
//
|
||||
// The phrase value is provided first by a call to `polyglot.extend()` or
|
||||
// `polyglot.replace()`.
|
||||
//
|
||||
// Pass in an object as the second argument to perform interpolation.
|
||||
//
|
||||
// polyglot.t("hello_name", {name: "Spike"});
|
||||
// => "Hello, Spike"
|
||||
//
|
||||
// If you like, you can provide a default value in case the phrase is missing.
|
||||
// Use the special option key "_" to specify a default.
|
||||
//
|
||||
// polyglot.t("i_like_to_write_in_language", {
|
||||
// _: "I like to write in %{language}.",
|
||||
// language: "JavaScript"
|
||||
// });
|
||||
// => "I like to write in JavaScript."
|
||||
//
|
||||
Polyglot.prototype.t = function (key, options) {
|
||||
var phrase, result;
|
||||
var opts = options == null ? {} : options;
|
||||
if (typeof this.phrases[key] === 'string') {
|
||||
phrase = this.phrases[key];
|
||||
} else if (typeof opts._ === 'string') {
|
||||
phrase = opts._;
|
||||
} else if (this.onMissingKey) {
|
||||
var onMissingKey = this.onMissingKey;
|
||||
result = onMissingKey(
|
||||
key,
|
||||
opts,
|
||||
this.currentLocale,
|
||||
this.tokenRegex,
|
||||
this.pluralRules,
|
||||
this.replaceImplementation
|
||||
);
|
||||
} else {
|
||||
this.warn('Missing translation for key: "' + key + '"');
|
||||
result = key;
|
||||
}
|
||||
if (typeof phrase === 'string') {
|
||||
result = transformPhrase(
|
||||
phrase,
|
||||
opts,
|
||||
this.currentLocale,
|
||||
this.tokenRegex,
|
||||
this.pluralRules,
|
||||
this.replaceImplementation
|
||||
);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// ### polyglot.has(key)
|
||||
//
|
||||
// Check if polyglot has a translation for given key
|
||||
Polyglot.prototype.has = function (key) {
|
||||
return has(this.phrases, key);
|
||||
};
|
||||
|
||||
// export transformPhrase
|
||||
Polyglot.transformPhrase = function transform(phrase, substitutions, locale) {
|
||||
return transformPhrase(phrase, substitutions, locale);
|
||||
};
|
||||
|
||||
module.exports = Polyglot;
|
||||
Reference in New Issue
Block a user