i18next 23.7.19 → 23.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/i18next.js +88 -47
- package/dist/esm/i18next.bundled.js +88 -47
- package/dist/esm/i18next.js +88 -47
- package/dist/esm/package.json +1 -1
- package/dist/umd/i18next.js +88 -47
- package/dist/umd/i18next.min.js +1 -1
- package/i18next.js +88 -47
- package/i18next.min.js +1 -1
- package/package.json +1 -1
package/dist/cjs/i18next.js
CHANGED
|
@@ -78,8 +78,9 @@ class EventEmitter {
|
|
|
78
78
|
}
|
|
79
79
|
on(events, listener) {
|
|
80
80
|
events.split(' ').forEach(event => {
|
|
81
|
-
this.observers[event]
|
|
82
|
-
this.observers[event].
|
|
81
|
+
if (!this.observers[event]) this.observers[event] = new Map();
|
|
82
|
+
const numListeners = this.observers[event].get(listener) || 0;
|
|
83
|
+
this.observers[event].set(listener, numListeners + 1);
|
|
83
84
|
});
|
|
84
85
|
return this;
|
|
85
86
|
}
|
|
@@ -89,22 +90,28 @@ class EventEmitter {
|
|
|
89
90
|
delete this.observers[event];
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
|
-
this.observers[event]
|
|
93
|
+
this.observers[event].delete(listener);
|
|
93
94
|
}
|
|
94
95
|
emit(event) {
|
|
95
96
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
96
97
|
args[_key - 1] = arguments[_key];
|
|
97
98
|
}
|
|
98
99
|
if (this.observers[event]) {
|
|
99
|
-
const cloned =
|
|
100
|
-
cloned.forEach(
|
|
101
|
-
observer
|
|
100
|
+
const cloned = Array.from(this.observers[event].entries());
|
|
101
|
+
cloned.forEach(_ref => {
|
|
102
|
+
let [observer, numTimesAdded] = _ref;
|
|
103
|
+
for (let i = 0; i < numTimesAdded; i++) {
|
|
104
|
+
observer(...args);
|
|
105
|
+
}
|
|
102
106
|
});
|
|
103
107
|
}
|
|
104
108
|
if (this.observers['*']) {
|
|
105
|
-
const cloned =
|
|
106
|
-
cloned.forEach(
|
|
107
|
-
|
|
109
|
+
const cloned = Array.from(this.observers['*'].entries());
|
|
110
|
+
cloned.forEach(_ref2 => {
|
|
111
|
+
let [observer, numTimesAdded] = _ref2;
|
|
112
|
+
for (let i = 0; i < numTimesAdded; i++) {
|
|
113
|
+
observer.apply(observer, [event, ...args]);
|
|
114
|
+
}
|
|
108
115
|
});
|
|
109
116
|
}
|
|
110
117
|
}
|
|
@@ -130,28 +137,31 @@ function copy(a, s, t) {
|
|
|
130
137
|
if (s[m]) t[m] = s[m];
|
|
131
138
|
});
|
|
132
139
|
}
|
|
140
|
+
const lastOfPathSeparatorRegExp = /###/g;
|
|
133
141
|
function getLastOfPath(object, path, Empty) {
|
|
134
142
|
function cleanKey(key) {
|
|
135
|
-
return key && key.indexOf('###') > -1 ? key.replace(
|
|
143
|
+
return key && key.indexOf('###') > -1 ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
|
|
136
144
|
}
|
|
137
145
|
function canNotTraverseDeeper() {
|
|
138
146
|
return !object || typeof object === 'string';
|
|
139
147
|
}
|
|
140
|
-
const stack = typeof path !== 'string' ?
|
|
141
|
-
|
|
148
|
+
const stack = typeof path !== 'string' ? path : path.split('.');
|
|
149
|
+
let stackIndex = 0;
|
|
150
|
+
while (stackIndex < stack.length - 1) {
|
|
142
151
|
if (canNotTraverseDeeper()) return {};
|
|
143
|
-
const key = cleanKey(stack
|
|
152
|
+
const key = cleanKey(stack[stackIndex]);
|
|
144
153
|
if (!object[key] && Empty) object[key] = new Empty();
|
|
145
154
|
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
146
155
|
object = object[key];
|
|
147
156
|
} else {
|
|
148
157
|
object = {};
|
|
149
158
|
}
|
|
159
|
+
++stackIndex;
|
|
150
160
|
}
|
|
151
161
|
if (canNotTraverseDeeper()) return {};
|
|
152
162
|
return {
|
|
153
163
|
obj: object,
|
|
154
|
-
k: cleanKey(stack
|
|
164
|
+
k: cleanKey(stack[stackIndex])
|
|
155
165
|
};
|
|
156
166
|
}
|
|
157
167
|
function setPath(object, path, newValue) {
|
|
@@ -218,13 +228,34 @@ function escape(data) {
|
|
|
218
228
|
}
|
|
219
229
|
return data;
|
|
220
230
|
}
|
|
231
|
+
class RegExpCache {
|
|
232
|
+
constructor(capacity) {
|
|
233
|
+
this.capacity = capacity;
|
|
234
|
+
this.regExpMap = new Map();
|
|
235
|
+
this.regExpQueue = [];
|
|
236
|
+
}
|
|
237
|
+
getRegExp(pattern) {
|
|
238
|
+
const regExpFromCache = this.regExpMap.get(pattern);
|
|
239
|
+
if (regExpFromCache !== undefined) {
|
|
240
|
+
return regExpFromCache;
|
|
241
|
+
}
|
|
242
|
+
const regExpNew = new RegExp(pattern);
|
|
243
|
+
if (this.regExpQueue.length === this.capacity) {
|
|
244
|
+
this.regExpMap.delete(this.regExpQueue.shift());
|
|
245
|
+
}
|
|
246
|
+
this.regExpMap.set(pattern, regExpNew);
|
|
247
|
+
this.regExpQueue.push(pattern);
|
|
248
|
+
return regExpNew;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
221
251
|
const chars = [' ', ',', '?', '!', ';'];
|
|
252
|
+
const looksLikeObjectPathRegExpCache = new RegExpCache(20);
|
|
222
253
|
function looksLikeObjectPath(key, nsSeparator, keySeparator) {
|
|
223
254
|
nsSeparator = nsSeparator || '';
|
|
224
255
|
keySeparator = keySeparator || '';
|
|
225
256
|
const possibleChars = chars.filter(c => nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0);
|
|
226
257
|
if (possibleChars.length === 0) return true;
|
|
227
|
-
const r =
|
|
258
|
+
const r = looksLikeObjectPathRegExpCache.getRegExp(`(${possibleChars.map(c => c === '?' ? '\\?' : c).join('|')})`);
|
|
228
259
|
let matched = !r.test(key);
|
|
229
260
|
if (!matched) {
|
|
230
261
|
const ki = key.indexOf(keySeparator);
|
|
@@ -238,33 +269,26 @@ function deepFind(obj, path) {
|
|
|
238
269
|
let keySeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.';
|
|
239
270
|
if (!obj) return undefined;
|
|
240
271
|
if (obj[path]) return obj[path];
|
|
241
|
-
const
|
|
272
|
+
const tokens = path.split(keySeparator);
|
|
242
273
|
let current = obj;
|
|
243
|
-
for (let i = 0; i <
|
|
244
|
-
if (!current)
|
|
245
|
-
if (typeof current[paths[i]] === 'string' && i + 1 < paths.length) {
|
|
274
|
+
for (let i = 0; i < tokens.length;) {
|
|
275
|
+
if (!current || typeof current !== 'object') {
|
|
246
276
|
return undefined;
|
|
247
277
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
j++;
|
|
254
|
-
p = paths.slice(i, i + j).join(keySeparator);
|
|
255
|
-
mix = current[p];
|
|
278
|
+
let next;
|
|
279
|
+
let nextPath = '';
|
|
280
|
+
for (let j = i; j < tokens.length; ++j) {
|
|
281
|
+
if (j !== i) {
|
|
282
|
+
nextPath += keySeparator;
|
|
256
283
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
284
|
+
nextPath += tokens[j];
|
|
285
|
+
next = current[nextPath];
|
|
286
|
+
if (next !== undefined) {
|
|
287
|
+
i += j - i + 1;
|
|
288
|
+
break;
|
|
262
289
|
}
|
|
263
|
-
const joinedPath = paths.slice(i + j).join(keySeparator);
|
|
264
|
-
if (joinedPath) return deepFind(mix, joinedPath, keySeparator);
|
|
265
|
-
return undefined;
|
|
266
290
|
}
|
|
267
|
-
current =
|
|
291
|
+
current = next;
|
|
268
292
|
}
|
|
269
293
|
return current;
|
|
270
294
|
}
|
|
@@ -304,11 +328,20 @@ class ResourceStore extends EventEmitter {
|
|
|
304
328
|
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
305
329
|
const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
|
|
306
330
|
const ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure;
|
|
307
|
-
let path
|
|
308
|
-
if (key && typeof key !== 'string') path = path.concat(key);
|
|
309
|
-
if (key && typeof key === 'string') path = path.concat(keySeparator ? key.split(keySeparator) : key);
|
|
331
|
+
let path;
|
|
310
332
|
if (lng.indexOf('.') > -1) {
|
|
311
333
|
path = lng.split('.');
|
|
334
|
+
} else {
|
|
335
|
+
path = [lng, ns];
|
|
336
|
+
if (key) {
|
|
337
|
+
if (Array.isArray(key)) {
|
|
338
|
+
path.push(...key);
|
|
339
|
+
} else if (typeof key === 'string' && keySeparator) {
|
|
340
|
+
path.push(...key.split(keySeparator));
|
|
341
|
+
} else {
|
|
342
|
+
path.push(key);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
312
345
|
}
|
|
313
346
|
const result = getPath(this.data, path);
|
|
314
347
|
if (result || !ignoreJSONStructure || typeof key !== 'string') return result;
|
|
@@ -606,7 +639,11 @@ class Translator extends EventEmitter {
|
|
|
606
639
|
if (this.options.saveMissing) {
|
|
607
640
|
if (this.options.saveMissingPlurals && needsPluralHandling) {
|
|
608
641
|
lngs.forEach(language => {
|
|
609
|
-
this.pluralResolver.getSuffixes(language, options)
|
|
642
|
+
const suffixes = this.pluralResolver.getSuffixes(language, options);
|
|
643
|
+
if (needsZeroSuffixLookup && options[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.indexOf(`${this.options.pluralSeparator}zero`) < 0) {
|
|
644
|
+
suffixes.push(`${this.options.pluralSeparator}zero`);
|
|
645
|
+
}
|
|
646
|
+
suffixes.forEach(suffix => {
|
|
610
647
|
send([language], key + suffix, options[`defaultValue${suffix}`] || defaultValue);
|
|
611
648
|
});
|
|
612
649
|
});
|
|
@@ -1129,7 +1166,7 @@ class PluralResolver {
|
|
|
1129
1166
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1130
1167
|
if (this.shouldUseIntlApi()) {
|
|
1131
1168
|
try {
|
|
1132
|
-
return new Intl.PluralRules(getCleanedCode(code), {
|
|
1169
|
+
return new Intl.PluralRules(getCleanedCode(code === 'dev' ? 'en' : code), {
|
|
1133
1170
|
type: options.ordinal ? 'ordinal' : 'cardinal'
|
|
1134
1171
|
});
|
|
1135
1172
|
} catch (err) {
|
|
@@ -1243,12 +1280,16 @@ class Interpolator {
|
|
|
1243
1280
|
if (this.options) this.init(this.options);
|
|
1244
1281
|
}
|
|
1245
1282
|
resetRegExp() {
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1283
|
+
const getOrResetRegExp = (existingRegExp, pattern) => {
|
|
1284
|
+
if (existingRegExp && existingRegExp.source === pattern) {
|
|
1285
|
+
existingRegExp.lastIndex = 0;
|
|
1286
|
+
return existingRegExp;
|
|
1287
|
+
}
|
|
1288
|
+
return new RegExp(pattern, 'g');
|
|
1289
|
+
};
|
|
1290
|
+
this.regexp = getOrResetRegExp(this.regexp, `${this.prefix}(.+?)${this.suffix}`);
|
|
1291
|
+
this.regexpUnescape = getOrResetRegExp(this.regexpUnescape, `${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`);
|
|
1292
|
+
this.nestingRegexp = getOrResetRegExp(this.nestingRegexp, `${this.nestingPrefix}(.+?)${this.nestingSuffix}`);
|
|
1252
1293
|
}
|
|
1253
1294
|
interpolate(str, data, lng, options) {
|
|
1254
1295
|
let match;
|
|
@@ -76,8 +76,9 @@ class EventEmitter {
|
|
|
76
76
|
}
|
|
77
77
|
on(events, listener) {
|
|
78
78
|
events.split(' ').forEach(event => {
|
|
79
|
-
this.observers[event]
|
|
80
|
-
this.observers[event].
|
|
79
|
+
if (!this.observers[event]) this.observers[event] = new Map();
|
|
80
|
+
const numListeners = this.observers[event].get(listener) || 0;
|
|
81
|
+
this.observers[event].set(listener, numListeners + 1);
|
|
81
82
|
});
|
|
82
83
|
return this;
|
|
83
84
|
}
|
|
@@ -87,22 +88,28 @@ class EventEmitter {
|
|
|
87
88
|
delete this.observers[event];
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
|
-
this.observers[event]
|
|
91
|
+
this.observers[event].delete(listener);
|
|
91
92
|
}
|
|
92
93
|
emit(event) {
|
|
93
94
|
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
|
94
95
|
args[_key - 1] = arguments[_key];
|
|
95
96
|
}
|
|
96
97
|
if (this.observers[event]) {
|
|
97
|
-
const cloned =
|
|
98
|
-
cloned.forEach(
|
|
99
|
-
observer
|
|
98
|
+
const cloned = Array.from(this.observers[event].entries());
|
|
99
|
+
cloned.forEach(_ref => {
|
|
100
|
+
let [observer, numTimesAdded] = _ref;
|
|
101
|
+
for (let i = 0; i < numTimesAdded; i++) {
|
|
102
|
+
observer(...args);
|
|
103
|
+
}
|
|
100
104
|
});
|
|
101
105
|
}
|
|
102
106
|
if (this.observers['*']) {
|
|
103
|
-
const cloned =
|
|
104
|
-
cloned.forEach(
|
|
105
|
-
|
|
107
|
+
const cloned = Array.from(this.observers['*'].entries());
|
|
108
|
+
cloned.forEach(_ref2 => {
|
|
109
|
+
let [observer, numTimesAdded] = _ref2;
|
|
110
|
+
for (let i = 0; i < numTimesAdded; i++) {
|
|
111
|
+
observer.apply(observer, [event, ...args]);
|
|
112
|
+
}
|
|
106
113
|
});
|
|
107
114
|
}
|
|
108
115
|
}
|
|
@@ -128,28 +135,31 @@ function copy(a, s, t) {
|
|
|
128
135
|
if (s[m]) t[m] = s[m];
|
|
129
136
|
});
|
|
130
137
|
}
|
|
138
|
+
const lastOfPathSeparatorRegExp = /###/g;
|
|
131
139
|
function getLastOfPath(object, path, Empty) {
|
|
132
140
|
function cleanKey(key) {
|
|
133
|
-
return key && key.indexOf('###') > -1 ? key.replace(
|
|
141
|
+
return key && key.indexOf('###') > -1 ? key.replace(lastOfPathSeparatorRegExp, '.') : key;
|
|
134
142
|
}
|
|
135
143
|
function canNotTraverseDeeper() {
|
|
136
144
|
return !object || typeof object === 'string';
|
|
137
145
|
}
|
|
138
|
-
const stack = typeof path !== 'string' ?
|
|
139
|
-
|
|
146
|
+
const stack = typeof path !== 'string' ? path : path.split('.');
|
|
147
|
+
let stackIndex = 0;
|
|
148
|
+
while (stackIndex < stack.length - 1) {
|
|
140
149
|
if (canNotTraverseDeeper()) return {};
|
|
141
|
-
const key = cleanKey(stack
|
|
150
|
+
const key = cleanKey(stack[stackIndex]);
|
|
142
151
|
if (!object[key] && Empty) object[key] = new Empty();
|
|
143
152
|
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
144
153
|
object = object[key];
|
|
145
154
|
} else {
|
|
146
155
|
object = {};
|
|
147
156
|
}
|
|
157
|
+
++stackIndex;
|
|
148
158
|
}
|
|
149
159
|
if (canNotTraverseDeeper()) return {};
|
|
150
160
|
return {
|
|
151
161
|
obj: object,
|
|
152
|
-
k: cleanKey(stack
|
|
162
|
+
k: cleanKey(stack[stackIndex])
|
|
153
163
|
};
|
|
154
164
|
}
|
|
155
165
|
function setPath(object, path, newValue) {
|
|
@@ -216,13 +226,34 @@ function escape(data) {
|
|
|
216
226
|
}
|
|
217
227
|
return data;
|
|
218
228
|
}
|
|
229
|
+
class RegExpCache {
|
|
230
|
+
constructor(capacity) {
|
|
231
|
+
this.capacity = capacity;
|
|
232
|
+
this.regExpMap = new Map();
|
|
233
|
+
this.regExpQueue = [];
|
|
234
|
+
}
|
|
235
|
+
getRegExp(pattern) {
|
|
236
|
+
const regExpFromCache = this.regExpMap.get(pattern);
|
|
237
|
+
if (regExpFromCache !== undefined) {
|
|
238
|
+
return regExpFromCache;
|
|
239
|
+
}
|
|
240
|
+
const regExpNew = new RegExp(pattern);
|
|
241
|
+
if (this.regExpQueue.length === this.capacity) {
|
|
242
|
+
this.regExpMap.delete(this.regExpQueue.shift());
|
|
243
|
+
}
|
|
244
|
+
this.regExpMap.set(pattern, regExpNew);
|
|
245
|
+
this.regExpQueue.push(pattern);
|
|
246
|
+
return regExpNew;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
219
249
|
const chars = [' ', ',', '?', '!', ';'];
|
|
250
|
+
const looksLikeObjectPathRegExpCache = new RegExpCache(20);
|
|
220
251
|
function looksLikeObjectPath(key, nsSeparator, keySeparator) {
|
|
221
252
|
nsSeparator = nsSeparator || '';
|
|
222
253
|
keySeparator = keySeparator || '';
|
|
223
254
|
const possibleChars = chars.filter(c => nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0);
|
|
224
255
|
if (possibleChars.length === 0) return true;
|
|
225
|
-
const r =
|
|
256
|
+
const r = looksLikeObjectPathRegExpCache.getRegExp(`(${possibleChars.map(c => c === '?' ? '\\?' : c).join('|')})`);
|
|
226
257
|
let matched = !r.test(key);
|
|
227
258
|
if (!matched) {
|
|
228
259
|
const ki = key.indexOf(keySeparator);
|
|
@@ -236,33 +267,26 @@ function deepFind(obj, path) {
|
|
|
236
267
|
let keySeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.';
|
|
237
268
|
if (!obj) return undefined;
|
|
238
269
|
if (obj[path]) return obj[path];
|
|
239
|
-
const
|
|
270
|
+
const tokens = path.split(keySeparator);
|
|
240
271
|
let current = obj;
|
|
241
|
-
for (let i = 0; i <
|
|
242
|
-
if (!current)
|
|
243
|
-
if (typeof current[paths[i]] === 'string' && i + 1 < paths.length) {
|
|
272
|
+
for (let i = 0; i < tokens.length;) {
|
|
273
|
+
if (!current || typeof current !== 'object') {
|
|
244
274
|
return undefined;
|
|
245
275
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
j++;
|
|
252
|
-
p = paths.slice(i, i + j).join(keySeparator);
|
|
253
|
-
mix = current[p];
|
|
276
|
+
let next;
|
|
277
|
+
let nextPath = '';
|
|
278
|
+
for (let j = i; j < tokens.length; ++j) {
|
|
279
|
+
if (j !== i) {
|
|
280
|
+
nextPath += keySeparator;
|
|
254
281
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (
|
|
258
|
-
|
|
259
|
-
|
|
282
|
+
nextPath += tokens[j];
|
|
283
|
+
next = current[nextPath];
|
|
284
|
+
if (next !== undefined) {
|
|
285
|
+
i += j - i + 1;
|
|
286
|
+
break;
|
|
260
287
|
}
|
|
261
|
-
const joinedPath = paths.slice(i + j).join(keySeparator);
|
|
262
|
-
if (joinedPath) return deepFind(mix, joinedPath, keySeparator);
|
|
263
|
-
return undefined;
|
|
264
288
|
}
|
|
265
|
-
current =
|
|
289
|
+
current = next;
|
|
266
290
|
}
|
|
267
291
|
return current;
|
|
268
292
|
}
|
|
@@ -302,11 +326,20 @@ class ResourceStore extends EventEmitter {
|
|
|
302
326
|
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
303
327
|
const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
|
|
304
328
|
const ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure;
|
|
305
|
-
let path
|
|
306
|
-
if (key && typeof key !== 'string') path = path.concat(key);
|
|
307
|
-
if (key && typeof key === 'string') path = path.concat(keySeparator ? key.split(keySeparator) : key);
|
|
329
|
+
let path;
|
|
308
330
|
if (lng.indexOf('.') > -1) {
|
|
309
331
|
path = lng.split('.');
|
|
332
|
+
} else {
|
|
333
|
+
path = [lng, ns];
|
|
334
|
+
if (key) {
|
|
335
|
+
if (Array.isArray(key)) {
|
|
336
|
+
path.push(...key);
|
|
337
|
+
} else if (typeof key === 'string' && keySeparator) {
|
|
338
|
+
path.push(...key.split(keySeparator));
|
|
339
|
+
} else {
|
|
340
|
+
path.push(key);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
310
343
|
}
|
|
311
344
|
const result = getPath(this.data, path);
|
|
312
345
|
if (result || !ignoreJSONStructure || typeof key !== 'string') return result;
|
|
@@ -604,7 +637,11 @@ class Translator extends EventEmitter {
|
|
|
604
637
|
if (this.options.saveMissing) {
|
|
605
638
|
if (this.options.saveMissingPlurals && needsPluralHandling) {
|
|
606
639
|
lngs.forEach(language => {
|
|
607
|
-
this.pluralResolver.getSuffixes(language, options)
|
|
640
|
+
const suffixes = this.pluralResolver.getSuffixes(language, options);
|
|
641
|
+
if (needsZeroSuffixLookup && options[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.indexOf(`${this.options.pluralSeparator}zero`) < 0) {
|
|
642
|
+
suffixes.push(`${this.options.pluralSeparator}zero`);
|
|
643
|
+
}
|
|
644
|
+
suffixes.forEach(suffix => {
|
|
608
645
|
send([language], key + suffix, options[`defaultValue${suffix}`] || defaultValue);
|
|
609
646
|
});
|
|
610
647
|
});
|
|
@@ -1127,7 +1164,7 @@ class PluralResolver {
|
|
|
1127
1164
|
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1128
1165
|
if (this.shouldUseIntlApi()) {
|
|
1129
1166
|
try {
|
|
1130
|
-
return new Intl.PluralRules(getCleanedCode(code), {
|
|
1167
|
+
return new Intl.PluralRules(getCleanedCode(code === 'dev' ? 'en' : code), {
|
|
1131
1168
|
type: options.ordinal ? 'ordinal' : 'cardinal'
|
|
1132
1169
|
});
|
|
1133
1170
|
} catch (err) {
|
|
@@ -1241,12 +1278,16 @@ class Interpolator {
|
|
|
1241
1278
|
if (this.options) this.init(this.options);
|
|
1242
1279
|
}
|
|
1243
1280
|
resetRegExp() {
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1281
|
+
const getOrResetRegExp = (existingRegExp, pattern) => {
|
|
1282
|
+
if (existingRegExp && existingRegExp.source === pattern) {
|
|
1283
|
+
existingRegExp.lastIndex = 0;
|
|
1284
|
+
return existingRegExp;
|
|
1285
|
+
}
|
|
1286
|
+
return new RegExp(pattern, 'g');
|
|
1287
|
+
};
|
|
1288
|
+
this.regexp = getOrResetRegExp(this.regexp, `${this.prefix}(.+?)${this.suffix}`);
|
|
1289
|
+
this.regexpUnescape = getOrResetRegExp(this.regexpUnescape, `${this.prefix}${this.unescapePrefix}(.+?)${this.unescapeSuffix}${this.suffix}`);
|
|
1290
|
+
this.nestingRegexp = getOrResetRegExp(this.nestingRegexp, `${this.nestingPrefix}(.+?)${this.nestingSuffix}`);
|
|
1250
1291
|
}
|
|
1251
1292
|
interpolate(str, data, lng, options) {
|
|
1252
1293
|
let match;
|