@lingui/format-po 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 +77 -0
- package/dist/po.cjs +111 -0
- package/dist/po.d.ts +33 -0
- package/dist/po.mjs +109 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
[![License][badge-license]][license]
|
|
2
|
+
[![Version][badge-version]][package]
|
|
3
|
+
[![Downloads][badge-downloads]][package]
|
|
4
|
+
|
|
5
|
+
# @lingui/format-po
|
|
6
|
+
|
|
7
|
+
> Read and write message catalogs in Gettext PO format with ICU plurals
|
|
8
|
+
|
|
9
|
+
`@lingui/format-po` is part of [LinguiJS][linguijs]. See the
|
|
10
|
+
[documentation][documentation] for all information, tutorials and examples.
|
|
11
|
+
|
|
12
|
+
## Catalog example
|
|
13
|
+
|
|
14
|
+
```po
|
|
15
|
+
#, Comment for translators
|
|
16
|
+
#: src/App.js:4, src/Component.js:2
|
|
17
|
+
msgid "MessageID"
|
|
18
|
+
msgstr "Translated Message"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install --save-dev @lingui/format-po
|
|
25
|
+
# yarn add --dev @lingui/format-po
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// lingui.config.{js,ts}
|
|
32
|
+
import {formatter} from "@lingui/format-po"
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
[...]
|
|
36
|
+
format: formatter({lineNumbers: false}),
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Possible options:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
export type PoFormatterOptions = {
|
|
44
|
+
/**
|
|
45
|
+
* Print places where message is used
|
|
46
|
+
*
|
|
47
|
+
* @default true
|
|
48
|
+
*/
|
|
49
|
+
origins?: boolean
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Print line numbers in origins
|
|
53
|
+
*
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
lineNumbers?: boolean
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Print `js-lingui-id: Xs4as` statement in extracted comments section
|
|
60
|
+
*
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
printLinguiId?: boolean
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
This package is licensed under [MIT][license] license.
|
|
70
|
+
|
|
71
|
+
[license]: https://github.com/lingui/js-lingui/blob/main/LICENSE
|
|
72
|
+
[linguijs]: https://github.com/lingui/js-lingui
|
|
73
|
+
[documentation]: https://lingui.dev
|
|
74
|
+
[package]: https://www.npmjs.com/package/@lingui/format-po
|
|
75
|
+
[badge-downloads]: https://img.shields.io/npm/dw/@lingui/format-po.svg
|
|
76
|
+
[badge-version]: https://img.shields.io/npm/v/@lingui/format-po.svg
|
|
77
|
+
[badge-license]: https://img.shields.io/npm/l/@lingui/format-po.svg
|
package/dist/po.cjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const dateFns = require('date-fns');
|
|
4
|
+
const PO = require('pofile');
|
|
5
|
+
const api = require('@lingui/cli/api');
|
|
6
|
+
|
|
7
|
+
const splitOrigin = (origin) => {
|
|
8
|
+
const [file, line] = origin.split(":");
|
|
9
|
+
return [file, line ? Number(line) : null];
|
|
10
|
+
};
|
|
11
|
+
const joinOrigin = (origin) => origin.join(":");
|
|
12
|
+
function isGeneratedId(id, message) {
|
|
13
|
+
return id === api.generateMessageId(message.message, message.context);
|
|
14
|
+
}
|
|
15
|
+
function getCreateHeaders(language) {
|
|
16
|
+
return {
|
|
17
|
+
"POT-Creation-Date": dateFns.format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mmxxxx"),
|
|
18
|
+
"MIME-Version": "1.0",
|
|
19
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
20
|
+
"Content-Transfer-Encoding": "8bit",
|
|
21
|
+
"X-Generator": "@lingui/cli",
|
|
22
|
+
...language ? { Language: language } : {}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const EXPLICIT_ID_FLAG = "explicit-id";
|
|
26
|
+
const serialize = (catalog, options) => {
|
|
27
|
+
return Object.keys(catalog).map((id) => {
|
|
28
|
+
const message = catalog[id];
|
|
29
|
+
const item = new PO.Item();
|
|
30
|
+
item.extractedComments = [...message.extractedComments || []];
|
|
31
|
+
item.flags = (message.flags || []).reduce((acc, flag) => {
|
|
32
|
+
acc[flag] = true;
|
|
33
|
+
return acc;
|
|
34
|
+
}, {});
|
|
35
|
+
const _isGeneratedId = isGeneratedId(id, message);
|
|
36
|
+
if (_isGeneratedId) {
|
|
37
|
+
item.msgid = message.message;
|
|
38
|
+
if (options.printLinguiId) {
|
|
39
|
+
if (!item.extractedComments.find((c) => c.includes("js-lingui-id"))) {
|
|
40
|
+
item.extractedComments.push(`js-lingui-id: ${id}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
item.flags[EXPLICIT_ID_FLAG] = true;
|
|
45
|
+
item.msgid = id;
|
|
46
|
+
}
|
|
47
|
+
if (message.context) {
|
|
48
|
+
item.msgctxt = message.context;
|
|
49
|
+
}
|
|
50
|
+
item.msgstr = [message.translation];
|
|
51
|
+
item.comments = message.comments || [];
|
|
52
|
+
if (options.origins !== false) {
|
|
53
|
+
if (message.origin && options.lineNumbers === false) {
|
|
54
|
+
item.references = message.origin.map(([path]) => path);
|
|
55
|
+
} else {
|
|
56
|
+
item.references = message.origin ? message.origin.map(joinOrigin) : [];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
item.obsolete = message.obsolete;
|
|
60
|
+
return item;
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
function deserialize(items) {
|
|
64
|
+
return items.reduce((catalog, item) => {
|
|
65
|
+
const message = {
|
|
66
|
+
translation: item.msgstr[0],
|
|
67
|
+
extractedComments: item.extractedComments || [],
|
|
68
|
+
comments: item.comments || [],
|
|
69
|
+
context: item.msgctxt ?? null,
|
|
70
|
+
obsolete: item.flags.obsolete || item.obsolete,
|
|
71
|
+
origin: (item.references || []).map((ref) => splitOrigin(ref)),
|
|
72
|
+
flags: Object.keys(item.flags).map((flag) => flag.trim())
|
|
73
|
+
};
|
|
74
|
+
let id = item.msgid;
|
|
75
|
+
if (!item.flags[EXPLICIT_ID_FLAG]) {
|
|
76
|
+
id = api.generateMessageId(item.msgid, item.msgctxt);
|
|
77
|
+
message.message = item.msgid;
|
|
78
|
+
}
|
|
79
|
+
catalog[id] = message;
|
|
80
|
+
return catalog;
|
|
81
|
+
}, {});
|
|
82
|
+
}
|
|
83
|
+
function formatter(options = {}) {
|
|
84
|
+
options = {
|
|
85
|
+
origins: true,
|
|
86
|
+
lineNumbers: true,
|
|
87
|
+
...options
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
catalogExtension: ".po",
|
|
91
|
+
templateExtension: ".pot",
|
|
92
|
+
parse(content) {
|
|
93
|
+
const po = PO.parse(content);
|
|
94
|
+
return deserialize(po.items);
|
|
95
|
+
},
|
|
96
|
+
serialize(catalog, ctx) {
|
|
97
|
+
let po;
|
|
98
|
+
if (ctx.existing) {
|
|
99
|
+
po = PO.parse(ctx.existing);
|
|
100
|
+
} else {
|
|
101
|
+
po = new PO();
|
|
102
|
+
po.headers = getCreateHeaders(ctx.locale);
|
|
103
|
+
po.headerOrder = Object.keys(po.headers);
|
|
104
|
+
}
|
|
105
|
+
po.items = serialize(catalog, options);
|
|
106
|
+
return po.toString();
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
exports.formatter = formatter;
|
package/dist/po.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CatalogType } from '@lingui/conf';
|
|
2
|
+
|
|
3
|
+
type PoFormatterOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Print places where message is used
|
|
6
|
+
*
|
|
7
|
+
* @default true
|
|
8
|
+
*/
|
|
9
|
+
origins?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Print line numbers in origins
|
|
12
|
+
*
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
lineNumbers?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Print `js-lingui-id: Xs4as` statement in extracted comments section
|
|
18
|
+
*
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
21
|
+
printLinguiId?: boolean;
|
|
22
|
+
};
|
|
23
|
+
declare function formatter(options?: PoFormatterOptions): {
|
|
24
|
+
catalogExtension: string;
|
|
25
|
+
templateExtension: string;
|
|
26
|
+
parse(content: string): CatalogType;
|
|
27
|
+
serialize(catalog: CatalogType, ctx: {
|
|
28
|
+
locale: string;
|
|
29
|
+
existing: string;
|
|
30
|
+
}): string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { PoFormatterOptions, formatter };
|
package/dist/po.mjs
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { format } from 'date-fns';
|
|
2
|
+
import PO from 'pofile';
|
|
3
|
+
import { generateMessageId } from '@lingui/cli/api';
|
|
4
|
+
|
|
5
|
+
const splitOrigin = (origin) => {
|
|
6
|
+
const [file, line] = origin.split(":");
|
|
7
|
+
return [file, line ? Number(line) : null];
|
|
8
|
+
};
|
|
9
|
+
const joinOrigin = (origin) => origin.join(":");
|
|
10
|
+
function isGeneratedId(id, message) {
|
|
11
|
+
return id === generateMessageId(message.message, message.context);
|
|
12
|
+
}
|
|
13
|
+
function getCreateHeaders(language) {
|
|
14
|
+
return {
|
|
15
|
+
"POT-Creation-Date": format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mmxxxx"),
|
|
16
|
+
"MIME-Version": "1.0",
|
|
17
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
18
|
+
"Content-Transfer-Encoding": "8bit",
|
|
19
|
+
"X-Generator": "@lingui/cli",
|
|
20
|
+
...language ? { Language: language } : {}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const EXPLICIT_ID_FLAG = "explicit-id";
|
|
24
|
+
const serialize = (catalog, options) => {
|
|
25
|
+
return Object.keys(catalog).map((id) => {
|
|
26
|
+
const message = catalog[id];
|
|
27
|
+
const item = new PO.Item();
|
|
28
|
+
item.extractedComments = [...message.extractedComments || []];
|
|
29
|
+
item.flags = (message.flags || []).reduce((acc, flag) => {
|
|
30
|
+
acc[flag] = true;
|
|
31
|
+
return acc;
|
|
32
|
+
}, {});
|
|
33
|
+
const _isGeneratedId = isGeneratedId(id, message);
|
|
34
|
+
if (_isGeneratedId) {
|
|
35
|
+
item.msgid = message.message;
|
|
36
|
+
if (options.printLinguiId) {
|
|
37
|
+
if (!item.extractedComments.find((c) => c.includes("js-lingui-id"))) {
|
|
38
|
+
item.extractedComments.push(`js-lingui-id: ${id}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
item.flags[EXPLICIT_ID_FLAG] = true;
|
|
43
|
+
item.msgid = id;
|
|
44
|
+
}
|
|
45
|
+
if (message.context) {
|
|
46
|
+
item.msgctxt = message.context;
|
|
47
|
+
}
|
|
48
|
+
item.msgstr = [message.translation];
|
|
49
|
+
item.comments = message.comments || [];
|
|
50
|
+
if (options.origins !== false) {
|
|
51
|
+
if (message.origin && options.lineNumbers === false) {
|
|
52
|
+
item.references = message.origin.map(([path]) => path);
|
|
53
|
+
} else {
|
|
54
|
+
item.references = message.origin ? message.origin.map(joinOrigin) : [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
item.obsolete = message.obsolete;
|
|
58
|
+
return item;
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
function deserialize(items) {
|
|
62
|
+
return items.reduce((catalog, item) => {
|
|
63
|
+
const message = {
|
|
64
|
+
translation: item.msgstr[0],
|
|
65
|
+
extractedComments: item.extractedComments || [],
|
|
66
|
+
comments: item.comments || [],
|
|
67
|
+
context: item.msgctxt ?? null,
|
|
68
|
+
obsolete: item.flags.obsolete || item.obsolete,
|
|
69
|
+
origin: (item.references || []).map((ref) => splitOrigin(ref)),
|
|
70
|
+
flags: Object.keys(item.flags).map((flag) => flag.trim())
|
|
71
|
+
};
|
|
72
|
+
let id = item.msgid;
|
|
73
|
+
if (!item.flags[EXPLICIT_ID_FLAG]) {
|
|
74
|
+
id = generateMessageId(item.msgid, item.msgctxt);
|
|
75
|
+
message.message = item.msgid;
|
|
76
|
+
}
|
|
77
|
+
catalog[id] = message;
|
|
78
|
+
return catalog;
|
|
79
|
+
}, {});
|
|
80
|
+
}
|
|
81
|
+
function formatter(options = {}) {
|
|
82
|
+
options = {
|
|
83
|
+
origins: true,
|
|
84
|
+
lineNumbers: true,
|
|
85
|
+
...options
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
catalogExtension: ".po",
|
|
89
|
+
templateExtension: ".pot",
|
|
90
|
+
parse(content) {
|
|
91
|
+
const po = PO.parse(content);
|
|
92
|
+
return deserialize(po.items);
|
|
93
|
+
},
|
|
94
|
+
serialize(catalog, ctx) {
|
|
95
|
+
let po;
|
|
96
|
+
if (ctx.existing) {
|
|
97
|
+
po = PO.parse(ctx.existing);
|
|
98
|
+
} else {
|
|
99
|
+
po = new PO();
|
|
100
|
+
po.headers = getCreateHeaders(ctx.locale);
|
|
101
|
+
po.headerOrder = Object.keys(po.headers);
|
|
102
|
+
}
|
|
103
|
+
po.items = serialize(catalog, options);
|
|
104
|
+
return po.toString();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { formatter };
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lingui/format-po",
|
|
3
|
+
"version": "4.0.0-next.2",
|
|
4
|
+
"description": "Gettext PO format for Lingui Catalogs",
|
|
5
|
+
"main": "./dist/po.cjs",
|
|
6
|
+
"module": "./dist/po.mjs",
|
|
7
|
+
"types": "./dist/po.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"i18n",
|
|
11
|
+
"lingui-format",
|
|
12
|
+
"lingui-formatter",
|
|
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
|
+
"date-fns": "^2.29.3",
|
|
45
|
+
"pofile": "^1.1.4"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@lingui/jest-mocks": "workspace:^",
|
|
49
|
+
"unbuild": "^1.1.2"
|
|
50
|
+
}
|
|
51
|
+
}
|