node-polyglot
Advanced tools
Comparing version 2.4.2 to 2.5.0
@@ -0,1 +1,8 @@ | ||
### v2.5.0: January 23, 2023 | ||
* [New] Add `replace` option for custom replace implementation (#171) | ||
* [New] Add Romanian and Macedonian (#176) | ||
* [Deps] update array.prototype.foreach, object.entries, `string.prototype.trim` (#172) | ||
* [Tests] Migrate tests to GitHub Actions (#169) | ||
* [Tests] Add passing tests (#168) | ||
### v2.4.2: August 16, 2021 | ||
@@ -2,0 +9,0 @@ * [Fix] Handle null and undefined gracefully in extend and unset (#161) |
42
index.js
@@ -30,3 +30,3 @@ // (c) 2012-2018 Airbnb, Inc. | ||
var replace = String.prototype.replace; | ||
var defaultReplace = String.prototype.replace; | ||
var split = String.prototype.split; | ||
@@ -92,2 +92,8 @@ | ||
return 3; | ||
}, | ||
romanian: function (n) { | ||
if (n === 1) { return 0; } | ||
var lastTwo = n % 100; | ||
if (n === 0 || (lastTwo >= 2 && lastTwo <= 19)) { return 1; } | ||
return 2; | ||
} | ||
@@ -110,4 +116,5 @@ }, | ||
polish: ['pl'], | ||
icelandic: ['is'], | ||
slovenian: ['sl-SL'] | ||
icelandic: ['is', 'mk'], | ||
slovenian: ['sl-SL'], | ||
romanian: ['ro'] | ||
} | ||
@@ -204,3 +211,10 @@ }; | ||
// It defaults to `'en'` with 2 plural forms. | ||
function transformPhrase(phrase, substitutions, locale, tokenRegex, pluralRules) { | ||
function transformPhrase( | ||
phrase, | ||
substitutions, | ||
locale, | ||
tokenRegex, | ||
pluralRules, | ||
replaceImplementation | ||
) { | ||
if (typeof phrase !== 'string') { | ||
@@ -216,2 +230,3 @@ throw new TypeError('Polyglot.transformPhrase expects argument #1 to be string'); | ||
var interpolationRegex = tokenRegex || defaultTokenRegex; | ||
var replace = replaceImplementation || defaultReplace; | ||
@@ -256,2 +271,3 @@ // allow number as a pluralization shortcut | ||
this.warn = opts.warn || warn; | ||
this.replaceImplementation = opts.replace || defaultReplace; | ||
this.tokenRegex = constructTokenRegex(opts.interpolation); | ||
@@ -412,3 +428,10 @@ this.pluralRules = opts.pluralRules || defaultPluralRules; | ||
var onMissingKey = this.onMissingKey; | ||
result = onMissingKey(key, opts, this.currentLocale, this.tokenRegex, this.pluralRules); | ||
result = onMissingKey( | ||
key, | ||
opts, | ||
this.currentLocale, | ||
this.tokenRegex, | ||
this.pluralRules, | ||
this.replaceImplementation | ||
); | ||
} else { | ||
@@ -419,3 +442,10 @@ this.warn('Missing translation for key: "' + key + '"'); | ||
if (typeof phrase === 'string') { | ||
result = transformPhrase(phrase, opts, this.currentLocale, this.tokenRegex, this.pluralRules); | ||
result = transformPhrase( | ||
phrase, | ||
opts, | ||
this.currentLocale, | ||
this.tokenRegex, | ||
this.pluralRules, | ||
this.replaceImplementation | ||
); | ||
} | ||
@@ -422,0 +452,0 @@ return result; |
{ | ||
"name": "node-polyglot", | ||
"version": "2.4.2", | ||
"version": "2.5.0", | ||
"description": "Give your JavaScript the ability to speak many languages.", | ||
"main": "index.js", | ||
"scripts": { | ||
"prepublish": "safe-publish-latest", | ||
"pretest": "npm run --silent lint", | ||
"test": "npm run --silent tests-only", | ||
"tests-only": "mocha test/*.js --reporter spec", | ||
"lint": "eslint *.js test/*.js", | ||
"prepublishOnly": "safe-publish-latest", | ||
"prepublish": "not-in-publish || npm run prepublishOnly", | ||
"pretest": "npm run lint", | ||
"test": "npm run tests-only", | ||
"tests-only": "nyc mocha test/*.js --reporter spec", | ||
"posttest": "aud --production", | ||
"lint": "eslint .", | ||
"docs": "docco -o docs/ index.js" | ||
@@ -29,16 +31,21 @@ }, | ||
"dependencies": { | ||
"array.prototype.foreach": "^1.0.0", | ||
"array.prototype.foreach": "^1.0.2", | ||
"has": "^1.0.3", | ||
"object.entries": "^1.1.4", | ||
"string.prototype.trim": "^1.2.4", | ||
"object.entries": "^1.1.5", | ||
"string.prototype.trim": "^1.2.6", | ||
"warning": "^4.0.3" | ||
}, | ||
"devDependencies": { | ||
"chai": "^4.3.4", | ||
"aud": "^2.0.0", | ||
"chai": "^3.5.0", | ||
"docco": "^0.7.0", | ||
"eslint": "^7.32.0", | ||
"eslint-config-airbnb-base": "^14.2.1", | ||
"eslint": "^8.18.0", | ||
"eslint-config-airbnb-base": "^15.0.0", | ||
"eslint-plugin-import": "^2.23.4", | ||
"in-publish": "^2.0.1", | ||
"iterate-iterator": "^1.0.2", | ||
"mocha": "^3.5.3", | ||
"safe-publish-latest": "^1.1.4", | ||
"nyc": "^10.3.2", | ||
"safe-publish-latest": "^2.0.0", | ||
"string.prototype.matchall": "^4.0.7", | ||
"uglify-js": "^2.7.3" | ||
@@ -45,0 +52,0 @@ }, |
@@ -6,2 +6,4 @@ 'use strict'; | ||
var forEach = require('array.prototype.foreach'); | ||
var iterate = require('iterate-iterator'); | ||
var matchAll = require('string.prototype.matchall'); | ||
@@ -133,2 +135,54 @@ describe('t', function () { | ||
it('supports custom replace implementation', function () { | ||
var instance = new Polyglot({ | ||
phrases: phrases, | ||
replace: function (interpolationRegex, callback) { | ||
var phrase = this; | ||
var i = 0; | ||
var children = []; | ||
iterate(matchAll(phrase, interpolationRegex), function (match) { | ||
if (match.index > i) { | ||
children.push(phrase.slice(i, match.index)); | ||
} | ||
children.push(callback(match[0], match[1])); | ||
i = match.index + match[0].length; | ||
}); | ||
if (i < phrase.length) { | ||
children.push(phrase.slice(i)); | ||
} | ||
return { type: 'might_be_react_fragment', children: children }; | ||
} | ||
}); | ||
expect(instance.t( | ||
'hi_name_welcome_to_place', | ||
{ | ||
name: { type: 'might_be_react_node', children: ['Rudolf'] }, | ||
place: { type: 'might_be_react_node', children: ['Earth'] } | ||
} | ||
)).to.deep.equal({ | ||
children: [ | ||
'Hi, ', | ||
{ | ||
children: [ | ||
'Rudolf' | ||
], | ||
type: 'might_be_react_node' | ||
}, | ||
', welcome to ', | ||
{ | ||
children: [ | ||
'Earth' | ||
], | ||
type: 'might_be_react_node' | ||
}, | ||
'!' | ||
], | ||
type: 'might_be_react_fragment' | ||
}); | ||
}); | ||
describe('onMissingKey', function () { | ||
@@ -219,2 +273,22 @@ it('calls the function when a key is missing', function () { | ||
it('interpolates properly in Arabic', function () { | ||
var phrases = { | ||
hello: 'الرمز ${code} غير صحيح' // eslint-disable-line no-template-curly-in-string | ||
}; | ||
var polyglot = new Polyglot({ | ||
phrases: phrases, | ||
locale: 'ar', | ||
interpolation: { prefix: '${', suffix: '}' } | ||
}); | ||
expect(polyglot.t('hello', { code: 'De30Niro' })).to.equal('الرمز De30Niro غير صحيح'); | ||
// note how the "30" in the next line shows up in the wrong place: | ||
expect(polyglot.t('hello', { code: '30DeNiro' })).to.equal('الرمز 30DeNiro غير صحيح'); | ||
// but with a directional marker character, it shows up in the right place: | ||
expect(polyglot.t('hello', { code: '\u200E30DeNiroMarker' })).to.equal('الرمز \u200E30DeNiroMarker غير صحيح'); | ||
// see https://github.com/airbnb/polyglot.js/issues/167 / https://stackoverflow.com/a/34903965 for why it's impractical to handle in polyglot | ||
}); | ||
it('pluralizes in Russian', function () { | ||
@@ -495,2 +569,48 @@ // English would be: "1 vote" / "%{smart_count} votes" | ||
}); | ||
it('pluralizes in Romanian', function () { | ||
var whatSomeoneTranslated = [ | ||
'%{smart_count} zi', | ||
'%{smart_count} zile', | ||
'%{smart_count} de zile' | ||
]; | ||
var phrases = { | ||
n_days: whatSomeoneTranslated.join(' |||| ') | ||
}; | ||
var polyglot = new Polyglot({ phrases: phrases, locale: 'ro' }); | ||
expect(polyglot.t('n_days', 0)).to.equal('0 zile'); | ||
expect(polyglot.t('n_days', 1)).to.equal('1 zi'); | ||
expect(polyglot.t('n_days', 2)).to.equal('2 zile'); | ||
expect(polyglot.t('n_days', 10)).to.equal('10 zile'); | ||
expect(polyglot.t('n_days', 19)).to.equal('19 zile'); | ||
expect(polyglot.t('n_days', 20)).to.equal('20 de zile'); | ||
expect(polyglot.t('n_days', 21)).to.equal('21 de zile'); | ||
expect(polyglot.t('n_days', 100)).to.equal('100 de zile'); | ||
expect(polyglot.t('n_days', 101)).to.equal('101 de zile'); | ||
expect(polyglot.t('n_days', 102)).to.equal('102 zile'); | ||
expect(polyglot.t('n_days', 119)).to.equal('119 zile'); | ||
expect(polyglot.t('n_days', 120)).to.equal('120 de zile'); | ||
}); | ||
it('pluralizes in Macedonian', function () { | ||
var whatSomeoneTranslated = [ | ||
'%{smart_count} ден', | ||
'%{smart_count} дена' | ||
]; | ||
var phrases = { | ||
n_days: whatSomeoneTranslated.join(' |||| ') | ||
}; | ||
var polyglot = new Polyglot({ phrases: phrases, locale: 'mk' }); | ||
expect(polyglot.t('n_days', 0)).to.equal('0 дена'); | ||
expect(polyglot.t('n_days', 1)).to.equal('1 ден'); | ||
expect(polyglot.t('n_days', 2)).to.equal('2 дена'); | ||
expect(polyglot.t('n_days', 10)).to.equal('10 дена'); | ||
expect(polyglot.t('n_days', 11)).to.equal('11 дена'); | ||
expect(polyglot.t('n_days', 21)).to.equal('21 ден'); | ||
expect(polyglot.t('n_days', 100)).to.equal('100 дена'); | ||
expect(polyglot.t('n_days', 101)).to.equal('101 ден'); | ||
expect(polyglot.t('n_days', 111)).to.equal('111 дена'); | ||
}); | ||
}); | ||
@@ -497,0 +617,0 @@ |
558893
28
1942
13
Updatedobject.entries@^1.1.5
Updatedstring.prototype.trim@^1.2.6