lingui-i18n
Advanced tools
Comparing version 1.0.0-1 to 1.0.0-2
{ | ||
"name": "lingui-i18n", | ||
"version": "1.0.0-1", | ||
"version": "1.0.0-2", | ||
"description": "I18n tools for javascript", | ||
"main": "lib/index.js", | ||
"module": "lib/index.es.js", | ||
"main": "index.js", | ||
"module": "index.es.js", | ||
"author": { | ||
@@ -28,3 +28,3 @@ "name": "Tomáš Ehrlich", | ||
"babel-runtime": "^6.23.0", | ||
"lingui-formats": "^1.0.0-1", | ||
"lingui-formats": "^1.0.0-2", | ||
"make-plural": "^4.0.1", | ||
@@ -31,0 +31,0 @@ "messageformat-parser": "^1.0.0" |
@@ -50,3 +50,3 @@ // @flow | ||
* @param language - Language of message | ||
* @param params - Parameters for variable interpolation | ||
* @param values - Parameters for variable interpolation | ||
* @param languageData - Language data (e.g: plurals) | ||
@@ -56,7 +56,7 @@ * @param formats - Custom format styles | ||
*/ | ||
function context ({ language, params, formats, languageData }: Object) { | ||
function context ({ language, values, formats, languageData }: Object) { | ||
const formatters = defaultFormats(language, languageData, formats) | ||
const ctx = (name: string, type: string, format: any) => { | ||
const value = params[name] | ||
const value = values[name] | ||
const formatted = formatters[type](value, format) | ||
@@ -71,5 +71,5 @@ const message = isFunction(formatted) ? formatted(ctx) : formatted | ||
export function interpolate (translation: Function, language: string, languageData: Object) { | ||
return (params: Object, formats?: Object = {}) => { | ||
return (values: Object, formats?: Object = {}) => { | ||
const message = translation(context({ | ||
language, languageData, formats, params | ||
language, languageData, formats, values | ||
})) | ||
@@ -76,0 +76,0 @@ |
/* @flow */ | ||
import { interpolate } from './context' | ||
import { isString } from './essentials' | ||
import { isString, isFunction } from './essentials' | ||
import t from './t' | ||
import { select, plural, selectOrdinal } from './select' | ||
type Catalog = {[key: string]: string | Function} | ||
type Catalogs = {[key: string]: Catalog} | ||
type Catalog = { [key: string]: string | Function } | ||
type Catalogs = { [key: string]: Catalog } | ||
type Message = {| | ||
id: string, | ||
defaults?: string, | ||
params?: Object, | ||
values?: Object, | ||
formats?: Object | ||
@@ -20,7 +19,34 @@ |} | ||
} | ||
type AllLanguageData = {[key: string]: LanguageData} | ||
type AllLanguageData = { [key: string]: LanguageData } | ||
type setupI18nProps = { | ||
language?: string, | ||
messages?: Catalogs, | ||
languageData?: AllLanguageData, | ||
development?: Object | ||
} | ||
function setupI18n (params?: setupI18nProps = {}): I18n { | ||
const i18n = new I18n() | ||
if (process.env.NODE_ENV !== 'production') { | ||
if (params.development) i18n.development(params.development) | ||
} | ||
if (params.messages) i18n.load(params.messages) | ||
if (params.language) i18n.activate(params.language) | ||
if (params.languageData) i18n.loadLanguageData(params.languageData) | ||
return i18n | ||
} | ||
class I18n { | ||
_language: string | ||
// Messages in all loaded language. | ||
_messages: Catalogs | ||
// Messages in active language. This is optimization, so we don't perform | ||
// object lookup _messages[language] for each translation. | ||
_activeMessages: Catalog | ||
_languageData: AllLanguageData | ||
@@ -35,10 +61,9 @@ | ||
constructor (language?: string, messages?: Catalogs = {}, languageData?: AllLanguageData = {}) { | ||
this._messages = messages | ||
this._languageData = languageData | ||
constructor () { | ||
// Messages and languageData are merged on load, | ||
// so we must initialize it manually | ||
this._activeMessages = {} | ||
this._messages = {} | ||
this._languageData = {} | ||
if (language) { | ||
this.activate(language) | ||
} | ||
if (process.env.NODE_ENV !== 'production') { | ||
@@ -57,3 +82,3 @@ this.t = t | ||
get messages (): Catalog { | ||
return this._messages[this.language] || {} | ||
return this._activeMessages | ||
} | ||
@@ -79,3 +104,3 @@ | ||
load (messages: Catalogs) { | ||
if (!messages) return | ||
if (typeof messages !== 'object') return | ||
@@ -89,7 +114,9 @@ // deeply merge Catalogs | ||
if (process.env.NODE_ENV !== 'production') { | ||
compiledMessages = Object.keys(compiledMessages).reduce((dict, id) => { | ||
const msg = compiledMessages[id] | ||
dict[id] = isString(msg) ? this._dev.compile(msg) : msg | ||
return dict | ||
}, {}) | ||
if (this._dev && isFunction(this._dev.compile)) { | ||
compiledMessages = Object.keys(compiledMessages).reduce((dict, id) => { | ||
const msg = compiledMessages[id] | ||
dict[id] = isString(msg) ? this._dev.compile(msg) : msg | ||
return dict | ||
}, {}) | ||
} | ||
} | ||
@@ -119,14 +146,26 @@ | ||
this._language = language | ||
this._activeMessages = this._messages[this.language] || {} | ||
} | ||
use (language: string) { | ||
return new I18n(language, this._messages) | ||
return setupI18n({ | ||
language, | ||
messages: this._messages, | ||
languageData: this._languageData, | ||
development: this._dev | ||
}) | ||
} | ||
// default translate method | ||
_ ({ id, defaults, params = {}, formats = {} }: Message) { | ||
const translation = this.messages[id] || defaults || id | ||
_ (id: string, { defaults, values = {}, formats = {} }: Message = {}) { | ||
let translation = this.messages[id] || defaults || id | ||
if (process.env.NODE_ENV !== 'development') { | ||
if (isString(translation) && this._dev && isFunction(this._dev.compile)) { | ||
translation = this._dev.compile(translation) | ||
} | ||
} | ||
if (typeof translation !== 'function') return translation | ||
return interpolate(translation, this.language, this.languageData)(params, formats) | ||
return interpolate(translation, this.language, this.languageData)(values, formats) | ||
} | ||
@@ -138,3 +177,3 @@ | ||
development(config: Object) { | ||
development (config: Object) { | ||
this._dev = config | ||
@@ -144,4 +183,4 @@ } | ||
export default new I18n() | ||
export { I18n } | ||
export type { Message, Catalog, Catalogs, AllLanguageData, LanguageData } | ||
export default setupI18n() | ||
export { setupI18n } | ||
export type { Message, Catalog, Catalogs, AllLanguageData, LanguageData, I18n } |
/* @flow */ | ||
import { I18n, default as exportedI18n } from '.' | ||
import i18n, { setupI18n } from '.' | ||
import { mockConsole, mockEnv } from './mocks' | ||
@@ -8,7 +8,7 @@ import linguiDev from './dev' | ||
it('should export default I18n instance', function () { | ||
expect(exportedI18n).toBeInstanceOf(I18n) | ||
expect(i18n).toBeDefined() | ||
}) | ||
it('should be initialized with empty catalog', function () { | ||
const i18n = new I18n() | ||
const i18n = setupI18n() | ||
expect(i18n.messages).toEqual({}) | ||
@@ -18,3 +18,3 @@ }) | ||
it('should bound t method', function () { | ||
const i18n = new I18n() | ||
const i18n = setupI18n() | ||
expect(i18n.t).toBeInstanceOf(Function) | ||
@@ -35,4 +35,5 @@ | ||
const i18n = new I18n() | ||
i18n.development(linguiDev) | ||
const i18n = setupI18n({ | ||
development: linguiDev | ||
}) | ||
expect(i18n.messages).toEqual({}) | ||
@@ -65,7 +66,8 @@ | ||
const i18n = new I18n() | ||
i18n.load({en: {}, fr: {}}) | ||
const i18n = setupI18n({ | ||
language: 'en', | ||
languageData, | ||
messages: {en: {}, fr: {}}, | ||
}) | ||
i18n.loadLanguageData(languageData) | ||
i18n.activate('en') | ||
expect(i18n.languageData).toEqual(languageData.en) | ||
@@ -81,4 +83,2 @@ | ||
it('.activate should switch active language', function () { | ||
const i18n = new I18n() | ||
i18n.development(linguiDev) | ||
const messages = { | ||
@@ -88,4 +88,8 @@ 'Hello': 'Salut' | ||
i18n.load({ fr: messages, en: {} }) | ||
i18n.activate('en') | ||
const i18n = setupI18n({ | ||
language: 'en', | ||
messages: { fr: messages, en: {} }, | ||
development: linguiDev | ||
}) | ||
expect(i18n.language).toEqual('en') | ||
@@ -102,3 +106,3 @@ expect(i18n.messages).toEqual({}) | ||
it('.activate should throw an error about incorrect language', function () { | ||
const i18n = new I18n() | ||
const i18n = setupI18n() | ||
@@ -119,4 +123,2 @@ mockConsole(console => { | ||
it('.use should return new i18n object with switched language', function () { | ||
const i18n = new I18n() | ||
i18n.development(linguiDev) | ||
const messages = { | ||
@@ -131,16 +133,18 @@ en: { | ||
i18n.load(messages) | ||
i18n.activate('en') | ||
expect(i18n._({ id: 'Hello' })).toEqual('Hello') | ||
const i18n = setupI18n({ | ||
language: 'en', | ||
messages: messages, | ||
development: linguiDev | ||
}) | ||
expect(i18n._('Hello')).toEqual('Hello') | ||
// change language locally | ||
expect(i18n.use('fr')._({ id: 'Hello' })).toEqual('Salut') | ||
expect(i18n.use('fr')._('Hello')).toEqual('Salut') | ||
// global language hasn't changed | ||
expect(i18n._({ id: 'Hello' })).toEqual('Hello') | ||
expect(i18n._('Hello')).toEqual('Hello') | ||
}) | ||
it('._ should format message from catalog', function () { | ||
const i18n = new I18n() | ||
i18n.development(linguiDev) | ||
const messages = { | ||
@@ -151,20 +155,19 @@ 'Hello': 'Salut', | ||
i18n.load({ fr: messages }) | ||
i18n.activate('fr') | ||
const i18n = setupI18n({ | ||
language: 'fr', | ||
messages: { fr: messages }, | ||
development: linguiDev | ||
}) | ||
expect(i18n._({ id: 'Hello' })).toEqual('Salut') | ||
expect(i18n._({ id: 'My name is {name}', params: { name: 'Fred' } })) | ||
expect(i18n._('Hello')).toEqual('Salut') | ||
expect(i18n._('My name is {name}', { values: { name: 'Fred' } })) | ||
.toEqual("Je m'appelle Fred") | ||
// missing { name } | ||
expect(i18n._({ id: 'My name is {name}' })) | ||
expect(i18n._('My name is {name}')) | ||
.toEqual("Je m'appelle") | ||
// Untranslated message | ||
expect(i18n._({ id: 'Missing message' })).toEqual('Missing message') | ||
expect(i18n._('Missing message')).toEqual('Missing message') | ||
}) | ||
it('._ shouldn\' compile messages in production', function () { | ||
}) | ||
}) |
/* @flow */ | ||
import i18n, { I18n } from './i18n' | ||
import type { Catalog, Catalogs, Message, LanguageData, AllLanguageData } from './i18n' | ||
import i18n, { setupI18n } from './i18n' | ||
import type { Catalog, Catalogs, Message, LanguageData, AllLanguageData, I18n } from './i18n' | ||
export default i18n | ||
export { I18n } | ||
export type { Catalog, Catalogs, Message, LanguageData, AllLanguageData } | ||
export { setupI18n } | ||
export type { Catalog, Catalogs, Message, LanguageData, AllLanguageData, I18n } |
/* @flow */ | ||
import { plural, select, selectOrdinal } from './select' | ||
import { I18n } from './i18n' | ||
import { setupI18n } from './i18n' | ||
import linguiDev from './dev' | ||
describe('plural', function () { | ||
const i18n = new I18n('en', {en: {}}) | ||
i18n.development(linguiDev) | ||
const i18n = setupI18n({ | ||
language: 'en', | ||
messages: {en: {}}, | ||
development: linguiDev | ||
}) | ||
@@ -35,4 +38,7 @@ it('should convert to message format string', function () { | ||
describe('selectOrdinal', function () { | ||
const i18n = new I18n('en', {en: {}}) | ||
i18n.development(linguiDev) | ||
const i18n = setupI18n({ | ||
language: 'en', | ||
messages: {en: {}}, | ||
development: linguiDev | ||
}) | ||
@@ -73,4 +79,8 @@ it('should convert to message format string', function () { | ||
it('should use other rule when ordinal ones are missing', function () { | ||
const i18nCS = new I18n('cs', {cs: {}}) | ||
i18nCS.development(linguiDev) | ||
const i18nCS = setupI18n({ | ||
language: 'cs', | ||
messages: { cs: {} }, | ||
development: linguiDev | ||
}) | ||
const s = selectOrdinal(i18nCS) | ||
@@ -77,0 +87,0 @@ expect(s({ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58455
35
1342
23
1
Updatedlingui-formats@^1.0.0-2