@lingui/format-po-gettext 4.13.0 → 4.14.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/po-gettext.cjs +110 -7
- package/dist/po-gettext.mjs +109 -7
- package/package.json +6 -5
package/dist/po-gettext.cjs
CHANGED
|
@@ -6,13 +6,72 @@ const PO = require('pofile');
|
|
|
6
6
|
const gettextPlurals = require('node-gettext/lib/plurals');
|
|
7
7
|
const generateMessageId = require('@lingui/message-utils/generateMessageId');
|
|
8
8
|
const formatPo = require('@lingui/format-po');
|
|
9
|
+
const cardinals = require('cldr-core/supplemental/plurals.json');
|
|
9
10
|
|
|
10
11
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
11
12
|
|
|
12
13
|
const pluralsCldr__default = /*#__PURE__*/_interopDefaultCompat(pluralsCldr);
|
|
13
14
|
const PO__default = /*#__PURE__*/_interopDefaultCompat(PO);
|
|
14
15
|
const gettextPlurals__default = /*#__PURE__*/_interopDefaultCompat(gettextPlurals);
|
|
16
|
+
const cardinals__default = /*#__PURE__*/_interopDefaultCompat(cardinals);
|
|
15
17
|
|
|
18
|
+
function renameKeys(rules) {
|
|
19
|
+
const result = {};
|
|
20
|
+
Object.keys(rules).forEach((k) => {
|
|
21
|
+
const newKey = k.match(/[^-]+$/)[0];
|
|
22
|
+
result[newKey] = rules[k];
|
|
23
|
+
});
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
function fillRange(value) {
|
|
27
|
+
let [start, end] = value.split("~");
|
|
28
|
+
const decimals = (start.split(".")[1] || "").length;
|
|
29
|
+
let mult = Math.pow(10, decimals);
|
|
30
|
+
const startNum = Number(start);
|
|
31
|
+
const endNum = Number(end);
|
|
32
|
+
let range = Array(Math.ceil(endNum * mult - startNum * mult + 1)).fill(0).map((v, idx) => (idx + startNum * mult) / mult);
|
|
33
|
+
let last = range[range.length - 1];
|
|
34
|
+
if (endNum !== last) {
|
|
35
|
+
throw new Error(`Range create error for ${value}: last value is ${last}`);
|
|
36
|
+
}
|
|
37
|
+
return range.map((v) => Number(v));
|
|
38
|
+
}
|
|
39
|
+
function createSamples(src) {
|
|
40
|
+
let result = [];
|
|
41
|
+
src.replace(/…/, "").trim().replace(/,$/, "").split(",").map(function(val) {
|
|
42
|
+
return val.trim();
|
|
43
|
+
}).forEach((val) => {
|
|
44
|
+
if (val.indexOf("~") !== -1) {
|
|
45
|
+
result = result.concat(fillRange(val));
|
|
46
|
+
} else {
|
|
47
|
+
result.push(Number(val));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
function createLocaleTest(rules) {
|
|
53
|
+
let result = {};
|
|
54
|
+
Object.keys(rules).forEach((form) => {
|
|
55
|
+
let samples = rules[form].split(/@integer|@decimal/).slice(1);
|
|
56
|
+
result[form] = [];
|
|
57
|
+
samples.forEach((sample) => {
|
|
58
|
+
result[form] = result[form].concat(createSamples(sample));
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
function getCldrPluralSamples() {
|
|
64
|
+
const pluralRules = {};
|
|
65
|
+
Object.entries(cardinals__default.supplemental["plurals-type-cardinal"]).forEach(
|
|
66
|
+
([loc, ruleset]) => {
|
|
67
|
+
let rules = renameKeys(ruleset);
|
|
68
|
+
pluralRules[loc.toLowerCase()] = createLocaleTest(rules);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
return pluralRules;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const cldrSamples = getCldrPluralSamples();
|
|
16
75
|
function stringifyICUCase(icuCase) {
|
|
17
76
|
return icuCase.tokens.map((token) => {
|
|
18
77
|
if (token.type === "content") {
|
|
@@ -90,13 +149,52 @@ function serializePlurals(item, message, id, isGeneratedId, options) {
|
|
|
90
149
|
}
|
|
91
150
|
return item;
|
|
92
151
|
}
|
|
93
|
-
const getPluralCases = (lang) => {
|
|
152
|
+
const getPluralCases = (lang, pluralFormsHeader) => {
|
|
153
|
+
let gettextPluralsInfo;
|
|
154
|
+
if (pluralFormsHeader) {
|
|
155
|
+
gettextPluralsInfo = parsePluralFormsFn(pluralFormsHeader);
|
|
156
|
+
}
|
|
94
157
|
const [correctLang] = lang.split(/[-_]/g);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
)
|
|
158
|
+
if (!gettextPluralsInfo) {
|
|
159
|
+
gettextPluralsInfo = gettextPlurals__default[correctLang];
|
|
160
|
+
}
|
|
161
|
+
if (!gettextPluralsInfo) {
|
|
162
|
+
if (lang !== "pseudo") {
|
|
163
|
+
console.warn(
|
|
164
|
+
`No plural rules found for language "${lang}". Please add a Plural-Forms header.`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
const cases = [...Array(pluralsCldr__default.forms(correctLang).length)];
|
|
170
|
+
for (let form of pluralsCldr__default.forms(correctLang)) {
|
|
171
|
+
const samples = cldrSamples[correctLang][form];
|
|
172
|
+
const pluralForm = Number(
|
|
173
|
+
gettextPluralsInfo.pluralsFunc(Number(samples[0]))
|
|
174
|
+
);
|
|
175
|
+
cases[pluralForm] = form;
|
|
176
|
+
}
|
|
177
|
+
return cases;
|
|
99
178
|
};
|
|
179
|
+
function parsePluralFormsFn(pluralFormsHeader) {
|
|
180
|
+
const [npluralsExpr, expr] = pluralFormsHeader.split(";");
|
|
181
|
+
try {
|
|
182
|
+
const nplurals = new Function(npluralsExpr + "; return nplurals;")();
|
|
183
|
+
const pluralsFunc = new Function(
|
|
184
|
+
"n",
|
|
185
|
+
expr + "; return plural;"
|
|
186
|
+
);
|
|
187
|
+
return {
|
|
188
|
+
nplurals,
|
|
189
|
+
pluralsFunc
|
|
190
|
+
};
|
|
191
|
+
} catch (e) {
|
|
192
|
+
console.warn(
|
|
193
|
+
`Plural-Forms header has incorrect value: ${pluralFormsHeader}`
|
|
194
|
+
);
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
100
198
|
const convertPluralsToICU = (item, pluralForms, lang, ctxPrefix = DEFAULT_CTX_PREFIX) => {
|
|
101
199
|
const translationCount = item.msgstr.length;
|
|
102
200
|
const messageKey = item.msgid;
|
|
@@ -138,7 +236,9 @@ const convertPluralsToICU = (item, pluralForms, lang, ctxPrefix = DEFAULT_CTX_PR
|
|
|
138
236
|
messageKey
|
|
139
237
|
);
|
|
140
238
|
}
|
|
141
|
-
const pluralClauses = item.msgstr.map(
|
|
239
|
+
const pluralClauses = item.msgstr.map(
|
|
240
|
+
(str, index) => pluralForms[index] ? pluralForms[index] + " {" + str + "}" : ""
|
|
241
|
+
).join(" ");
|
|
142
242
|
let pluralizeOn = ctx.get("pluralize_on");
|
|
143
243
|
if (!pluralizeOn) {
|
|
144
244
|
console.warn(
|
|
@@ -161,7 +261,10 @@ function formatter(options = {}) {
|
|
|
161
261
|
templateExtension: ".pot",
|
|
162
262
|
parse(content, ctx) {
|
|
163
263
|
const po = PO__default.parse(content);
|
|
164
|
-
let pluralForms = getPluralCases(
|
|
264
|
+
let pluralForms = getPluralCases(
|
|
265
|
+
po.headers.Language,
|
|
266
|
+
po.headers["Plural-Forms"]
|
|
267
|
+
);
|
|
165
268
|
po.items.forEach((item) => {
|
|
166
269
|
convertPluralsToICU(
|
|
167
270
|
item,
|
package/dist/po-gettext.mjs
CHANGED
|
@@ -4,7 +4,65 @@ import PO from 'pofile';
|
|
|
4
4
|
import gettextPlurals from 'node-gettext/lib/plurals';
|
|
5
5
|
import { generateMessageId } from '@lingui/message-utils/generateMessageId';
|
|
6
6
|
import { formatter as formatter$1 } from '@lingui/format-po';
|
|
7
|
+
import cardinals from 'cldr-core/supplemental/plurals.json';
|
|
7
8
|
|
|
9
|
+
function renameKeys(rules) {
|
|
10
|
+
const result = {};
|
|
11
|
+
Object.keys(rules).forEach((k) => {
|
|
12
|
+
const newKey = k.match(/[^-]+$/)[0];
|
|
13
|
+
result[newKey] = rules[k];
|
|
14
|
+
});
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
function fillRange(value) {
|
|
18
|
+
let [start, end] = value.split("~");
|
|
19
|
+
const decimals = (start.split(".")[1] || "").length;
|
|
20
|
+
let mult = Math.pow(10, decimals);
|
|
21
|
+
const startNum = Number(start);
|
|
22
|
+
const endNum = Number(end);
|
|
23
|
+
let range = Array(Math.ceil(endNum * mult - startNum * mult + 1)).fill(0).map((v, idx) => (idx + startNum * mult) / mult);
|
|
24
|
+
let last = range[range.length - 1];
|
|
25
|
+
if (endNum !== last) {
|
|
26
|
+
throw new Error(`Range create error for ${value}: last value is ${last}`);
|
|
27
|
+
}
|
|
28
|
+
return range.map((v) => Number(v));
|
|
29
|
+
}
|
|
30
|
+
function createSamples(src) {
|
|
31
|
+
let result = [];
|
|
32
|
+
src.replace(/…/, "").trim().replace(/,$/, "").split(",").map(function(val) {
|
|
33
|
+
return val.trim();
|
|
34
|
+
}).forEach((val) => {
|
|
35
|
+
if (val.indexOf("~") !== -1) {
|
|
36
|
+
result = result.concat(fillRange(val));
|
|
37
|
+
} else {
|
|
38
|
+
result.push(Number(val));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
function createLocaleTest(rules) {
|
|
44
|
+
let result = {};
|
|
45
|
+
Object.keys(rules).forEach((form) => {
|
|
46
|
+
let samples = rules[form].split(/@integer|@decimal/).slice(1);
|
|
47
|
+
result[form] = [];
|
|
48
|
+
samples.forEach((sample) => {
|
|
49
|
+
result[form] = result[form].concat(createSamples(sample));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function getCldrPluralSamples() {
|
|
55
|
+
const pluralRules = {};
|
|
56
|
+
Object.entries(cardinals.supplemental["plurals-type-cardinal"]).forEach(
|
|
57
|
+
([loc, ruleset]) => {
|
|
58
|
+
let rules = renameKeys(ruleset);
|
|
59
|
+
pluralRules[loc.toLowerCase()] = createLocaleTest(rules);
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
return pluralRules;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const cldrSamples = getCldrPluralSamples();
|
|
8
66
|
function stringifyICUCase(icuCase) {
|
|
9
67
|
return icuCase.tokens.map((token) => {
|
|
10
68
|
if (token.type === "content") {
|
|
@@ -82,13 +140,52 @@ function serializePlurals(item, message, id, isGeneratedId, options) {
|
|
|
82
140
|
}
|
|
83
141
|
return item;
|
|
84
142
|
}
|
|
85
|
-
const getPluralCases = (lang) => {
|
|
143
|
+
const getPluralCases = (lang, pluralFormsHeader) => {
|
|
144
|
+
let gettextPluralsInfo;
|
|
145
|
+
if (pluralFormsHeader) {
|
|
146
|
+
gettextPluralsInfo = parsePluralFormsFn(pluralFormsHeader);
|
|
147
|
+
}
|
|
86
148
|
const [correctLang] = lang.split(/[-_]/g);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
149
|
+
if (!gettextPluralsInfo) {
|
|
150
|
+
gettextPluralsInfo = gettextPlurals[correctLang];
|
|
151
|
+
}
|
|
152
|
+
if (!gettextPluralsInfo) {
|
|
153
|
+
if (lang !== "pseudo") {
|
|
154
|
+
console.warn(
|
|
155
|
+
`No plural rules found for language "${lang}". Please add a Plural-Forms header.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return void 0;
|
|
159
|
+
}
|
|
160
|
+
const cases = [...Array(pluralsCldr.forms(correctLang).length)];
|
|
161
|
+
for (let form of pluralsCldr.forms(correctLang)) {
|
|
162
|
+
const samples = cldrSamples[correctLang][form];
|
|
163
|
+
const pluralForm = Number(
|
|
164
|
+
gettextPluralsInfo.pluralsFunc(Number(samples[0]))
|
|
165
|
+
);
|
|
166
|
+
cases[pluralForm] = form;
|
|
167
|
+
}
|
|
168
|
+
return cases;
|
|
91
169
|
};
|
|
170
|
+
function parsePluralFormsFn(pluralFormsHeader) {
|
|
171
|
+
const [npluralsExpr, expr] = pluralFormsHeader.split(";");
|
|
172
|
+
try {
|
|
173
|
+
const nplurals = new Function(npluralsExpr + "; return nplurals;")();
|
|
174
|
+
const pluralsFunc = new Function(
|
|
175
|
+
"n",
|
|
176
|
+
expr + "; return plural;"
|
|
177
|
+
);
|
|
178
|
+
return {
|
|
179
|
+
nplurals,
|
|
180
|
+
pluralsFunc
|
|
181
|
+
};
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.warn(
|
|
184
|
+
`Plural-Forms header has incorrect value: ${pluralFormsHeader}`
|
|
185
|
+
);
|
|
186
|
+
return void 0;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
92
189
|
const convertPluralsToICU = (item, pluralForms, lang, ctxPrefix = DEFAULT_CTX_PREFIX) => {
|
|
93
190
|
const translationCount = item.msgstr.length;
|
|
94
191
|
const messageKey = item.msgid;
|
|
@@ -130,7 +227,9 @@ const convertPluralsToICU = (item, pluralForms, lang, ctxPrefix = DEFAULT_CTX_PR
|
|
|
130
227
|
messageKey
|
|
131
228
|
);
|
|
132
229
|
}
|
|
133
|
-
const pluralClauses = item.msgstr.map(
|
|
230
|
+
const pluralClauses = item.msgstr.map(
|
|
231
|
+
(str, index) => pluralForms[index] ? pluralForms[index] + " {" + str + "}" : ""
|
|
232
|
+
).join(" ");
|
|
134
233
|
let pluralizeOn = ctx.get("pluralize_on");
|
|
135
234
|
if (!pluralizeOn) {
|
|
136
235
|
console.warn(
|
|
@@ -153,7 +252,10 @@ function formatter(options = {}) {
|
|
|
153
252
|
templateExtension: ".pot",
|
|
154
253
|
parse(content, ctx) {
|
|
155
254
|
const po = PO.parse(content);
|
|
156
|
-
let pluralForms = getPluralCases(
|
|
255
|
+
let pluralForms = getPluralCases(
|
|
256
|
+
po.headers.Language,
|
|
257
|
+
po.headers["Plural-Forms"]
|
|
258
|
+
);
|
|
157
259
|
po.items.forEach((item) => {
|
|
158
260
|
convertPluralsToICU(
|
|
159
261
|
item,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingui/format-po-gettext",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.14.0",
|
|
4
4
|
"description": "Gettext PO format with gettext-style plurals for Lingui Catalogs",
|
|
5
5
|
"main": "./dist/po-gettext.cjs",
|
|
6
6
|
"module": "./dist/po-gettext.mjs",
|
|
@@ -41,10 +41,11 @@
|
|
|
41
41
|
"dist/"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@lingui/conf": "4.
|
|
45
|
-
"@lingui/format-po": "4.
|
|
46
|
-
"@lingui/message-utils": "4.
|
|
44
|
+
"@lingui/conf": "4.14.0",
|
|
45
|
+
"@lingui/format-po": "4.14.0",
|
|
46
|
+
"@lingui/message-utils": "4.14.0",
|
|
47
47
|
"@messageformat/parser": "^5.0.0",
|
|
48
|
+
"cldr-core": "^45.0.0",
|
|
48
49
|
"node-gettext": "^3.0.0",
|
|
49
50
|
"plurals-cldr": "^2.0.1",
|
|
50
51
|
"pofile": "^1.1.4"
|
|
@@ -55,5 +56,5 @@
|
|
|
55
56
|
"tsd": "^0.28.0",
|
|
56
57
|
"unbuild": "2.0.0"
|
|
57
58
|
},
|
|
58
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "8dcb749688e2f452f85fc0eaad4d033a44975b42"
|
|
59
60
|
}
|