diff --git a/.eslintrc.js b/.eslintrc.js index 17b9073eb8f3b..0a1a691ac49a4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -27,6 +27,7 @@ module.exports = { 'packages/kbn-pm/**/*', 'packages/kbn-es/**/*', 'packages/kbn-datemath/**/*.js', + 'packages/kbn-i18n/**/*', 'packages/kbn-plugin-generator/**/*', 'packages/kbn-test/**/*', 'packages/kbn-eslint-import-resolver-kibana/**/*', diff --git a/package.json b/package.json index 1c258d29400c8..4b7724cabd434 100644 --- a/package.json +++ b/package.json @@ -81,11 +81,11 @@ "@elastic/ui-ace": "0.2.3", "@kbn/babel-preset": "link:packages/kbn-babel-preset", "@kbn/datemath": "link:packages/kbn-datemath", + "@kbn/i18n": "link:packages/kbn-i18n", "@kbn/pm": "link:packages/kbn-pm", "@kbn/test-subj-selector": "link:packages/kbn-test-subj-selector", "@kbn/ui-framework": "link:packages/kbn-ui-framework", "JSONStream": "1.1.1", - "accept-language-parser": "1.2.0", "abortcontroller-polyfill": "^1.1.9", "angular": "1.6.9", "angular-aria": "1.6.6", diff --git a/packages/kbn-i18n/.babelrc b/packages/kbn-i18n/.babelrc new file mode 100644 index 0000000000000..4216ef3ceccd9 --- /dev/null +++ b/packages/kbn-i18n/.babelrc @@ -0,0 +1,10 @@ +{ + "env": { + "web": { + "presets": ["@kbn/babel-preset/webpack_preset"] + }, + "node": { + "presets": ["@kbn/babel-preset/node_preset"] + } + } +} diff --git a/src/ui/ui_i18n/README.md b/packages/kbn-i18n/README.md similarity index 76% rename from src/ui/ui_i18n/README.md rename to packages/kbn-i18n/README.md index 4aecb8f1f0346..ff00cb1e837da 100644 --- a/src/ui/ui_i18n/README.md +++ b/packages/kbn-i18n/README.md @@ -98,6 +98,8 @@ data to UI frameworks and provides methods for the direct translation. Here is the public API exposed by this engine: +- `addMessages(messages: Map, [locale: string])` - provides a way to register +translations with the engine - `getMessages()` - returns messages for the current language - `setLocale(locale: string)` - tells the engine which language to use by given language key @@ -105,9 +107,14 @@ language key - `setDefaultLocale(locale: string)` - tells the library which language to fallback when missing translations - `getDefaultLocale()` - returns the default locale -- `defineFormats(formats: object)` - supplies a set of options to the underlying formatter. +- `setFormats(formats: object)` - supplies a set of options to the underlying formatter. For the detailed explanation, see the section below -- `translate(id: string, [{values: object, defaultMessage: string}])` – translate message by id +- `getFormats()` - returns current formats +- `getRegisteredLocales()` - returns array of locales having translations +- `translate(id: string, [{values: object, defaultMessage: string, context: string}])` – +translate message by id. `context` is optional context comment that will be extracted +by i18n tools and added as a comment next to translation message at `defaultMessages.json`. +- `init(messages: Map)` - initializes the engine #### I18n engine internals @@ -179,28 +186,22 @@ React Intl uses the provider pattern to scope an i18n context to a tree of compo are able to use `FormattedMessage` component in order to translate messages. `IntlProvider` should wrap react app's root component (inside each react render method). -In order to translate messages we need to pass them into the `IntlProvider` -from I18n engine: +In order to translate messages we need to use `I18nProvider` component that +uses I18n engine under the hood: ```js import React from 'react'; import ReactDOM from 'react-dom'; +import { ReactI18n } from '@kbn/i18n'; -import i18n from 'kbn-i18n'; -import { IntlProvider } from 'ui/i18n/react-intl'; - -const locale = i18n.getLocale(); -const messages = i18n.getMessages(); +const { I18nProvider } = ReactI18n; ReactDOM.render( - + ... - , + , document.getElementById('container') ); ``` @@ -208,8 +209,9 @@ ReactDOM.render( After that we can use `FormattedMessage` components inside `RootComponent`: ```js import React, { Component } from 'react'; +import { ReactI18n } from '@kbn/i18n'; -import { FormattedMessage } from 'ui/i18n/react-intl'; +const { FormattedMessage } = ReactI18n; class RootComponent extends Component { constructor(props) { @@ -244,6 +246,40 @@ class RootComponent extends Component { } ``` +Optionally we can pass `context` prop into `FormattedMessage` component. +This prop is optional context comment that will be extracted by i18n tools +and added as a comment next to translation message at `defaultMessages.json` + + +#### Attributes translation in React +React wrapper provides an API to inject the imperative formatting API into a React +component by using render callback pattern. This should be used when your React +component needs to format data to a string value where a React element is not +suitable; e.g., a `title` or `aria` attribute. In order to use it, you should +wrap your components into `I18nContext` component. The child of this component +should be a function that takes `intl` object into parameters: + +```js +import React from 'react'; +import { ReactI18n } from '@kbn/i18n'; + +const { I18nContext } = ReactI18n; + +const MyComponent = () => ( + + {intl => ( + + )} + +); +``` + ## Angular Angular wrapper has 4 entities: translation `provider`, `service`, `directive` @@ -260,15 +296,19 @@ language key - `setDefaultLocale(locale: string)` - tells the library which language to fallback when missing translations - `getDefaultLocale()` - returns the default locale -- `defineFormats(formats: object)` - supplies a set of options to the underlying formatter +- `setFormats(formats: object)` - supplies a set of options to the underlying formatter +- `getFormats()` - returns current formats +- `getRegisteredLocales()` - returns array of locales having translations +- `init(messages: Map)` - initializes the engine The translation `service` provides only one method: -- `translate(id: string, [{values: object, defaultMessage: string}])` – translate message by id +- `i18n(id: string, [{values: object, defaultMessage: string, context: string }])`– +translate message by id The translation `filter` is used for attributes translation and has the following syntax: ``` -{{'translationId' | i18n[:{ values: object, defaultMessage: string }]}} +{{'translationId' | i18n[:{ values: object, defaultMessage: string, context: string }]}} ``` Where: @@ -276,6 +316,8 @@ Where: - `values` - values to pass into translation - `defaultMessage` - will be used unless translation was successful (the final fallback in english, will be used for generating `en.json`) +- `context` - optional context comment that will be extracted by i18n tools +and added as a comment next to translation message at `defaultMessages.json` The translation `directive` has the following syntax: ```html @@ -283,6 +325,7 @@ The translation `directive` has the following syntax: i18n-id="{string}" [i18n-values="{object}"] [i18n-default-message="{string}"] + [i18n-context="{string}"] > ``` @@ -290,21 +333,11 @@ Where: - `i18n-id` - translation id to be translated - `i18n-values` - values to pass into translation - `i18n-default-message` - will be used unless translation was successful +- `i18n-context` - optional context comment that will be extracted by i18n tools +and added as a comment next to translation message at `defaultMessages.json` -In order to initialize the translation service, we need to pass locale and -localization messages from I18n engine into the `i18nProvider`: - -```js -import { uiModules } from 'ui/modules'; -import i18n from 'kbn-i18n'; - -uiModules.get('kibana').config(function (i18nProvider) { - i18nProvider.addMessages(i18n.getMessages()); - i18nProvider.setLocale(i18n.getLocale()); -}); -``` - -After that we can use i18n directive in Angular templates: +Angular `I18n` module is placed into `autoload` module, so it will be +loaded automatically. After that we can use i18n directive in Angular templates: ```html ``` +In order to translate attributes in Angular we should use `i18nFilter`: +```html + +``` + ## Node.JS `Intl-messageformat` package assumes that the @@ -320,10 +363,13 @@ global object exists in the runtime. `Intl` is present in all modern browsers and Node.js 0.10+. In order to load i18n engine in Node.js we should simply `import` this module (in Node.js, the [data](https://github.com/yahoo/intl-messageformat/tree/master/dist/locale-data) -for all 200+ languages is loaded along with the library): +for all 200+ languages is loaded along with the library) and pass the translation +messages into `init` method: ```js -import i18n from 'kbn-i18n'; +import { i18n } from '@kbn/i18n'; + +i18n.init(messages); ``` After that we are able to use all methods exposed by the i18n engine diff --git a/packages/kbn-i18n/package.json b/packages/kbn-i18n/package.json new file mode 100644 index 0000000000000..da276e01c8d33 --- /dev/null +++ b/packages/kbn-i18n/package.json @@ -0,0 +1,32 @@ +{ + "name": "@kbn/i18n", + "browser": "./target/web/browser.js", + "main": "./target/node/index.js", + "module": "./src/index.js", + "version": "1.0.0", + "license": "Apache-2.0", + "private": true, + "scripts": { + "build": "yarn build:web && yarn build:node", + "build:web": "cross-env BABEL_ENV=web babel src --out-dir target/web", + "build:node": "cross-env BABEL_ENV=node babel src --out-dir target/node", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "devDependencies": { + "@kbn/babel-preset": "link:../kbn-babel-preset", + "@kbn/dev-utils": "link:../kbn-dev-utils", + "babel-cli": "^6.26.0", + "cross-env": "^5.2.0" + }, + "dependencies": { + "accept-language-parser": "^1.5.0", + "intl-format-cache": "^2.1.0", + "intl-messageformat": "^2.2.0", + "intl-relativeformat": "^2.1.0", + "json5": "^1.0.1", + "prop-types": "^15.5.8", + "react": "^16.3.0", + "react-intl": "^2.4.0" + } +} diff --git a/packages/kbn-i18n/src/angular/directive.js b/packages/kbn-i18n/src/angular/directive.js new file mode 100644 index 0000000000000..f9421814d9817 --- /dev/null +++ b/packages/kbn-i18n/src/angular/directive.js @@ -0,0 +1,43 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function i18nDirective(i18n) { + return { + restrict: 'A', + scope: { + id: '@i18nId', + defaultMessage: '@i18nDefaultMessage', + values: '=i18nValues', + }, + link: function($scope, $element) { + $scope.$watchGroup(['id', 'defaultMessage', 'values'], function([ + id, + defaultMessage = '', + values = {}, + ]) { + $element.html( + i18n(id, { + values, + defaultMessage, + }) + ); + }); + }, + }; +} diff --git a/packages/kbn-i18n/src/angular/filter.js b/packages/kbn-i18n/src/angular/filter.js new file mode 100644 index 0000000000000..cdbe869237b1a --- /dev/null +++ b/packages/kbn-i18n/src/angular/filter.js @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function i18nFilter(i18n) { + return function(id, { defaultMessage = '', values = {} } = {}) { + return i18n(id, { + values, + defaultMessage, + }); + }; +} diff --git a/packages/kbn-i18n/src/angular/index.js b/packages/kbn-i18n/src/angular/index.js new file mode 100644 index 0000000000000..a7af6fbeffc35 --- /dev/null +++ b/packages/kbn-i18n/src/angular/index.js @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { i18nProvider } from './provider'; +export { i18nFilter } from './filter'; +export { i18nDirective } from './directive'; diff --git a/packages/kbn-i18n/src/angular/provider.js b/packages/kbn-i18n/src/angular/provider.js new file mode 100644 index 0000000000000..97fd160cc3554 --- /dev/null +++ b/packages/kbn-i18n/src/angular/provider.js @@ -0,0 +1,34 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as i18n from '../core/i18n'; + +export function i18nProvider() { + this.addMessages = i18n.addMessages; + this.getMessages = i18n.getMessages; + this.setLocale = i18n.setLocale; + this.getLocale = i18n.getLocale; + this.setDefaultLocale = i18n.setDefaultLocale; + this.getDefaultLocale = i18n.getDefaultLocale; + this.setFormats = i18n.setFormats; + this.getFormats = i18n.getFormats; + this.getRegisteredLocales = i18n.getRegisteredLocales; + this.init = i18n.init; + this.$get = () => i18n.translate; +} diff --git a/packages/kbn-i18n/src/browser.js b/packages/kbn-i18n/src/browser.js new file mode 100644 index 0000000000000..4f5c40dcfdcd2 --- /dev/null +++ b/packages/kbn-i18n/src/browser.js @@ -0,0 +1,28 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as angular from './angular'; +import * as react from './react'; +import * as i18nCore from './core/i18n'; + +export { formats } from './core/formats'; + +export const AngularI18n = angular; +export const ReactI18n = react; +export const i18n = i18nCore; diff --git a/packages/kbn-i18n/src/core/formats.js b/packages/kbn-i18n/src/core/formats.js new file mode 100644 index 0000000000000..6a74040a7e1b7 --- /dev/null +++ b/packages/kbn-i18n/src/core/formats.js @@ -0,0 +1,86 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Default format options used for "en" locale. + * These are used when constructing the internal Intl.NumberFormat + * (`number` formatter) and Intl.DateTimeFormat (`date` and `time` formatters) instances. + * The value of each parameter of `number` formatter is options object which is + * described in `options` section of [NumberFormat constructor]. + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat} + * The value of each parameter of `date` and `time` formatters is options object which is + * described in `options` section of [DateTimeFormat constructor]. + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat} + */ +export const formats = { + number: { + currency: { + style: 'currency', + }, + percent: { + style: 'percent', + }, + }, + date: { + short: { + month: 'numeric', + day: 'numeric', + year: '2-digit', + }, + medium: { + month: 'short', + day: 'numeric', + year: 'numeric', + }, + long: { + month: 'long', + day: 'numeric', + year: 'numeric', + }, + full: { + weekday: 'long', + month: 'long', + day: 'numeric', + year: 'numeric', + }, + }, + time: { + short: { + hour: 'numeric', + minute: 'numeric', + }, + medium: { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + }, + long: { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + timeZoneName: 'short', + }, + full: { + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + timeZoneName: 'short', + }, + }, +}; diff --git a/packages/kbn-i18n/src/core/helper.js b/packages/kbn-i18n/src/core/helper.js new file mode 100644 index 0000000000000..c13b1b3a303e9 --- /dev/null +++ b/packages/kbn-i18n/src/core/helper.js @@ -0,0 +1,44 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export const isString = value => typeof value === 'string'; + +export const isObject = value => typeof value === 'object' && value !== null; + +export const hasValues = values => Object.keys(values).length > 0; + +export const unique = (arr = []) => [...new Set(arr)]; + +const merge = (a, b) => + unique([...Object.keys(a), ...Object.keys(b)]).reduce((acc, key) => { + if (isObject(a[key]) && isObject(b[key]) && !Array.isArray(a[key]) && !Array.isArray(b[key])) { + return { + ...acc, + [key]: merge(a[key], b[key]), + }; + } + + return { + ...acc, + [key]: b[key] === undefined ? a[key] : b[key], + }; + }, {}); + +export const mergeAll = (...sources) => + sources.filter(isObject).reduce((acc, source) => merge(acc, source)); diff --git a/packages/kbn-i18n/src/core/i18n.js b/packages/kbn-i18n/src/core/i18n.js new file mode 100644 index 0000000000000..bde687b763978 --- /dev/null +++ b/packages/kbn-i18n/src/core/i18n.js @@ -0,0 +1,231 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + @typedef Messages - messages tree, where leafs are translated strings + @type {object} + @property {string} [locale] - locale of the messages + @property {object} [formats] - set of options to the underlying formatter + */ + +import IntlMessageFormat from 'intl-messageformat'; +import IntlRelativeFormat from 'intl-relativeformat'; +import memoizeIntlConstructor from 'intl-format-cache'; +import { isString, isObject, hasValues, mergeAll } from './helper'; +import { formats as EN_FORMATS } from './formats'; + +// Add all locale data to `IntlMessageFormat`. +import './locales'; + +const EN_LOCALE = 'en'; +const LOCALE_DELIMITER = '-'; +const messages = {}; +const getMessageFormat = memoizeIntlConstructor(IntlMessageFormat); + +let defaultLocale = EN_LOCALE; +let currentLocale = EN_LOCALE; +let formats = EN_FORMATS; + +IntlMessageFormat.defaultLocale = defaultLocale; +IntlRelativeFormat.defaultLocale = defaultLocale; + +/** + * Returns message by the given message id. + * @param {string} id - path to the message + * @returns {string} message - translated message from messages tree + */ +function getMessageById(id) { + return getMessages()[id]; +} + +/** + * Normalizes locale to make it consistent with IntlMessageFormat locales + * @param {string} locale + * @returns {string} normalizedLocale + */ +function normalizeLocale(locale) { + return locale.toLowerCase().replace('_', LOCALE_DELIMITER); +} + +/** + * Provides a way to register translations with the engine + * @param {Messages} newMessages + * @param {string} [locale = messages.locale] + */ +export function addMessages(newMessages = {}, locale = newMessages.locale) { + if (!locale || !isString(locale)) { + throw new Error('[I18n] A `locale` must be a non-empty string to add messages.'); + } + + const normalizedLocale = normalizeLocale(locale); + + messages[normalizedLocale] = { + ...messages[normalizedLocale], + ...newMessages, + }; +} + +/** + * Returns messages for the current language + * @returns {Messages} messages + */ +export function getMessages() { + return messages[currentLocale] || {}; +} + +/** + * Tells the engine which language to use by given language key + * @param {string} locale + */ +export function setLocale(locale) { + if (!locale || !isString(locale)) { + throw new Error('[I18n] A `locale` must be a non-empty string.'); + } + + currentLocale = normalizeLocale(locale); +} + +/** + * Returns the current locale + * @returns {string} locale + */ +export function getLocale() { + return currentLocale; +} + +/** + * Tells the library which language to fallback when missing translations + * @param {string} locale + */ +export function setDefaultLocale(locale) { + if (!locale || !isString(locale)) { + throw new Error('[I18n] A `locale` must be a non-empty string.'); + } + + defaultLocale = normalizeLocale(locale); + IntlMessageFormat.defaultLocale = defaultLocale; + IntlRelativeFormat.defaultLocale = defaultLocale; +} + +/** + * Returns the default locale + * @returns {string} defaultLocale + */ +export function getDefaultLocale() { + return defaultLocale; +} + +/** + * Supplies a set of options to the underlying formatter + * [Default format options used as the prototype of the formats] + * {@link https://github.com/yahoo/intl-messageformat/blob/master/src/core.js#L62} + * These are used when constructing the internal Intl.NumberFormat + * and Intl.DateTimeFormat instances. + * @param {object} newFormats + * @param {object} [newFormats.number] + * @param {object} [newFormats.date] + * @param {object} [newFormats.time] + */ +export function setFormats(newFormats) { + if (!isObject(newFormats) || !hasValues(newFormats)) { + throw new Error('[I18n] A `formats` must be a non-empty object.'); + } + + formats = mergeAll(formats, newFormats); +} + +/** + * Returns current formats + * @returns {object} formats + */ +export function getFormats() { + return formats; +} + +/** + * Returns array of locales having translations + * @returns {string[]} locales + */ +export function getRegisteredLocales() { + return Object.keys(messages); +} + +/** + * Translate message by id + * @param {string} id - translation id to be translated + * @param {object} [options] + * @param {object} [options.values] - values to pass into translation + * @param {string} [options.defaultMessage] - will be used unless translation was successful + * @returns {string} + */ +export function translate(id, { values = {}, defaultMessage = '' } = {}) { + if (!id || !isString(id)) { + throw new Error('[I18n] An `id` must be a non-empty string to translate a message.'); + } + + const message = getMessageById(id); + + if (!message && !defaultMessage) { + throw new Error(`[I18n] Cannot format message: "${id}". Default message must be provided.`); + } + + if (!hasValues(values)) { + return message || defaultMessage; + } + + if (message) { + try { + const msg = getMessageFormat(message, getLocale(), getFormats()); + + return msg.format(values); + } catch (e) { + throw new Error( + `[I18n] Error formatting message: "${id}" for locale: "${getLocale()}".\n${e}` + ); + } + } + + try { + const msg = getMessageFormat(defaultMessage, getDefaultLocale(), getFormats()); + + return msg.format(values); + } catch (e) { + throw new Error(`[I18n] Error formatting the default message for: "${id}".\n${e}`); + } +} + +/** + * Initializes the engine + * @param {Messages} newMessages + */ +export function init(newMessages) { + if (!newMessages) { + return; + } + + addMessages(newMessages); + + if (newMessages.locale) { + setLocale(newMessages.locale); + } + + if (newMessages.formats) { + setFormats(newMessages.formats); + } +} diff --git a/packages/kbn-i18n/src/core/loader.js b/packages/kbn-i18n/src/core/loader.js new file mode 100644 index 0000000000000..2b45c5e890878 --- /dev/null +++ b/packages/kbn-i18n/src/core/loader.js @@ -0,0 +1,207 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + @typedef Messages - messages tree, where leafs are translated strings + @type {object} + @property {string} [locale] - locale of the messages + @property {object} [formats] - set of options to the underlying formatter + */ + +import path from 'path'; +import { readFile } from 'fs'; +import { promisify } from 'util'; +import { pick } from 'accept-language-parser'; +import JSON5 from 'json5'; +import { unique } from './helper'; + +const asyncReadFile = promisify(readFile); + +const TRANSLATION_FILE_EXTENSION = '.json'; + +/** + * Internal property for storing registered translations paths + * @type {Map|{}} - Key is locale, value is array of registered paths + */ +const translationsRegistry = {}; + +/** + * Internal property for caching loaded translations files + * @type {Map|{}} - Key is path to translation file, value is + * object with translation messages + */ +const loadedFiles = {}; + +/** + * Returns locale by the given translation file name + * @param {string} fullFileName + * @returns {string} locale + * @example + * getLocaleFromFileName('./path/to/translation/ru.json') // => 'ru' + */ +function getLocaleFromFileName(fullFileName) { + if (!fullFileName) { + throw new Error('Filename is empty'); + } + + const fileExt = path.extname(fullFileName); + + if (fileExt !== TRANSLATION_FILE_EXTENSION) { + throw new Error( + `Translations must have 'json' extension. File being registered is ${fullFileName}` + ); + } + + return path.basename(fullFileName, TRANSLATION_FILE_EXTENSION); +} + +/** + * Loads file and parses it as JSON5 + * @param {string} pathToFile + * @returns {Promise} + */ +async function loadFile(pathToFile) { + return JSON5.parse(await asyncReadFile(pathToFile, 'utf8')); +} + +/** + * Parses the accept-language header from an HTTP request and picks + * the best match of the locale from the registered locales + * @param {string} header - accept-language header from an HTTP request + * @returns {string} locale + */ +function pickLocaleByLanguageHeader(header) { + return pick(getRegisteredLocales(), header); +} + +/** + * Loads translations files and adds them into "loadedFiles" cache + * @param {string[]} files + * @returns {Promise} + */ +async function loadAndCacheFiles(files) { + const translations = await Promise.all(files.map(loadFile)); + + files.forEach((file, index) => { + loadedFiles[file] = translations[index]; + }); +} + +/** + * Registers translation file with i18n loader + * @param {string} translationFilePath - Absolute path to the translation file to register. + */ +export function registerTranslationFile(translationFilePath) { + if (!path.isAbsolute(translationFilePath)) { + throw new TypeError( + 'Paths to translation files must be absolute. ' + + `Got relative path: "${translationFilePath}"` + ); + } + + const locale = getLocaleFromFileName(translationFilePath); + + translationsRegistry[locale] = unique([ + ...(translationsRegistry[locale] || []), + translationFilePath, + ]); +} + +/** + * Registers array of translation files with i18n loader + * @param {string[]} arrayOfPaths - Array of absolute paths to the translation files to register. + */ +export function registerTranslationFiles(arrayOfPaths = []) { + arrayOfPaths.forEach(registerTranslationFile); +} + +/** + * Returns an array of locales that have been registered with i18n loader + * @returns {string[]} registeredTranslations + */ +export function getRegisteredLocales() { + return Object.keys(translationsRegistry); +} + +/** + * Returns translations for a suitable locale based on accept-language header. + * This object will contain all registered translations for the highest priority + * locale which is registered with the i18n loader. This object can be empty + * if no locale in the language tags can be matched against the registered locales. + * @param {string} header - accept-language header from an HTTP request + * @returns {Promise} translations - translation messages + */ +export async function getTranslationsByLanguageHeader(header) { + return getTranslationsByLocale(pickLocaleByLanguageHeader(header)); +} + +/** + * Returns translation messages by specified locale + * @param {string} locale + * @returns {Promise} translations - translation messages + */ +export async function getTranslationsByLocale(locale) { + const files = translationsRegistry[locale] || []; + const notLoadedFiles = files.filter(file => !loadedFiles[file]); + + if (notLoadedFiles.length) { + await loadAndCacheFiles(notLoadedFiles); + } + + return files.length + ? files.reduce( + (messages, file) => ({ + ...messages, + ...loadedFiles[file], + }), + { locale } + ) + : {}; +} + +/** + * Returns all translations for registered locales + * @return {Promise>} translations - A Promise object + * where keys are the locale and values are objects of translation messages + */ +export async function getAllTranslations() { + const locales = getRegisteredLocales(); + const translations = await Promise.all(locales.map(getTranslationsByLocale)); + + return locales.reduce( + (acc, locale, index) => ({ + ...acc, + [locale]: translations[index], + }), + {} + ); +} + +/** + * Registers passed translations files, loads them and returns promise with + * all translation messages + * @param {string[]} paths - Array of absolute paths to the translation files + * @returns {Promise>} translations - A Promise object + * where keys are the locale and values are objects of translation messages + */ +export async function getAllTranslationsFromPaths(paths) { + registerTranslationFiles(paths); + + return await getAllTranslations(); +} diff --git a/packages/kbn-i18n/src/core/locales.js b/packages/kbn-i18n/src/core/locales.js new file mode 100644 index 0000000000000..e3c85b96898b8 --- /dev/null +++ b/packages/kbn-i18n/src/core/locales.js @@ -0,0 +1,566 @@ +/* eslint-disable */ + +// TODO: Get rid of this file once https://github.com/elastic/kibana/pull/20105 +// is merged and use dynamic import for asynchronous loading of specific locale data + +import IntlMessageFormat from 'intl-messageformat'; +import IntlRelativeFormat from 'intl-relativeformat'; + +function addLocaleData(localeData) { + IntlMessageFormat.__addLocaleData(localeData); + IntlRelativeFormat.__addLocaleData(localeData); +} + +addLocaleData({"locale":"af","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"af-NA","parentLocale":"af"}); +addLocaleData({"locale":"agq","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ak","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"am","pluralRuleFunction":function (n,ord){if(ord)return"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"ar","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n,n100=t0&&s[0].slice(-2);if(ord)return"other";return n==0?"zero":n==1?"one":n==2?"two":n100>=3&&n100<=10?"few":n100>=11&&n100<=99?"many":"other"}}); +addLocaleData({"locale":"ar-AE","parentLocale":"ar"}); +addLocaleData({"locale":"ar-BH","parentLocale":"ar"}); +addLocaleData({"locale":"ar-DJ","parentLocale":"ar"}); +addLocaleData({"locale":"ar-DZ","parentLocale":"ar"}); +addLocaleData({"locale":"ar-EG","parentLocale":"ar"}); +addLocaleData({"locale":"ar-EH","parentLocale":"ar"}); +addLocaleData({"locale":"ar-ER","parentLocale":"ar"}); +addLocaleData({"locale":"ar-IL","parentLocale":"ar"}); +addLocaleData({"locale":"ar-IQ","parentLocale":"ar"}); +addLocaleData({"locale":"ar-JO","parentLocale":"ar"}); +addLocaleData({"locale":"ar-KM","parentLocale":"ar"}); +addLocaleData({"locale":"ar-KW","parentLocale":"ar"}); +addLocaleData({"locale":"ar-LB","parentLocale":"ar"}); +addLocaleData({"locale":"ar-LY","parentLocale":"ar"}); +addLocaleData({"locale":"ar-MA","parentLocale":"ar"}); +addLocaleData({"locale":"ar-MR","parentLocale":"ar"}); +addLocaleData({"locale":"ar-OM","parentLocale":"ar"}); +addLocaleData({"locale":"ar-PS","parentLocale":"ar"}); +addLocaleData({"locale":"ar-QA","parentLocale":"ar"}); +addLocaleData({"locale":"ar-SA","parentLocale":"ar"}); +addLocaleData({"locale":"ar-SD","parentLocale":"ar"}); +addLocaleData({"locale":"ar-SO","parentLocale":"ar"}); +addLocaleData({"locale":"ar-SS","parentLocale":"ar"}); +addLocaleData({"locale":"ar-SY","parentLocale":"ar"}); +addLocaleData({"locale":"ar-TD","parentLocale":"ar"}); +addLocaleData({"locale":"ar-TN","parentLocale":"ar"}); +addLocaleData({"locale":"ar-YE","parentLocale":"ar"}); +addLocaleData({"locale":"as","pluralRuleFunction":function (n,ord){if(ord)return n==1||n==5||n==7||n==8||n==9||n==10?"one":n==2||n==3?"two":n==4?"few":n==6?"many":"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"asa","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ast","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"az","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],i10=i.slice(-1),i100=i.slice(-2),i1000=i.slice(-3);if(ord)return i10==1||i10==2||i10==5||i10==7||i10==8||(i100==20||i100==50||i100==70||i100==80)?"one":i10==3||i10==4||(i1000==100||i1000==200||i1000==300||i1000==400||i1000==500||i1000==600||i1000==700||i1000==800||i1000==900)?"few":i==0||i10==6||(i100==40||i100==60||i100==90)?"many":"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"az-Arab","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"az-Cyrl","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"az-Latn","parentLocale":"az"}); +addLocaleData({"locale":"bas","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"be","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return(n10==2||n10==3)&&n100!=12&&n100!=13?"few":"other";return n10==1&&n100!=11?"one":n10>=2&&n10<=4&&(n100<12||n100>14)?"few":t0&&n10==0||n10>=5&&n10<=9||n100>=11&&n100<=14?"many":"other"}}); +addLocaleData({"locale":"bem","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"bez","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"bg","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"bh","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"bm","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"bm-Nkoo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"bn","pluralRuleFunction":function (n,ord){if(ord)return n==1||n==5||n==7||n==8||n==9||n==10?"one":n==2||n==3?"two":n==4?"few":n==6?"many":"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"bn-IN","parentLocale":"bn"}); +addLocaleData({"locale":"bo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"bo-IN","parentLocale":"bo"}); +addLocaleData({"locale":"br","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2),n1000000=t0&&s[0].slice(-6);if(ord)return"other";return n10==1&&n100!=11&&n100!=71&&n100!=91?"one":n10==2&&n100!=12&&n100!=72&&n100!=92?"two":(n10==3||n10==4||n10==9)&&(n100<10||n100>19)&&(n100<70||n100>79)&&(n100<90||n100>99)?"few":n!=0&&t0&&n1000000==0?"many":"other"}}); +addLocaleData({"locale":"brx","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"bs","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),i100=i.slice(-2),f10=f.slice(-1),f100=f.slice(-2);if(ord)return"other";return v0&&i10==1&&i100!=11||f10==1&&f100!=11?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)||f10>=2&&f10<=4&&(f100<12||f100>14)?"few":"other"}}); +addLocaleData({"locale":"bs-Cyrl","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"bs-Latn","parentLocale":"bs"}); +addLocaleData({"locale":"ca","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return n==1||n==3?"one":n==2?"two":n==4?"few":"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"ca-AD","parentLocale":"ca"}); +addLocaleData({"locale":"ca-ES-VALENCIA","parentLocale":"ca-ES"}); +addLocaleData({"locale":"ca-ES","parentLocale":"ca"}); +addLocaleData({"locale":"ca-FR","parentLocale":"ca"}); +addLocaleData({"locale":"ca-IT","parentLocale":"ca"}); +addLocaleData({"locale":"ce","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"cgg","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"chr","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ckb","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ckb-IR","parentLocale":"ckb"}); +addLocaleData({"locale":"cs","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1];if(ord)return"other";return n==1&&v0?"one":i>=2&&i<=4&&v0?"few":!v0?"many":"other"}}); +addLocaleData({"locale":"cu","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"cy","pluralRuleFunction":function (n,ord){if(ord)return n==0||n==7||n==8||n==9?"zero":n==1?"one":n==2?"two":n==3||n==4?"few":n==5||n==6?"many":"other";return n==0?"zero":n==1?"one":n==2?"two":n==3?"few":n==6?"many":"other"}}); +addLocaleData({"locale":"da","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],t0=Number(s[0])==n;if(ord)return"other";return n==1||!t0&&(i==0||i==1)?"one":"other"}}); +addLocaleData({"locale":"da-GL","parentLocale":"da"}); +addLocaleData({"locale":"dav","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"de","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"de-AT","parentLocale":"de"}); +addLocaleData({"locale":"de-BE","parentLocale":"de"}); +addLocaleData({"locale":"de-CH","parentLocale":"de"}); +addLocaleData({"locale":"de-LI","parentLocale":"de"}); +addLocaleData({"locale":"de-LU","parentLocale":"de"}); +addLocaleData({"locale":"dje","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"dsb","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i100=i.slice(-2),f100=f.slice(-2);if(ord)return"other";return v0&&i100==1||f100==1?"one":v0&&i100==2||f100==2?"two":v0&&(i100==3||i100==4)||(f100==3||f100==4)?"few":"other"}}); +addLocaleData({"locale":"dua","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"dv","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"dyo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"dz","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ebu","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ee","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ee-TG","parentLocale":"ee"}); +addLocaleData({"locale":"el","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"el-CY","parentLocale":"el"}); +addLocaleData({"locale":"en","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return n10==1&&n100!=11?"one":n10==2&&n100!=12?"two":n10==3&&n100!=13?"few":"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"en-001","parentLocale":"en"}); +addLocaleData({"locale":"en-150","parentLocale":"en-001"}); +addLocaleData({"locale":"en-AG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-AI","parentLocale":"en-001"}); +addLocaleData({"locale":"en-AS","parentLocale":"en"}); +addLocaleData({"locale":"en-AT","parentLocale":"en-150"}); +addLocaleData({"locale":"en-AU","parentLocale":"en-001"}); +addLocaleData({"locale":"en-BB","parentLocale":"en-001"}); +addLocaleData({"locale":"en-BE","parentLocale":"en-001"}); +addLocaleData({"locale":"en-BI","parentLocale":"en"}); +addLocaleData({"locale":"en-BM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-BS","parentLocale":"en-001"}); +addLocaleData({"locale":"en-BW","parentLocale":"en-001"}); +addLocaleData({"locale":"en-BZ","parentLocale":"en-001"}); +addLocaleData({"locale":"en-CA","parentLocale":"en-001"}); +addLocaleData({"locale":"en-CC","parentLocale":"en-001"}); +addLocaleData({"locale":"en-CH","parentLocale":"en-150"}); +addLocaleData({"locale":"en-CK","parentLocale":"en-001"}); +addLocaleData({"locale":"en-CM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-CX","parentLocale":"en-001"}); +addLocaleData({"locale":"en-CY","parentLocale":"en-001"}); +addLocaleData({"locale":"en-DE","parentLocale":"en-150"}); +addLocaleData({"locale":"en-DG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-DK","parentLocale":"en-150"}); +addLocaleData({"locale":"en-DM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-Dsrt","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"en-ER","parentLocale":"en-001"}); +addLocaleData({"locale":"en-FI","parentLocale":"en-150"}); +addLocaleData({"locale":"en-FJ","parentLocale":"en-001"}); +addLocaleData({"locale":"en-FK","parentLocale":"en-001"}); +addLocaleData({"locale":"en-FM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GB","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GD","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GH","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GI","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-GU","parentLocale":"en"}); +addLocaleData({"locale":"en-GY","parentLocale":"en-001"}); +addLocaleData({"locale":"en-HK","parentLocale":"en-001"}); +addLocaleData({"locale":"en-IE","parentLocale":"en-001"}); +addLocaleData({"locale":"en-IL","parentLocale":"en-001"}); +addLocaleData({"locale":"en-IM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-IN","parentLocale":"en-001"}); +addLocaleData({"locale":"en-IO","parentLocale":"en-001"}); +addLocaleData({"locale":"en-JE","parentLocale":"en-001"}); +addLocaleData({"locale":"en-JM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-KE","parentLocale":"en-001"}); +addLocaleData({"locale":"en-KI","parentLocale":"en-001"}); +addLocaleData({"locale":"en-KN","parentLocale":"en-001"}); +addLocaleData({"locale":"en-KY","parentLocale":"en-001"}); +addLocaleData({"locale":"en-LC","parentLocale":"en-001"}); +addLocaleData({"locale":"en-LR","parentLocale":"en-001"}); +addLocaleData({"locale":"en-LS","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MH","parentLocale":"en"}); +addLocaleData({"locale":"en-MO","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MP","parentLocale":"en"}); +addLocaleData({"locale":"en-MS","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MT","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MU","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MW","parentLocale":"en-001"}); +addLocaleData({"locale":"en-MY","parentLocale":"en-001"}); +addLocaleData({"locale":"en-NA","parentLocale":"en-001"}); +addLocaleData({"locale":"en-NF","parentLocale":"en-001"}); +addLocaleData({"locale":"en-NG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-NL","parentLocale":"en-150"}); +addLocaleData({"locale":"en-NR","parentLocale":"en-001"}); +addLocaleData({"locale":"en-NU","parentLocale":"en-001"}); +addLocaleData({"locale":"en-NZ","parentLocale":"en-001"}); +addLocaleData({"locale":"en-PG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-PH","parentLocale":"en-001"}); +addLocaleData({"locale":"en-PK","parentLocale":"en-001"}); +addLocaleData({"locale":"en-PN","parentLocale":"en-001"}); +addLocaleData({"locale":"en-PR","parentLocale":"en"}); +addLocaleData({"locale":"en-PW","parentLocale":"en-001"}); +addLocaleData({"locale":"en-RW","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SB","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SC","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SD","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SE","parentLocale":"en-150"}); +addLocaleData({"locale":"en-SG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SH","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SI","parentLocale":"en-150"}); +addLocaleData({"locale":"en-SL","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SS","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SX","parentLocale":"en-001"}); +addLocaleData({"locale":"en-SZ","parentLocale":"en-001"}); +addLocaleData({"locale":"en-Shaw","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"en-TC","parentLocale":"en-001"}); +addLocaleData({"locale":"en-TK","parentLocale":"en-001"}); +addLocaleData({"locale":"en-TO","parentLocale":"en-001"}); +addLocaleData({"locale":"en-TT","parentLocale":"en-001"}); +addLocaleData({"locale":"en-TV","parentLocale":"en-001"}); +addLocaleData({"locale":"en-TZ","parentLocale":"en-001"}); +addLocaleData({"locale":"en-UG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-UM","parentLocale":"en"}); +addLocaleData({"locale":"en-US","parentLocale":"en"}); +addLocaleData({"locale":"en-VC","parentLocale":"en-001"}); +addLocaleData({"locale":"en-VG","parentLocale":"en-001"}); +addLocaleData({"locale":"en-VI","parentLocale":"en"}); +addLocaleData({"locale":"en-VU","parentLocale":"en-001"}); +addLocaleData({"locale":"en-WS","parentLocale":"en-001"}); +addLocaleData({"locale":"en-ZA","parentLocale":"en-001"}); +addLocaleData({"locale":"en-ZM","parentLocale":"en-001"}); +addLocaleData({"locale":"en-ZW","parentLocale":"en-001"}); +addLocaleData({"locale":"eo","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"es","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"es-419","parentLocale":"es"}); +addLocaleData({"locale":"es-AR","parentLocale":"es-419"}); +addLocaleData({"locale":"es-BO","parentLocale":"es-419"}); +addLocaleData({"locale":"es-CL","parentLocale":"es-419"}); +addLocaleData({"locale":"es-CO","parentLocale":"es-419"}); +addLocaleData({"locale":"es-CR","parentLocale":"es-419"}); +addLocaleData({"locale":"es-CU","parentLocale":"es-419"}); +addLocaleData({"locale":"es-DO","parentLocale":"es-419"}); +addLocaleData({"locale":"es-EA","parentLocale":"es"}); +addLocaleData({"locale":"es-EC","parentLocale":"es-419"}); +addLocaleData({"locale":"es-GQ","parentLocale":"es"}); +addLocaleData({"locale":"es-GT","parentLocale":"es-419"}); +addLocaleData({"locale":"es-HN","parentLocale":"es-419"}); +addLocaleData({"locale":"es-IC","parentLocale":"es"}); +addLocaleData({"locale":"es-MX","parentLocale":"es-419"}); +addLocaleData({"locale":"es-NI","parentLocale":"es-419"}); +addLocaleData({"locale":"es-PA","parentLocale":"es-419"}); +addLocaleData({"locale":"es-PE","parentLocale":"es-419"}); +addLocaleData({"locale":"es-PH","parentLocale":"es"}); +addLocaleData({"locale":"es-PR","parentLocale":"es-419"}); +addLocaleData({"locale":"es-PY","parentLocale":"es-419"}); +addLocaleData({"locale":"es-SV","parentLocale":"es-419"}); +addLocaleData({"locale":"es-US","parentLocale":"es-419"}); +addLocaleData({"locale":"es-UY","parentLocale":"es-419"}); +addLocaleData({"locale":"es-VE","parentLocale":"es-419"}); +addLocaleData({"locale":"et","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"eu","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ewo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"fa","pluralRuleFunction":function (n,ord){if(ord)return"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"fa-AF","parentLocale":"fa"}); +addLocaleData({"locale":"ff","pluralRuleFunction":function (n,ord){if(ord)return"other";return n>=0&&n<2?"one":"other"}}); +addLocaleData({"locale":"ff-CM","parentLocale":"ff"}); +addLocaleData({"locale":"ff-GN","parentLocale":"ff"}); +addLocaleData({"locale":"ff-MR","parentLocale":"ff"}); +addLocaleData({"locale":"fi","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"fil","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),f10=f.slice(-1);if(ord)return n==1?"one":"other";return v0&&(i==1||i==2||i==3)||v0&&i10!=4&&i10!=6&&i10!=9||!v0&&f10!=4&&f10!=6&&f10!=9?"one":"other"}}); +addLocaleData({"locale":"fo","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"fo-DK","parentLocale":"fo"}); +addLocaleData({"locale":"fr","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":"other";return n>=0&&n<2?"one":"other"}}); +addLocaleData({"locale":"fr-BE","parentLocale":"fr"}); +addLocaleData({"locale":"fr-BF","parentLocale":"fr"}); +addLocaleData({"locale":"fr-BI","parentLocale":"fr"}); +addLocaleData({"locale":"fr-BJ","parentLocale":"fr"}); +addLocaleData({"locale":"fr-BL","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CA","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CD","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CF","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CG","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CH","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CI","parentLocale":"fr"}); +addLocaleData({"locale":"fr-CM","parentLocale":"fr"}); +addLocaleData({"locale":"fr-DJ","parentLocale":"fr"}); +addLocaleData({"locale":"fr-DZ","parentLocale":"fr"}); +addLocaleData({"locale":"fr-GA","parentLocale":"fr"}); +addLocaleData({"locale":"fr-GF","parentLocale":"fr"}); +addLocaleData({"locale":"fr-GN","parentLocale":"fr"}); +addLocaleData({"locale":"fr-GP","parentLocale":"fr"}); +addLocaleData({"locale":"fr-GQ","parentLocale":"fr"}); +addLocaleData({"locale":"fr-HT","parentLocale":"fr"}); +addLocaleData({"locale":"fr-KM","parentLocale":"fr"}); +addLocaleData({"locale":"fr-LU","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MA","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MC","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MF","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MG","parentLocale":"fr"}); +addLocaleData({"locale":"fr-ML","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MQ","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MR","parentLocale":"fr"}); +addLocaleData({"locale":"fr-MU","parentLocale":"fr"}); +addLocaleData({"locale":"fr-NC","parentLocale":"fr"}); +addLocaleData({"locale":"fr-NE","parentLocale":"fr"}); +addLocaleData({"locale":"fr-PF","parentLocale":"fr"}); +addLocaleData({"locale":"fr-PM","parentLocale":"fr"}); +addLocaleData({"locale":"fr-RE","parentLocale":"fr"}); +addLocaleData({"locale":"fr-RW","parentLocale":"fr"}); +addLocaleData({"locale":"fr-SC","parentLocale":"fr"}); +addLocaleData({"locale":"fr-SN","parentLocale":"fr"}); +addLocaleData({"locale":"fr-SY","parentLocale":"fr"}); +addLocaleData({"locale":"fr-TD","parentLocale":"fr"}); +addLocaleData({"locale":"fr-TG","parentLocale":"fr"}); +addLocaleData({"locale":"fr-TN","parentLocale":"fr"}); +addLocaleData({"locale":"fr-VU","parentLocale":"fr"}); +addLocaleData({"locale":"fr-WF","parentLocale":"fr"}); +addLocaleData({"locale":"fr-YT","parentLocale":"fr"}); +addLocaleData({"locale":"fur","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"fy","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"ga","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n;if(ord)return n==1?"one":"other";return n==1?"one":n==2?"two":t0&&n>=3&&n<=6?"few":t0&&n>=7&&n<=10?"many":"other"}}); +addLocaleData({"locale":"gd","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n;if(ord)return"other";return n==1||n==11?"one":n==2||n==12?"two":t0&&n>=3&&n<=10||t0&&n>=13&&n<=19?"few":"other"}}); +addLocaleData({"locale":"gl","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"gsw","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"gsw-FR","parentLocale":"gsw"}); +addLocaleData({"locale":"gsw-LI","parentLocale":"gsw"}); +addLocaleData({"locale":"gu","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":n==2||n==3?"two":n==4?"few":n==6?"many":"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"guw","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"guz","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"gv","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],i10=i.slice(-1),i100=i.slice(-2);if(ord)return"other";return v0&&i10==1?"one":v0&&i10==2?"two":v0&&(i100==0||i100==20||i100==40||i100==60||i100==80)?"few":!v0?"many":"other"}}); +addLocaleData({"locale":"ha","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ha-Arab","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ha-GH","parentLocale":"ha"}); +addLocaleData({"locale":"ha-NE","parentLocale":"ha"}); +addLocaleData({"locale":"haw","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"he","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1);if(ord)return"other";return n==1&&v0?"one":i==2&&v0?"two":v0&&(n<0||n>10)&&t0&&n10==0?"many":"other"}}); +addLocaleData({"locale":"hi","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":n==2||n==3?"two":n==4?"few":n==6?"many":"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"hr","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),i100=i.slice(-2),f10=f.slice(-1),f100=f.slice(-2);if(ord)return"other";return v0&&i10==1&&i100!=11||f10==1&&f100!=11?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)||f10>=2&&f10<=4&&(f100<12||f100>14)?"few":"other"}}); +addLocaleData({"locale":"hr-BA","parentLocale":"hr"}); +addLocaleData({"locale":"hsb","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i100=i.slice(-2),f100=f.slice(-2);if(ord)return"other";return v0&&i100==1||f100==1?"one":v0&&i100==2||f100==2?"two":v0&&(i100==3||i100==4)||(f100==3||f100==4)?"few":"other"}}); +addLocaleData({"locale":"hu","pluralRuleFunction":function (n,ord){if(ord)return n==1||n==5?"one":"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"hy","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":"other";return n>=0&&n<2?"one":"other"}}); +addLocaleData({"locale":"id","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ig","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ii","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"in","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"is","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],t0=Number(s[0])==n,i10=i.slice(-1),i100=i.slice(-2);if(ord)return"other";return t0&&i10==1&&i100!=11||!t0?"one":"other"}}); +addLocaleData({"locale":"it","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return n==11||n==8||n==80||n==800?"many":"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"it-CH","parentLocale":"it"}); +addLocaleData({"locale":"it-SM","parentLocale":"it"}); +addLocaleData({"locale":"iu","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"iu-Latn","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"iw","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1);if(ord)return"other";return n==1&&v0?"one":i==2&&v0?"two":v0&&(n<0||n>10)&&t0&&n10==0?"many":"other"}}); +addLocaleData({"locale":"ja","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"jbo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"jgo","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ji","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"jmc","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"jv","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"jw","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ka","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],i100=i.slice(-2);if(ord)return i==1?"one":i==0||(i100>=2&&i100<=20||i100==40||i100==60||i100==80)?"many":"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kab","pluralRuleFunction":function (n,ord){if(ord)return"other";return n>=0&&n<2?"one":"other"}}); +addLocaleData({"locale":"kaj","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kam","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"kcg","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kde","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"kea","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"khq","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ki","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"kk","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n,n10=t0&&s[0].slice(-1);if(ord)return n10==6||n10==9||t0&&n10==0&&n!=0?"many":"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kkj","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kl","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kln","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"km","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"kn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"ko","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ko-KP","parentLocale":"ko"}); +addLocaleData({"locale":"kok","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ks","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ksb","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ksf","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ksh","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0?"zero":n==1?"one":"other"}}); +addLocaleData({"locale":"ku","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"kw","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"ky","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"lag","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0];if(ord)return"other";return n==0?"zero":(i==0||i==1)&&n!=0?"one":"other"}}); +addLocaleData({"locale":"lb","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"lg","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"lkt","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ln","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"ln-AO","parentLocale":"ln"}); +addLocaleData({"locale":"ln-CF","parentLocale":"ln"}); +addLocaleData({"locale":"ln-CG","parentLocale":"ln"}); +addLocaleData({"locale":"lo","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":"other";return"other"}}); +addLocaleData({"locale":"lrc","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"lrc-IQ","parentLocale":"lrc"}); +addLocaleData({"locale":"lt","pluralRuleFunction":function (n,ord){var s=String(n).split("."),f=s[1]||"",t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return"other";return n10==1&&(n100<11||n100>19)?"one":n10>=2&&n10<=9&&(n100<11||n100>19)?"few":f!=0?"many":"other"}}); +addLocaleData({"locale":"lu","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"luo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"luy","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"lv","pluralRuleFunction":function (n,ord){var s=String(n).split("."),f=s[1]||"",v=f.length,t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2),f100=f.slice(-2),f10=f.slice(-1);if(ord)return"other";return t0&&n10==0||n100>=11&&n100<=19||v==2&&(f100>=11&&f100<=19)?"zero":n10==1&&n100!=11||v==2&&f10==1&&f100!=11||v!=2&&f10==1?"one":"other"}}); +addLocaleData({"locale":"mas","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"mas-TZ","parentLocale":"mas"}); +addLocaleData({"locale":"mer","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"mfe","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"mg","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"mgh","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"mgo","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"mk","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),i100=i.slice(-2),f10=f.slice(-1);if(ord)return i10==1&&i100!=11?"one":i10==2&&i100!=12?"two":(i10==7||i10==8)&&i100!=17&&i100!=18?"many":"other";return v0&&i10==1||f10==1?"one":"other"}}); +addLocaleData({"locale":"ml","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"mn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"mn-Mong","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"mo","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n100=t0&&s[0].slice(-2);if(ord)return n==1?"one":"other";return n==1&&v0?"one":!v0||n==0||n!=1&&(n100>=1&&n100<=19)?"few":"other"}}); +addLocaleData({"locale":"mr","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":n==2||n==3?"two":n==4?"few":"other";return n>=0&&n<=1?"one":"other"}}); +addLocaleData({"locale":"ms","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":"other";return"other"}}); +addLocaleData({"locale":"ms-Arab","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ms-BN","parentLocale":"ms"}); +addLocaleData({"locale":"ms-SG","parentLocale":"ms"}); +addLocaleData({"locale":"mt","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n,n100=t0&&s[0].slice(-2);if(ord)return"other";return n==1?"one":n==0||n100>=2&&n100<=10?"few":n100>=11&&n100<=19?"many":"other"}}); +addLocaleData({"locale":"mua","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"my","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"mzn","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"nah","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"naq","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"nb","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"nb-SJ","parentLocale":"nb"}); +addLocaleData({"locale":"nd","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ne","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n;if(ord)return t0&&n>=1&&n<=4?"one":"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ne-IN","parentLocale":"ne"}); +addLocaleData({"locale":"nl","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"nl-AW","parentLocale":"nl"}); +addLocaleData({"locale":"nl-BE","parentLocale":"nl"}); +addLocaleData({"locale":"nl-BQ","parentLocale":"nl"}); +addLocaleData({"locale":"nl-CW","parentLocale":"nl"}); +addLocaleData({"locale":"nl-SR","parentLocale":"nl"}); +addLocaleData({"locale":"nl-SX","parentLocale":"nl"}); +addLocaleData({"locale":"nmg","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"nn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"nnh","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"no","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"nqo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"nr","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"nso","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"nus","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ny","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"nyn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"om","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"om-KE","parentLocale":"om"}); +addLocaleData({"locale":"or","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"os","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"os-RU","parentLocale":"os"}); +addLocaleData({"locale":"pa","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"pa-Arab","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"pa-Guru","parentLocale":"pa"}); +addLocaleData({"locale":"pap","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"pl","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],i10=i.slice(-1),i100=i.slice(-2);if(ord)return"other";return n==1&&v0?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)?"few":v0&&i!=1&&(i10==0||i10==1)||v0&&(i10>=5&&i10<=9)||v0&&(i100>=12&&i100<=14)?"many":"other"}}); +addLocaleData({"locale":"prg","pluralRuleFunction":function (n,ord){var s=String(n).split("."),f=s[1]||"",v=f.length,t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2),f100=f.slice(-2),f10=f.slice(-1);if(ord)return"other";return t0&&n10==0||n100>=11&&n100<=19||v==2&&(f100>=11&&f100<=19)?"zero":n10==1&&n100!=11||v==2&&f10==1&&f100!=11||v!=2&&f10==1?"one":"other"}}); +addLocaleData({"locale":"ps","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"pt","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n;if(ord)return"other";return t0&&n>=0&&n<=2&&n!=2?"one":"other"}}); +addLocaleData({"locale":"pt-AO","parentLocale":"pt-PT"}); +addLocaleData({"locale":"pt-PT","parentLocale":"pt","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"pt-CV","parentLocale":"pt-PT"}); +addLocaleData({"locale":"pt-GW","parentLocale":"pt-PT"}); +addLocaleData({"locale":"pt-MO","parentLocale":"pt-PT"}); +addLocaleData({"locale":"pt-MZ","parentLocale":"pt-PT"}); +addLocaleData({"locale":"pt-ST","parentLocale":"pt-PT"}); +addLocaleData({"locale":"pt-TL","parentLocale":"pt-PT"}); +addLocaleData({"locale":"qu","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"qu-BO","parentLocale":"qu"}); +addLocaleData({"locale":"qu-EC","parentLocale":"qu"}); +addLocaleData({"locale":"rm","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"rn","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ro","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n100=t0&&s[0].slice(-2);if(ord)return n==1?"one":"other";return n==1&&v0?"one":!v0||n==0||n!=1&&(n100>=1&&n100<=19)?"few":"other"}}); +addLocaleData({"locale":"ro-MD","parentLocale":"ro"}); +addLocaleData({"locale":"rof","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ru","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],i10=i.slice(-1),i100=i.slice(-2);if(ord)return"other";return v0&&i10==1&&i100!=11?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)?"few":v0&&i10==0||v0&&(i10>=5&&i10<=9)||v0&&(i100>=11&&i100<=14)?"many":"other"}}); +addLocaleData({"locale":"ru-BY","parentLocale":"ru"}); +addLocaleData({"locale":"ru-KG","parentLocale":"ru"}); +addLocaleData({"locale":"ru-KZ","parentLocale":"ru"}); +addLocaleData({"locale":"ru-MD","parentLocale":"ru"}); +addLocaleData({"locale":"ru-UA","parentLocale":"ru"}); +addLocaleData({"locale":"rw","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"rwk","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"sah","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"saq","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"sbp","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"sdh","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"se","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"se-FI","parentLocale":"se"}); +addLocaleData({"locale":"se-SE","parentLocale":"se"}); +addLocaleData({"locale":"seh","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ses","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"sg","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"sh","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),i100=i.slice(-2),f10=f.slice(-1),f100=f.slice(-2);if(ord)return"other";return v0&&i10==1&&i100!=11||f10==1&&f100!=11?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)||f10>=2&&f10<=4&&(f100<12||f100>14)?"few":"other"}}); +addLocaleData({"locale":"shi","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n;if(ord)return"other";return n>=0&&n<=1?"one":t0&&n>=2&&n<=10?"few":"other"}}); +addLocaleData({"locale":"shi-Latn","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"shi-Tfng","parentLocale":"shi"}); +addLocaleData({"locale":"si","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"";if(ord)return"other";return n==0||n==1||i==0&&f==1?"one":"other"}}); +addLocaleData({"locale":"sk","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1];if(ord)return"other";return n==1&&v0?"one":i>=2&&i<=4&&v0?"few":!v0?"many":"other"}}); +addLocaleData({"locale":"sl","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],i100=i.slice(-2);if(ord)return"other";return v0&&i100==1?"one":v0&&i100==2?"two":v0&&(i100==3||i100==4)||!v0?"few":"other"}}); +addLocaleData({"locale":"sma","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"smi","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"smj","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"smn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"sms","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":n==2?"two":"other"}}); +addLocaleData({"locale":"sn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"so","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"so-DJ","parentLocale":"so"}); +addLocaleData({"locale":"so-ET","parentLocale":"so"}); +addLocaleData({"locale":"so-KE","parentLocale":"so"}); +addLocaleData({"locale":"sq","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return n==1?"one":n10==4&&n100!=14?"many":"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"sq-MK","parentLocale":"sq"}); +addLocaleData({"locale":"sq-XK","parentLocale":"sq"}); +addLocaleData({"locale":"sr","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),i100=i.slice(-2),f10=f.slice(-1),f100=f.slice(-2);if(ord)return"other";return v0&&i10==1&&i100!=11||f10==1&&f100!=11?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)||f10>=2&&f10<=4&&(f100<12||f100>14)?"few":"other"}}); +addLocaleData({"locale":"sr-Cyrl","parentLocale":"sr"}); +addLocaleData({"locale":"sr-Cyrl-BA","parentLocale":"sr-Cyrl"}); +addLocaleData({"locale":"sr-Cyrl-ME","parentLocale":"sr-Cyrl"}); +addLocaleData({"locale":"sr-Cyrl-XK","parentLocale":"sr-Cyrl"}); +addLocaleData({"locale":"sr-Latn","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"sr-Latn-BA","parentLocale":"sr-Latn"}); +addLocaleData({"locale":"sr-Latn-ME","parentLocale":"sr-Latn"}); +addLocaleData({"locale":"sr-Latn-XK","parentLocale":"sr-Latn"}); +addLocaleData({"locale":"ss","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ssy","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"st","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"sv","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return(n10==1||n10==2)&&n100!=11&&n100!=12?"one":"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"sv-AX","parentLocale":"sv"}); +addLocaleData({"locale":"sv-FI","parentLocale":"sv"}); +addLocaleData({"locale":"sw","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"sw-CD","parentLocale":"sw"}); +addLocaleData({"locale":"sw-KE","parentLocale":"sw"}); +addLocaleData({"locale":"sw-UG","parentLocale":"sw"}); +addLocaleData({"locale":"syr","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ta","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"ta-LK","parentLocale":"ta"}); +addLocaleData({"locale":"ta-MY","parentLocale":"ta"}); +addLocaleData({"locale":"ta-SG","parentLocale":"ta"}); +addLocaleData({"locale":"te","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"teo","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"teo-KE","parentLocale":"teo"}); +addLocaleData({"locale":"th","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"ti","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"ti-ER","parentLocale":"ti"}); +addLocaleData({"locale":"tig","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"tk","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"tl","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],f=s[1]||"",v0=!s[1],i10=i.slice(-1),f10=f.slice(-1);if(ord)return n==1?"one":"other";return v0&&(i==1||i==2||i==3)||v0&&i10!=4&&i10!=6&&i10!=9||!v0&&f10!=4&&f10!=6&&f10!=9?"one":"other"}}); +addLocaleData({"locale":"tn","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"to","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"tr","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"tr-CY","parentLocale":"tr"}); +addLocaleData({"locale":"ts","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"twq","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"tzm","pluralRuleFunction":function (n,ord){var s=String(n).split("."),t0=Number(s[0])==n;if(ord)return"other";return n==0||n==1||t0&&n>=11&&n<=99?"one":"other"}}); +addLocaleData({"locale":"ug","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"uk","pluralRuleFunction":function (n,ord){var s=String(n).split("."),i=s[0],v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2),i10=i.slice(-1),i100=i.slice(-2);if(ord)return n10==3&&n100!=13?"few":"other";return v0&&i10==1&&i100!=11?"one":v0&&(i10>=2&&i10<=4)&&(i100<12||i100>14)?"few":v0&&i10==0||v0&&(i10>=5&&i10<=9)||v0&&(i100>=11&&i100<=14)?"many":"other"}}); +addLocaleData({"locale":"ur","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"ur-IN","parentLocale":"ur"}); +addLocaleData({"locale":"uz","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"uz-Arab","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"uz-Cyrl","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"uz-Latn","parentLocale":"uz"}); +addLocaleData({"locale":"vai","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"vai-Latn","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"vai-Vaii","parentLocale":"vai"}); +addLocaleData({"locale":"ve","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"vi","pluralRuleFunction":function (n,ord){if(ord)return n==1?"one":"other";return"other"}}); +addLocaleData({"locale":"vo","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"vun","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"wa","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==0||n==1?"one":"other"}}); +addLocaleData({"locale":"wae","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"wo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"xh","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"xog","pluralRuleFunction":function (n,ord){if(ord)return"other";return n==1?"one":"other"}}); +addLocaleData({"locale":"yav","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"yi","pluralRuleFunction":function (n,ord){var s=String(n).split("."),v0=!s[1];if(ord)return"other";return n==1&&v0?"one":"other"}}); +addLocaleData({"locale":"yo","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"yo-BJ","parentLocale":"yo"}); +addLocaleData({"locale":"zgh","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"zh","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"zh-Hans","parentLocale":"zh"}); +addLocaleData({"locale":"zh-Hans-HK","parentLocale":"zh-Hans"}); +addLocaleData({"locale":"zh-Hans-MO","parentLocale":"zh-Hans"}); +addLocaleData({"locale":"zh-Hans-SG","parentLocale":"zh-Hans"}); +addLocaleData({"locale":"zh-Hant","pluralRuleFunction":function (n,ord){if(ord)return"other";return"other"}}); +addLocaleData({"locale":"zh-Hant-HK","parentLocale":"zh-Hant"}); +addLocaleData({"locale":"zh-Hant-MO","parentLocale":"zh-Hant-HK"}); +addLocaleData({"locale":"zu","pluralRuleFunction":function (n,ord){if(ord)return"other";return n>=0&&n<=1?"one":"other"}}); diff --git a/packages/kbn-i18n/src/index.js b/packages/kbn-i18n/src/index.js new file mode 100644 index 0000000000000..19619fc1c740a --- /dev/null +++ b/packages/kbn-i18n/src/index.js @@ -0,0 +1,26 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as i18nCore from './core/i18n'; +import * as loader from './core/loader'; + +export { formats } from './core/formats'; + +export const i18n = i18nCore; +export const i18nLoader = loader; diff --git a/packages/kbn-i18n/src/react/context.js b/packages/kbn-i18n/src/react/context.js new file mode 100644 index 0000000000000..df7c8877725fb --- /dev/null +++ b/packages/kbn-i18n/src/react/context.js @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import { intlShape } from 'react-intl'; + +/** + * Provides intl context to a child component using React render callback pattern + * @example + * + * {intl => ( + * + * )} + * + */ +export class I18nContext extends PureComponent { + static propTypes = { + children: PropTypes.func.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + return this.props.children(this.context.intl); + } +} diff --git a/packages/kbn-i18n/src/react/index.js b/packages/kbn-i18n/src/react/index.js new file mode 100644 index 0000000000000..f80dd27268f96 --- /dev/null +++ b/packages/kbn-i18n/src/react/index.js @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { + intlShape, + FormattedDate, + FormattedTime, + FormattedRelative, + FormattedNumber, + FormattedPlural, + FormattedMessage, + FormattedHTMLMessage, +} from 'react-intl'; + +export { I18nProvider } from './provider'; +export { I18nContext } from './context'; diff --git a/packages/kbn-i18n/src/react/provider.js b/packages/kbn-i18n/src/react/provider.js new file mode 100644 index 0000000000000..96ed0e8b023ee --- /dev/null +++ b/packages/kbn-i18n/src/react/provider.js @@ -0,0 +1,51 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import { IntlProvider } from 'react-intl'; + +import * as i18n from '../core/i18n'; + +/** + * The library uses the provider pattern to scope an i18n context to a tree + * of components. This component is used to setup the i18n context for a tree. + * IntlProvider should wrap react app's root component (inside each react render method). + */ +export class I18nProvider extends PureComponent { + static propTypes = { + children: PropTypes.object, + }; + + render() { + const { children } = this.props; + + return ( + + {children} + + ); + } +} diff --git a/packages/kbn-i18n/yarn.lock b/packages/kbn-i18n/yarn.lock new file mode 100644 index 0000000000000..3d44b09a4f1b5 --- /dev/null +++ b/packages/kbn-i18n/yarn.lock @@ -0,0 +1,1745 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@kbn/babel-preset@link:../kbn-babel-preset": + version "0.0.0" + uid "" + +"@kbn/dev-utils@link:../kbn-dev-utils": + version "0.0.0" + uid "" + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +accept-language-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +anymatch@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + dependencies: + micromatch "^2.1.5" + normalize-path "^2.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +asap@~2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +babel-cli@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" + dependencies: + babel-core "^6.26.0" + babel-polyfill "^6.26.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + commander "^2.11.0" + convert-source-map "^1.5.0" + fs-readdir-recursive "^1.0.0" + glob "^7.1.2" + lodash "^4.17.4" + output-file-sync "^1.1.2" + path-is-absolute "^1.0.1" + slash "^1.0.0" + source-map "^0.5.6" + v8flags "^2.1.1" + optionalDependencies: + chokidar "^1.6.1" + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-builder-react-jsx@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz#39ff8313b75c8b65dceff1f31d383e0ff2a408a0" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + esutils "^2.0.2" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-add-module-exports@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-0.2.1.tgz#9ae9a1f4a8dc67f0cdec4f4aeda1e43a5ff65e25" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-define@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-define/-/babel-plugin-transform-define-1.3.0.tgz#94c5f9459c810c738cc7c50cbd44a31829d6f319" + dependencies: + lodash "4.17.4" + traverse "0.6.6" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-react-display-name@^6.23.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz#67e2bf1f1e9c93ab08db96792e05392bf2cc28d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-self@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz#df6d80a9da2612a121e6ddd7558bcbecf06e636e" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx-source@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz#66ac12153f5cd2d17b3c19268f4bf0197f44ecd6" + dependencies: + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-react-jsx@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz#840a028e7df460dfc3a2d29f0c0d91f6376e66a3" + dependencies: + babel-helper-builder-react-jsx "^6.24.1" + babel-plugin-syntax-jsx "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-env@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^1.4.0" + invariant "^2.2.2" + +babel-preset-flow@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d" + dependencies: + babel-plugin-transform-flow-strip-types "^6.22.0" + +babel-preset-react@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" + dependencies: + babel-plugin-syntax-jsx "^6.3.13" + babel-plugin-transform-react-display-name "^6.23.0" + babel-plugin-transform-react-jsx "^6.24.1" + babel-plugin-transform-react-jsx-self "^6.22.0" + babel-plugin-transform-react-jsx-source "^6.22.0" + babel-preset-flow "^6.23.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browserslist@^1.4.0: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +caniuse-db@^1.0.30000639: + version "1.0.30000850" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000850.tgz#965c816641576d08709bee12256a0550164b95d5" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^1.6.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +commander@^2.11.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +convert-source-map@^1.5.0, convert-source-map@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cross-env@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.0.tgz#6ecd4c015d5773e614039ee529076669b9d126f2" + dependencies: + cross-spawn "^6.0.5" + is-windows "^1.0.0" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@^2.1.2, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +electron-to-chromium@^1.2.7: + version "1.3.48" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz#d3b0d8593814044e092ece2108fc3ac9aea4b900" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +fbjs@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-readdir-recursive@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.5, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +graceful-fs@^4.1.2, graceful-fs@^4.1.4: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +iconv-lite@^0.4.4, iconv-lite@~0.4.13: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +intl-format-cache@^2.0.5, intl-format-cache@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316" + +intl-messageformat-parser@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075" + +intl-messageformat@^2.0.0, intl-messageformat@^2.1.0, intl-messageformat@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc" + dependencies: + intl-messageformat-parser "1.4.0" + +intl-relativeformat@^2.0.0, intl-relativeformat@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-2.1.0.tgz#010f1105802251f40ac47d0e3e1a201348a255df" + dependencies: + intl-messageformat "^2.0.0" + +invariant@^2.1.1, invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-windows@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isomorphic-fetch@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" + dependencies: + node-fetch "^1.0.1" + whatwg-fetch ">=0.10.0" + +js-tokens@^3.0.0, js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + dependencies: + minimist "^1.2.0" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +lodash@4.17.4: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@^4.17.4: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + +micromatch@^2.1.5: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment@^2.20.1: + version "2.22.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +needle@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-pre-gyp@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz#6e4ef5bb5c5203c6552448828c852c40111aac46" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.0" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.1.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-path@^2.0.0, normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + +prop-types@^15.5.8, prop-types@^15.6.0: + version "15.6.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" + +randomatic@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +rc@^1.1.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-intl@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.4.0.tgz#66c14dc9df9a73b2fbbfbd6021726e80a613eb15" + dependencies: + intl-format-cache "^2.0.5" + intl-messageformat "^2.1.0" + intl-relativeformat "^2.0.0" + invariant "^2.1.1" + +react@^16.3.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + +readable-stream@^2.0.2, readable-stream@^2.0.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +regenerate@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +rxjs@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9" + dependencies: + tslib "^1.9.0" + +safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +semver@^5.3.0, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + dependencies: + source-map "^0.5.6" + +source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +tar@^4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +traverse@0.6.6: + version "0.6.6" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" + +tree-kill@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tslib@^1.9.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.2.tgz#8be0cc9a1f6dc7727c38deb16c2ebd1a2892988e" + +ua-parser-js@^0.7.9: + version "0.7.18" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.18.tgz#a7bfd92f56edfb117083b69e31d2aa8882d4b1ed" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +v8flags@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + +whatwg-fetch@>=0.10.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index c13a5675b9d0e..e32a174fcb3e8 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -17,8 +17,6 @@ * under the License. */ -import { resolve } from 'path'; - import Promise from 'bluebird'; import { mkdirp as mkdirpNode } from 'mkdirp'; @@ -124,9 +122,7 @@ export default function (kibana) { }; }, - translations: [ - resolve(__dirname, './translations/en.json') - ], + translations: [], mappings, uiSettingDefaults: getUiSettingDefaults(), diff --git a/src/core_plugins/kibana/translations/en.json b/src/core_plugins/kibana/translations/en.json deleted file mode 100644 index ddb7a272e1129..0000000000000 --- a/src/core_plugins/kibana/translations/en.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "UI-WELCOME_MESSAGE": "Loading Kibana", - "UI-WELCOME_ERROR": "Kibana did not load properly. Check the server output for more information." -} diff --git a/src/ui/public/autoload/modules.js b/src/ui/public/autoload/modules.js index 194279dfd05bf..e4058ec22a427 100644 --- a/src/ui/public/autoload/modules.js +++ b/src/ui/public/autoload/modules.js @@ -53,3 +53,4 @@ import '../validate_date_interval'; import '../watch_multi'; import '../courier/saved_object/ui/saved_object_save_as_checkbox'; import '../react_components'; +import '../i18n'; diff --git a/src/ui/public/i18n/index.js b/src/ui/public/i18n/index.js new file mode 100644 index 0000000000000..fe1062f1ae1ac --- /dev/null +++ b/src/ui/public/i18n/index.js @@ -0,0 +1,36 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AngularI18n } from '@kbn/i18n'; +import { uiModules } from 'ui/modules'; +import { metadata } from 'ui/metadata'; + +const { + i18nProvider, + i18nFilter, + i18nDirective, +} = AngularI18n; + +uiModules.get('i18n') + .provider('i18n', i18nProvider) + .filter('i18n', i18nFilter) + .directive('i18nId', i18nDirective) + .config((i18nProvider) => { + i18nProvider.init(metadata.translations); + }); diff --git a/src/ui/ui_exports/ui_export_defaults.js b/src/ui/ui_exports/ui_export_defaults.js index d7af504487921..8c9a579ce1bee 100644 --- a/src/ui/ui_exports/ui_export_defaults.js +++ b/src/ui/ui_exports/ui_export_defaults.js @@ -35,9 +35,7 @@ export const UI_EXPORT_DEFAULTS = { 'moment-timezone$': resolve(ROOT, 'webpackShims/moment-timezone') }, - translationPaths: [ - resolve(ROOT, 'src/ui/ui_i18n/translations/en.json'), - ], + translationPaths: [], appExtensions: { fieldFormatEditors: [ diff --git a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/de.json b/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/de.json deleted file mode 100644 index ab9171f3a86cf..0000000000000 --- a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/de.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "test_plugin_1-NO_SSL": "Dont run the DE dev server using HTTPS", - "test_plugin_1-DEV": "Run the DE server with development mode defaults" -} diff --git a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/en.json b/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/en.json deleted file mode 100644 index 53dddcb859f70..0000000000000 --- a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/en.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "test_plugin_1-NO_SSL": "Dont run the dev server using HTTPS", - "test_plugin_1-DEV": "Run the server with development mode defaults", - "test_plugin_1-NO_RUN_SERVER": "Dont run the dev server", - "test_plugin_1-HOME": "Run along home now!" -} diff --git a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/es-ES.json b/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/es-ES.json deleted file mode 100644 index cd7e296e8f9de..0000000000000 --- a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_1/es-ES.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "test_plugin_1-NO_SSL": "Dont run the es-ES dev server using HTTPS! I am registered afterwards!" -} diff --git a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_2/de.json b/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_2/de.json deleted file mode 100644 index 512c71c54a550..0000000000000 --- a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_2/de.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "test_plugin_1-NO_SSL": "Dont run the DE dev server using HTTPS! I am registered afterwards!" -} diff --git a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_2/en.json b/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_2/en.json deleted file mode 100644 index 3e791c7d6e776..0000000000000 --- a/src/ui/ui_i18n/__tests__/fixtures/translations/test_plugin_2/en.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "test_plugin_2-XXXXXX": "This is XXXXXX string", - "test_plugin_2-YYYY_PPPP": "This is YYYY_PPPP string", - "test_plugin_2-FFFFFFFFFFFF": "This is FFFFFFFFFFFF string", - "test_plugin_2-ZZZ": "This is ZZZ string" -} diff --git a/src/ui/ui_i18n/__tests__/i18n.js b/src/ui/ui_i18n/__tests__/i18n.js deleted file mode 100644 index 6a218177abbd4..0000000000000 --- a/src/ui/ui_i18n/__tests__/i18n.js +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import expect from 'expect.js'; -import _ from 'lodash'; -import { join } from 'path'; - -import { I18n } from '../'; - -const FIXTURES = join(__dirname, 'fixtures'); - -describe('ui/i18n module', function () { - - describe('one plugin', function () { - - const i18nObj = new I18n(); - - before('registerTranslations - one plugin', function () { - const pluginName = 'test_plugin_1'; - const pluginTranslationPath = join(FIXTURES, 'translations', pluginName); - const translationFiles = [ - join(pluginTranslationPath, 'de.json'), - join(pluginTranslationPath, 'en.json') - ]; - const filesLen = translationFiles.length; - for (let indx = 0; indx < filesLen; indx++) { - i18nObj.registerTranslations(translationFiles[indx]); - } - }); - - describe('getTranslations', function () { - - it('should return the translations for en locale as registered', function () { - const languageTag = ['en']; - const expectedTranslationJson = { - 'test_plugin_1-NO_SSL': 'Dont run the dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the server with development mode defaults', - 'test_plugin_1-NO_RUN_SERVER': 'Dont run the dev server', - 'test_plugin_1-HOME': 'Run along home now!' - }; - return checkTranslations(expectedTranslationJson, languageTag, i18nObj); - }); - - it('should return the translations for de locale as registered', function () { - const languageTag = ['de']; - const expectedTranslationJson = { - 'test_plugin_1-NO_SSL': 'Dont run the DE dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the DE server with development mode defaults' - }; - return checkTranslations(expectedTranslationJson, languageTag, i18nObj); - }); - - it('should pick the highest priority language for which translations exist', function () { - const languageTags = ['es-ES', 'de', 'en']; - const expectedTranslations = { - 'test_plugin_1-NO_SSL': 'Dont run the DE dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the DE server with development mode defaults', - }; - return checkTranslations(expectedTranslations, languageTags, i18nObj); - }); - - it('should return translations for highest priority locale where best case match is chosen from registered locales', function () { - const languageTags = ['es', 'de']; - const expectedTranslations = { - 'test_plugin_1-NO_SSL': 'Dont run the es-ES dev server using HTTPS! I am registered afterwards!' - }; - i18nObj.registerTranslations(join(FIXTURES, 'translations', 'test_plugin_1', 'es-ES.json')); - return checkTranslations(expectedTranslations, languageTags, i18nObj); - }); - - it('should return an empty object for locales with no translations', function () { - const languageTags = ['ja-JA', 'fr']; - return checkTranslations({}, languageTags, i18nObj); - }); - - }); - - describe('getTranslationsForDefaultLocale', function () { - - it('should return translations for default locale which is set to the en locale', function () { - const i18nObj1 = new I18n('en'); - const expectedTranslations = { - 'test_plugin_1-NO_SSL': 'Dont run the dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the server with development mode defaults', - 'test_plugin_1-NO_RUN_SERVER': 'Dont run the dev server', - 'test_plugin_1-HOME': 'Run along home now!' - }; - i18nObj1.registerTranslations(join(FIXTURES, 'translations', 'test_plugin_1', 'en.json')); - return checkTranslationsForDefaultLocale(expectedTranslations, i18nObj1); - }); - - it('should return translations for default locale which is set to the de locale', function () { - const i18nObj1 = new I18n('de'); - const expectedTranslations = { - 'test_plugin_1-NO_SSL': 'Dont run the DE dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the DE server with development mode defaults', - }; - i18nObj1.registerTranslations(join(FIXTURES, 'translations', 'test_plugin_1', 'de.json')); - return checkTranslationsForDefaultLocale(expectedTranslations, i18nObj1); - }); - - }); - - describe('getAllTranslations', function () { - - it('should return all translations', function () { - const expectedTranslations = { - de: { - 'test_plugin_1-NO_SSL': 'Dont run the DE dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the DE server with development mode defaults' - }, - en: { - 'test_plugin_1-NO_SSL': 'Dont run the dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the server with development mode defaults', - 'test_plugin_1-NO_RUN_SERVER': 'Dont run the dev server', - 'test_plugin_1-HOME': 'Run along home now!' - }, - 'es-ES': { - 'test_plugin_1-NO_SSL': 'Dont run the es-ES dev server using HTTPS! I am registered afterwards!' - } - }; - return checkAllTranslations(expectedTranslations, i18nObj); - }); - - }); - - }); - - describe('multiple plugins', function () { - - const i18nObj = new I18n(); - - beforeEach('registerTranslations - multiple plugin', function () { - const pluginTranslationPath = join(FIXTURES, 'translations'); - const translationFiles = [ - join(pluginTranslationPath, 'test_plugin_1', 'de.json'), - join(pluginTranslationPath, 'test_plugin_1', 'en.json'), - join(pluginTranslationPath, 'test_plugin_2', 'en.json') - ]; - const filesLen = translationFiles.length; - for (let indx = 0; indx < filesLen; indx++) { - i18nObj.registerTranslations(translationFiles[indx]); - } - }); - - describe('getTranslations', function () { - - it('should return the translations for en locale as registered', function () { - const languageTag = ['en']; - const expectedTranslationJson = { - 'test_plugin_1-NO_SSL': 'Dont run the dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the server with development mode defaults', - 'test_plugin_1-NO_RUN_SERVER': 'Dont run the dev server', - 'test_plugin_1-HOME': 'Run along home now!', - 'test_plugin_2-XXXXXX': 'This is XXXXXX string', - 'test_plugin_2-YYYY_PPPP': 'This is YYYY_PPPP string', - 'test_plugin_2-FFFFFFFFFFFF': 'This is FFFFFFFFFFFF string', - 'test_plugin_2-ZZZ': 'This is ZZZ string' - }; - return checkTranslations(expectedTranslationJson, languageTag, i18nObj); - }); - - it('should return the translations for de locale as registered', function () { - const languageTag = ['de']; - const expectedTranslationJson = { - 'test_plugin_1-NO_SSL': 'Dont run the DE dev server using HTTPS', - 'test_plugin_1-DEV': 'Run the DE server with development mode defaults' - }; - return checkTranslations(expectedTranslationJson, languageTag, i18nObj); - }); - - it('should return the most recently registered translation for a key that has multiple translations', function () { - i18nObj.registerTranslations(join(FIXTURES, 'translations', 'test_plugin_2', 'de.json')); - const languageTag = ['de']; - const expectedTranslationJson = { - 'test_plugin_1-NO_SSL': 'Dont run the DE dev server using HTTPS! I am registered afterwards!', - 'test_plugin_1-DEV': 'Run the DE server with development mode defaults' - }; - return checkTranslations(expectedTranslationJson, languageTag, i18nObj); - }); - - }); - - }); - - describe('registerTranslations', function () { - - const i18nObj = new I18n(); - - it('should throw error when registering relative path', function () { - return expect(i18nObj.registerTranslations).withArgs('./some/path').to.throwError(); - }); - - it('should throw error when registering empty filename', function () { - return expect(i18nObj.registerTranslations).withArgs('').to.throwError(); - }); - - it('should throw error when registering filename with no extension', function () { - return expect(i18nObj.registerTranslations).withArgs('file1').to.throwError(); - }); - - it('should throw error when registering filename with non JSON extension', function () { - return expect(i18nObj.registerTranslations).withArgs('file1.txt').to.throwError(); - }); - - }); - -}); - -function checkTranslations(expectedTranslations, languageTags, i18nObj) { - return i18nObj.getTranslations(...languageTags) - .then(function (actualTranslations) { - expect(_.isEqual(actualTranslations, expectedTranslations)).to.be(true); - }); -} - -function checkAllTranslations(expectedTranslations, i18nObj) { - return i18nObj.getAllTranslations() - .then(function (actualTranslations) { - expect(_.isEqual(actualTranslations, expectedTranslations)).to.be(true); - }); -} - -function checkTranslationsForDefaultLocale(expectedTranslations, i18nObj) { - return i18nObj.getTranslationsForDefaultLocale() - .then(function (actualTranslations) { - expect(_.isEqual(actualTranslations, expectedTranslations)).to.be(true); - }); -} diff --git a/src/ui/ui_i18n/i18n.js b/src/ui/ui_i18n/i18n.js deleted file mode 100644 index 4f466c1a62ad8..0000000000000 --- a/src/ui/ui_i18n/i18n.js +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import path from 'path'; -import Promise from 'bluebird'; -import { readFile } from 'fs'; -import _ from 'lodash'; - -const asyncReadFile = Promise.promisify(readFile); - -const TRANSLATION_FILE_EXTENSION = '.json'; - -function getLocaleFromFileName(fullFileName) { - if (_.isEmpty(fullFileName)) throw new Error('Filename empty'); - - const fileExt = path.extname(fullFileName); - if (fileExt.length <= 0 || fileExt !== TRANSLATION_FILE_EXTENSION) { - throw new Error('Translations must be in a JSON file. File being registered is ' + fullFileName); - } - - return path.basename(fullFileName, TRANSLATION_FILE_EXTENSION); -} - -function getBestLocaleMatch(languageTag, registeredLocales) { - if (_.contains(registeredLocales, languageTag)) { - return languageTag; - } - - // Find the first registered locale that begins with one of the language codes from the provided language tag. - // For example, if there is an 'en' language code, it would match an 'en-US' registered locale. - const languageCode = _.first(languageTag.split('-')) || []; - return _.find(registeredLocales, (locale) => _.startsWith(locale, languageCode)); -} - -export class I18n { - static async getAllTranslationsFromPaths(paths) { - const i18n = new I18n(); - - paths.forEach(path => { - i18n.registerTranslations(path); - }); - - return await i18n.getAllTranslations(); - } - - _registeredTranslations = {}; - - constructor(defaultLocale = 'en') { - this._defaultLocale = defaultLocale; - } - - /** - * Return all translations for registered locales - * @return {Promise} translations - A Promise object where keys are - * the locale and values are Objects - * of translation keys and translations - */ - getAllTranslations() { - const localeTranslations = {}; - - const locales = this._getRegisteredTranslationLocales(); - const translations = _.map(locales, (locale) => { - return this._getTranslationsForLocale(locale) - .then(function (translations) { - localeTranslations[locale] = translations; - }); - }); - - return Promise.all(translations) - .then(() => _.assign({}, localeTranslations)); - } - - /** - * Return translations for a suitable locale from a user side locale list - * @param {...string} languageTags - BCP 47 language tags. The tags are listed in priority order as set in the Accept-Language header. - * @returns {Promise} translations - promise for an object where - * keys are translation keys and - * values are translations - * This object will contain all registered translations for the highest priority locale which is registered with the i18n module. - * This object can be empty if no locale in the language tags can be matched against the registered locales. - */ - getTranslations(...languageTags) { - const locale = this._getTranslationLocale(languageTags); - return this._getTranslationsForLocale(locale); - } - - /** - * Return all translations registered for the default locale. - * @returns {Promise} translations - promise for an object where - * keys are translation keys and - * values are translations - */ - getTranslationsForDefaultLocale() { - return this._getTranslationsForLocale(this._defaultLocale); - } - - /** - * The translation file is registered with i18n plugin. The plugin contains a list of registered translation file paths per language. - * @param {String} absolutePluginTranslationFilePath - Absolute path to the translation file to register. - */ - registerTranslations(absolutePluginTranslationFilePath) { - if (!path.isAbsolute(absolutePluginTranslationFilePath)) { - throw new TypeError( - 'Paths to translation files must be absolute. ' + - `Got relative path: "${absolutePluginTranslationFilePath}"` - ); - } - - const locale = getLocaleFromFileName(absolutePluginTranslationFilePath); - - this._registeredTranslations[locale] = - _.uniq(_.get(this._registeredTranslations, locale, []).concat(absolutePluginTranslationFilePath)); - } - - _getRegisteredTranslationLocales() { - return Object.keys(this._registeredTranslations); - } - - _getTranslationLocale(languageTags) { - let locale = ''; - const registeredLocales = this._getRegisteredTranslationLocales(); - _.forEach(languageTags, (tag) => { - locale = locale || getBestLocaleMatch(tag, registeredLocales); - }); - return locale; - } - - _getTranslationsForLocale(locale) { - if (!this._registeredTranslations.hasOwnProperty(locale)) { - return Promise.resolve({}); - } - - const translationFiles = this._registeredTranslations[locale]; - const translations = _.map(translationFiles, (filename) => { - return asyncReadFile(filename, 'utf8') - .then(fileContents => JSON.parse(fileContents)) - .catch(SyntaxError, function () { - throw new Error('Invalid json in ' + filename); - }) - .catch(function () { - throw new Error('Cannot read file ' + filename); - }); - }); - - return Promise.all(translations) - .then(translations => _.assign({}, ...translations)); - } -} diff --git a/src/ui/ui_i18n/index.js b/src/ui/ui_i18n/index.js index a4b45b9875326..fdc27afc99a65 100644 --- a/src/ui/ui_i18n/index.js +++ b/src/ui/ui_i18n/index.js @@ -17,5 +17,48 @@ * under the License. */ -export { I18n } from './i18n'; -export { uiI18nMixin } from './ui_i18n_mixin'; +/** + @typedef Messages - messages tree, where leafs are translated strings + @type {object} + @property {string} [locale] - locale of the messages + @property {object} [formats] - set of options to the underlying formatter + */ + +import { i18nLoader } from '@kbn/i18n'; + +export function uiI18nMixin(kbnServer, server, config) { + const defaultLocale = config.get('i18n.defaultLocale'); + const { translationPaths = [] } = kbnServer.uiExports; + + i18nLoader.registerTranslationFiles(translationPaths); + + /** + * Fetch the translations matching the Accept-Language header for a requests. + * @name request.getUiTranslations + * @returns {Promise} translations - translation messages + */ + server.decorate('request', 'getUiTranslations', async function () { + const header = this.headers['accept-language']; + + const [defaultTranslations, requestedTranslations] = await Promise.all([ + i18nLoader.getTranslationsByLocale(defaultLocale), + i18nLoader.getTranslationsByLanguageHeader(header), + ]); + + return { + locale: defaultLocale, + ...defaultTranslations, + ...requestedTranslations, + }; + }); + + /** + * Return all translations for registered locales + * @name server.getAllUiTranslations + * @return {Promise>} translations - A Promise object + * where keys are the locale and values are objects of translation messages + */ + server.decorate('server', 'getAllUiTranslations', async () => { + return await i18nLoader.getAllTranslations(); + }); +} diff --git a/src/ui/ui_i18n/translations/en.json b/src/ui/ui_i18n/translations/en.json deleted file mode 100644 index ac491cf6f3465..0000000000000 --- a/src/ui/ui_i18n/translations/en.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "UI-WELCOME_MESSAGE": "Loading", - "UI-WELCOME_ERROR": "" -} diff --git a/src/ui/ui_i18n/ui_i18n_mixin.js b/src/ui/ui_i18n/ui_i18n_mixin.js deleted file mode 100644 index f0c9caab2cabc..0000000000000 --- a/src/ui/ui_i18n/ui_i18n_mixin.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { defaults, compact } from 'lodash'; -import langParser from 'accept-language-parser'; - -import { I18n } from './i18n'; - -function acceptLanguageHeaderToBCP47Tags(header) { - return langParser.parse(header).map(lang => ( - compact([lang.code, lang.region, lang.script]).join('-') - )); -} - -export function uiI18nMixin(kbnServer, server, config) { - const defaultLocale = config.get('i18n.defaultLocale'); - - const i18n = new I18n(defaultLocale); - const { translationPaths = [] } = kbnServer.uiExports; - translationPaths.forEach(translationPath => { - i18n.registerTranslations(translationPath); - }); - - /** - * Fetch the translations matching the Accept-Language header for a requests. - * @name request.getUiTranslations - * @returns {Promise>} translations - */ - server.decorate('request', 'getUiTranslations', async function () { - const header = this.headers['accept-language']; - const tags = acceptLanguageHeaderToBCP47Tags(header); - - const requestedTranslations = await i18n.getTranslations(...tags); - const defaultTranslations = await i18n.getTranslationsForDefaultLocale(); - - return defaults( - {}, - requestedTranslations, - defaultTranslations - ); - }); - - /** - * Return all translations for registered locales - * @name server.getAllUiTranslations - * @return {Promise>>} - */ - server.decorate('server', 'getAllUiTranslations', async () => { - return await i18n.getAllTranslations(); - }); - -} diff --git a/src/ui/ui_render/bootstrap/app_bootstrap.js b/src/ui/ui_render/bootstrap/app_bootstrap.js index f21aa3eda2279..0016773865dbe 100644 --- a/src/ui/ui_render/bootstrap/app_bootstrap.js +++ b/src/ui/ui_render/bootstrap/app_bootstrap.js @@ -17,17 +17,17 @@ * under the License. */ -import _ from 'lodash'; import Handlebars from 'handlebars'; import { createHash } from 'crypto'; import { readFile } from 'fs'; import { resolve } from 'path'; +import { i18n } from '@kbn/i18n'; export class AppBootstrap { constructor({ templateData, translations }) { this.templateData = templateData; - this.translations = translations; this._rawTemplate = undefined; + i18n.init(translations); } async getJsFile() { @@ -35,7 +35,7 @@ export class AppBootstrap { this._rawTemplate = await loadRawTemplate(); } - Handlebars.registerHelper('i18n', key => _.get(this.translations, key, '')); + Handlebars.registerHelper('i18n', (id, options) => i18n.translate(id, JSON.parse(options))); const template = Handlebars.compile(this._rawTemplate, { knownHelpers: { i18n: true }, knownHelpersOnly: true, diff --git a/src/ui/ui_render/bootstrap/app_bootstrap.test.js b/src/ui/ui_render/bootstrap/app_bootstrap.test.js index 87c6b83016826..64101b7830b38 100644 --- a/src/ui/ui_render/bootstrap/app_bootstrap.test.js +++ b/src/ui/ui_render/bootstrap/app_bootstrap.test.js @@ -23,7 +23,7 @@ import { resolve } from 'path'; const mockTemplate = ` {{appId}} {{bundlePath}} -{{i18n 'foo'}} +{{i18n 'foo' '{"defaultMessage": "bar"}'}} `; const templatePath = resolve(__dirname, 'template.js.hbs'); @@ -131,6 +131,7 @@ describe('ui_render/AppBootstrap', () => { const config2 = { ...mockConfig(), translations: { + locale: 'en', foo: 'not translated foo' } }; @@ -147,6 +148,7 @@ describe('ui_render/AppBootstrap', () => { function mockConfig() { return { translations: { + locale: 'en', foo: 'translated foo' }, templateData: { diff --git a/src/ui/ui_render/bootstrap/template.js.hbs b/src/ui/ui_render/bootstrap/template.js.hbs index ec19aceba3b47..7ab440dac4908 100644 --- a/src/ui/ui_render/bootstrap/template.js.hbs +++ b/src/ui/ui_render/bootstrap/template.js.hbs @@ -33,7 +33,7 @@ window.onload = function () { err.style['text-align'] = 'center'; err.style['background'] = '#F44336'; err.style['padding'] = '25px'; - err.innerText = '{{i18n 'UI-WELCOME_ERROR'}}'; + err.innerText = '{{i18n 'UI-WELCOME_ERROR' '{"defaultMessage": "Kibana did not load properly. Check the server output for more information."}'}}'; document.body.innerHTML = err.outerHTML; } diff --git a/src/ui/ui_render/ui_render_mixin.js b/src/ui/ui_render/ui_render_mixin.js index 87fba7f187162..d9c24452cf8ee 100644 --- a/src/ui/ui_render/ui_render_mixin.js +++ b/src/ui/ui_render/ui_render_mixin.js @@ -17,10 +17,11 @@ * under the License. */ -import { defaults, get } from 'lodash'; +import { defaults } from 'lodash'; import { props, reduce as reduceAsync } from 'bluebird'; import Boom from 'boom'; import { resolve } from 'path'; +import { i18n } from '@kbn/i18n'; import { AppBootstrap } from './bootstrap'; export function uiRenderMixin(kbnServer, server, config) { @@ -142,10 +143,12 @@ export function uiRenderMixin(kbnServer, server, config) { const translations = await request.getUiTranslations(); const basePath = config.get('server.basePath'); + i18n.init(translations); + return reply.view('ui_app', { uiPublicUrl: `${basePath}/ui`, bootstrapScriptUrl: `${basePath}/bundles/app/${app.getId()}/bootstrap.js`, - i18n: key => get(translations, key, ''), + i18n: (id, options) => i18n.translate(id, options), injectedMetadata: { version: kbnServer.version, diff --git a/src/ui/ui_render/views/ui_app.jade b/src/ui/ui_render/views/ui_app.jade index 0726dd785dfdd..7c8b7c2efa74a 100644 --- a/src/ui/ui_render/views/ui_app.jade +++ b/src/ui/ui_render/views/ui_app.jade @@ -108,6 +108,6 @@ block content .kibanaWelcomeLogoCircle .kibanaWelcomeLogo .kibanaWelcomeText - | #{i18n('UI-WELCOME_MESSAGE')} + | #{i18n('UI-WELCOME_MESSAGE', { defaultMessage: 'Loading Kibana' })} script(src=bootstrapScriptUrl) diff --git a/tasks/verify_translations.js b/tasks/verify_translations.js index 6f286267e5861..67666ba65545c 100644 --- a/tasks/verify_translations.js +++ b/tasks/verify_translations.js @@ -17,11 +17,14 @@ * under the License. */ +// TODO: Integrate a new tool for translations checking +// https://github.com/elastic/kibana/pull/19826 +import { i18nLoader } from '@kbn/i18n'; + import { toArray } from 'rxjs/operators'; import { fromRoot, formatListAsProse } from '../src/utils'; import { findPluginSpecs } from '../src/plugin_discovery'; import { collectUiExports } from '../src/ui'; -import { I18n } from '../src/ui/ui_i18n/i18n'; import * as i18nVerify from './utils/i18n_verify_keys'; @@ -65,7 +68,7 @@ async function verifyTranslations(uiExports) { } // get all of the translations from uiExports - const translations = await I18n.getAllTranslationsFromPaths(uiExports.translationPaths); + const translations = await i18nLoader.getAllTranslationsFromPaths(uiExports.translationPaths); const keysWithoutTranslations = Object.entries( i18nVerify.getNonTranslatedKeys(keysUsedInViews, translations) ); diff --git a/yarn.lock b/yarn.lock index 18b520abe3c75..6304318af89cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -145,6 +145,10 @@ version "0.0.0" uid "" +"@kbn/i18n@link:packages/kbn-i18n": + version "0.0.0" + uid "" + "@kbn/plugin-generator@link:packages/kbn-plugin-generator": version "0.0.0" uid "" @@ -565,9 +569,9 @@ abortcontroller-polyfill@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.1.9.tgz#9fefe359fda2e9e0932dc85e6106453ac393b2da" -accept-language-parser@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.2.0.tgz#6a18942acab3f090a4a09590e03101a99fa22bff" +accept-language-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791" accept@2.x.x: version "2.1.4" @@ -6647,6 +6651,26 @@ interpret@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" +intl-format-cache@^2.0.5, intl-format-cache@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316" + +intl-messageformat-parser@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz#b43d45a97468cadbe44331d74bb1e8dea44fc075" + +intl-messageformat@^2.0.0, intl-messageformat@^2.1.0, intl-messageformat@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-2.2.0.tgz#345bcd46de630b7683330c2e52177ff5eab484fc" + dependencies: + intl-messageformat-parser "1.4.0" + +intl-relativeformat@^2.0.0, intl-relativeformat@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/intl-relativeformat/-/intl-relativeformat-2.1.0.tgz#010f1105802251f40ac47d0e3e1a201348a255df" + dependencies: + intl-messageformat "^2.0.0" + into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" @@ -6654,7 +6678,7 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2: +invariant@^2.0.0, invariant@^2.1.1, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: @@ -7804,6 +7828,12 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + dependencies: + minimist "^1.2.0" + jsonfile@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" @@ -10837,6 +10867,15 @@ react-is@^16.3.1: version "16.4.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.1.tgz#d624c4650d2c65dbd52c72622bbf389435d9776e" +react-intl@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-2.4.0.tgz#66c14dc9df9a73b2fbbfbd6021726e80a613eb15" + dependencies: + intl-format-cache "^2.0.5" + intl-messageformat "^2.1.0" + intl-relativeformat "^2.0.0" + invariant "^2.1.1" + react-is@^16.4.0: version "16.4.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.0.tgz#cc9fdc855ac34d2e7d9d2eb7059bbc240d35ffcf"