%PDF- %PDF-
Direktori : /home/opti/workflow/node_modules/messageformat/lib/ |
Current File : /home/opti/workflow/node_modules/messageformat/lib/messageformat.js |
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _messageformatFormatters = _interopRequireDefault(require("messageformat-formatters")); var _compiler = _interopRequireDefault(require("./compiler")); var _utils = require("./utils"); var _plurals = require("./plurals"); var _runtime = _interopRequireDefault(require("./runtime")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } class MessageFormat { /** * The default locale * * Used by the constructor when no `locale` has been set to initialise the value * of its instance counterpart, `MessageFormat#defaultLocale`. * * @memberof MessageFormat * @default 'en' */ /** Escape special characaters * * Surround the characters `{` and `}` in the input string with 'quotes'. * This will allow those characters to not be considered as MessageFormat * control characters. * * @memberof MessageFormat * @param {string} str - The input string * @param {boolean} [octothorpe=false] - Include `#` in the escaped characters * @returns {string} The escaped string */ static escape(str, octothorpe) { const esc = octothorpe ? /[#{}]/g : /[{}]/g; return String(str).replace(esc, "'$&'"); } /** * Create a new MessageFormat compiler * * If set, the `locale` parameter limits the compiler to use a subset of the 204 * languages' pluralisation rules made available by the Unicode CLDR. * * Leaving `locale` undefined or using an array of strings will create a * MessageFormat instance with multi-language support. To select which to use, * use the second parameter of `{@link MessageFormat#compile compile()}`, or use * message keys corresponding to your locales. The default locale will be the * first entry of the array, or `{@link MessageFormat.defaultLocale defaultLocale}` * if not set. * * A string `locale` will create a single-locale MessageFormat instance. * * Using an object `locale` with all properties of type `function` allows for * the use of custom or externally defined pluralisation rules; in this case * * @class MessageFormat * @classdesc MessageFormat-to-JavaScript compiler * @param {string|string[]|Object} [locale] - The locale(s) to use * @param {Object} [options] - Compiler options * @param {boolean} [options.biDiSupport=false] - Add Unicode control * characters to all input parts to preserve the integrity of the output * when mixing LTR and RTL text * @param {Object} [options.customFormatters] - Map of custom formatting * functions to include. See the {@tutorial guide} for more details. * @param {boolean} [options.pluralKeyChecks=true] - Validate plural and * selectordinal case keys according to the current locale * @param {boolean} [options.strictNumberSign=false] - Allow `#` only directly * within a plural or selectordinal case, rather than in any inner select * case as well. * * ``` * import MessageFormat from 'messageformat' * ``` */ constructor(locale, options) { this.options = Object.assign({ biDiSupport: false, customFormatters: null, pluralKeyChecks: true, strictNumberSign: false }, options); this.pluralFuncs = {}; if (typeof locale === 'string') { this.pluralFuncs[locale] = (0, _plurals.getPlural)(locale, this.options); this.defaultLocale = locale; } else if (Array.isArray(locale)) { locale.forEach(lc => { this.pluralFuncs[lc] = (0, _plurals.getPlural)(lc, this.options); }); this.defaultLocale = locale[0]; } else { if (locale) { const lcKeys = Object.keys(locale); for (let i = 0; i < lcKeys.length; ++i) { const lc = lcKeys[i]; if (typeof locale[lc] !== 'function') { const errMsg = 'Expected function value for locale ' + String(lc); throw new Error(errMsg); } this.pluralFuncs[lc] = locale[lc]; if (!this.defaultLocale) this.defaultLocale = lc; } } if (this.defaultLocale) { this.hasCustomPluralFuncs = true; } else { this.defaultLocale = MessageFormat.defaultLocale; this.hasCustomPluralFuncs = false; } } this.fmt = Object.assign({}, this.options.customFormatters); this.runtime = new _runtime.default(this); } /** * Add custom formatter functions to this MessageFormat instance. See the * {@tutorial guide} for more details. * * The general syntax for calling a formatting function in MessageFormat is * `{var, fn[, arg]}`, where `var` is the variable that will be set by the * user code, `fn` determines the formatting function, and `arg` is an * optional string argument. * * In JavaScript, each formatting function is called with three parameters; * the variable value `v`, the current locale `lc`, and `arg` as a string, or * undefined if not set. `arg` will be trimmed of surrounding whitespace. * Formatting functions should not have side effects. * * @memberof MessageFormat * @instance * @param {Object.<string,function>} fmt - A map of formatting functions * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * const mf = new MessageFormat('en-GB') * mf.addFormatters({ * upcase: function(v) { return v.toUpperCase() }, * locale: function(v, lc) { return lc }, * prop: function(v, lc, p) { return v[p] } * }) * const messages = mf.compile({ * describe: 'This is {VAR, upcase}.', * locale: 'The current locale is {_, locale}.', * answer: 'Answer: {obj, prop, a}' * } * * messages.describe({ VAR: 'big' }) // 'This is BIG.' * messages.locale({}) // 'The current locale is en-GB.' * messages.answer({ obj: {q: 3, a: 42} }) // 'Answer: 42' */ addFormatters(fmt) { const fmtKeys = Object.keys(fmt); for (let i = 0; i < fmtKeys.length; ++i) { const name = fmtKeys[i]; this.fmt[name] = fmt[name]; } return this; } /** * Disable the validation of plural & selectordinal keys * * Previous versions of messageformat allowed the use of plural & * selectordinal statements with any keys; now we throw an error when a * statement uses a non-numerical key that will never be matched as a * pluralization category for the current locale. * * Use this method to disable the validation and allow usage as previously. * To re-enable, you'll need to create a new MessageFormat instance. * * @memberof MessageFormat * @instance * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * const mf = new MessageFormat('en') * const msg = '{X, plural, zero{no answers} one{an answer} other{# answers}}' * * mf.compile(msg) * // Error: Invalid key `zero` for argument `X`. Valid plural keys for this * // locale are `one`, `other`, and explicit keys like `=0`. * * mf.disablePluralKeyChecks() * mf.compile(msg)({ X: 0 }) // '0 answers' */ disablePluralKeyChecks() { this.options.pluralKeyChecks = false; for (const lc in this.pluralFuncs) { const pf = this.pluralFuncs[lc]; if (pf) { pf.cardinal = []; pf.ordinal = []; } } return this; } /** * Enable or disable the addition of Unicode control characters to all input * to preserve the integrity of the output when mixing LTR and RTL text. * * @see http://cldr.unicode.org/development/development-process/design-proposals/bidi-handling-of-structured-text * * @memberof MessageFormat * @instance * @param {boolean} [enable=true] * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * // upper case stands for RTL characters, output is shown as rendered * const mf = new MessageFormat('en') * * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD']) * // 'first >> THIRD << SECOND' * * mf.setBiDiSupport(true) * mf.compile('{0} >> {1} >> {2}')(['first', 'SECOND', 'THIRD']) * // 'first >> SECOND >> THIRD' */ setBiDiSupport(enable) { this.options.biDiSupport = !!enable || typeof enable == 'undefined'; return this; } /** * According to the ICU MessageFormat spec, a `#` character directly inside a * `plural` or `selectordinal` statement should be replaced by the number * matching the surrounding statement. By default, messageformat will replace * `#` signs with the value of the nearest surrounding `plural` or * `selectordinal` statement. * * Set this to true to follow the stricter ICU MessageFormat spec, and to * throw a runtime error if `#` is used with non-numeric input. * * @memberof MessageFormat * @instance * @param {boolean} [enable=true] * @returns {MessageFormat} The MessageFormat instance, to allow for chaining * * @example * const mf = new MessageFormat('en') * const src = { * cookie: '#: {X, plural, =0{no cookies} one{a cookie} other{# cookies}}', * pastry: `{X, plural, * one {{P, select, cookie{a cookie} other{a pie}}} * other {{P, select, cookie{# cookies} other{# pies}}} * }` * } * let messages = mf.compile(src) * * messages.cookie({ X: 3 }) // '#: 3 cookies' * messages.pastry({ X: 3, P: 'pie' }) // '3 pies' * * mf.setStrictNumberSign(true) * messages = mf.compile(src) * messages.pastry({ X: 3, P: 'pie' }) // '# pies' */ setStrictNumberSign(enable) { this.options.strictNumberSign = !!enable || typeof enable == 'undefined'; this.runtime.setStrictNumber(this.options.strictNumberSign); return this; } /** * Compile messages into storable functions * * If `messages` is a single string including ICU MessageFormat declarations, * the result of `compile()` is a function taking a single Object parameter * `d` representing each of the input's defined variables. * * If `messages` is a hierarchical structure of such strings, the output of * `compile()` will match that structure, with each string replaced by its * corresponding JavaScript function. * * If the input `messages` -- and therefore the output -- of `compile()` is an * object, the output object will have a `toString(global)` method that may be * used to store or cache the compiled functions to disk, for later inclusion * in any JS environment, without a local MessageFormat instance required. If * its `global` parameter is null or undefined, the result is an ES6 module * with a default export. If `global` is a string containing `.`, the result * will be a script setting its value. Otherwise, the output defaults to an UMD * pattern that sets the value of `global` if used outside of AMD and CommonJS * loaders. * * If `locale` is not set, it will default to * `{@link MessageFormat.defaultLocale defaultLocale}`; using a key at any * depth of `messages` that is a declared locale will set its child elements to * use that locale. * * If `locale` is set, it is used for all messages, ignoring any otherwise * matching locale keys. If the constructor declared any locales, `locale` * needs to be one of them. * * If `compile()` is called with a `messages` object on a MessageFormat * instance that does not specify any locales, it will match keys to *all* 204 * available locales. This is really useful if you want your messages to be * completely determined by your data, but may provide surprising results if * your input includes any 2-3 letter strings that are not locale identifiers. * * @memberof MessageFormat * @instance * @param {string|Object} messages - The input message(s) to be compiled, in ICU MessageFormat * @param {string} [locale] - A locale to use for the messages * @returns {function|Object} The first match found for the given locale(s) * * @example * const mf = new MessageFormat('en') * const msg = mf.compile('A {TYPE} example.') * * msg({ TYPE: 'simple' }) // 'A simple example.' * * @example * const mf = new MessageFormat(['en', 'fi']) * const messages = mf.compile({ * en: { a: 'A {TYPE} example.', * b: 'This is the {COUNT, selectordinal, one{#st} two{#nd} few{#rd} other{#th}} example.' }, * fi: { a: '{TYPE} esimerkki.', * b: 'Tämä on {COUNT, selectordinal, other{#.}} esimerkki.' } * }) * * messages.en.b({ COUNT: 2 }) // 'This is the 2nd example.' * messages.fi.b({ COUNT: 2 }) // 'Tämä on 2. esimerkki.' * * @example * const fs = require('fs') * const mf = new MessageFormat('en') * const msgSet = { * a: 'A {TYPE} example.', * b: 'This has {COUNT, plural, one{one member} other{# members}}.', * c: 'We have {P, number, percent} code coverage.' * } * const msgStr = mf.compile(msgSet).toString('module.exports') * fs.writeFileSync('messages.js', msgStr) * * ... * * const messages = require('./messages') * * messages.a({ TYPE: 'more complex' }) // 'A more complex example.' * messages.b({ COUNT: 3 }) // 'This has 3 members.' */ compile(messages, locale) { function _stringify(obj, level) { if (!level) level = 0; if (typeof obj != 'object') return obj; let indent = ''; for (let i = 0; i < level; ++i) indent += ' '; const o = []; for (const k in obj) { const v = _stringify(obj[k], level + 1); o.push(`\n${indent} ${(0, _utils.propname)(k)}: ${v}`); } return `{${o.join(',')}\n${indent}}`; } let pf = {}; if (Object.keys(this.pluralFuncs).length === 0) { if (locale) { const pfn0 = (0, _plurals.getPlural)(locale, this.options); if (!pfn0) { const lcs = JSON.stringify(locale); throw new Error(`Locale ${lcs} not found!`); } pf[locale] = pfn0; } else { locale = this.defaultLocale; pf = (0, _plurals.getAllPlurals)(this.options); } } else if (locale) { const pfn1 = this.pluralFuncs[locale]; if (!pfn1) { const lcs = JSON.stringify(locale); const pfs = JSON.stringify(this.pluralFuncs); throw new Error(`Locale ${lcs} not found in ${pfs}!`); } pf[locale] = pfn1; } else { locale = this.defaultLocale; pf = this.pluralFuncs; } const compiler = new _compiler.default(this); const obj = compiler.compile(messages, locale, pf); if (typeof messages != 'object') { const fn = new Function('number, plural, select, fmt', (0, _utils.funcname)(locale), 'return ' + obj); const rt = this.runtime; return fn(rt.number, rt.plural, rt.select, this.fmt, pf[locale]); } const rtStr = this.runtime.toString(pf, compiler) + '\n'; const objStr = _stringify(obj); const result = new Function(rtStr + 'return ' + objStr)(); // eslint-disable-next-line no-prototype-builtins if (result.hasOwnProperty('toString')) throw new Error('The top-level message key `toString` is reserved'); result.toString = function (global) { if (!global || global === 'export default') { return rtStr + 'export default ' + objStr; } else if (global.indexOf('.') > -1) { return rtStr + global + ' = ' + objStr; } else { return rtStr + ['(function (root, G) {', ' if (typeof define === "function" && define.amd) { define(G); }', ' else if (typeof exports === "object") { module.exports = G; }', ' else { ' + (0, _utils.propname)(global, 'root') + ' = G; }', '})(this, ' + objStr + ');'].join('\n'); } }; return result; } } exports.default = MessageFormat; MessageFormat.defaultLocale = 'en'; MessageFormat.formatters = _messageformatFormatters.default;