Browse Source

Convert i18n to class

pull/4265/head
Alex Ritter 5 years ago
parent
commit
fe3b85e22a
  1. 386
      src/i18n/index.js
  2. 52
      test/specs/i18n/index.js

386
src/i18n/index.js

@ -27,8 +27,8 @@
* @module I18n * @module I18n
*/ */
import { isUndefined, isString } from 'underscore'; import { isUndefined, isString } from 'underscore';
import { hasWin } from '../utils/mixins'; import { hasWin } from 'utils/mixins';
import config from './config'; import defaults from './config';
const isObj = el => !Array.isArray(el) && el !== null && typeof el === 'object'; const isObj = el => !Array.isArray(el) && el !== null && typeof el === 'object';
@ -53,199 +53,197 @@ const deepAssign = (...args) => {
return target; return target;
}; };
export default () => { export default class I18nModule {
return { name = 'I18n';
name: 'I18n',
//config;
config,
/**
/** * Initialize module
* Initialize module * @param {Object} config Configurations
* @param {Object} config Configurations * @private
* @private */
*/ init(opts = {}) {
init(opts = {}) { this.config = {
this.config = { ...defaults,
...config, ...opts,
...opts, messages: {
messages: { ...defaults.messages,
...config.messages, ...(opts.messages || {}),
...(opts.messages || {}), },
}, };
}; const add = this.config.messagesAdd;
const add = this.config.messagesAdd; add && this.addMessages(add);
add && this.addMessages(add);
if (this.config.detectLocale) {
if (this.config.detectLocale) { this.config.locale = this._localLang();
this.config.locale = this._localLang(); }
}
this.em = opts.em; this.em = opts.em;
return this; return this;
}, }
/**
* Get module configurations
* @returns {Object} Configuration object
*/
getConfig() {
return this.config;
},
/**
* Update current locale
* @param {String} locale Locale value
* @returns {this}
* @example
* i18n.setLocale('it');
*/
setLocale(locale) {
const { em, config } = this;
const evObj = { value: locale, valuePrev: config.locale };
em && em.trigger('i18n:locale', evObj);
config.locale = locale;
return this;
},
/**
* Get current locale
* @returns {String} Current locale value
*/
getLocale() {
return this.config.locale;
},
/**
* Get all messages
* @param {String} [lang] Specify the language of messages to return
* @param {Object} [opts] Options
* @param {Boolean} [opts.debug] Show warnings in case of missing language
* @returns {Object}
* @example
* i18n.getMessages();
* // -> { en: { hello: '...' }, ... }
* i18n.getMessages('en');
* // -> { hello: '...' }
*/
getMessages(lang, opts = {}) {
const { messages } = this.config;
lang && !messages[lang] && this._debug(`'${lang}' i18n lang not found`, opts);
return lang ? messages[lang] : messages;
},
/**
* Set new set of messages
* @param {Object} msg Set of messages
* @returns {this}
* @example
* i18n.getMessages();
* // -> { en: { msg1: 'Msg 1', msg2: 'Msg 2', } }
* i18n.setMessages({ en: { msg2: 'Msg 2 up', msg3: 'Msg 3', } });
* // Set replaced
* i18n.getMessages();
* // -> { en: { msg2: 'Msg 2 up', msg3: 'Msg 3', } }
*/
setMessages(msg) {
const { em, config } = this;
config.messages = msg;
em && em.trigger('i18n:update', msg);
return this;
},
/**
* Update messages
* @param {Object} msg Set of messages to add
* @returns {this}
* @example
* i18n.getMessages();
* // -> { en: { msg1: 'Msg 1', msg2: 'Msg 2', } }
* i18n.addMessages({ en: { msg2: 'Msg 2 up', msg3: 'Msg 3', } });
* // Set updated
* i18n.getMessages();
* // -> { en: { msg1: 'Msg 1', msg2: 'Msg 2 up', msg3: 'Msg 3', } }
*/
addMessages(msg) {
const { em } = this;
const { messages } = this.config;
em && em.trigger('i18n:add', msg);
this.setMessages(deepAssign(messages, msg));
return this;
},
/**
* Translate the locale message
* @param {String} key Label to translate
* @param {Object} [opts] Options for the translation
* @param {Object} [opts.params] Params for the translation
* @param {Boolean} [opts.debug] Show warnings in case of missing resources
* @returns {String}
* @example
* obj.setMessages({
* en: { msg: 'Msg', msg2: 'Msg {test}'},
* it: { msg2: 'Msg {test} it'},
* });
* obj.t('msg');
* // -> outputs `Msg`
* obj.t('msg2', { params: { test: 'hello' } }); // use params
* // -> outputs `Msg hello`
* obj.t('msg2', { l: 'it', params: { test: 'hello' } }); // custom local
* // -> outputs `Msg hello it`
*/
t(key, opts = {}) {
const { config } = this;
const param = opts.params || {};
const locale = opts.l || this.getLocale();
const localeFlb = opts.lFlb || config.localeFallback;
let result = this._getMsg(key, locale, opts);
// Try with fallback
if (!result) result = this._getMsg(key, localeFlb, opts);
!result && this._debug(`'${key}' i18n key not found in '${locale}' lang`, opts);
result = result && isString(result) ? this._addParams(result, param) : result;
return result;
},
_localLang() {
const nav = (hasWin() && window.navigator) || {};
const lang = nav.language || nav.userLanguage;
return lang ? lang.split('-')[0] : 'en';
},
_addParams(str, params) {
const reg = new RegExp(`\{([\\w\\d-]*)\}`, 'g');
return str.replace(reg, (m, val) => params[val] || '').trim();
},
_getMsg(key, locale, opts = {}) {
const msgSet = this.getMessages(locale, opts);
// Lang set is missing
if (!msgSet) return;
let result = msgSet[key];
// Check for nested getter
if (!result && key.indexOf('.') > 0) {
result = key.split('.').reduce((lang, key) => {
if (isUndefined(lang)) return;
return lang[key];
}, msgSet);
}
return result; /**
}, * Get module configurations
* @returns {Object} Configuration object
*/
getConfig() {
return this.config;
}
_debug(str, opts = {}) { /**
const { em, config } = this; * Update current locale
(opts.debug || config.debug) && em && em.logWarning(str); * @param {String} locale Locale value
}, * @returns {this}
* @example
* i18n.setLocale('it');
*/
setLocale(locale) {
const { em, config } = this;
const evObj = { value: locale, valuePrev: config.locale };
em && em.trigger('i18n:locale', evObj);
config.locale = locale;
return this;
}
destroy() { /**
this.config = config; * Get current locale
this.em = {}; * @returns {String} Current locale value
}, */
}; getLocale() {
}; return this.config.locale;
}
/**
* Get all messages
* @param {String} [lang] Specify the language of messages to return
* @param {Object} [opts] Options
* @param {Boolean} [opts.debug] Show warnings in case of missing language
* @returns {Object}
* @example
* i18n.getMessages();
* // -> { en: { hello: '...' }, ... }
* i18n.getMessages('en');
* // -> { hello: '...' }
*/
getMessages(lang, opts = {}) {
const { messages } = this.config;
lang && !messages[lang] && this._debug(`'${lang}' i18n lang not found`, opts);
return lang ? messages[lang] : messages;
}
/**
* Set new set of messages
* @param {Object} msg Set of messages
* @returns {this}
* @example
* i18n.getMessages();
* // -> { en: { msg1: 'Msg 1', msg2: 'Msg 2', } }
* i18n.setMessages({ en: { msg2: 'Msg 2 up', msg3: 'Msg 3', } });
* // Set replaced
* i18n.getMessages();
* // -> { en: { msg2: 'Msg 2 up', msg3: 'Msg 3', } }
*/
setMessages(msg) {
const { em, config } = this;
config.messages = msg;
em && em.trigger('i18n:update', msg);
return this;
}
/**
* Update messages
* @param {Object} msg Set of messages to add
* @returns {this}
* @example
* i18n.getMessages();
* // -> { en: { msg1: 'Msg 1', msg2: 'Msg 2', } }
* i18n.addMessages({ en: { msg2: 'Msg 2 up', msg3: 'Msg 3', } });
* // Set updated
* i18n.getMessages();
* // -> { en: { msg1: 'Msg 1', msg2: 'Msg 2 up', msg3: 'Msg 3', } }
*/
addMessages(msg) {
const { em } = this;
const { messages } = this.config;
em && em.trigger('i18n:add', msg);
this.setMessages(deepAssign(messages, msg));
return this;
}
/**
* Translate the locale message
* @param {String} key Label to translate
* @param {Object} [opts] Options for the translation
* @param {Object} [opts.params] Params for the translation
* @param {Boolean} [opts.debug] Show warnings in case of missing resources
* @returns {String}
* @example
* obj.setMessages({
* en: { msg: 'Msg', msg2: 'Msg {test}'},
* it: { msg2: 'Msg {test} it'},
* });
* obj.t('msg');
* // -> outputs `Msg`
* obj.t('msg2', { params: { test: 'hello' } }); // use params
* // -> outputs `Msg hello`
* obj.t('msg2', { l: 'it', params: { test: 'hello' } }); // custom local
* // -> outputs `Msg hello it`
*/
t(key, opts = {}) {
const { config } = this;
const param = opts.params || {};
const locale = opts.l || this.getLocale();
const localeFlb = opts.lFlb || config.localeFallback;
let result = this._getMsg(key, locale, opts);
// Try with fallback
if (!result) result = this._getMsg(key, localeFlb, opts);
!result && this._debug(`'${key}' i18n key not found in '${locale}' lang`, opts);
result = result && isString(result) ? this._addParams(result, param) : result;
return result;
}
_localLang() {
const nav = (hasWin() && window.navigator) || {};
const lang = nav.language || nav.userLanguage;
return lang ? lang.split('-')[0] : 'en';
}
_addParams(str, params) {
const reg = new RegExp(`\{([\\w\\d-]*)\}`, 'g');
return str.replace(reg, (m, val) => params[val] || '').trim();
}
_getMsg(key, locale, opts = {}) {
const msgSet = this.getMessages(locale, opts);
// Lang set is missing
if (!msgSet) return;
let result = msgSet[key];
// Check for nested getter
if (!result && key.indexOf('.') > 0) {
result = key.split('.').reduce((lang, key) => {
if (isUndefined(lang)) return;
return lang[key];
}, msgSet);
}
return result;
}
_debug(str, opts = {}) {
const { em, config } = this;
(opts.debug || config.debug) && em && em.logWarning(str);
}
destroy() {
this.config = {};
this.em = {};
}
}

52
test/specs/i18n/index.js

@ -8,7 +8,7 @@ describe('I18n', () => {
let em = editor.getModel(); let em = editor.getModel();
beforeEach(() => { beforeEach(() => {
obj = I18n(); obj = new I18n();
obj.init({ em }); obj.init({ em });
}); });
@ -34,8 +34,8 @@ describe('I18n', () => {
localeFallback, localeFallback,
detectLocale: 0, detectLocale: 0,
messages: { messages: {
en: { msg } en: { msg },
} },
}); });
expect(obj.getLocale()).toBe(locale); expect(obj.getLocale()).toBe(locale);
expect(obj.getConfig().localeFallback).toBe(localeFallback); expect(obj.getConfig().localeFallback).toBe(localeFallback);
@ -44,7 +44,7 @@ describe('I18n', () => {
test('English always imported', () => { test('English always imported', () => {
obj.init({ obj.init({
messages: { it: {} } messages: { it: {} },
}); });
expect(Object.keys(obj.getMessages())).toEqual(['en', 'it']); expect(Object.keys(obj.getMessages())).toEqual(['en', 'it']);
}); });
@ -74,12 +74,12 @@ describe('I18n', () => {
obj.setMessages(set1); obj.setMessages(set1);
const set2 = { const set2 = {
en: { msg2: 'Msg 2 up', msg3: 'Msg 3' }, en: { msg2: 'Msg 2 up', msg3: 'Msg 3' },
it: { msg1: 'Msg 1' } it: { msg1: 'Msg 1' },
}; };
obj.addMessages(set2); obj.addMessages(set2);
expect(obj.getMessages()).toEqual({ expect(obj.getMessages()).toEqual({
en: { msg1: 'Msg 1', msg2: 'Msg 2 up', msg3: 'Msg 3' }, en: { msg1: 'Msg 1', msg2: 'Msg 2 up', msg3: 'Msg 3' },
it: { msg1: 'Msg 1' } it: { msg1: 'Msg 1' },
}); });
}); });
@ -90,19 +90,19 @@ describe('I18n', () => {
msg2: 'Msg 2', msg2: 'Msg 2',
msg3: { msg3: {
msg31: 'Msg 31', msg31: 'Msg 31',
msg32: { msg321: 'Msg 321' } msg32: { msg321: 'Msg 321' },
} },
} },
}); });
obj.addMessages({ obj.addMessages({
en: { en: {
msg2: { msg21: 'Msg 21' }, msg2: { msg21: 'Msg 21' },
msg3: { msg3: {
msg32: { msg322: 'Msg 322' }, msg32: { msg322: 'Msg 322' },
msg33: 'Msg 33' msg33: 'Msg 33',
}, },
msg4: 'Msg 4' msg4: 'Msg 4',
} },
}); });
expect(obj.getMessages()).toEqual({ expect(obj.getMessages()).toEqual({
en: { en: {
@ -112,12 +112,12 @@ describe('I18n', () => {
msg31: 'Msg 31', msg31: 'Msg 31',
msg32: { msg32: {
msg321: 'Msg 321', msg321: 'Msg 321',
msg322: 'Msg 322' msg322: 'Msg 322',
}, },
msg33: 'Msg 33' msg33: 'Msg 33',
}, },
msg4: 'Msg 4' msg4: 'Msg 4',
} },
}); });
}); });
@ -126,7 +126,7 @@ describe('I18n', () => {
obj.setLocale('en'); obj.setLocale('en');
obj.setMessages({ obj.setMessages({
en: { msg1 }, en: { msg1 },
it: { msg1: `${msg1} it` } it: { msg1: `${msg1} it` },
}); });
expect(obj.t('msg2')).toBe(undefined); expect(obj.t('msg2')).toBe(undefined);
expect(obj.t('msg1')).toBe(msg1); expect(obj.t('msg1')).toBe(msg1);
@ -141,10 +141,10 @@ describe('I18n', () => {
key1: { key1: {
msg1, msg1,
key2: { key2: {
msg2 msg2,
} },
} },
} },
}); });
expect(obj.t('key1.msg1')).toBe(msg1); expect(obj.t('key1.msg1')).toBe(msg1);
expect(obj.t('key1.key2.msg2')).toBe(msg2); expect(obj.t('key1.key2.msg2')).toBe(msg2);
@ -158,7 +158,7 @@ describe('I18n', () => {
obj.setLocale('en'); obj.setLocale('en');
obj.setMessages({ obj.setMessages({
en: { msg1 }, en: { msg1 },
it: { msg1: msg1Alt } it: { msg1: msg1Alt },
}); });
expect(obj.t('msg1', { l: 'it' })).toBe(msg1Alt); expect(obj.t('msg1', { l: 'it' })).toBe(msg1Alt);
}); });
@ -168,7 +168,7 @@ describe('I18n', () => {
obj.setLocale('it'); obj.setLocale('it');
obj.setMessages({ obj.setMessages({
en: { msg1 }, en: { msg1 },
it: {} it: {},
}); });
expect(obj.t('msg1')).toBe(msg1); expect(obj.t('msg1')).toBe(msg1);
}); });
@ -179,12 +179,10 @@ describe('I18n', () => {
obj.setLocale('en'); obj.setLocale('en');
obj.setMessages({ obj.setMessages({
en: { msg1 }, en: { msg1 },
it: { msg1: msg1Alt } it: { msg1: msg1Alt },
}); });
expect(obj.t('msg1', { params: { test: 'Hello' } })).toBe('Msg 1 Hello'); expect(obj.t('msg1', { params: { test: 'Hello' } })).toBe('Msg 1 Hello');
expect(obj.t('msg1', { l: 'it', params: { test: 'Hello' } })).toBe( expect(obj.t('msg1', { l: 'it', params: { test: 'Hello' } })).toBe('Msg 1 Hello it');
'Msg 1 Hello it'
);
}); });
test('i18n events', () => { test('i18n events', () => {

Loading…
Cancel
Save