@lingui/format-po-gettext 4.0.0-next.2
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/README.md +92 -0
- package/dist/po-gettext.cjs +176 -0
- package/dist/po-gettext.d.ts +17 -0
- package/dist/po-gettext.mjs +174 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
[![License][badge-license]][license]
|
|
2
|
+
[![Version][badge-version]][package]
|
|
3
|
+
[![Downloads][badge-downloads]][package]
|
|
4
|
+
|
|
5
|
+
# @lingui/format-po-gettext
|
|
6
|
+
|
|
7
|
+
> Read and write message catalogs in Gettext PO format with gettext-style plurals
|
|
8
|
+
>
|
|
9
|
+
> Converts ICU Plural expressions into native gettext plurals
|
|
10
|
+
|
|
11
|
+
`@lingui/format-po-gettext` is part of [LinguiJS][linguijs]. See the
|
|
12
|
+
[documentation][documentation] for all information, tutorials and examples.
|
|
13
|
+
|
|
14
|
+
> **Warning**
|
|
15
|
+
> This formatter is made for compatibility with TMS, which does not support ICU expressions in PO files.
|
|
16
|
+
>
|
|
17
|
+
> It does not support all features of LinguiJS and should be carefully considered over other formats.
|
|
18
|
+
>
|
|
19
|
+
> Not supported features (native gettext doesn't support this):
|
|
20
|
+
> - SelectOrdinal
|
|
21
|
+
> - Select
|
|
22
|
+
> - Nested ICU Expressions
|
|
23
|
+
> - Signed digits and fractions (-5, and 0.15) in plurals
|
|
24
|
+
|
|
25
|
+
## Catalog example
|
|
26
|
+
|
|
27
|
+
```po
|
|
28
|
+
#. js-lingui-id: WGI12K
|
|
29
|
+
#. js-lingui:icu=%7BanotherCount%2C+plural%2C+one+%7BSingular+case%7D+other+%7BCase+number+%7BanotherCount%7D%7D%7D&pluralize_on=anotherCount
|
|
30
|
+
msgid "Singular case"
|
|
31
|
+
msgid_plural "Case number {anotherCount}"
|
|
32
|
+
msgstr[0] "Singular case"
|
|
33
|
+
msgstr[1] "Case number {anotherCount}"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npm install --save-dev @lingui/format-po-gettext
|
|
40
|
+
# yarn add --dev @lingui/format-po-gettext
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
// lingui.config.{js,ts}
|
|
47
|
+
import {formatter} from "@lingui/format-po-gettext"
|
|
48
|
+
|
|
49
|
+
export default {
|
|
50
|
+
[...]
|
|
51
|
+
format: formatter({lineNumbers: false}),
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Possible options:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
export type PoGettextFormatterOptions = {
|
|
59
|
+
/**
|
|
60
|
+
* Print places where message is used
|
|
61
|
+
*
|
|
62
|
+
* @default true
|
|
63
|
+
*/
|
|
64
|
+
origins?: boolean
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Print line numbers in origins
|
|
68
|
+
*
|
|
69
|
+
* @default true
|
|
70
|
+
*/
|
|
71
|
+
lineNumbers?: boolean
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Disable warning about unsupported `Select` feature encountered in catalogs
|
|
75
|
+
*
|
|
76
|
+
* @default false
|
|
77
|
+
*/
|
|
78
|
+
disableSelectWarning?: boolean
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
This package is licensed under [MIT][license] license.
|
|
85
|
+
|
|
86
|
+
[license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
|
|
87
|
+
[linguijs]: https://github.com/lingui/js-lingui
|
|
88
|
+
[documentation]: https://lingui.dev
|
|
89
|
+
[package]: https://www.npmjs.com/package/@lingui/format-po-gettext
|
|
90
|
+
[badge-downloads]: https://img.shields.io/npm/dw/@lingui/format-po-gettext.svg
|
|
91
|
+
[badge-version]: https://img.shields.io/npm/v/@lingui/format-po-gettext.svg
|
|
92
|
+
[badge-license]: https://img.shields.io/npm/l/@lingui/format-po-gettext.svg
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const parser = require('@messageformat/parser');
|
|
4
|
+
const pluralsCldr = require('plurals-cldr');
|
|
5
|
+
const PO = require('pofile');
|
|
6
|
+
const gettextPlurals = require('node-gettext/lib/plurals');
|
|
7
|
+
const api = require('@lingui/cli/api');
|
|
8
|
+
const formatPo = require('@lingui/format-po');
|
|
9
|
+
|
|
10
|
+
function stringifyICUCase(icuCase) {
|
|
11
|
+
return icuCase.tokens.map((token) => {
|
|
12
|
+
if (token.type === "content") {
|
|
13
|
+
return token.value;
|
|
14
|
+
} else if (token.type === "octothorpe") {
|
|
15
|
+
return "#";
|
|
16
|
+
} else if (token.type === "argument") {
|
|
17
|
+
return "{" + token.arg + "}";
|
|
18
|
+
} else {
|
|
19
|
+
console.warn(
|
|
20
|
+
`Unexpected token "${token}" while stringifying plural case "${icuCase}". Token will be ignored.`
|
|
21
|
+
);
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
}).join("");
|
|
25
|
+
}
|
|
26
|
+
const ICU_PLURAL_REGEX = /^{.*, plural, .*}$/;
|
|
27
|
+
const ICU_SELECT_REGEX = /^{.*, select(Ordinal)?, .*}$/;
|
|
28
|
+
const LINE_ENDINGS = /\r?\n/g;
|
|
29
|
+
const CTX_PREFIX = "js-lingui:";
|
|
30
|
+
function serializePlurals(item, message, id, isGeneratedId, options) {
|
|
31
|
+
const icuMessage = message.message;
|
|
32
|
+
if (!icuMessage) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const _simplifiedMessage = icuMessage.replace(LINE_ENDINGS, " ");
|
|
36
|
+
if (ICU_PLURAL_REGEX.test(_simplifiedMessage)) {
|
|
37
|
+
try {
|
|
38
|
+
const messageAst = parser.parse(icuMessage)[0];
|
|
39
|
+
if (messageAst.cases.some(
|
|
40
|
+
(icuCase) => icuCase.tokens.some((token) => token.type === "plural")
|
|
41
|
+
)) {
|
|
42
|
+
console.warn(
|
|
43
|
+
`Nested plurals cannot be expressed with gettext plurals. Message with key "%s" will not be saved correctly.`,
|
|
44
|
+
id
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
const ctx = new URLSearchParams({
|
|
48
|
+
pluralize_on: messageAst.arg
|
|
49
|
+
});
|
|
50
|
+
if (isGeneratedId) {
|
|
51
|
+
item.msgid = stringifyICUCase(messageAst.cases[0]);
|
|
52
|
+
item.msgid_plural = stringifyICUCase(
|
|
53
|
+
messageAst.cases[messageAst.cases.length - 1]
|
|
54
|
+
);
|
|
55
|
+
ctx.set("icu", icuMessage);
|
|
56
|
+
} else {
|
|
57
|
+
item.msgid_plural = id + "_plural";
|
|
58
|
+
}
|
|
59
|
+
ctx.sort();
|
|
60
|
+
item.extractedComments.push(CTX_PREFIX + ctx.toString());
|
|
61
|
+
if (message.translation?.length > 0) {
|
|
62
|
+
const ast = parser.parse(message.translation)[0];
|
|
63
|
+
if (ast.cases == null) {
|
|
64
|
+
console.warn(
|
|
65
|
+
`Found translation without plural cases for key "${id}". This likely means that a translated .po file misses multiple msgstr[] entries for the key. Translation found: "${message.translation}"`
|
|
66
|
+
);
|
|
67
|
+
item.msgstr = [message.translation];
|
|
68
|
+
} else {
|
|
69
|
+
item.msgstr = ast.cases.map(stringifyICUCase);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
console.error(`Error parsing message ICU for key "${id}":`, e);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
if (!options.disableSelectWarning && ICU_SELECT_REGEX.test(_simplifiedMessage)) {
|
|
77
|
+
console.warn(
|
|
78
|
+
`ICU 'select' and 'selectOrdinal' formats cannot be expressed natively in gettext format. Item with key "%s" will be included in the catalog as raw ICU message. To disable this warning, include '{ disableSelectWarning: true }' in the config's 'formatOptions'`,
|
|
79
|
+
id
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
item.msgstr = [message.translation];
|
|
83
|
+
}
|
|
84
|
+
return item;
|
|
85
|
+
}
|
|
86
|
+
const getPluralCases = (lang) => {
|
|
87
|
+
const [correctLang] = lang.split(/[-_]/g);
|
|
88
|
+
const gettextPluralsInfo = gettextPlurals[correctLang];
|
|
89
|
+
return gettextPluralsInfo?.examples.map(
|
|
90
|
+
(pluralCase) => pluralsCldr(correctLang, pluralCase.sample)
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
const convertPluralsToICU = (item, pluralForms, lang) => {
|
|
94
|
+
const translationCount = item.msgstr.length;
|
|
95
|
+
const messageKey = item.msgid;
|
|
96
|
+
if (translationCount <= 1 && !item.msgid_plural) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (!item.msgid_plural) {
|
|
100
|
+
console.warn(
|
|
101
|
+
`Multiple translations for item with key "%s" but missing 'msgid_plural' in catalog "${lang}". This is not supported and the plural cases will be ignored.`,
|
|
102
|
+
messageKey
|
|
103
|
+
);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const contextComment = item.extractedComments.find((comment) => comment.startsWith(CTX_PREFIX))?.substr(CTX_PREFIX.length);
|
|
107
|
+
const ctx = new URLSearchParams(contextComment);
|
|
108
|
+
if (contextComment != null) {
|
|
109
|
+
item.extractedComments = item.extractedComments.filter(
|
|
110
|
+
(comment) => !comment.startsWith(CTX_PREFIX)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const storedICU = ctx.get("icu");
|
|
114
|
+
if (storedICU != null) {
|
|
115
|
+
item.msgid = storedICU;
|
|
116
|
+
}
|
|
117
|
+
if (item.msgstr.every((str) => str.length === 0)) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (pluralForms == null) {
|
|
121
|
+
console.warn(
|
|
122
|
+
`Multiple translations for item with key "%s" in language "${lang}", but no plural cases were found. This prohibits the translation of .po plurals into ICU plurals. Pluralization will not work for this key.`,
|
|
123
|
+
messageKey
|
|
124
|
+
);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const pluralCount = pluralForms.length;
|
|
128
|
+
if (translationCount > pluralCount) {
|
|
129
|
+
console.warn(
|
|
130
|
+
`More translations provided (${translationCount}) for item with key "%s" in language "${lang}" than there are plural cases available (${pluralCount}). This will result in not all translations getting picked up.`,
|
|
131
|
+
messageKey
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
const pluralClauses = item.msgstr.map((str, index) => pluralForms[index] + " {" + str + "}").join(" ");
|
|
135
|
+
let pluralizeOn = ctx.get("pluralize_on");
|
|
136
|
+
if (!pluralizeOn) {
|
|
137
|
+
console.warn(
|
|
138
|
+
`Unable to determine plural placeholder name for item with key "%s" in language "${lang}" (should be stored in a comment starting with "#. ${CTX_PREFIX}"), assuming "count".`,
|
|
139
|
+
messageKey
|
|
140
|
+
);
|
|
141
|
+
pluralizeOn = "count";
|
|
142
|
+
}
|
|
143
|
+
item.msgstr = ["{" + pluralizeOn + ", plural, " + pluralClauses + "}"];
|
|
144
|
+
};
|
|
145
|
+
function formatter(options = {}) {
|
|
146
|
+
options = {
|
|
147
|
+
origins: true,
|
|
148
|
+
lineNumbers: true,
|
|
149
|
+
...options
|
|
150
|
+
};
|
|
151
|
+
const formatter2 = formatPo.formatter(options);
|
|
152
|
+
return {
|
|
153
|
+
catalogExtension: ".po",
|
|
154
|
+
templateExtension: ".pot",
|
|
155
|
+
parse(content) {
|
|
156
|
+
const po = PO.parse(content);
|
|
157
|
+
let pluralForms = getPluralCases(po.headers.Language);
|
|
158
|
+
po.items.forEach((item) => {
|
|
159
|
+
convertPluralsToICU(item, pluralForms, po.headers.Language);
|
|
160
|
+
});
|
|
161
|
+
return formatter2.parse(po.toString());
|
|
162
|
+
},
|
|
163
|
+
serialize(catalog, ctx) {
|
|
164
|
+
const po = PO.parse(formatter2.serialize(catalog, ctx));
|
|
165
|
+
po.items = po.items.map((item) => {
|
|
166
|
+
const isGeneratedId = !item.flags["explicit-id"];
|
|
167
|
+
const id = isGeneratedId ? api.generateMessageId(item.msgid, item.msgctxt) : item.msgid;
|
|
168
|
+
const message = catalog[id];
|
|
169
|
+
return serializePlurals(item, message, id, isGeneratedId, options);
|
|
170
|
+
});
|
|
171
|
+
return po.toString();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
exports.formatter = formatter;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CatalogType } from '@lingui/conf';
|
|
2
|
+
import { PoFormatterOptions } from '@lingui/format-po';
|
|
3
|
+
|
|
4
|
+
type PoGettextFormatterOptions = PoFormatterOptions & {
|
|
5
|
+
disableSelectWarning?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare function formatter(options?: PoGettextFormatterOptions): {
|
|
8
|
+
catalogExtension: string;
|
|
9
|
+
templateExtension: string;
|
|
10
|
+
parse(content: string): CatalogType;
|
|
11
|
+
serialize(catalog: CatalogType, ctx: {
|
|
12
|
+
locale: string;
|
|
13
|
+
existing: string;
|
|
14
|
+
}): string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { PoGettextFormatterOptions, formatter };
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { parse } from '@messageformat/parser';
|
|
2
|
+
import pluralsCldr from 'plurals-cldr';
|
|
3
|
+
import PO from 'pofile';
|
|
4
|
+
import gettextPlurals from 'node-gettext/lib/plurals';
|
|
5
|
+
import { generateMessageId } from '@lingui/cli/api';
|
|
6
|
+
import { formatter as formatter$1 } from '@lingui/format-po';
|
|
7
|
+
|
|
8
|
+
function stringifyICUCase(icuCase) {
|
|
9
|
+
return icuCase.tokens.map((token) => {
|
|
10
|
+
if (token.type === "content") {
|
|
11
|
+
return token.value;
|
|
12
|
+
} else if (token.type === "octothorpe") {
|
|
13
|
+
return "#";
|
|
14
|
+
} else if (token.type === "argument") {
|
|
15
|
+
return "{" + token.arg + "}";
|
|
16
|
+
} else {
|
|
17
|
+
console.warn(
|
|
18
|
+
`Unexpected token "${token}" while stringifying plural case "${icuCase}". Token will be ignored.`
|
|
19
|
+
);
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
}).join("");
|
|
23
|
+
}
|
|
24
|
+
const ICU_PLURAL_REGEX = /^{.*, plural, .*}$/;
|
|
25
|
+
const ICU_SELECT_REGEX = /^{.*, select(Ordinal)?, .*}$/;
|
|
26
|
+
const LINE_ENDINGS = /\r?\n/g;
|
|
27
|
+
const CTX_PREFIX = "js-lingui:";
|
|
28
|
+
function serializePlurals(item, message, id, isGeneratedId, options) {
|
|
29
|
+
const icuMessage = message.message;
|
|
30
|
+
if (!icuMessage) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const _simplifiedMessage = icuMessage.replace(LINE_ENDINGS, " ");
|
|
34
|
+
if (ICU_PLURAL_REGEX.test(_simplifiedMessage)) {
|
|
35
|
+
try {
|
|
36
|
+
const messageAst = parse(icuMessage)[0];
|
|
37
|
+
if (messageAst.cases.some(
|
|
38
|
+
(icuCase) => icuCase.tokens.some((token) => token.type === "plural")
|
|
39
|
+
)) {
|
|
40
|
+
console.warn(
|
|
41
|
+
`Nested plurals cannot be expressed with gettext plurals. Message with key "%s" will not be saved correctly.`,
|
|
42
|
+
id
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const ctx = new URLSearchParams({
|
|
46
|
+
pluralize_on: messageAst.arg
|
|
47
|
+
});
|
|
48
|
+
if (isGeneratedId) {
|
|
49
|
+
item.msgid = stringifyICUCase(messageAst.cases[0]);
|
|
50
|
+
item.msgid_plural = stringifyICUCase(
|
|
51
|
+
messageAst.cases[messageAst.cases.length - 1]
|
|
52
|
+
);
|
|
53
|
+
ctx.set("icu", icuMessage);
|
|
54
|
+
} else {
|
|
55
|
+
item.msgid_plural = id + "_plural";
|
|
56
|
+
}
|
|
57
|
+
ctx.sort();
|
|
58
|
+
item.extractedComments.push(CTX_PREFIX + ctx.toString());
|
|
59
|
+
if (message.translation?.length > 0) {
|
|
60
|
+
const ast = parse(message.translation)[0];
|
|
61
|
+
if (ast.cases == null) {
|
|
62
|
+
console.warn(
|
|
63
|
+
`Found translation without plural cases for key "${id}". This likely means that a translated .po file misses multiple msgstr[] entries for the key. Translation found: "${message.translation}"`
|
|
64
|
+
);
|
|
65
|
+
item.msgstr = [message.translation];
|
|
66
|
+
} else {
|
|
67
|
+
item.msgstr = ast.cases.map(stringifyICUCase);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
console.error(`Error parsing message ICU for key "${id}":`, e);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
if (!options.disableSelectWarning && ICU_SELECT_REGEX.test(_simplifiedMessage)) {
|
|
75
|
+
console.warn(
|
|
76
|
+
`ICU 'select' and 'selectOrdinal' formats cannot be expressed natively in gettext format. Item with key "%s" will be included in the catalog as raw ICU message. To disable this warning, include '{ disableSelectWarning: true }' in the config's 'formatOptions'`,
|
|
77
|
+
id
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
item.msgstr = [message.translation];
|
|
81
|
+
}
|
|
82
|
+
return item;
|
|
83
|
+
}
|
|
84
|
+
const getPluralCases = (lang) => {
|
|
85
|
+
const [correctLang] = lang.split(/[-_]/g);
|
|
86
|
+
const gettextPluralsInfo = gettextPlurals[correctLang];
|
|
87
|
+
return gettextPluralsInfo?.examples.map(
|
|
88
|
+
(pluralCase) => pluralsCldr(correctLang, pluralCase.sample)
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
const convertPluralsToICU = (item, pluralForms, lang) => {
|
|
92
|
+
const translationCount = item.msgstr.length;
|
|
93
|
+
const messageKey = item.msgid;
|
|
94
|
+
if (translationCount <= 1 && !item.msgid_plural) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!item.msgid_plural) {
|
|
98
|
+
console.warn(
|
|
99
|
+
`Multiple translations for item with key "%s" but missing 'msgid_plural' in catalog "${lang}". This is not supported and the plural cases will be ignored.`,
|
|
100
|
+
messageKey
|
|
101
|
+
);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const contextComment = item.extractedComments.find((comment) => comment.startsWith(CTX_PREFIX))?.substr(CTX_PREFIX.length);
|
|
105
|
+
const ctx = new URLSearchParams(contextComment);
|
|
106
|
+
if (contextComment != null) {
|
|
107
|
+
item.extractedComments = item.extractedComments.filter(
|
|
108
|
+
(comment) => !comment.startsWith(CTX_PREFIX)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const storedICU = ctx.get("icu");
|
|
112
|
+
if (storedICU != null) {
|
|
113
|
+
item.msgid = storedICU;
|
|
114
|
+
}
|
|
115
|
+
if (item.msgstr.every((str) => str.length === 0)) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (pluralForms == null) {
|
|
119
|
+
console.warn(
|
|
120
|
+
`Multiple translations for item with key "%s" in language "${lang}", but no plural cases were found. This prohibits the translation of .po plurals into ICU plurals. Pluralization will not work for this key.`,
|
|
121
|
+
messageKey
|
|
122
|
+
);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const pluralCount = pluralForms.length;
|
|
126
|
+
if (translationCount > pluralCount) {
|
|
127
|
+
console.warn(
|
|
128
|
+
`More translations provided (${translationCount}) for item with key "%s" in language "${lang}" than there are plural cases available (${pluralCount}). This will result in not all translations getting picked up.`,
|
|
129
|
+
messageKey
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
const pluralClauses = item.msgstr.map((str, index) => pluralForms[index] + " {" + str + "}").join(" ");
|
|
133
|
+
let pluralizeOn = ctx.get("pluralize_on");
|
|
134
|
+
if (!pluralizeOn) {
|
|
135
|
+
console.warn(
|
|
136
|
+
`Unable to determine plural placeholder name for item with key "%s" in language "${lang}" (should be stored in a comment starting with "#. ${CTX_PREFIX}"), assuming "count".`,
|
|
137
|
+
messageKey
|
|
138
|
+
);
|
|
139
|
+
pluralizeOn = "count";
|
|
140
|
+
}
|
|
141
|
+
item.msgstr = ["{" + pluralizeOn + ", plural, " + pluralClauses + "}"];
|
|
142
|
+
};
|
|
143
|
+
function formatter(options = {}) {
|
|
144
|
+
options = {
|
|
145
|
+
origins: true,
|
|
146
|
+
lineNumbers: true,
|
|
147
|
+
...options
|
|
148
|
+
};
|
|
149
|
+
const formatter2 = formatter$1(options);
|
|
150
|
+
return {
|
|
151
|
+
catalogExtension: ".po",
|
|
152
|
+
templateExtension: ".pot",
|
|
153
|
+
parse(content) {
|
|
154
|
+
const po = PO.parse(content);
|
|
155
|
+
let pluralForms = getPluralCases(po.headers.Language);
|
|
156
|
+
po.items.forEach((item) => {
|
|
157
|
+
convertPluralsToICU(item, pluralForms, po.headers.Language);
|
|
158
|
+
});
|
|
159
|
+
return formatter2.parse(po.toString());
|
|
160
|
+
},
|
|
161
|
+
serialize(catalog, ctx) {
|
|
162
|
+
const po = PO.parse(formatter2.serialize(catalog, ctx));
|
|
163
|
+
po.items = po.items.map((item) => {
|
|
164
|
+
const isGeneratedId = !item.flags["explicit-id"];
|
|
165
|
+
const id = isGeneratedId ? generateMessageId(item.msgid, item.msgctxt) : item.msgid;
|
|
166
|
+
const message = catalog[id];
|
|
167
|
+
return serializePlurals(item, message, id, isGeneratedId, options);
|
|
168
|
+
});
|
|
169
|
+
return po.toString();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export { formatter };
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lingui/format-po-gettext",
|
|
3
|
+
"version": "4.0.0-next.2",
|
|
4
|
+
"description": "Gettext PO format with gettext-style plurals for Lingui Catalogs",
|
|
5
|
+
"main": "./dist/po-gettext.cjs",
|
|
6
|
+
"module": "./dist/po-gettext.mjs",
|
|
7
|
+
"types": "./dist/po-gettext.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"i18n",
|
|
11
|
+
"lingui-formatter",
|
|
12
|
+
"lingui-format",
|
|
13
|
+
"gettext",
|
|
14
|
+
"po",
|
|
15
|
+
"pot",
|
|
16
|
+
"internationalization",
|
|
17
|
+
"i10n",
|
|
18
|
+
"localization",
|
|
19
|
+
"i9n",
|
|
20
|
+
"translation"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "rimraf ./dist && unbuild",
|
|
24
|
+
"stub": "unbuild --stub"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/lingui/js-lingui.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/lingui/js-lingui/issues"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=16.0.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"README.md",
|
|
39
|
+
"dist/"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@lingui/cli": "4.0.0-next.2",
|
|
43
|
+
"@lingui/conf": "4.0.0-next.2",
|
|
44
|
+
"@lingui/format-po": "4.0.0-next.2",
|
|
45
|
+
"@messageformat/parser": "^5.0.0",
|
|
46
|
+
"node-gettext": "^3.0.0",
|
|
47
|
+
"plurals-cldr": "^2.0.1",
|
|
48
|
+
"pofile": "^1.1.4"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@lingui/jest-mocks": "workspace:^",
|
|
52
|
+
"unbuild": "^1.1.2"
|
|
53
|
+
}
|
|
54
|
+
}
|