From d7d21f47e9042e3d86f453504fba279da989b473 Mon Sep 17 00:00:00 2001 From: Kevin Mitchell Date: Tue, 22 Mar 2016 17:41:32 -0400 Subject: [PATCH] Support for universal apps / server-side rendering - Add `loadNamespaces` method that iterates through components, discovering and loading namespaces that are declared using `@translate` - Add `namespaces` property to `Translate` wrapper returned by `@translate`. --- README.md | 22 + react-i18next.js | 2492 ++++++++++++++++++++++++++++++++++++----- react-i18next.min.js | 3 +- src/index.js | 2 + src/loadNamespaces.js | 37 + src/translate.js | 2 + 6 files changed, 2293 insertions(+), 265 deletions(-) create mode 100644 src/loadNamespaces.js diff --git a/README.md b/README.md index 7b95a449f..a8582c004 100644 --- a/README.md +++ b/README.md @@ -114,3 +114,25 @@ function TranslatableView(props) { ) } +``` + +### Universal Rendering + +__loadNamespaces__: Function that will pre-load all namespaces used by your components. Works well with `react-router` `match` function + +__props__: + +- components: Components that need to have namespaces loaded. +- i18n: the i18n instance to load translations into + +```javascript +import { I18nextProvider, loadNamespaces } from 'react-i18next'; +import { match } from 'react-router'; + +match({...matchArguments}, (error, redirectLocation, renderProps) => { + loadNamespaces({ ...renderProps, i18n: i18nInstance }) + .then(()=>{ + // All i18n namespaces required to render this route are loaded + }) +}); +``` diff --git a/react-i18next.js b/react-i18next.js index 75586e4e3..67971c2fd 100644 --- a/react-i18next.js +++ b/react-i18next.js @@ -1,269 +1,2233 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : - typeof define === 'function' && define.amd ? define('react-i18next', ['exports', 'react'], factory) : - (factory((global.react-i18next = global.react-i18next || {}),global.React)); + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : + typeof define === 'function' && define.amd ? define('react-i18next', ['exports', 'react'], factory) : + (factory((global.react-i18next = global.react-i18next || {}),global.React)); }(this, function (exports,React) { 'use strict'; - var React__default = 'default' in React ? React['default'] : React; - - var babelHelpers = {}; - - babelHelpers.classCallCheck = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - }; - - babelHelpers.createClass = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; - }(); - - babelHelpers.extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; - }; - - babelHelpers.inherits = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } - }); - if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; - }; - - babelHelpers.possibleConstructorReturn = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return call && (typeof call === "object" || typeof call === "function") ? call : self; - }; - - babelHelpers; - - function getDisplayName(component) { - return component.displayName || component.name || 'Component'; - } - - function translate(namespaces) { - return function Wrapper(WrappedComponent) { - var t = void 0, - i18n = void 0; - - var Translate = function (_Component) { - babelHelpers.inherits(Translate, _Component); - - function Translate(props, context) { - babelHelpers.classCallCheck(this, Translate); - - var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Translate).call(this, props, context)); - - i18n = context.i18n; - - _this.state = { - i18nLoadedAt: null - }; - return _this; - } - - babelHelpers.createClass(Translate, [{ - key: 'getChildContext', - value: function getChildContext() { - return { t: t }; - } - }, { - key: 'componentWillMount', - value: function componentWillMount() { - this.mounted = true; - i18n.loadNamespaces(namespaces); - t = i18n.getFixedT(null, namespaces); - } - }, { - key: 'componentDidMount', - value: function componentDidMount() { - var _this2 = this; - - this.onI18nChanged = function () { - if (!_this2.mounted) return; - - _this2.setState({ i18nLoadedAt: new Date() }); - }; - - i18n.on('languageChanged loaded', this.onI18nChanged); - } - }, { - key: 'componentWillUnmount', - value: function componentWillUnmount() { - this.mounted = false; - if (this.onI18nChanged) { - i18n.off('languageChanged', this.onI18nChanged); - i18n.off('loaded', this.onI18nChanged); - } - } - }, { - key: 'onI18nChange', - value: function onI18nChange() { - if (!this.mounted) return; - - this.setState({ i18nLoadedAt: new Date() }); - } - }, { - key: 'render', - value: function render() { - var i18nLoadedAt = this.state.i18nLoadedAt; - - return React__default.createElement(WrappedComponent, babelHelpers.extends({}, this.props, { t: t, i18nLoadedAt: i18nLoadedAt })); - } - }]); - return Translate; - }(React.Component); - - Translate.WrappedComponent = WrappedComponent; - - Translate.contextTypes = { - i18n: React.PropTypes.object.isRequired - }; - - Translate.childContextTypes = { - t: React.PropTypes.func.isRequired - }; - - Translate.displayName = 'Translate[' + getDisplayName(WrappedComponent) + ']'; - - return Translate; - }; - } - - var Interpolate = function (_Component) { - babelHelpers.inherits(Interpolate, _Component); - - function Interpolate(props, context) { - babelHelpers.classCallCheck(this, Interpolate); - - var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Interpolate).call(this, props, context)); - - _this.i18n = context.i18n; - _this.t = context.t; - return _this; - } - - babelHelpers.createClass(Interpolate, [{ - key: 'render', - value: function render() { - var _this2 = this; - - var parent = this.props.parent || 'span'; - var REGEXP = this.props.regexp || this.i18n.services.interpolator.regexp; - - var tOpts = babelHelpers.extends({}, this.props.options, { interpolation: { prefix: '#$?', suffix: '?$#' } }); - var format = this.t(this.props.i18nKey, tOpts); - - if (!format || typeof format !== 'string') return React__default.createElement('noscript', null);; - - var children = []; - - format.split(REGEXP).reduce(function (memo, match, index) { - var child; - - if (index % 2 === 0) { - if (match.length === 0) return memo; - child = match; - } else { - child = _this2.props[match]; - } - - memo.push(child); - return memo; - }, children); - - return React__default.createElement.apply(this, [parent, this.props].concat(children)); - } - }]); - return Interpolate; - }(React.Component); - - Interpolate.contextTypes = { - i18n: React.PropTypes.object.isRequired, - t: React.PropTypes.func.isRequired - }; - - var I18nextProvider = function (_Component) { - babelHelpers.inherits(I18nextProvider, _Component); - - function I18nextProvider(props, context) { - babelHelpers.classCallCheck(this, I18nextProvider); - - var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(I18nextProvider).call(this, props, context)); - - _this.i18n = props.i18n; - return _this; - } - - babelHelpers.createClass(I18nextProvider, [{ - key: 'getChildContext', - value: function getChildContext() { - return { i18n: this.i18n }; - } - }, { - key: 'componentWillReceiveProps', - value: function componentWillReceiveProps(nextProps) { - if (this.props.i18n !== nextProps.i18n) { - console.error('[react-i18next][I18nextProvider]does not support changing the i18n object.'); - } - } - }, { - key: 'render', - value: function render() { - var children = this.props.children; - - return React.Children.only(children); - } - }]); - return I18nextProvider; - }(React.Component); - - I18nextProvider.propTypes = { - i18n: React.PropTypes.object.isRequired, - children: React.PropTypes.element.isRequired - }; - - I18nextProvider.childContextTypes = { - i18n: React.PropTypes.object.isRequired - }; - - exports.translate = translate; - exports.Interpolate = Interpolate; - exports.I18nextProvider = I18nextProvider; + var React__default = 'default' in React ? React['default'] : React; + + var babelHelpers = {}; + babelHelpers.typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; + }; + + babelHelpers.classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + babelHelpers.createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + babelHelpers.extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + babelHelpers.inherits = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); + } + + subClass.prototype = Object.create(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; + }; + + babelHelpers.possibleConstructorReturn = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && (typeof call === "object" || typeof call === "function") ? call : self; + }; + + babelHelpers.slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + babelHelpers; + + function getDisplayName(component) { + return component.displayName || component.name || 'Component'; + } + + function translate(namespaces) { + return function Wrapper(WrappedComponent) { + var t = void 0, + i18n = void 0; + + var Translate = function (_Component) { + babelHelpers.inherits(Translate, _Component); + + function Translate(props, context) { + babelHelpers.classCallCheck(this, Translate); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Translate).call(this, props, context)); + + i18n = context.i18n; + + _this.state = { + i18nLoadedAt: null + }; + return _this; + } + + babelHelpers.createClass(Translate, [{ + key: 'getChildContext', + value: function getChildContext() { + return { t: t }; + } + }, { + key: 'componentWillMount', + value: function componentWillMount() { + this.mounted = true; + i18n.loadNamespaces(namespaces); + t = i18n.getFixedT(null, namespaces); + } + }, { + key: 'componentDidMount', + value: function componentDidMount() { + var _this2 = this; + + this.onI18nChanged = function () { + if (!_this2.mounted) return; + + _this2.setState({ i18nLoadedAt: new Date() }); + }; + + i18n.on('languageChanged loaded', this.onI18nChanged); + } + }, { + key: 'componentWillUnmount', + value: function componentWillUnmount() { + this.mounted = false; + if (this.onI18nChanged) { + i18n.off('languageChanged', this.onI18nChanged); + i18n.off('loaded', this.onI18nChanged); + } + } + }, { + key: 'onI18nChange', + value: function onI18nChange() { + if (!this.mounted) return; + + this.setState({ i18nLoadedAt: new Date() }); + } + }, { + key: 'render', + value: function render() { + var i18nLoadedAt = this.state.i18nLoadedAt; + + return React__default.createElement(WrappedComponent, babelHelpers.extends({}, this.props, { t: t, i18nLoadedAt: i18nLoadedAt })); + } + }]); + return Translate; + }(React.Component); + + Translate.WrappedComponent = WrappedComponent; + + Translate.contextTypes = { + i18n: React.PropTypes.object.isRequired + }; + + Translate.childContextTypes = { + t: React.PropTypes.func.isRequired + }; + + Translate.displayName = 'Translate[' + getDisplayName(WrappedComponent) + ']'; + + Translate.namespaces = namespaces; + + return Translate; + }; + } + + var Interpolate = function (_Component) { + babelHelpers.inherits(Interpolate, _Component); + + function Interpolate(props, context) { + babelHelpers.classCallCheck(this, Interpolate); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Interpolate).call(this, props, context)); + + _this.i18n = context.i18n; + _this.t = context.t; + return _this; + } + + babelHelpers.createClass(Interpolate, [{ + key: 'render', + value: function render() { + var _this2 = this; + + var parent = this.props.parent || 'span'; + var REGEXP = this.props.regexp || this.i18n.services.interpolator.regexp; + + var tOpts = babelHelpers.extends({}, this.props.options, { interpolation: { prefix: '#$?', suffix: '?$#' } }); + var format = this.t(this.props.i18nKey, tOpts); + + if (!format || typeof format !== 'string') return React__default.createElement('noscript', null);; + + var children = []; + + format.split(REGEXP).reduce(function (memo, match, index) { + var child; + + if (index % 2 === 0) { + if (match.length === 0) return memo; + child = match; + } else { + child = _this2.props[match]; + } + + memo.push(child); + return memo; + }, children); + + return React__default.createElement.apply(this, [parent, this.props].concat(children)); + } + }]); + return Interpolate; + }(React.Component); + + Interpolate.contextTypes = { + i18n: React.PropTypes.object.isRequired, + t: React.PropTypes.func.isRequired + }; + + var I18nextProvider = function (_Component) { + babelHelpers.inherits(I18nextProvider, _Component); + + function I18nextProvider(props, context) { + babelHelpers.classCallCheck(this, I18nextProvider); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(I18nextProvider).call(this, props, context)); + + _this.i18n = props.i18n; + return _this; + } + + babelHelpers.createClass(I18nextProvider, [{ + key: 'getChildContext', + value: function getChildContext() { + return { i18n: this.i18n }; + } + }, { + key: 'componentWillReceiveProps', + value: function componentWillReceiveProps(nextProps) { + if (this.props.i18n !== nextProps.i18n) { + console.error('[react-i18next][I18nextProvider]does not support changing the i18n object.'); + } + } + }, { + key: 'render', + value: function render() { + var children = this.props.children; + + return React.Children.only(children); + } + }]); + return I18nextProvider; + }(React.Component); + + I18nextProvider.propTypes = { + i18n: React.PropTypes.object.isRequired, + children: React.PropTypes.element.isRequired + }; + + I18nextProvider.childContextTypes = { + i18n: React.PropTypes.object.isRequired + }; + + var consoleLogger = { + type: 'logger', + + log: function log(args) { + this._output('log', args); + }, + warn: function warn(args) { + this._output('warn', args); + }, + error: function error(args) { + this._output('error', args); + }, + _output: function _output(type, args) { + if (console && console[type]) console[type].apply(console, Array.prototype.slice.call(args)); + } + }; + + var Logger = function () { + function Logger(concreteLogger) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + babelHelpers.classCallCheck(this, Logger); + + this.subs = []; + this.init(concreteLogger, options); + } + + babelHelpers.createClass(Logger, [{ + key: 'init', + value: function init(concreteLogger) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + this.prefix = options.prefix || 'i18next:'; + this.logger = concreteLogger || consoleLogger; + this.options = options; + this.debug = options.debug === false ? false : true; + } + }, { + key: 'setDebug', + value: function setDebug(bool) { + this.debug = bool; + this.subs.forEach(function (sub) { + sub.setDebug(bool); + }); + } + }, { + key: 'log', + value: function log() { + this.forward(arguments, 'log', '', true); + } + }, { + key: 'warn', + value: function warn() { + this.forward(arguments, 'warn', '', true); + } + }, { + key: 'error', + value: function error() { + this.forward(arguments, 'error', ''); + } + }, { + key: 'deprecate', + value: function deprecate() { + this.forward(arguments, 'warn', 'WARNING DEPRECATED: ', true); + } + }, { + key: 'forward', + value: function forward(args, lvl, prefix, debugOnly) { + if (debugOnly && !this.debug) return; + if (typeof args[0] === 'string') args[0] = prefix + this.prefix + ' ' + args[0]; + this.logger[lvl](args); + } + }, { + key: 'create', + value: function create(moduleName) { + var sub = new Logger(this.logger, babelHelpers.extends({ prefix: this.prefix + ':' + moduleName + ':' }, this.options)); + this.subs.push(sub); + + return sub; + } + + // createInstance(options = {}) { + // return new Logger(options, callback); + // } + + }]); + return Logger; + }(); + + ; + + var baseLogger = new Logger(); + + var EventEmitter = function () { + function EventEmitter() { + babelHelpers.classCallCheck(this, EventEmitter); + + this.observers = {}; + } + + babelHelpers.createClass(EventEmitter, [{ + key: 'on', + value: function on(events, listener) { + var _this = this; + + events.split(' ').forEach(function (event) { + _this.observers[event] = _this.observers[event] || []; + _this.observers[event].push(listener); + }); + } + }, { + key: 'off', + value: function off(event, listener) { + var _this2 = this; + + if (!this.observers[event]) { + return; + } + + this.observers[event].forEach(function () { + if (!listener) { + delete _this2.observers[event]; + } else { + var index = _this2.observers[event].indexOf(listener); + if (index > -1) { + _this2.observers[event].splice(index, 1); + } + } + }); + } + }, { + key: 'emit', + value: function emit(event) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (this.observers[event]) { + this.observers[event].forEach(function (observer) { + observer.apply(undefined, args); + }); + } + + if (this.observers['*']) { + this.observers['*'].forEach(function (observer) { + var _ref; + + observer.apply(observer, (_ref = [event]).concat.apply(_ref, args)); + }); + } + } + }]); + return EventEmitter; + }(); + + function makeString(object) { + if (object == null) return ''; + return '' + object; + } + + function copy(a, s, t) { + a.forEach(function (m) { + if (s[m]) t[m] = s[m]; + }); + } + + function getLastOfPath(object, path, Empty) { + function cleanKey(key) { + return key && key.indexOf('###') > -1 ? key.replace(/###/g, '.') : key; + } + + var stack = typeof path !== 'string' ? [].concat(path) : path.split('.'); + while (stack.length > 1) { + if (!object) return {}; + + var key = cleanKey(stack.shift()); + if (!object[key] && Empty) object[key] = new Empty(); + object = object[key]; + } + + if (!object) return {}; + return { + obj: object, + k: cleanKey(stack.shift()) + }; + } + + function setPath(object, path, newValue) { + var _getLastOfPath = getLastOfPath(object, path, Object); + + var obj = _getLastOfPath.obj; + var k = _getLastOfPath.k; + + + obj[k] = newValue; + } + + function pushPath(object, path, newValue, concat) { + var _getLastOfPath2 = getLastOfPath(object, path, Object); + + var obj = _getLastOfPath2.obj; + var k = _getLastOfPath2.k; + + + obj[k] = obj[k] || []; + if (concat) obj[k] = obj[k].concat(newValue); + if (!concat) obj[k].push(newValue); + } + + function getPath(object, path) { + var _getLastOfPath3 = getLastOfPath(object, path); + + var obj = _getLastOfPath3.obj; + var k = _getLastOfPath3.k; + + + if (!obj) return undefined; + return obj[k]; + } + + function deepExtend(target, source, overwrite) { + for (var prop in source) { + if (prop in target) { + // If we reached a leaf string in target or source then replace with source or skip depending on the 'overwrite' switch + if (typeof target[prop] === 'string' || target[prop] instanceof String || typeof source[prop] === 'string' || source[prop] instanceof String) { + if (overwrite) target[prop] = source[prop]; + } else { + deepExtend(target[prop], source[prop], overwrite); + } + } else { + target[prop] = source[prop]; + } + }return target; + } + + function regexEscape(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); + } + + /* eslint-disable */ + var _entityMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''', + "/": '/' + }; + /* eslint-enable */ + + function escape(data) { + if (typeof data === 'string') { + return data.replace(/[&<>"'\/]/g, function (s) { + return _entityMap[s]; + }); + } else { + return data; + } + } + + var ResourceStore = function (_EventEmitter) { + babelHelpers.inherits(ResourceStore, _EventEmitter); + + function ResourceStore() { + var data = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var options = arguments.length <= 1 || arguments[1] === undefined ? { ns: ['translation'], defaultNS: 'translation' } : arguments[1]; + babelHelpers.classCallCheck(this, ResourceStore); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(ResourceStore).call(this)); + + _this.data = data; + _this.options = options; + return _this; + } + + babelHelpers.createClass(ResourceStore, [{ + key: 'addNamespaces', + value: function addNamespaces(ns) { + if (this.options.ns.indexOf(ns) < 0) { + this.options.ns.push(ns); + } + } + }, { + key: 'removeNamespaces', + value: function removeNamespaces(ns) { + var index = this.options.ns.indexOf(ns); + if (index > -1) { + this.options.ns.splice(index, 1); + } + } + }, { + key: 'getResource', + value: function getResource(lng, ns, key) { + var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; + + var keySeparator = options.keySeparator || this.options.keySeparator; + if (keySeparator === undefined) keySeparator = '.'; + + var path = [lng, ns]; + if (key && typeof key !== 'string') path = path.concat(key); + if (key && typeof key === 'string') path = path.concat(keySeparator ? key.split(keySeparator) : key); + + if (lng.indexOf('.') > -1) { + path = lng.split('.'); + } + + return getPath(this.data, path); + } + }, { + key: 'addResource', + value: function addResource(lng, ns, key, value) { + var options = arguments.length <= 4 || arguments[4] === undefined ? { silent: false } : arguments[4]; + + var keySeparator = this.options.keySeparator; + if (keySeparator === undefined) keySeparator = '.'; + + var path = [lng, ns]; + if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key); + + if (lng.indexOf('.') > -1) { + path = lng.split('.'); + value = ns; + ns = path[1]; + } + + this.addNamespaces(ns); + + setPath(this.data, path, value); + + if (!options.silent) this.emit('added', lng, ns, key, value); + } + }, { + key: 'addResources', + value: function addResources(lng, ns, resources) { + for (var m in resources) { + if (typeof resources[m] === 'string') this.addResource(lng, ns, m, resources[m], { silent: true }); + } + this.emit('added', lng, ns, resources); + } + }, { + key: 'addResourceBundle', + value: function addResourceBundle(lng, ns, resources, deep, overwrite) { + var path = [lng, ns]; + if (lng.indexOf('.') > -1) { + path = lng.split('.'); + deep = resources; + resources = ns; + ns = path[1]; + } + + this.addNamespaces(ns); + + var pack = getPath(this.data, path) || {}; + + if (deep) { + deepExtend(pack, resources, overwrite); + } else { + pack = babelHelpers.extends({}, pack, resources); + } + + setPath(this.data, path, pack); + + this.emit('added', lng, ns, resources); + } + }, { + key: 'removeResourceBundle', + value: function removeResourceBundle(lng, ns) { + if (this.hasResourceBundle(lng, ns)) { + delete this.data[lng][ns]; + } + this.removeNamespaces(ns); + + this.emit('removed', lng, ns); + } + }, { + key: 'hasResourceBundle', + value: function hasResourceBundle(lng, ns) { + return this.getResource(lng, ns) !== undefined; + } + }, { + key: 'getResourceBundle', + value: function getResourceBundle(lng, ns) { + if (!ns) ns = this.options.defaultNS; + + // TODO: COMPATIBILITY remove extend in v2.1.0 + if (this.options.compatibilityAPI === 'v1') return babelHelpers.extends({}, this.getResource(lng, ns)); + + return this.getResource(lng, ns); + } + }, { + key: 'toJSON', + value: function toJSON() { + return this.data; + } + }]); + return ResourceStore; + }(EventEmitter); + + var postProcessor = { + + processors: {}, + + addPostProcessor: function addPostProcessor(module) { + this.processors[module.name] = module; + }, + handle: function handle(processors, value, key, options, translator) { + var _this = this; + + processors.forEach(function (processor) { + if (_this.processors[processor]) value = _this.processors[processor].process(value, key, options, translator); + }); + + return value; + } + }; + + function convertInterpolation(options) { + + options.interpolation = { + unescapeSuffix: 'HTML' + }; + + options.interpolation.prefix = options.interpolationPrefix || '__'; + options.interpolation.suffix = options.interpolationSuffix || '__'; + options.interpolation.escapeValue = options.escapeInterpolation || false; + + options.interpolation.nestingPrefix = options.reusePrefix || '$t('; + options.interpolation.nestingSuffix = options.reuseSuffix || ')'; + + return options; + } + + function convertAPIOptions(options) { + if (options.resStore) options.resources = options.resStore; + + if (options.ns && options.ns.defaultNs) { + options.defaultNS = options.ns.defaultNs; + options.ns = options.ns.namespaces; + } else { + options.defaultNS = options.ns || 'translation'; + } + + if (options.fallbackToDefaultNS && options.defaultNS) options.fallbackNS = options.defaultNS; + + options.saveMissing = options.sendMissing; + options.saveMissingTo = options.sendMissingTo || 'current'; + options.returnNull = options.fallbackOnNull ? false : true; + options.returnEmptyString = options.fallbackOnEmpty ? false : true; + options.returnObjects = options.returnObjectTrees; + options.joinArrays = '\n'; + + options.returnedObjectHandler = options.objectTreeKeyHandler; + options.parseMissingKeyHandler = options.parseMissingKey; + options.appendNamespaceToMissingKey = true; + + options.nsSeparator = options.nsseparator; + options.keySeparator = options.keyseparator; + + if (options.shortcutFunction === 'sprintf') { + options.overloadTranslationOptionHandler = function (args) { + var values = []; + + for (var i = 1; i < args.length; i++) { + values.push(args[i]); + } + + return { + postProcess: 'sprintf', + sprintf: values + }; + }; + } + + options.whitelist = options.lngWhitelist; + options.preload = options.preload; + if (options.load === 'current') options.load = 'currentOnly'; + if (options.load === 'unspecific') options.load = 'languageOnly'; + + // backend + options.backend = options.backend || {}; + options.backend.loadPath = options.resGetPath || 'locales/__lng__/__ns__.json'; + options.backend.addPath = options.resPostPath || 'locales/add/__lng__/__ns__'; + options.backend.allowMultiLoading = options.dynamicLoad; + + // cache + options.cache = options.cache || {}; + options.cache.prefix = 'res_'; + options.cache.expirationTime = 7 * 24 * 60 * 60 * 1000; + options.cache.enabled = options.useLocalStorage ? true : false; + + options = convertInterpolation(options); + if (options.defaultVariables) options.interpolation.defaultVariables = options.defaultVariables; + + // TODO: deprecation + // if (options.getAsync === false) throw deprecation error + + return options; + } + + function convertJSONOptions(options) { + options = convertInterpolation(options); + options.joinArrays = '\n'; + + return options; + } + + function convertTOptions(options) { + if (options.interpolationPrefix || options.interpolationSuffix || options.escapeInterpolation) { + options = convertInterpolation(options); + } + + options.nsSeparator = options.nsseparator; + options.keySeparator = options.keyseparator; + + options.returnObjects = options.returnObjectTrees; + + return options; + } + + function appendBackwardsAPI(i18n) { + i18n.lng = function () { + baseLogger.deprecate('i18next.lng() can be replaced by i18next.language for detected language or i18next.languages for languages ordered by translation lookup.'); + return i18n.services.languageUtils.toResolveHierarchy(i18n.language)[0]; + }; + + i18n.preload = function (lngs, cb) { + baseLogger.deprecate('i18next.preload() can be replaced with i18next.loadLanguages()'); + i18n.loadLanguages(lngs, cb); + }; + + i18n.setLng = function (lng, options, callback) { + baseLogger.deprecate('i18next.setLng() can be replaced with i18next.changeLanguage() or i18next.getFixedT() to get a translation function with fixed language or namespace.'); + if (typeof options === 'function') { + callback = options; + options = {}; + } + if (!options) options = {}; + + if (options.fixLng === true) { + if (callback) return callback(null, i18n.getFixedT(lng)); + } + + i18n.changeLanguage(lng, callback); + }; + + i18n.addPostProcessor = function (name, fc) { + baseLogger.deprecate('i18next.addPostProcessor() can be replaced by i18next.use({ type: \'postProcessor\', name: \'name\', process: fc })'); + i18n.use({ + type: 'postProcessor', + name: name, + process: fc + }); + }; + } + + var Translator = function (_EventEmitter) { + babelHelpers.inherits(Translator, _EventEmitter); + + function Translator(services) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + babelHelpers.classCallCheck(this, Translator); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Translator).call(this)); + + copy(['resourceStore', 'languageUtils', 'pluralResolver', 'interpolator', 'backendConnector'], services, _this); + + _this.options = options; + _this.logger = baseLogger.create('translator'); + return _this; + } + + babelHelpers.createClass(Translator, [{ + key: 'changeLanguage', + value: function changeLanguage(lng) { + if (lng) this.language = lng; + } + }, { + key: 'exists', + value: function exists(key) { + var options = arguments.length <= 1 || arguments[1] === undefined ? { interpolation: {} } : arguments[1]; + + if (this.options.compatibilityAPI === 'v1') { + options = convertTOptions(options); + } + + return this.resolve(key, options) !== undefined; + } + }, { + key: 'extractFromKey', + value: function extractFromKey(key, options) { + var nsSeparator = options.nsSeparator || this.options.nsSeparator; + if (nsSeparator === undefined) nsSeparator = ':'; + + var namespaces = options.ns || this.options.defaultNS; + if (nsSeparator && key.indexOf(nsSeparator) > -1) { + var parts = key.split(nsSeparator); + namespaces = parts[0]; + key = parts[1]; + } + if (typeof namespaces === 'string') namespaces = [namespaces]; + + return { + key: key, + namespaces: namespaces + }; + } + }, { + key: 'translate', + value: function translate(keys) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + if ((typeof options === 'undefined' ? 'undefined' : babelHelpers.typeof(options)) !== 'object') { + options = this.options.overloadTranslationOptionHandler(arguments); + } else if (this.options.compatibilityAPI === 'v1') { + options = convertTOptions(options); + } + + // non valid keys handling + if (keys === undefined || keys === null || keys === '') return ''; + if (typeof keys === 'number') keys = String(keys); + if (typeof keys === 'string') keys = [keys]; + + // return key on CIMode + var lng = options.lng || this.language; + if (lng && lng.toLowerCase() === 'cimode') return keys[keys.length - 1]; + + // separators + var keySeparator = options.keySeparator || this.options.keySeparator || '.'; + + // get namespace(s) + + var _extractFromKey = this.extractFromKey(keys[keys.length - 1], options); + + var key = _extractFromKey.key; + var namespaces = _extractFromKey.namespaces; + + var namespace = namespaces[namespaces.length - 1]; + + // resolve from store + var res = this.resolve(keys, options); + + var resType = Object.prototype.toString.apply(res); + var noObject = ['[object Number]', '[object Function]', '[object RegExp]']; + var joinArrays = options.joinArrays !== undefined ? options.joinArrays : this.options.joinArrays; + + // object + if (res && typeof res !== 'string' && noObject.indexOf(resType) < 0 && !(joinArrays && resType === '[object Array]')) { + if (!options.returnObjects && !this.options.returnObjects) { + this.logger.warn('accessing an object - but returnObjects options is not enabled!'); + return this.options.returnedObjectHandler ? this.options.returnedObjectHandler(key, res, options) : 'key \'' + key + ' (' + this.language + ')\' returned an object instead of string.'; + } + + var copy = resType === '[object Array]' ? [] : {}; // apply child translation on a copy + + for (var m in res) { + copy[m] = this.translate('' + key + keySeparator + m, babelHelpers.extends({ joinArrays: false, ns: namespaces }, options)); + } + res = copy; + } + // array special treatment + else if (joinArrays && resType === '[object Array]') { + res = res.join(joinArrays); + if (res) res = this.extendTranslation(res, key, options); + } + // string, empty or null + else { + var usedDefault = false, + usedKey = false; + + // fallback value + if (!this.isValidLookup(res) && options.defaultValue) { + usedDefault = true; + res = options.defaultValue; + } + if (!this.isValidLookup(res)) { + usedKey = true; + res = key; + } + + // save missing + if (usedKey || usedDefault) { + this.logger.log('missingKey', lng, namespace, key, res); + + if (this.options.saveMissing) { + var lngs = []; + if (this.options.saveMissingTo === 'fallback' && this.options.fallbackLng && this.options.fallbackLng[0]) { + for (var i = 0; i < this.options.fallbackLng.length; i++) { + lngs.push(this.options.fallbackLng[i]); + } + } else if (this.options.saveMissingTo === 'all') { + lngs = this.languageUtils.toResolveHierarchy(options.lng || this.language); + } else { + //(this.options.saveMissingTo === 'current' || (this.options.saveMissingTo === 'fallback' && this.options.fallbackLng[0] === false) ) { + lngs.push(options.lng || this.language); + } + + if (this.options.missingKeyHandler) { + this.options.missingKeyHandler(lngs, namespace, key, res); + } else if (this.backendConnector && this.backendConnector.saveMissing) { + this.backendConnector.saveMissing(lngs, namespace, key, res); + } + + this.emit('missingKey', lngs, namespace, key, res); + } + } + + // extend + res = this.extendTranslation(res, key, options); + + // append namespace if still key + if (usedKey && res === key && this.options.appendNamespaceToMissingKey) res = namespace + ':' + key; + + // parseMissingKeyHandler + if (usedKey && this.options.parseMissingKeyHandler) res = this.options.parseMissingKeyHandler(res); + } + + // return + return res; + } + }, { + key: 'extendTranslation', + value: function extendTranslation(res, key, options) { + var _this2 = this; + + if (options.interpolation) this.interpolator.init(options); + + // interpolate + var data = options.replace && typeof options.replace !== 'string' ? options.replace : options; + if (this.options.interpolation.defaultVariables) data = babelHelpers.extends({}, this.options.interpolation.defaultVariables, data); + res = this.interpolator.interpolate(res, data); + + // nesting + res = this.interpolator.nest(res, function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return _this2.translate.apply(_this2, args); + }, options); + + if (options.interpolation) this.interpolator.reset(); + + // post process + var postProcess = options.postProcess || this.options.postProcess; + var postProcessorNames = typeof postProcess === 'string' ? [postProcess] : postProcess; + + if (res !== undefined && postProcessorNames && postProcessorNames.length && options.applyPostProcessor !== false) { + res = postProcessor.handle(postProcessorNames, res, key, options, this); + } + + return res; + } + }, { + key: 'resolve', + value: function resolve(keys) { + var _this3 = this; + + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + + var found = void 0; + + if (typeof keys === 'string') keys = [keys]; + + // forEach possible key + keys.forEach(function (k) { + if (_this3.isValidLookup(found)) return; + + var _extractFromKey2 = _this3.extractFromKey(k, options); + + var key = _extractFromKey2.key; + var namespaces = _extractFromKey2.namespaces; + + if (_this3.options.fallbackNS) namespaces = namespaces.concat(_this3.options.fallbackNS); + + var needsPluralHandling = options.count !== undefined && typeof options.count !== 'string'; + var needsContextHandling = options.context !== undefined && typeof options.context === 'string' && options.context !== ''; + + var codes = options.lngs ? options.lngs : _this3.languageUtils.toResolveHierarchy(options.lng || _this3.language); + + namespaces.forEach(function (ns) { + if (_this3.isValidLookup(found)) return; + + codes.forEach(function (code) { + if (_this3.isValidLookup(found)) return; + + var finalKey = key; + var finalKeys = [finalKey]; + + var pluralSuffix = void 0; + if (needsPluralHandling) pluralSuffix = _this3.pluralResolver.getSuffix(code, options.count); + + // fallback for plural if context not found + if (needsPluralHandling && needsContextHandling) finalKeys.push(finalKey + pluralSuffix); + + // get key for context if needed + if (needsContextHandling) finalKeys.push(finalKey += '' + _this3.options.contextSeparator + options.context); + + // get key for plural if needed + if (needsPluralHandling) finalKeys.push(finalKey += pluralSuffix); + + // iterate over finalKeys starting with most specific pluralkey (-> contextkey only) -> singularkey only + var possibleKey = void 0; + while (possibleKey = finalKeys.pop()) { + if (_this3.isValidLookup(found)) continue; + found = _this3.getResource(code, ns, possibleKey, options); + } + }); + }); + }); + + return found; + } + }, { + key: 'isValidLookup', + value: function isValidLookup(res) { + return res !== undefined && !(!this.options.returnNull && res === null) && !(!this.options.returnEmptyString && res === ''); + } + }, { + key: 'getResource', + value: function getResource(code, ns, key) { + var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; + + return this.resourceStore.getResource(code, ns, key, options); + } + }]); + return Translator; + }(EventEmitter); + + var LanguageUtil = function () { + function LanguageUtil(options) { + babelHelpers.classCallCheck(this, LanguageUtil); + + this.options = options; + + this.whitelist = this.options.whitelist || false; + this.logger = baseLogger.create('languageUtils'); + } + + babelHelpers.createClass(LanguageUtil, [{ + key: 'getLanguagePartFromCode', + value: function getLanguagePartFromCode(code) { + if (code.indexOf('-') < 0) return code; + + var specialCases = ['nb-NO', 'nn-NO', 'nb-no', 'nn-no']; + var p = code.split('-'); + return this.formatLanguageCode(specialCases.indexOf(code) > -1 ? p[1].toLowerCase() : p[0]); + } + }, { + key: 'formatLanguageCode', + value: function formatLanguageCode(code) { + if (typeof code === 'string' && code.indexOf('-') > -1) { + var _code$split = code.split('-'); + + var _code$split2 = babelHelpers.slicedToArray(_code$split, 2); + + var head = _code$split2[0]; + var tail = _code$split2[1]; + + return this.options.lowerCaseLng ? head.toLowerCase() + '-' + tail.toLowerCase() : head.toLowerCase() + '-' + tail.toUpperCase(); + } else { + return this.options.cleanCode || this.options.lowerCaseLng ? code.toLowerCase() : code; + } + } + }, { + key: 'isWhitelisted', + value: function isWhitelisted(code) { + if (this.options.load === 'languageOnly') code = this.getLanguagePartFromCode(code); + return !this.whitelist || !this.whitelist.length || this.whitelist.indexOf(code) > -1 ? true : false; + } + }, { + key: 'toResolveHierarchy', + value: function toResolveHierarchy(code, fallbackCode) { + var _this = this; + + fallbackCode = fallbackCode || this.options.fallbackLng || []; + if (typeof fallbackCode === 'string') fallbackCode = [fallbackCode]; + + var codes = []; + var addCode = function addCode(code) { + if (_this.isWhitelisted(code)) { + codes.push(code); + } else { + _this.logger.warn('rejecting non-whitelisted language code: ' + code); + } + }; + + if (typeof code === 'string' && code.indexOf('-') > -1) { + if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code)); + if (this.options.load !== 'currentOnly') addCode(this.getLanguagePartFromCode(code)); + } else if (typeof code === 'string') { + addCode(this.formatLanguageCode(code)); + } + + fallbackCode.forEach(function (fc) { + if (codes.indexOf(fc) < 0) addCode(_this.formatLanguageCode(fc)); + }); + + return codes; + } + }]); + return LanguageUtil; + }(); + + ; + + // definition http://translate.sourceforge.net/wiki/l10n/pluralforms + /* eslint-disable */ + var sets = [{ lngs: ['ach', 'ak', 'am', 'arn', 'br', 'fil', 'gun', 'ln', 'mfe', 'mg', 'mi', 'oc', 'tg', 'ti', 'tr', 'uz', 'wa'], nr: [1, 2], fc: 1 }, { lngs: ['af', 'an', 'ast', 'az', 'bg', 'bn', 'ca', 'da', 'de', 'dev', 'el', 'en', 'eo', 'es', 'es_ar', 'et', 'eu', 'fi', 'fo', 'fur', 'fy', 'gl', 'gu', 'ha', 'he', 'hi', 'hu', 'hy', 'ia', 'it', 'kn', 'ku', 'lb', 'mai', 'ml', 'mn', 'mr', 'nah', 'nap', 'nb', 'ne', 'nl', 'nn', 'no', 'nso', 'pa', 'pap', 'pms', 'ps', 'pt', 'pt_br', 'rm', 'sco', 'se', 'si', 'so', 'son', 'sq', 'sv', 'sw', 'ta', 'te', 'tk', 'ur', 'yo'], nr: [1, 2], fc: 2 }, { lngs: ['ay', 'bo', 'cgg', 'fa', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky', 'lo', 'ms', 'sah', 'su', 'th', 'tt', 'ug', 'vi', 'wo', 'zh'], nr: [1], fc: 3 }, { lngs: ['be', 'bs', 'dz', 'hr', 'ru', 'sr', 'uk'], nr: [1, 2, 5], fc: 4 }, { lngs: ['ar'], nr: [0, 1, 2, 3, 11, 100], fc: 5 }, { lngs: ['cs', 'sk'], nr: [1, 2, 5], fc: 6 }, { lngs: ['csb', 'pl'], nr: [1, 2, 5], fc: 7 }, { lngs: ['cy'], nr: [1, 2, 3, 8], fc: 8 }, { lngs: ['fr'], nr: [1, 2], fc: 9 }, { lngs: ['ga'], nr: [1, 2, 3, 7, 11], fc: 10 }, { lngs: ['gd'], nr: [1, 2, 3, 20], fc: 11 }, { lngs: ['is'], nr: [1, 2], fc: 12 }, { lngs: ['jv'], nr: [0, 1], fc: 13 }, { lngs: ['kw'], nr: [1, 2, 3, 4], fc: 14 }, { lngs: ['lt'], nr: [1, 2, 10], fc: 15 }, { lngs: ['lv'], nr: [1, 2, 0], fc: 16 }, { lngs: ['mk'], nr: [1, 2], fc: 17 }, { lngs: ['mnk'], nr: [0, 1, 2], fc: 18 }, { lngs: ['mt'], nr: [1, 2, 11, 20], fc: 19 }, { lngs: ['or'], nr: [2, 1], fc: 2 }, { lngs: ['ro'], nr: [1, 2, 20], fc: 20 }, { lngs: ['sl'], nr: [5, 1, 2, 3], fc: 21 }]; + + var _rulesPluralsTypes = { + 1: function _(n) { + return Number(n > 1); + }, + 2: function _(n) { + return Number(n != 1); + }, + 3: function _(n) { + return 0; + }, + 4: function _(n) { + return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); + }, + 5: function _(n) { + return Number(n === 0 ? 0 : n == 1 ? 1 : n == 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5); + }, + 6: function _(n) { + return Number(n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2); + }, + 7: function _(n) { + return Number(n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); + }, + 8: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : n != 8 && n != 11 ? 2 : 3); + }, + 9: function _(n) { + return Number(n >= 2); + }, + 10: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4); + }, + 11: function _(n) { + return Number(n == 1 || n == 11 ? 0 : n == 2 || n == 12 ? 1 : n > 2 && n < 20 ? 2 : 3); + }, + 12: function _(n) { + return Number(n % 10 != 1 || n % 100 == 11); + }, + 13: function _(n) { + return Number(n !== 0); + }, + 14: function _(n) { + return Number(n == 1 ? 0 : n == 2 ? 1 : n == 3 ? 2 : 3); + }, + 15: function _(n) { + return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); + }, + 16: function _(n) { + return Number(n % 10 == 1 && n % 100 != 11 ? 0 : n !== 0 ? 1 : 2); + }, + 17: function _(n) { + return Number(n == 1 || n % 10 == 1 ? 0 : 1); + }, + 18: function _(n) { + return Number(n == 0 ? 0 : n == 1 ? 1 : 2); + }, + 19: function _(n) { + return Number(n == 1 ? 0 : n === 0 || n % 100 > 1 && n % 100 < 11 ? 1 : n % 100 > 10 && n % 100 < 20 ? 2 : 3); + }, + 20: function _(n) { + return Number(n == 1 ? 0 : n === 0 || n % 100 > 0 && n % 100 < 20 ? 1 : 2); + }, + 21: function _(n) { + return Number(n % 100 == 1 ? 1 : n % 100 == 2 ? 2 : n % 100 == 3 || n % 100 == 4 ? 3 : 0); + } + }; + /* eslint-enable */ + + var PluralResolver = function () { + function PluralResolver(languageUtils) { + var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; + babelHelpers.classCallCheck(this, PluralResolver); + + this.rules = function () { + var l, + rules = {}; + sets.forEach(function (set) { + set.lngs.forEach(function (l) { + return rules[l] = { + numbers: set.nr, + plurals: _rulesPluralsTypes[set.fc] + }; + }); + }); + return rules; + }(); + + this.languageUtils = languageUtils; + this.options = options; + + this.logger = baseLogger.create('pluralResolver'); + } + + babelHelpers.createClass(PluralResolver, [{ + key: 'addRule', + value: function addRule(lng, obj) { + this.rules[lng] = obj; + } + }, { + key: 'getRule', + value: function getRule(code) { + return this.rules[this.languageUtils.getLanguagePartFromCode(code)]; + } + }, { + key: 'needsPlural', + value: function needsPlural(code) { + var rule = this.getRule(code); + + return rule && rule.numbers.length <= 1 ? false : true; + } + }, { + key: 'getSuffix', + value: function getSuffix(code, count) { + var rule = this.getRule(code); + + if (rule) { + if (rule.numbers.length === 1) return ''; // only singular + + var idx = rule.noAbs ? rule.plurals(count) : rule.plurals(Math.abs(count)); + var suffix = rule.numbers[idx]; + + // special treatment for lngs only having singular and plural + if (rule.numbers.length === 2 && rule.numbers[0] === 1) { + if (suffix === 2) { + suffix = 'plural'; + } else if (suffix === 1) { + suffix = ''; + } + } + + // COMPATIBILITY JSON + if (this.options.compatibilityJSON === 'v1') { + if (suffix === 1) return ''; + if (typeof suffix === 'number') return '_plural_' + suffix.toString(); + } + + return this.options.prepend && suffix.toString() ? this.options.prepend + suffix.toString() : suffix.toString(); + } else { + this.logger.warn('no plural rule found for: ' + code); + return ''; + } + } + }]); + return PluralResolver; + }(); + + ; + + var Interpolator = function () { + function Interpolator() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + babelHelpers.classCallCheck(this, Interpolator); + + this.logger = baseLogger.create('interpolator'); + + this.init(options, true); + } + + babelHelpers.createClass(Interpolator, [{ + key: 'init', + value: function init() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var reset = arguments[1]; + + if (reset) this.options = options; + if (!options.interpolation) options.interpolation = { escapeValue: true }; + + var iOpts = options.interpolation; + + this.escapeValue = iOpts.escapeValue; + + this.prefix = iOpts.prefix ? regexEscape(iOpts.prefix) : iOpts.prefixEscaped || '{{'; + this.suffix = iOpts.suffix ? regexEscape(iOpts.suffix) : iOpts.suffixEscaped || '}}'; + + this.unescapePrefix = iOpts.unescapeSuffix ? '' : iOpts.unescapePrefix || '-'; + this.unescapeSuffix = this.unescapePrefix ? '' : iOpts.unescapeSuffix || ''; + + this.nestingPrefix = iOpts.nestingPrefix ? regexEscape(iOpts.nestingPrefix) : iOpts.nestingPrefixEscaped || regexEscape('$t('); + this.nestingSuffix = iOpts.nestingSuffix ? regexEscape(iOpts.nestingSuffix) : iOpts.nestingSuffixEscaped || regexEscape(')'); + + // the regexp + var regexpStr = this.prefix + '(.+?)' + this.suffix; + this.regexp = new RegExp(regexpStr, 'g'); + + var regexpUnescapeStr = this.prefix + this.unescapePrefix + '(.+?)' + this.unescapeSuffix + this.suffix; + this.regexpUnescape = new RegExp(regexpUnescapeStr, 'g'); + + var nestingRegexpStr = this.nestingPrefix + '(.+?)' + this.nestingSuffix; + this.nestingRegexp = new RegExp(nestingRegexpStr, 'g'); + } + }, { + key: 'reset', + value: function reset() { + if (this.options) this.init(this.options); + } + }, { + key: 'interpolate', + value: function interpolate(str, data) { + var match = void 0, + value = void 0; + + function regexSafe(val) { + return val.replace(/\$/g, '$$$$'); + } + + // unescape if has unescapePrefix/Suffix + while (match = this.regexpUnescape.exec(str)) { + var _value = getPath(data, match[1].trim()); + str = str.replace(match[0], _value); + } + + // regular escape on demand + while (match = this.regexp.exec(str)) { + value = getPath(data, match[1].trim()); + if (typeof value !== 'string') value = makeString(value); + if (!value) { + this.logger.warn('missed to pass in variable ' + match[1] + ' for interpolating ' + str); + value = ''; + } + value = this.escapeValue ? regexSafe(escape(value)) : regexSafe(value); + str = str.replace(match[0], value); + this.regexp.lastIndex = 0; + } + return str; + } + }, { + key: 'nest', + value: function nest(str, fc) { + var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; + + var match = void 0, + value = void 0; + + var clonedOptions = JSON.parse(JSON.stringify(options)); + clonedOptions.applyPostProcessor = false; // avoid post processing on nested lookup + + function regexSafe(val) { + return val.replace(/\$/g, '$$$$'); + } + + // if value is something like "myKey": "lorem $(anotherKey, { "count": {{aValueInOptions}} })" + function handleHasOptions(key) { + if (key.indexOf(',') < 0) return key; + + var p = key.split(','); + key = p.shift(); + var optionsString = p.join(','); + optionsString = this.interpolate(optionsString, clonedOptions); + + try { + clonedOptions = JSON.parse(optionsString); + } catch (e) { + this.logger.error('failed parsing options string in nesting for key ' + key, e); + } + + return key; + } + + // regular escape on demand + while (match = this.nestingRegexp.exec(str)) { + value = fc(handleHasOptions.call(this, match[1].trim()), clonedOptions); + if (typeof value !== 'string') value = makeString(value); + if (!value) { + this.logger.warn('missed to pass in variable ' + match[1] + ' for interpolating ' + str); + value = ''; + } + value = this.escapeValue ? regexSafe(escape(value)) : regexSafe(value); + str = str.replace(match[0], value); + this.regexp.lastIndex = 0; + } + return str; + } + }]); + return Interpolator; + }(); + + function remove(arr, what) { + var found = arr.indexOf(what); + + while (found !== -1) { + arr.splice(found, 1); + found = arr.indexOf(what); + } + } + + var Connector = function (_EventEmitter) { + babelHelpers.inherits(Connector, _EventEmitter); + + function Connector(backend, store, services) { + var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; + babelHelpers.classCallCheck(this, Connector); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Connector).call(this)); + + _this.backend = backend; + _this.store = store; + _this.services = services; + _this.options = options; + _this.logger = baseLogger.create('backendConnector'); + + _this.state = {}; + _this.queue = []; + + _this.backend && _this.backend.init && _this.backend.init(services, options.backend, options); + return _this; + } + + babelHelpers.createClass(Connector, [{ + key: 'queueLoad', + value: function queueLoad(languages, namespaces, callback) { + var _this2 = this; + + // find what needs to be loaded + var toLoad = [], + pending = [], + toLoadLanguages = [], + toLoadNamespaces = []; + + languages.forEach(function (lng) { + var hasAllNamespaces = true; + + namespaces.forEach(function (ns) { + var name = lng + '|' + ns; + + if (_this2.store.hasResourceBundle(lng, ns)) { + _this2.state[name] = 2; // loaded + } else if (_this2.state[name] < 0) { + // nothing to do for err + } else if (_this2.state[name] === 1) { + if (pending.indexOf(name) < 0) pending.push(name); + } else { + _this2.state[name] = 1; // pending + + hasAllNamespaces = false; + + if (pending.indexOf(name) < 0) pending.push(name); + if (toLoad.indexOf(name) < 0) toLoad.push(name); + if (toLoadNamespaces.indexOf(ns) < 0) toLoadNamespaces.push(ns); + } + }); + + if (!hasAllNamespaces) toLoadLanguages.push(lng); + }); + + if (toLoad.length || pending.length) { + this.queue.push({ + pending: pending, + loaded: {}, + errors: [], + callback: callback + }); + } + + return { + toLoad: toLoad, + pending: pending, + toLoadLanguages: toLoadLanguages, + toLoadNamespaces: toLoadNamespaces + }; + } + }, { + key: 'loaded', + value: function loaded(name, err, data) { + var _this3 = this; + + var _name$split = name.split('|'); + + var _name$split2 = babelHelpers.slicedToArray(_name$split, 2); + + var lng = _name$split2[0]; + var ns = _name$split2[1]; + + + if (err) this.emit('failedLoading', lng, ns, err); + + if (data) { + this.store.addResourceBundle(lng, ns, data); + } + + // set loaded + this.state[name] = err ? -1 : 2; + // callback if ready + this.queue.forEach(function (q) { + pushPath(q.loaded, [lng], ns); + remove(q.pending, name); + + if (err) q.errors.push(err); + + if (q.pending.length === 0 && !q.done) { + q.errors.length ? q.callback(q.errors) : q.callback(); + _this3.emit('loaded', q.loaded); + q.done = true; + } + }); + + // remove done load requests + this.queue = this.queue.filter(function (q) { + return !q.done; + }); + } + }, { + key: 'read', + value: function read(lng, ns, fcName, tried, wait, callback) { + var _this4 = this; + + if (!tried) tried = 0; + if (!wait) wait = 250; + + if (!lng.length) return callback(null, {}); // noting to load + + this.backend[fcName](lng, ns, function (err, data) { + if (err && data /* = retryFlag */ && tried < 5) { + setTimeout(function () { + _this4.read.call(_this4, lng, ns, fcName, ++tried, wait * 2, callback); + }, wait); + return; + } + callback(err, data); + }); + } + }, { + key: 'load', + value: function load(languages, namespaces, callback) { + var _this5 = this; + + if (!this.backend) { + this.logger.warn('No backend was added via i18next.use. Will not load resources.'); + return callback && callback(); + } + var options = babelHelpers.extends({}, this.backend.options, this.options.backend); + + if (typeof languages === 'string') languages = this.services.languageUtils.toResolveHierarchy(languages); + if (typeof namespaces === 'string') namespaces = [namespaces]; + + var toLoad = this.queueLoad(languages, namespaces, callback); + if (!toLoad.toLoad.length) { + if (!toLoad.pending.length) callback(); // nothing to load and no pendings...callback now + return; // pendings will trigger callback + } + + // load with multi-load + if (options.allowMultiLoading && this.backend.readMulti) { + this.read(toLoad.toLoadLanguages, toLoad.toLoadNamespaces, 'readMulti', null, null, function (err, data) { + if (err) _this5.logger.warn('loading namespaces ' + toLoad.toLoadNamespaces.join(', ') + ' for languages ' + toLoad.toLoadLanguages.join(', ') + ' via multiloading failed', err); + if (!err && data) _this5.logger.log('loaded namespaces ' + toLoad.toLoadNamespaces.join(', ') + ' for languages ' + toLoad.toLoadLanguages.join(', ') + ' via multiloading', data); + + toLoad.toLoad.forEach(function (name) { + var _name$split3 = name.split('|'); + + var _name$split4 = babelHelpers.slicedToArray(_name$split3, 2); + + var l = _name$split4[0]; + var n = _name$split4[1]; + + + var bundle = getPath(data, [l, n]); + if (bundle) { + _this5.loaded(name, err, bundle); + } else { + var _err = 'loading namespace ' + n + ' for language ' + l + ' via multiloading failed'; + _this5.loaded(name, _err); + _this5.logger.error(_err); + } + }); + }); + } + + // load one by one + else { + (function () { + var read = function read(name) { + var _this6 = this; + + var _name$split5 = name.split('|'); + + var _name$split6 = babelHelpers.slicedToArray(_name$split5, 2); + + var lng = _name$split6[0]; + var ns = _name$split6[1]; + + + this.read(lng, ns, 'read', null, null, function (err, data) { + if (err) _this6.logger.warn('loading namespace ' + ns + ' for language ' + lng + ' failed', err); + if (!err && data) _this6.logger.log('loaded namespace ' + ns + ' for language ' + lng, data); + + _this6.loaded(name, err, data); + }); + }; + + ; + + toLoad.toLoad.forEach(function (name) { + read.call(_this5, name); + }); + })(); + } + } + }, { + key: 'saveMissing', + value: function saveMissing(languages, namespace, key, fallbackValue) { + if (this.backend && this.backend.create) this.backend.create(languages, namespace, key, fallbackValue); + + // write to store to avoid resending + this.store.addResource(languages[0], namespace, key, fallbackValue); + } + }]); + return Connector; + }(EventEmitter); + + var Connector$1 = function (_EventEmitter) { + babelHelpers.inherits(Connector, _EventEmitter); + + function Connector(cache, store, services) { + var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; + babelHelpers.classCallCheck(this, Connector); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(Connector).call(this)); + + _this.cache = cache; + _this.store = store; + _this.services = services; + _this.options = options; + _this.logger = baseLogger.create('cacheConnector'); + + _this.cache && _this.cache.init && _this.cache.init(services, options.cache, options); + return _this; + } + + babelHelpers.createClass(Connector, [{ + key: 'load', + value: function load(languages, namespaces, callback) { + var _this2 = this; + + if (!this.cache) return callback && callback(); + var options = babelHelpers.extends({}, this.cache.options, this.options.cache); + + if (typeof languages === 'string') languages = this.services.languageUtils.toResolveHierarchy(languages); + if (typeof namespaces === 'string') namespaces = [namespaces]; + + if (options.enabled) { + this.cache.load(languages, function (err, data) { + if (err) _this2.logger.error('loading languages ' + languages.join(', ') + ' from cache failed', err); + if (data) { + for (var l in data) { + for (var n in data[l]) { + if (n === 'i18nStamp') continue; + var bundle = data[l][n]; + if (bundle) _this2.store.addResourceBundle(l, n, bundle); + } + } + } + if (callback) callback(); + }); + } else { + if (callback) callback(); + } + } + }, { + key: 'save', + value: function save() { + if (this.cache && this.options.cache && this.options.cache.enabled) this.cache.save(this.store.data); + } + }]); + return Connector; + }(EventEmitter); + + function get() { + return { + debug: false, + + ns: ['translation'], + defaultNS: ['translation'], + fallbackLng: ['dev'], + fallbackNS: false, // string or array of namespaces + + whitelist: false, // array with whitelisted languages + load: 'all', // | currentOnly | languageOnly + preload: false, // array with preload languages + + keySeparator: '.', + nsSeparator: ':', + pluralSeparator: '_', + contextSeparator: '_', + + saveMissing: false, // enable to send missing values + saveMissingTo: 'fallback', // 'current' || 'all' + missingKeyHandler: false, // function(lng, ns, key, fallbackValue) -> override if prefer on handling + + postProcess: false, // string or array of postProcessor names + returnNull: true, // allows null value as valid translation + returnEmptyString: true, // allows empty string value as valid translation + returnObjects: false, + joinArrays: false, // or string to join array + returnedObjectHandler: function returnedObjectHandler() {}, // function(key, value, options) triggered if key returns object but returnObjects is set to false + parseMissingKeyHandler: false, // function(key) parsed a key that was not found in t() before returning + appendNamespaceToMissingKey: false, + overloadTranslationOptionHandler: function overloadTranslationOptionHandler(args) { + return { defaultValue: args[1] }; + }, + + interpolation: { + escapeValue: true, + prefix: '{{', + suffix: '}}', + // prefixEscaped: '{{', + // suffixEscaped: '}}', + // unescapeSuffix: '', + unescapePrefix: '-', + + nestingPrefix: '$t(', + nestingSuffix: ')', + // nestingPrefixEscaped: '$t(', + // nestingSuffixEscaped: ')', + defaultVariables: undefined // object that can have values to interpolate on - extends passed in interpolation data + } + }; + } + + function transformOptions(options) { + // create namespace object if namespace is passed in as string + if (typeof options.ns === 'string') options.ns = [options.ns]; + if (typeof options.fallbackLng === 'string') options.fallbackLng = [options.fallbackLng]; + if (typeof options.fallbackNS === 'string') options.fallbackNS = [options.fallbackNS]; + + // extend whitelist with cimode + if (options.whitelist && options.whitelist.indexOf('cimode') < 0) options.whitelist.push('cimode'); + + return options; + } + + var I18n = function (_EventEmitter) { + babelHelpers.inherits(I18n, _EventEmitter); + + function I18n() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var callback = arguments[1]; + babelHelpers.classCallCheck(this, I18n); + + var _this = babelHelpers.possibleConstructorReturn(this, Object.getPrototypeOf(I18n).call(this)); + + _this.options = transformOptions(options); + _this.services = {}; + _this.logger = baseLogger; + _this.modules = {}; + + if (callback && !_this.isInitialized) _this.init(options, callback); + return _this; + } + + babelHelpers.createClass(I18n, [{ + key: 'init', + value: function init(options, callback) { + var _this2 = this; + + if (typeof options === 'function') { + callback = options; + options = {}; + } + if (!options) options = {}; + + if (options.compatibilityAPI === 'v1') { + this.options = babelHelpers.extends({}, get(), transformOptions(convertAPIOptions(options)), {}); + } else if (options.compatibilityJSON === 'v1') { + this.options = babelHelpers.extends({}, get(), transformOptions(convertJSONOptions(options)), {}); + } else { + this.options = babelHelpers.extends({}, get(), this.options, transformOptions(options)); + } + if (!callback) callback = function callback() {}; + + function createClassOnDemand(ClassOrObject) { + if (!ClassOrObject) return; + if (typeof ClassOrObject === 'function') return new ClassOrObject(); + return ClassOrObject; + } + + // init services + if (!this.options.isClone) { + if (this.modules.logger) { + baseLogger.init(createClassOnDemand(this.modules.logger), this.options); + } else { + baseLogger.init(null, this.options); + } + + var lu = new LanguageUtil(this.options); + this.store = new ResourceStore(this.options.resources, this.options); + + var s = this.services; + s.logger = baseLogger; + s.resourceStore = this.store; + s.resourceStore.on('added removed', function (lng, ns) { + s.cacheConnector.save(); + }); + s.languageUtils = lu; + s.pluralResolver = new PluralResolver(lu, { prepend: this.options.pluralSeparator, compatibilityJSON: this.options.compatibilityJSON }); + s.interpolator = new Interpolator(this.options); + + s.backendConnector = new Connector(createClassOnDemand(this.modules.backend), s.resourceStore, s, this.options); + // pipe events from backendConnector + s.backendConnector.on('*', function (event) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + _this2.emit.apply(_this2, [event].concat(args)); + }); + + s.backendConnector.on('loaded', function (loaded) { + s.cacheConnector.save(); + }); + + s.cacheConnector = new Connector$1(createClassOnDemand(this.modules.cache), s.resourceStore, s, this.options); + // pipe events from backendConnector + s.cacheConnector.on('*', function (event) { + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + _this2.emit.apply(_this2, [event].concat(args)); + }); + + if (this.modules.languageDetector) { + s.languageDetector = createClassOnDemand(this.modules.languageDetector); + s.languageDetector.init(s, this.options.detection, this.options); + } + + this.translator = new Translator(this.services, this.options); + // pipe events from translator + this.translator.on('*', function (event) { + for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { + args[_key3 - 1] = arguments[_key3]; + } + + _this2.emit.apply(_this2, [event].concat(args)); + }); + } + + // append api + var storeApi = ['getResource', 'addResource', 'addResources', 'addResourceBundle', 'removeResourceBundle', 'hasResourceBundle', 'getResourceBundle']; + storeApi.forEach(function (fcName) { + _this2[fcName] = function () { + return this.store[fcName].apply(this.store, arguments); + }; + }); + + // TODO: COMPATIBILITY remove this + if (this.options.compatibilityAPI === 'v1') appendBackwardsAPI(this); + + this.changeLanguage(this.options.lng, function (err, t) { + _this2.emit('initialized', _this2.options); + _this2.logger.log('initialized', _this2.options); + + callback(err, t); + }); + + return this; + } + }, { + key: 'loadResources', + value: function loadResources(callback) { + var _this3 = this; + + if (!callback) callback = function callback() {}; + + if (!this.options.resources) { + var _ret = function () { + if (_this3.language && _this3.language.toLowerCase() === 'cimode') return { + v: callback() + }; // avoid loading resources for cimode + + var toLoad = []; + + var append = function append(lng) { + var lngs = _this3.services.languageUtils.toResolveHierarchy(lng); + lngs.forEach(function (l) { + if (toLoad.indexOf(l) < 0) toLoad.push(l); + }); + }; + + append(_this3.language); + + if (_this3.options.preload) { + _this3.options.preload.forEach(function (l) { + append(l); + }); + } + + _this3.services.cacheConnector.load(toLoad, _this3.options.ns, function () { + _this3.services.backendConnector.load(toLoad, _this3.options.ns, callback); + }); + }(); + + if ((typeof _ret === 'undefined' ? 'undefined' : babelHelpers.typeof(_ret)) === "object") return _ret.v; + } else { + callback(null); + } + } + }, { + key: 'use', + value: function use(module) { + if (module.type === 'backend') { + this.modules.backend = module; + } + + if (module.type === 'cache') { + this.modules.cache = module; + } + + if (module.type === 'logger' || module.log && module.warn && module.warn) { + this.modules.logger = module; + } + + if (module.type === 'languageDetector') { + this.modules.languageDetector = module; + } + + if (module.type === 'postProcessor') { + postProcessor.addPostProcessor(module); + } + + return this; + } + }, { + key: 'changeLanguage', + value: function changeLanguage(lng, callback) { + var _this4 = this; + + var done = function done(err) { + if (lng) { + _this4.emit('languageChanged', lng); + _this4.logger.log('languageChanged', lng); + } + + if (callback) callback(err, function () { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + return _this4.t.apply(_this4, args); + }); + }; + + if (!lng && this.services.languageDetector) lng = this.services.languageDetector.detect(); + + if (lng) { + this.language = lng; + this.languages = this.services.languageUtils.toResolveHierarchy(lng); + + this.translator.changeLanguage(lng); + + if (this.services.languageDetector) this.services.languageDetector.cacheUserLanguage(lng); + } + + this.loadResources(function (err) { + done(err); + }); + } + }, { + key: 'getFixedT', + value: function getFixedT(lng, ns) { + var _this5 = this; + + var fixedT = function fixedT(key, options) { + options = options || {}; + options.lng = options.lng || fixedT.lng; + options.ns = options.ns || fixedT.ns; + return _this5.t(key, options); + }; + fixedT.lng = lng; + fixedT.ns = ns; + return fixedT; + } + }, { + key: 't', + value: function t() { + return this.translator && this.translator.translate.apply(this.translator, arguments); + } + }, { + key: 'exists', + value: function exists() { + return this.translator && this.translator.exists.apply(this.translator, arguments); + } + }, { + key: 'setDefaultNamespace', + value: function setDefaultNamespace(ns) { + this.options.defaultNS = ns; + } + }, { + key: 'loadNamespaces', + value: function loadNamespaces(ns, callback) { + var _this6 = this; + + if (!this.options.ns) return callback && callback(); + if (typeof ns === 'string') ns = [ns]; + + ns.forEach(function (n) { + if (_this6.options.ns.indexOf(n) < 0) _this6.options.ns.push(n); + }); + + this.loadResources(callback); + } + }, { + key: 'loadLanguages', + value: function loadLanguages(lngs, callback) { + if (typeof lngs === 'string') lngs = [lngs]; + this.options.preload = this.options.preload ? this.options.preload.concat(lngs) : lngs; + + this.loadResources(callback); + } + }, { + key: 'dir', + value: function dir(lng) { + if (!lng) lng = this.language; + + var ltrLngs = ['ar', 'shu', 'sqr', 'ssh', 'xaa', 'yhd', 'yud', 'aao', 'abh', 'abv', 'acm', 'acq', 'acw', 'acx', 'acy', 'adf', 'ads', 'aeb', 'aec', 'afb', 'ajp', 'apc', 'apd', 'arb', 'arq', 'ars', 'ary', 'arz', 'auz', 'avl', 'ayh', 'ayl', 'ayn', 'ayp', 'bbz', 'pga', 'he', 'iw', 'ps', 'pbt', 'pbu', 'pst', 'prp', 'prd', 'ur', 'ydd', 'yds', 'yih', 'ji', 'yi', 'hbo', 'men', 'xmn', 'fa', 'jpr', 'peo', 'pes', 'prs', 'dv', 'sam']; + + return ltrLngs.indexOf(this.services.languageUtils.getLanguagePartFromCode(lng)) ? 'ltr' : 'rtl'; + } + }, { + key: 'createInstance', + value: function createInstance() { + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var callback = arguments[1]; + + return new I18n(options, callback); + } + }, { + key: 'cloneInstance', + value: function cloneInstance() { + var _this7 = this; + + var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; + var callback = arguments[1]; + + var clone = new I18n(babelHelpers.extends({}, options, this.options, { isClone: true }), callback); + var membersToCopy = ['store', 'translator', 'services', 'language']; + membersToCopy.forEach(function (m) { + clone[m] = _this7[m]; + }); + + return clone; + } + }]); + return I18n; + }(EventEmitter); + + new I18n(); + + // Borrowed from https://github.com/Rezonans/redux-async-connect/blob/master/modules/ReduxAsyncConnect.js#L16 + function eachComponents(components, iterator) { + for (var i = 0, l = components.length; i < l; i++) { + // eslint-disable-line id-length + if (babelHelpers.typeof(components[i]) === 'object') { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = Object.entries(components[i])[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var _step$value = babelHelpers.slicedToArray(_step.value, 2); + + var key = _step$value[0]; + var value = _step$value[1]; + + iterator(value, i, key); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + } else { + iterator(components[i], i); + } + } + } + + function filterAndFlattenComponents(components) { + var flattened = []; + eachComponents(components, function (Component) { + if (Component && Component.namespaces) { + + Component.namespaces.forEach(function (namespace) { + if (flattened.indexOf(namespace) === -1) { + flattened.push(namespace); + } + }); + } + }); + return flattened; + } + + function loadNamespaces(_ref) { + var components = _ref.components; + var i18n = _ref.i18n; + + var allNamespaces = filterAndFlattenComponents(components); + + return new Promise(function (resolve) { + i18n.loadNamespaces(allNamespaces, resolve); + }); + } + + exports.loadNamespaces = loadNamespaces; + exports.translate = translate; + exports.Interpolate = Interpolate; + exports.I18nextProvider = I18nextProvider; })); \ No newline at end of file diff --git a/react-i18next.min.js b/react-i18next.min.js index 224a4c3fc..7ad141f3f 100644 --- a/react-i18next.min.js +++ b/react-i18next.min.js @@ -1 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define("react-i18next",["exports","react"],t):t(e.react-i18next=e.react-i18next||{},e.React)}(this,function(e,t){"use strict";function n(e){return e.displayName||e.name||"Component"}function r(e){return function(r){var s=void 0,a=void 0,u=function(t){function n(e,t){i.classCallCheck(this,n);var r=i.possibleConstructorReturn(this,Object.getPrototypeOf(n).call(this,e,t));return a=t.i18n,r.state={i18nLoadedAt:null},r}return i.inherits(n,t),i.createClass(n,[{key:"getChildContext",value:function(){return{t:s}}},{key:"componentWillMount",value:function(){this.mounted=!0,a.loadNamespaces(e),s=a.getFixedT(null,e)}},{key:"componentDidMount",value:function(){var e=this;this.onI18nChanged=function(){e.mounted&&e.setState({i18nLoadedAt:new Date})},a.on("languageChanged loaded",this.onI18nChanged)}},{key:"componentWillUnmount",value:function(){this.mounted=!1,this.onI18nChanged&&(a.off("languageChanged",this.onI18nChanged),a.off("loaded",this.onI18nChanged))}},{key:"onI18nChange",value:function(){this.mounted&&this.setState({i18nLoadedAt:new Date})}},{key:"render",value:function(){var e=this.state.i18nLoadedAt;return o.createElement(r,i["extends"]({},this.props,{t:s,i18nLoadedAt:e}))}}]),n}(t.Component);return u.WrappedComponent=r,u.contextTypes={i18n:t.PropTypes.object.isRequired},u.childContextTypes={t:t.PropTypes.func.isRequired},u.displayName="Translate["+n(r)+"]",u}}var o="default"in t?t["default"]:t,i={};i.classCallCheck=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},i.createClass=function(){function e(e,t){for(var n=0;n-1?e.replace(/###/g,"."):e}for(var i="string"!=typeof t?[].concat(t):t.split(".");i.length>1;){if(!e)return{};var o=r(i.shift());!e[o]&&n&&(e[o]=new n),e=e[o]}return e?{obj:e,k:r(i.shift())}:{}}function a(e,t,n){var r=s(e,t,Object),i=r.obj,o=r.k;i[o]=n}function l(e,t,n,r){var i=s(e,t,Object),o=i.obj,a=i.k;o[a]=o[a]||[],r&&(o[a]=o[a].concat(n)),r||o[a].push(n)}function u(e,t){var n=s(e,t),r=n.obj,i=n.k;return r?r[i]:void 0}function c(e,t,n){for(var r in t)r in e?"string"==typeof e[r]||e[r]instanceof String||"string"==typeof t[r]||t[r]instanceof String?n&&(e[r]=t[r]):c(e[r],t[r],n):e[r]=t[r];return e}function f(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function p(e){return"string"==typeof e?e.replace(/[&<>"'\/]/g,function(e){return E[e]}):e}function h(e){return e.interpolation={unescapeSuffix:"HTML"},e.interpolation.prefix=e.interpolationPrefix||"__",e.interpolation.suffix=e.interpolationSuffix||"__",e.interpolation.escapeValue=e.escapeInterpolation||!1,e.interpolation.nestingPrefix=e.reusePrefix||"$t(",e.interpolation.nestingSuffix=e.reuseSuffix||")",e}function d(e){return e.resStore&&(e.resources=e.resStore),e.ns&&e.ns.defaultNs?(e.defaultNS=e.ns.defaultNs,e.ns=e.ns.namespaces):e.defaultNS=e.ns||"translation",e.fallbackToDefaultNS&&e.defaultNS&&(e.fallbackNS=e.defaultNS),e.saveMissing=e.sendMissing,e.saveMissingTo=e.sendMissingTo||"current",e.returnNull=!e.fallbackOnNull,e.returnEmptyString=!e.fallbackOnEmpty,e.returnObjects=e.returnObjectTrees,e.joinArrays="\n",e.returnedObjectHandler=e.objectTreeKeyHandler,e.parseMissingKeyHandler=e.parseMissingKey,e.appendNamespaceToMissingKey=!0,e.nsSeparator=e.nsseparator,e.keySeparator=e.keyseparator,"sprintf"===e.shortcutFunction&&(e.overloadTranslationOptionHandler=function(e){for(var t=[],n=1;nn;n++)if("object"===w["typeof"](e[n])){var i=!0,o=!1,s=void 0;try{for(var a,l=Object.entries(e[n])[Symbol.iterator]();!(i=(a=l.next()).done);i=!0){var u=w.slicedToArray(a.value,2),c=u[0],f=u[1];t(f,n,c)}}catch(p){o=!0,s=p}finally{try{!i&&l["return"]&&l["return"]()}finally{if(o)throw s}}}else t(e[n],n)}function C(e){var t=[];return x(e,function(e){e&&e.namespaces&&e.namespaces.forEach(function(e){-1===t.indexOf(e)&&t.push(e)})}),t}function S(e){var t=e.components,n=e.i18n,r=C(t);return new Promise(function(e){n.loadNamespaces(r,e)})}var O="default"in t?t["default"]:t,w={};w["typeof"]="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},w.classCallCheck=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},w.createClass=function(){function e(e,t){for(var n=0;n-1&&n.observers[e].splice(r,1)}else delete n.observers[e]})}},{key:"emit",value:function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;t>r;r++)n[r-1]=arguments[r];this.observers[e]&&this.observers[e].forEach(function(e){e.apply(void 0,n)}),this.observers["*"]&&this.observers["*"].forEach(function(t){var r;t.apply(t,(r=[e]).concat.apply(r,n))})}}]),e}(),E={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},A=function(e){function t(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=arguments.length<=1||void 0===arguments[1]?{ns:["translation"],defaultNS:"translation"}:arguments[1];w.classCallCheck(this,t);var r=w.possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this));return r.data=e,r.options=n,r}return w.inherits(t,e),w.createClass(t,[{key:"addNamespaces",value:function(e){this.options.ns.indexOf(e)<0&&this.options.ns.push(e)}},{key:"removeNamespaces",value:function(e){var t=this.options.ns.indexOf(e);t>-1&&this.options.ns.splice(t,1)}},{key:"getResource",value:function(e,t,n){var r=arguments.length<=3||void 0===arguments[3]?{}:arguments[3],i=r.keySeparator||this.options.keySeparator;void 0===i&&(i=".");var o=[e,t];return n&&"string"!=typeof n&&(o=o.concat(n)),n&&"string"==typeof n&&(o=o.concat(i?n.split(i):n)),e.indexOf(".")>-1&&(o=e.split(".")),u(this.data,o)}},{key:"addResource",value:function(e,t,n,r){var i=arguments.length<=4||void 0===arguments[4]?{silent:!1}:arguments[4],o=this.options.keySeparator;void 0===o&&(o=".");var s=[e,t];n&&(s=s.concat(o?n.split(o):n)),e.indexOf(".")>-1&&(s=e.split("."),r=t,t=s[1]),this.addNamespaces(t),a(this.data,s,r),i.silent||this.emit("added",e,t,n,r)}},{key:"addResources",value:function(e,t,n){for(var r in n)"string"==typeof n[r]&&this.addResource(e,t,r,n[r],{silent:!0});this.emit("added",e,t,n)}},{key:"addResourceBundle",value:function(e,t,n,r,i){var o=[e,t];e.indexOf(".")>-1&&(o=e.split("."),r=n,n=t,t=o[1]),this.addNamespaces(t);var s=u(this.data,o)||{};r?c(s,n,i):s=w["extends"]({},s,n),a(this.data,o,s),this.emit("added",e,t,n)}},{key:"removeResourceBundle",value:function(e,t){this.hasResourceBundle(e,t)&&delete this.data[e][t],this.removeNamespaces(t),this.emit("removed",e,t)}},{key:"hasResourceBundle",value:function(e,t){return void 0!==this.getResource(e,t)}},{key:"getResourceBundle",value:function(e,t){return t||(t=this.options.defaultNS),"v1"===this.options.compatibilityAPI?w["extends"]({},this.getResource(e,t)):this.getResource(e,t)}},{key:"toJSON",value:function(){return this.data}}]),t}(T),_={processors:{},addPostProcessor:function(e){this.processors[e.name]=e},handle:function(e,t,n,r,i){var o=this;return e.forEach(function(e){o.processors[e]&&(t=o.processors[e].process(t,n,r,i))}),t}},M=function(e){function t(e){var n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];w.classCallCheck(this,t);var r=w.possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this));return o(["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector"],e,r),r.options=n,r.logger=R.create("translator"),r}return w.inherits(t,e),w.createClass(t,[{key:"changeLanguage",value:function(e){e&&(this.language=e)}},{key:"exists",value:function(e){var t=arguments.length<=1||void 0===arguments[1]?{interpolation:{}}:arguments[1];return"v1"===this.options.compatibilityAPI&&(t=v(t)),void 0!==this.resolve(e,t)}},{key:"extractFromKey",value:function(e,t){var n=t.nsSeparator||this.options.nsSeparator;void 0===n&&(n=":");var r=t.ns||this.options.defaultNS;if(n&&e.indexOf(n)>-1){var i=e.split(n);r=i[0],e=i[1]}return"string"==typeof r&&(r=[r]),{key:e,namespaces:r}}},{key:"translate",value:function(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];if("object"!==("undefined"==typeof t?"undefined":w["typeof"](t))?t=this.options.overloadTranslationOptionHandler(arguments):"v1"===this.options.compatibilityAPI&&(t=v(t)),void 0===e||null===e||""===e)return"";"number"==typeof e&&(e=String(e)),"string"==typeof e&&(e=[e]);var n=t.lng||this.language;if(n&&"cimode"===n.toLowerCase())return e[e.length-1];var r=t.keySeparator||this.options.keySeparator||".",i=this.extractFromKey(e[e.length-1],t),o=i.key,s=i.namespaces,a=s[s.length-1],l=this.resolve(e,t),u=Object.prototype.toString.apply(l),c=["[object Number]","[object Function]","[object RegExp]"],f=void 0!==t.joinArrays?t.joinArrays:this.options.joinArrays;if(l&&"string"!=typeof l&&c.indexOf(u)<0&&(!f||"[object Array]"!==u)){if(!t.returnObjects&&!this.options.returnObjects)return this.logger.warn("accessing an object - but returnObjects options is not enabled!"),this.options.returnedObjectHandler?this.options.returnedObjectHandler(o,l,t):"key '"+o+" ("+this.language+")' returned an object instead of string.";var p="[object Array]"===u?[]:{};for(var h in l)p[h]=this.translate(""+o+r+h,w["extends"]({joinArrays:!1,ns:s},t));l=p}else if(f&&"[object Array]"===u)l=l.join(f),l&&(l=this.extendTranslation(l,o,t));else{var d=!1,g=!1;if(!this.isValidLookup(l)&&t.defaultValue&&(d=!0,l=t.defaultValue),this.isValidLookup(l)||(g=!0,l=o),(g||d)&&(this.logger.log("missingKey",n,a,o,l),this.options.saveMissing)){var y=[];if("fallback"===this.options.saveMissingTo&&this.options.fallbackLng&&this.options.fallbackLng[0])for(var b=0;bn;n++)t[n]=arguments[n];return r.translate.apply(r,t)},n),n.interpolation&&this.interpolator.reset();var o=n.postProcess||this.options.postProcess,s="string"==typeof o?[o]:o;return void 0!==e&&s&&s.length&&n.applyPostProcessor!==!1&&(e=_.handle(s,e,t,n,this)),e}},{key:"resolve",value:function(e){var t=this,n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1],r=void 0;return"string"==typeof e&&(e=[e]),e.forEach(function(e){if(!t.isValidLookup(r)){var i=t.extractFromKey(e,n),o=i.key,s=i.namespaces;t.options.fallbackNS&&(s=s.concat(t.options.fallbackNS));var a=void 0!==n.count&&"string"!=typeof n.count,l=void 0!==n.context&&"string"==typeof n.context&&""!==n.context,u=n.lngs?n.lngs:t.languageUtils.toResolveHierarchy(n.lng||t.language);s.forEach(function(e){t.isValidLookup(r)||u.forEach(function(i){if(!t.isValidLookup(r)){var s=o,u=[s],c=void 0;a&&(c=t.pluralResolver.getSuffix(i,n.count)),a&&l&&u.push(s+c),l&&u.push(s+=""+t.options.contextSeparator+n.context),a&&u.push(s+=c);for(var f=void 0;f=u.pop();)t.isValidLookup(r)||(r=t.getResource(i,e,f,n))}})})}}),r}},{key:"isValidLookup",value:function(e){return!(void 0===e||!this.options.returnNull&&null===e||!this.options.returnEmptyString&&""===e)}},{key:"getResource",value:function(e,t,n){var r=arguments.length<=3||void 0===arguments[3]?{}:arguments[3];return this.resourceStore.getResource(e,t,n,r)}}]),t}(T),H=function(){function e(t){w.classCallCheck(this,e),this.options=t,this.whitelist=this.options.whitelist||!1,this.logger=R.create("languageUtils")}return w.createClass(e,[{key:"getLanguagePartFromCode",value:function(e){if(e.indexOf("-")<0)return e;var t=["nb-NO","nn-NO","nb-no","nn-no"],n=e.split("-");return this.formatLanguageCode(t.indexOf(e)>-1?n[1].toLowerCase():n[0])}},{key:"formatLanguageCode",value:function(e){if("string"==typeof e&&e.indexOf("-")>-1){var t=e.split("-"),n=w.slicedToArray(t,2),r=n[0],i=n[1];return this.options.lowerCaseLng?r.toLowerCase()+"-"+i.toLowerCase():r.toLowerCase()+"-"+i.toUpperCase()}return this.options.cleanCode||this.options.lowerCaseLng?e.toLowerCase():e}},{key:"isWhitelisted",value:function(e){return"languageOnly"===this.options.load&&(e=this.getLanguagePartFromCode(e)),!this.whitelist||!this.whitelist.length||this.whitelist.indexOf(e)>-1}},{key:"toResolveHierarchy",value:function(e,t){var n=this;t=t||this.options.fallbackLng||[],"string"==typeof t&&(t=[t]);var r=[],i=function(e){n.isWhitelisted(e)?r.push(e):n.logger.warn("rejecting non-whitelisted language code: "+e)};return"string"==typeof e&&e.indexOf("-")>-1?("languageOnly"!==this.options.load&&i(this.formatLanguageCode(e)),"currentOnly"!==this.options.load&&i(this.getLanguagePartFromCode(e))):"string"==typeof e&&i(this.formatLanguageCode(e)),t.forEach(function(e){r.indexOf(e)<0&&i(n.formatLanguageCode(e))}),r}}]),e}(),I=[{lngs:["ach","ak","am","arn","br","fil","gun","ln","mfe","mg","mi","oc","tg","ti","tr","uz","wa"],nr:[1,2],fc:1},{lngs:["af","an","ast","az","bg","bn","ca","da","de","dev","el","en","eo","es","es_ar","et","eu","fi","fo","fur","fy","gl","gu","ha","he","hi","hu","hy","ia","it","kn","ku","lb","mai","ml","mn","mr","nah","nap","nb","ne","nl","nn","no","nso","pa","pap","pms","ps","pt","pt_br","rm","sco","se","si","so","son","sq","sv","sw","ta","te","tk","ur","yo"],nr:[1,2],fc:2},{lngs:["ay","bo","cgg","fa","id","ja","jbo","ka","kk","km","ko","ky","lo","ms","sah","su","th","tt","ug","vi","wo","zh"],nr:[1],fc:3},{lngs:["be","bs","dz","hr","ru","sr","uk"],nr:[1,2,5],fc:4},{lngs:["ar"],nr:[0,1,2,3,11,100],fc:5},{lngs:["cs","sk"],nr:[1,2,5],fc:6},{lngs:["csb","pl"],nr:[1,2,5],fc:7},{lngs:["cy"],nr:[1,2,3,8],fc:8},{lngs:["fr"],nr:[1,2],fc:9},{lngs:["ga"],nr:[1,2,3,7,11],fc:10},{lngs:["gd"],nr:[1,2,3,20],fc:11},{lngs:["is"],nr:[1,2],fc:12},{lngs:["jv"],nr:[0,1],fc:13},{lngs:["kw"],nr:[1,2,3,4],fc:14},{lngs:["lt"],nr:[1,2,10],fc:15},{lngs:["lv"],nr:[1,2,0],fc:16},{lngs:["mk"],nr:[1,2],fc:17},{lngs:["mnk"],nr:[0,1,2],fc:18},{lngs:["mt"],nr:[1,2,11,20],fc:19},{lngs:["or"],nr:[2,1],fc:2},{lngs:["ro"],nr:[1,2,20],fc:20},{lngs:["sl"],nr:[5,1,2,3],fc:21}],V={1:function(e){return Number(e>1)},2:function(e){return Number(1!=e)},3:function(e){return 0},4:function(e){return Number(e%10==1&&e%100!=11?0:e%10>=2&&4>=e%10&&(10>e%100||e%100>=20)?1:2)},5:function(e){return Number(0===e?0:1==e?1:2==e?2:e%100>=3&&10>=e%100?3:e%100>=11?4:5)},6:function(e){return Number(1==e?0:e>=2&&4>=e?1:2)},7:function(e){return Number(1==e?0:e%10>=2&&4>=e%10&&(10>e%100||e%100>=20)?1:2)},8:function(e){return Number(1==e?0:2==e?1:8!=e&&11!=e?2:3)},9:function(e){return Number(e>=2)},10:function(e){return Number(1==e?0:2==e?1:7>e?2:11>e?3:4)},11:function(e){return Number(1==e||11==e?0:2==e||12==e?1:e>2&&20>e?2:3)},12:function(e){return Number(e%10!=1||e%100==11)},13:function(e){return Number(0!==e)},14:function(e){return Number(1==e?0:2==e?1:3==e?2:3)},15:function(e){return Number(e%10==1&&e%100!=11?0:e%10>=2&&(10>e%100||e%100>=20)?1:2)},16:function(e){return Number(e%10==1&&e%100!=11?0:0!==e?1:2)},17:function(e){return Number(1==e||e%10==1?0:1)},18:function(e){return Number(0==e?0:1==e?1:2)},19:function(e){return Number(1==e?0:0===e||e%100>1&&11>e%100?1:e%100>10&&20>e%100?2:3)},20:function(e){return Number(1==e?0:0===e||e%100>0&&20>e%100?1:2)},21:function(e){return Number(e%100==1?1:e%100==2?2:e%100==3||e%100==4?3:0)}},q=function(){function e(t){var n=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];w.classCallCheck(this,e),this.rules=function(){var e={};return I.forEach(function(t){t.lngs.forEach(function(n){return e[n]={numbers:t.nr,plurals:V[t.fc]}})}),e}(),this.languageUtils=t,this.options=n,this.logger=R.create("pluralResolver")}return w.createClass(e,[{key:"addRule",value:function(e,t){this.rules[e]=t}},{key:"getRule",value:function(e){return this.rules[this.languageUtils.getLanguagePartFromCode(e)]}},{key:"needsPlural",value:function(e){var t=this.getRule(e);return!(t&&t.numbers.length<=1)}},{key:"getSuffix",value:function(e,t){var n=this.getRule(e);if(n){if(1===n.numbers.length)return"";var r=n.noAbs?n.plurals(t):n.plurals(Math.abs(t)),i=n.numbers[r];if(2===n.numbers.length&&1===n.numbers[0]&&(2===i?i="plural":1===i&&(i="")),"v1"===this.options.compatibilityJSON){if(1===i)return"";if("number"==typeof i)return"_plural_"+i.toString()}return this.options.prepend&&i.toString()?this.options.prepend+i.toString():i.toString()}return this.logger.warn("no plural rule found for: "+e),""}}]),e}(),D=function(){function e(){var t=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];w.classCallCheck(this,e),this.logger=R.create("interpolator"),this.init(t,!0)}return w.createClass(e,[{key:"init",value:function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],t=arguments[1];t&&(this.options=e),e.interpolation||(e.interpolation={escapeValue:!0});var n=e.interpolation;this.escapeValue=n.escapeValue,this.prefix=n.prefix?f(n.prefix):n.prefixEscaped||"{{",this.suffix=n.suffix?f(n.suffix):n.suffixEscaped||"}}",this.unescapePrefix=n.unescapeSuffix?"":n.unescapePrefix||"-",this.unescapeSuffix=this.unescapePrefix?"":n.unescapeSuffix||"",this.nestingPrefix=n.nestingPrefix?f(n.nestingPrefix):n.nestingPrefixEscaped||f("$t("),this.nestingSuffix=n.nestingSuffix?f(n.nestingSuffix):n.nestingSuffixEscaped||f(")");var r=this.prefix+"(.+?)"+this.suffix;this.regexp=new RegExp(r,"g");var i=this.prefix+this.unescapePrefix+"(.+?)"+this.unescapeSuffix+this.suffix;this.regexpUnescape=new RegExp(i,"g");var o=this.nestingPrefix+"(.+?)"+this.nestingSuffix;this.nestingRegexp=new RegExp(o,"g")}},{key:"reset",value:function(){this.options&&this.init(this.options)}},{key:"interpolate",value:function(e,t){function n(e){return e.replace(/\$/g,"$$$$")}for(var r=void 0,o=void 0;r=this.regexpUnescape.exec(e);){var s=u(t,r[1].trim());e=e.replace(r[0],s)}for(;r=this.regexp.exec(e);)o=u(t,r[1].trim()),"string"!=typeof o&&(o=i(o)),o||(this.logger.warn("missed to pass in variable "+r[1]+" for interpolating "+e),o=""),o=n(this.escapeValue?p(o):o),e=e.replace(r[0],o),this.regexp.lastIndex=0;return e}},{key:"nest",value:function(e,t){function n(e){return e.replace(/\$/g,"$$$$")}function r(e){if(e.indexOf(",")<0)return e;var t=e.split(",");e=t.shift();var n=t.join(",");n=this.interpolate(n,l);try{l=JSON.parse(n)}catch(r){this.logger.error("failed parsing options string in nesting for key "+e,r)}return e}var o=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],s=void 0,a=void 0,l=JSON.parse(JSON.stringify(o));for(l.applyPostProcessor=!1;s=this.nestingRegexp.exec(e);)a=t(r.call(this,s[1].trim()),l),"string"!=typeof a&&(a=i(a)),a||(this.logger.warn("missed to pass in variable "+s[1]+" for interpolating "+e),a=""),a=n(this.escapeValue?p(a):a),e=e.replace(s[0],a),this.regexp.lastIndex=0;return e}}]),e}(),K=function(e){function t(e,n,r){var i=arguments.length<=3||void 0===arguments[3]?{}:arguments[3];w.classCallCheck(this,t);var o=w.possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this));return o.backend=e,o.store=n,o.services=r,o.options=i,o.logger=R.create("backendConnector"),o.state={},o.queue=[],o.backend&&o.backend.init&&o.backend.init(r,i.backend,i),o}return w.inherits(t,e),w.createClass(t,[{key:"queueLoad",value:function(e,t,n){var r=this,i=[],o=[],s=[],a=[];return e.forEach(function(e){var n=!0;t.forEach(function(t){var s=e+"|"+t;r.store.hasResourceBundle(e,t)?r.state[s]=2:r.state[s]<0||(1===r.state[s]?o.indexOf(s)<0&&o.push(s):(r.state[s]=1,n=!1,o.indexOf(s)<0&&o.push(s),i.indexOf(s)<0&&i.push(s),a.indexOf(t)<0&&a.push(t)))}),n||s.push(e)}),(i.length||o.length)&&this.queue.push({pending:o,loaded:{},errors:[],callback:n}),{toLoad:i,pending:o,toLoadLanguages:s,toLoadNamespaces:a}}},{key:"loaded",value:function(e,t,n){var r=this,i=e.split("|"),o=w.slicedToArray(i,2),s=o[0],a=o[1];t&&this.emit("failedLoading",s,a,t),n&&this.store.addResourceBundle(s,a,n),this.state[e]=t?-1:2,this.queue.forEach(function(n){l(n.loaded,[s],a),b(n.pending,e),t&&n.errors.push(t),0!==n.pending.length||n.done||(n.errors.length?n.callback(n.errors):n.callback(),r.emit("loaded",n.loaded),n.done=!0)}),this.queue=this.queue.filter(function(e){return!e.done})}},{key:"read",value:function(e,t,n,r,i,o){var s=this;return r||(r=0),i||(i=250),e.length?void this.backend[n](e,t,function(a,l){return a&&l&&5>r?void setTimeout(function(){s.read.call(s,e,t,n,++r,2*i,o)},i):void o(a,l)}):o(null,{})}},{key:"load",value:function(e,t,n){var r=this;if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),n&&n();var i=w["extends"]({},this.backend.options,this.options.backend);"string"==typeof e&&(e=this.services.languageUtils.toResolveHierarchy(e)),"string"==typeof t&&(t=[t]);var o=this.queueLoad(e,t,n);return o.toLoad.length?void(i.allowMultiLoading&&this.backend.readMulti?this.read(o.toLoadLanguages,o.toLoadNamespaces,"readMulti",null,null,function(e,t){e&&r.logger.warn("loading namespaces "+o.toLoadNamespaces.join(", ")+" for languages "+o.toLoadLanguages.join(", ")+" via multiloading failed",e),!e&&t&&r.logger.log("loaded namespaces "+o.toLoadNamespaces.join(", ")+" for languages "+o.toLoadLanguages.join(", ")+" via multiloading",t),o.toLoad.forEach(function(n){var i=n.split("|"),o=w.slicedToArray(i,2),s=o[0],a=o[1],l=u(t,[s,a]);if(l)r.loaded(n,e,l);else{var c="loading namespace "+a+" for language "+s+" via multiloading failed";r.loaded(n,c),r.logger.error(c)}})}):!function(){var e=function(e){var t=this,n=e.split("|"),r=w.slicedToArray(n,2),i=r[0],o=r[1];this.read(i,o,"read",null,null,function(n,r){n&&t.logger.warn("loading namespace "+o+" for language "+i+" failed",n),!n&&r&&t.logger.log("loaded namespace "+o+" for language "+i,r),t.loaded(e,n,r)})};o.toLoad.forEach(function(t){e.call(r,t)})}()):void(o.pending.length||n())}},{key:"saveMissing",value:function(e,t,n,r){this.backend&&this.backend.create&&this.backend.create(e,t,n,r),this.store.addResource(e[0],t,n,r)}}]),t}(T),U=function(e){function t(e,n,r){var i=arguments.length<=3||void 0===arguments[3]?{}:arguments[3];w.classCallCheck(this,t);var o=w.possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this));return o.cache=e,o.store=n,o.services=r,o.options=i,o.logger=R.create("cacheConnector"),o.cache&&o.cache.init&&o.cache.init(r,i.cache,i),o}return w.inherits(t,e),w.createClass(t,[{key:"load",value:function(e,t,n){var r=this;if(!this.cache)return n&&n();var i=w["extends"]({},this.cache.options,this.options.cache);"string"==typeof e&&(e=this.services.languageUtils.toResolveHierarchy(e)),"string"==typeof t&&(t=[t]),i.enabled?this.cache.load(e,function(t,i){if(t&&r.logger.error("loading languages "+e.join(", ")+" from cache failed",t),i)for(var o in i)for(var s in i[o])if("i18nStamp"!==s){var a=i[o][s];a&&r.store.addResourceBundle(o,s,a)}n&&n()}):n&&n()}},{key:"save",value:function(){this.cache&&this.options.cache&&this.options.cache.enabled&&this.cache.save(this.store.data)}}]),t}(T),$=function(e){function t(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=arguments[1];w.classCallCheck(this,t);var r=w.possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this));return r.options=k(e),r.services={},r.logger=R,r.modules={},n&&!r.isInitialized&&r.init(e,n),r}return w.inherits(t,e),w.createClass(t,[{key:"init",value:function(e,t){function n(e){return e?"function"==typeof e?new e:e:void 0}var r=this;if("function"==typeof e&&(t=e,e={}),e||(e={}),"v1"===e.compatibilityAPI?this.options=w["extends"]({},m(),k(d(e)),{}):"v1"===e.compatibilityJSON?this.options=w["extends"]({},m(),k(g(e)),{}):this.options=w["extends"]({},m(),this.options,k(e)),t||(t=function(){}),!this.options.isClone){this.modules.logger?R.init(n(this.modules.logger),this.options):R.init(null,this.options);var i=new H(this.options);this.store=new A(this.options.resources,this.options);var o=this.services;o.logger=R,o.resourceStore=this.store,o.resourceStore.on("added removed",function(e,t){o.cacheConnector.save()}),o.languageUtils=i,o.pluralResolver=new q(i,{prepend:this.options.pluralSeparator,compatibilityJSON:this.options.compatibilityJSON}),o.interpolator=new D(this.options), +o.backendConnector=new K(n(this.modules.backend),o.resourceStore,o,this.options),o.backendConnector.on("*",function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),i=1;t>i;i++)n[i-1]=arguments[i];r.emit.apply(r,[e].concat(n))}),o.backendConnector.on("loaded",function(e){o.cacheConnector.save()}),o.cacheConnector=new U(n(this.modules.cache),o.resourceStore,o,this.options),o.cacheConnector.on("*",function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),i=1;t>i;i++)n[i-1]=arguments[i];r.emit.apply(r,[e].concat(n))}),this.modules.languageDetector&&(o.languageDetector=n(this.modules.languageDetector),o.languageDetector.init(o,this.options.detection,this.options)),this.translator=new M(this.services,this.options),this.translator.on("*",function(e){for(var t=arguments.length,n=Array(t>1?t-1:0),i=1;t>i;i++)n[i-1]=arguments[i];r.emit.apply(r,[e].concat(n))})}var s=["getResource","addResource","addResources","addResourceBundle","removeResourceBundle","hasResourceBundle","getResourceBundle"];return s.forEach(function(e){r[e]=function(){return this.store[e].apply(this.store,arguments)}}),"v1"===this.options.compatibilityAPI&&y(this),this.changeLanguage(this.options.lng,function(e,n){r.emit("initialized",r.options),r.logger.log("initialized",r.options),t(e,n)}),this}},{key:"loadResources",value:function(e){var t=this;if(e||(e=function(){}),this.options.resources)e(null);else{var n=function(){if(t.language&&"cimode"===t.language.toLowerCase())return{v:e()};var n=[],r=function(e){var r=t.services.languageUtils.toResolveHierarchy(e);r.forEach(function(e){n.indexOf(e)<0&&n.push(e)})};r(t.language),t.options.preload&&t.options.preload.forEach(function(e){r(e)}),t.services.cacheConnector.load(n,t.options.ns,function(){t.services.backendConnector.load(n,t.options.ns,e)})}();if("object"===("undefined"==typeof n?"undefined":w["typeof"](n)))return n.v}}},{key:"use",value:function(e){return"backend"===e.type&&(this.modules.backend=e),"cache"===e.type&&(this.modules.cache=e),("logger"===e.type||e.log&&e.warn&&e.warn)&&(this.modules.logger=e),"languageDetector"===e.type&&(this.modules.languageDetector=e),"postProcessor"===e.type&&_.addPostProcessor(e),this}},{key:"changeLanguage",value:function(e,t){var n=this,r=function(r){e&&(n.emit("languageChanged",e),n.logger.log("languageChanged",e)),t&&t(r,function(){for(var e=arguments.length,t=Array(e),r=0;e>r;r++)t[r]=arguments[r];return n.t.apply(n,t)})};!e&&this.services.languageDetector&&(e=this.services.languageDetector.detect()),e&&(this.language=e,this.languages=this.services.languageUtils.toResolveHierarchy(e),this.translator.changeLanguage(e),this.services.languageDetector&&this.services.languageDetector.cacheUserLanguage(e)),this.loadResources(function(e){r(e)})}},{key:"getFixedT",value:function(e,t){var n=this,r=function i(e,t){return t=t||{},t.lng=t.lng||i.lng,t.ns=t.ns||i.ns,n.t(e,t)};return r.lng=e,r.ns=t,r}},{key:"t",value:function(){return this.translator&&this.translator.translate.apply(this.translator,arguments)}},{key:"exists",value:function(){return this.translator&&this.translator.exists.apply(this.translator,arguments)}},{key:"setDefaultNamespace",value:function(e){this.options.defaultNS=e}},{key:"loadNamespaces",value:function(e,t){var n=this;return this.options.ns?("string"==typeof e&&(e=[e]),e.forEach(function(e){n.options.ns.indexOf(e)<0&&n.options.ns.push(e)}),void this.loadResources(t)):t&&t()}},{key:"loadLanguages",value:function(e,t){"string"==typeof e&&(e=[e]),this.options.preload=this.options.preload?this.options.preload.concat(e):e,this.loadResources(t)}},{key:"dir",value:function(e){e||(e=this.language);var t=["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam"];return t.indexOf(this.services.languageUtils.getLanguagePartFromCode(e))?"ltr":"rtl"}},{key:"createInstance",value:function(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],n=arguments[1];return new t(e,n)}},{key:"cloneInstance",value:function(){var e=this,n=arguments.length<=0||void 0===arguments[0]?{}:arguments[0],r=arguments[1],i=new t(w["extends"]({},n,this.options,{isClone:!0}),r),o=["store","translator","services","language"];return o.forEach(function(t){i[t]=e[t]}),i}}]),t}(T);new $,e.loadNamespaces=S,e.translate=r,e.Interpolate=L,e.I18nextProvider=j}); \ No newline at end of file diff --git a/src/index.js b/src/index.js index 7ecfddf73..c315ef262 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,10 @@ import translate from './translate'; import Interpolate from './interpolate'; import I18nextProvider from './I18nextProvider'; +import loadNamespaces from './loadNamespaces'; export { + loadNamespaces, translate, Interpolate, I18nextProvider diff --git a/src/loadNamespaces.js b/src/loadNamespaces.js new file mode 100644 index 000000000..b8fd5f775 --- /dev/null +++ b/src/loadNamespaces.js @@ -0,0 +1,37 @@ +import i18n from 'i18next'; + +// Borrowed from https://github.com/Rezonans/redux-async-connect/blob/master/modules/ReduxAsyncConnect.js#L16 +function eachComponents(components, iterator) { + for (let i = 0, l = components.length; i < l; i++) { // eslint-disable-line id-length + if (typeof components[i] === 'object') { + for (let [key, value] of Object.entries(components[i])) { + iterator(value, i, key); + } + } else { + iterator(components[i], i); + } + } +} + +function filterAndFlattenComponents(components) { + const flattened = []; + eachComponents(components, (Component) => { + if (Component && Component.namespaces) { + + Component.namespaces.forEach((namespace)=>{ + if (flattened.indexOf(namespace) === -1) { + flattened.push(namespace); + } + }); + } + }); + return flattened; +} + +export default function loadNamespaces({ components, i18n }) { + const allNamespaces = filterAndFlattenComponents(components); + + return new Promise((resolve)=>{ + i18n.loadNamespaces(allNamespaces, resolve); + }); +} diff --git a/src/translate.js b/src/translate.js index 7e72a4b73..65e0297df 100644 --- a/src/translate.js +++ b/src/translate.js @@ -73,6 +73,8 @@ function translate(namespaces) { Translate.displayName = 'Translate[' + getDisplayName(WrappedComponent) + ']'; + Translate.namespaces = namespaces; + return Translate; }; }