@lingui/format-po 5.9.1 → 6.0.0-next.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.d.mts CHANGED
@@ -69,4 +69,5 @@ type PoFormatterOptions = {
69
69
  };
70
70
  declare function formatter(options?: PoFormatterOptions): CatalogFormatter;
71
71
 
72
- export { type PoFormatterOptions, formatter };
72
+ export { formatter };
73
+ export type { PoFormatterOptions };
package/dist/po.mjs CHANGED
@@ -1,10 +1,23 @@
1
- import { format } from 'date-fns';
2
1
  import PO from 'pofile';
3
2
  import { generateMessageId } from '@lingui/message-utils/generateMessageId';
4
3
 
5
4
  function normalizePlaceholderValue(text) {
6
5
  return text.replace(/\n/g, " ").replace(/\s{2,}/g, " ");
7
6
  }
7
+ function formatPotCreationDate(date) {
8
+ const pad = (n) => String(n).padStart(2, "0");
9
+ const year = date.getFullYear();
10
+ const month = pad(date.getMonth() + 1);
11
+ const day = pad(date.getDate());
12
+ const hour = pad(date.getHours());
13
+ const minute = pad(date.getMinutes());
14
+ const offsetMinutes = -date.getTimezoneOffset();
15
+ const sign = offsetMinutes >= 0 ? "+" : "-";
16
+ const abs = Math.abs(offsetMinutes);
17
+ const offsetH = pad(Math.floor(abs / 60));
18
+ const offsetM = pad(abs % 60);
19
+ return `${year}-${month}-${day} ${hour}:${minute}${sign}${offsetH}${offsetM}`;
20
+ }
8
21
 
9
22
  const splitOrigin = (origin) => {
10
23
  const [file, line] = origin.split(":");
@@ -21,7 +34,7 @@ function isGeneratedId(id, message) {
21
34
  }
22
35
  function getCreateHeaders(language, customHeaderAttributes) {
23
36
  return {
24
- "POT-Creation-Date": format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mmxxxx"),
37
+ "POT-Creation-Date": formatPotCreationDate(/* @__PURE__ */ new Date()),
25
38
  "MIME-Version": "1.0",
26
39
  "Content-Type": "text/plain; charset=utf-8",
27
40
  "Content-Transfer-Encoding": "8bit",
@@ -84,7 +97,7 @@ const serialize = (catalog, options, ctx) => {
84
97
  if (message.context) {
85
98
  item.msgctxt = message.context;
86
99
  }
87
- if (!_isGeneratedId && (ctx.locale === ctx.sourceLocale || ctx.locale === null)) {
100
+ if (!_isGeneratedId && (ctx.locale === ctx.sourceLocale || !ctx.locale)) {
88
101
  item.msgstr = [message.translation || message.message];
89
102
  } else {
90
103
  item.msgstr = [message.translation];
@@ -97,7 +110,7 @@ const serialize = (catalog, options, ctx) => {
97
110
  item.references = message.origin ? message.origin.map(joinOrigin) : [];
98
111
  }
99
112
  }
100
- item.obsolete = message.obsolete;
113
+ item.obsolete = message.obsolete || false;
101
114
  return item;
102
115
  });
103
116
  };
@@ -110,7 +123,7 @@ function deserialize(items, options) {
110
123
  // drop flags from comments
111
124
  (c) => c !== GENERATED_ID_FLAG && c !== EXPLICIT_ID_FLAG
112
125
  ),
113
- context: item.msgctxt ?? null,
126
+ context: item.msgctxt ?? void 0,
114
127
  obsolete: item.flags.obsolete || item.obsolete,
115
128
  origin: (item.references || []).map((ref) => splitOrigin(ref)),
116
129
  extra: {
package/package.json CHANGED
@@ -1,10 +1,8 @@
1
1
  {
2
2
  "name": "@lingui/format-po",
3
- "version": "5.9.1",
3
+ "version": "6.0.0-next.0",
4
4
  "description": "Gettext PO format for Lingui Catalogs",
5
- "main": "./dist/po.cjs",
6
- "module": "./dist/po.mjs",
7
- "types": "./dist/po.d.ts",
5
+ "type": "module",
8
6
  "sideEffects": false,
9
7
  "license": "MIT",
10
8
  "keywords": [
@@ -21,9 +19,13 @@
21
19
  "translation",
22
20
  "multilingual"
23
21
  ],
22
+ "exports": {
23
+ ".": "./dist/po.mjs"
24
+ },
24
25
  "scripts": {
25
- "build": "rimraf ./dist && unbuild",
26
- "stub": "unbuild --stub"
26
+ "test": "vitest run",
27
+ "build": "unbuild",
28
+ "check-types": "tsc --noEmit"
27
29
  },
28
30
  "homepage": "https://lingui.dev",
29
31
  "repository": {
@@ -35,7 +37,7 @@
35
37
  "url": "https://github.com/lingui/js-lingui/issues"
36
38
  },
37
39
  "engines": {
38
- "node": ">=20.0.0"
40
+ "node": ">=22.19.0"
39
41
  },
40
42
  "files": [
41
43
  "LICENSE",
@@ -43,15 +45,16 @@
43
45
  "dist/"
44
46
  ],
45
47
  "dependencies": {
46
- "@lingui/conf": "5.9.1",
47
- "@lingui/message-utils": "5.9.1",
48
- "date-fns": "^3.6.0",
48
+ "@lingui/conf": "6.0.0-next.0",
49
+ "@lingui/message-utils": "6.0.0-next.0",
49
50
  "pofile": "^1.1.4"
50
51
  },
51
52
  "devDependencies": {
52
- "@lingui/jest-mocks": "^3.0.3",
53
- "mockdate": "^3.0.5",
54
- "unbuild": "2.0.0"
53
+ "unbuild": "3.6.1",
54
+ "vitest": "4.0.18"
55
+ },
56
+ "unbuild": {
57
+ "declaration": "node16"
55
58
  },
56
- "gitHead": "4abb5a8fff1e1936a83a7d1ae602092607c520a1"
59
+ "gitHead": "a9576050487a4f7dfbc88db20814d5a1bb861c8c"
57
60
  }
package/dist/po.cjs DELETED
@@ -1,170 +0,0 @@
1
- 'use strict';
2
-
3
- const dateFns = require('date-fns');
4
- const PO = require('pofile');
5
- const generateMessageId = require('@lingui/message-utils/generateMessageId');
6
-
7
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
8
-
9
- const PO__default = /*#__PURE__*/_interopDefaultCompat(PO);
10
-
11
- function normalizePlaceholderValue(text) {
12
- return text.replace(/\n/g, " ").replace(/\s{2,}/g, " ");
13
- }
14
-
15
- const splitOrigin = (origin) => {
16
- const [file, line] = origin.split(":");
17
- return [file, line ? Number(line) : null];
18
- };
19
- const splitMultiLineComments = (comments) => {
20
- return comments.flatMap(
21
- (comment) => comment.includes("\n") ? comment.split("\n").map((slice) => slice.trim()).filter(Boolean) : comment
22
- );
23
- };
24
- const joinOrigin = (origin) => origin.join(":");
25
- function isGeneratedId(id, message) {
26
- return id === generateMessageId.generateMessageId(message.message, message.context);
27
- }
28
- function getCreateHeaders(language, customHeaderAttributes) {
29
- return {
30
- "POT-Creation-Date": dateFns.format(/* @__PURE__ */ new Date(), "yyyy-MM-dd HH:mmxxxx"),
31
- "MIME-Version": "1.0",
32
- "Content-Type": "text/plain; charset=utf-8",
33
- "Content-Transfer-Encoding": "8bit",
34
- "X-Generator": "@lingui/cli",
35
- ...language ? { Language: language } : {},
36
- ...customHeaderAttributes ?? {}
37
- };
38
- }
39
- const EXPLICIT_ID_FLAG = "js-lingui-explicit-id";
40
- const GENERATED_ID_FLAG = "js-lingui-generated-id";
41
- const serialize = (catalog, options, ctx) => {
42
- return Object.keys(catalog).map((id) => {
43
- const message = catalog[id];
44
- const item = new PO__default.Item();
45
- item.extractedComments = [
46
- ...message.comments?.length ? splitMultiLineComments(message.comments) : []
47
- ];
48
- item.flags = (message.extra?.flags || []).reduce((acc, flag) => {
49
- acc[flag] = true;
50
- return acc;
51
- }, {});
52
- const _isGeneratedId = isGeneratedId(id, message);
53
- if (_isGeneratedId) {
54
- item.msgid = message.message;
55
- if (options.explicitIdAsDefault) {
56
- if (!item.extractedComments.includes(GENERATED_ID_FLAG)) {
57
- item.extractedComments.push(GENERATED_ID_FLAG);
58
- }
59
- }
60
- if (options.printLinguiId) {
61
- if (!item.extractedComments.find((c) => c.includes("js-lingui-id"))) {
62
- item.extractedComments.push(`js-lingui-id: ${id}`);
63
- }
64
- }
65
- } else {
66
- if (!options.explicitIdAsDefault) {
67
- if (!item.extractedComments.includes(EXPLICIT_ID_FLAG)) {
68
- item.extractedComments.push(EXPLICIT_ID_FLAG);
69
- }
70
- }
71
- item.msgid = id;
72
- }
73
- if (options.printPlaceholdersInComments !== false) {
74
- item.extractedComments = item.extractedComments.filter(
75
- (comment) => !comment.startsWith("placeholder ")
76
- );
77
- const limit = typeof options.printPlaceholdersInComments === "object" && options.printPlaceholdersInComments.limit ? options.printPlaceholdersInComments.limit : 3;
78
- if (message.placeholders) {
79
- Object.entries(message.placeholders).forEach(([name, value]) => {
80
- if (/^\d+$/.test(name)) {
81
- value.slice(0, limit).forEach((entry) => {
82
- item.extractedComments.push(
83
- `placeholder {${name}}: ${normalizePlaceholderValue(entry)}`
84
- );
85
- });
86
- }
87
- });
88
- }
89
- }
90
- if (message.context) {
91
- item.msgctxt = message.context;
92
- }
93
- if (!_isGeneratedId && (ctx.locale === ctx.sourceLocale || ctx.locale === null)) {
94
- item.msgstr = [message.translation || message.message];
95
- } else {
96
- item.msgstr = [message.translation];
97
- }
98
- item.comments = message.extra?.translatorComments || [];
99
- if (options.origins !== false) {
100
- if (message.origin && options.lineNumbers === false) {
101
- item.references = message.origin.map(([path]) => path);
102
- } else {
103
- item.references = message.origin ? message.origin.map(joinOrigin) : [];
104
- }
105
- }
106
- item.obsolete = message.obsolete;
107
- return item;
108
- });
109
- };
110
- function deserialize(items, options) {
111
- return items.reduce((catalog, item) => {
112
- const comments = item.extractedComments;
113
- const message = {
114
- translation: item.msgstr[0],
115
- comments: comments.filter(
116
- // drop flags from comments
117
- (c) => c !== GENERATED_ID_FLAG && c !== EXPLICIT_ID_FLAG
118
- ),
119
- context: item.msgctxt ?? null,
120
- obsolete: item.flags.obsolete || item.obsolete,
121
- origin: (item.references || []).map((ref) => splitOrigin(ref)),
122
- extra: {
123
- translatorComments: item.comments || [],
124
- flags: Object.keys(item.flags).map((flag) => flag.trim())
125
- }
126
- };
127
- let id = item.msgid;
128
- if (options.explicitIdAsDefault ? comments.includes(GENERATED_ID_FLAG) : !comments.includes(EXPLICIT_ID_FLAG)) {
129
- id = generateMessageId.generateMessageId(item.msgid, item.msgctxt);
130
- message.message = item.msgid;
131
- }
132
- catalog[id] = message;
133
- return catalog;
134
- }, {});
135
- }
136
- function formatter(options = {}) {
137
- options = {
138
- origins: true,
139
- lineNumbers: true,
140
- ...options
141
- };
142
- return {
143
- catalogExtension: ".po",
144
- templateExtension: ".pot",
145
- parse(content) {
146
- const po = PO__default.parse(content);
147
- return deserialize(po.items, options);
148
- },
149
- serialize(catalog, ctx) {
150
- let po;
151
- if (ctx.existing) {
152
- po = PO__default.parse(ctx.existing);
153
- } else {
154
- po = new PO__default();
155
- po.headers = getCreateHeaders(
156
- ctx.locale,
157
- options.customHeaderAttributes
158
- );
159
- po.headerOrder = Object.keys(po.headers);
160
- }
161
- po.items = serialize(catalog, options, {
162
- locale: ctx.locale,
163
- sourceLocale: ctx.sourceLocale
164
- });
165
- return po.toString();
166
- }
167
- };
168
- }
169
-
170
- exports.formatter = formatter;
package/dist/po.d.cts DELETED
@@ -1,72 +0,0 @@
1
- import { CatalogFormatter } 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
- * By default, the po-formatter treats the pair `msgid` + `msgctx` as the source
24
- * for generating an ID by hashing its value.
25
- *
26
- * For messages with explicit IDs, the formatter adds a special comment `js-lingui-explicit-id` as a flag.
27
- * When this flag is present, the formatter will use the `msgid` as-is without any additional processing.
28
- *
29
- * Set this option to true if you exclusively use explicit-ids in your project.
30
- *
31
- * https://lingui.dev/tutorials/explicit-vs-generated-ids#using-custom-id
32
- *
33
- * @default false
34
- */
35
- explicitIdAsDefault?: boolean;
36
- /**
37
- * Custom attributes to append to the PO file header
38
- *
39
- * @default {}
40
- */
41
- customHeaderAttributes?: {
42
- [key: string]: string;
43
- };
44
- /**
45
- * Print values for unnamed placeholders as comments for each message.
46
- *
47
- * This can give more context to translators for better translations.
48
- *
49
- * By default first 3 placeholders are shown.
50
- *
51
- * Example:
52
- *
53
- * ```js
54
- * t`Hello ${user.name} ${value}`
55
- * ```
56
- *
57
- * This will be extracted as
58
- *
59
- * ```po
60
- * #. placeholder {0}: user.name
61
- * msgid "Hello {0} {value}"
62
- * ```
63
- *
64
- * @default true
65
- */
66
- printPlaceholdersInComments?: boolean | {
67
- limit?: number;
68
- };
69
- };
70
- declare function formatter(options?: PoFormatterOptions): CatalogFormatter;
71
-
72
- export { type PoFormatterOptions, formatter };
package/dist/po.d.ts DELETED
@@ -1,72 +0,0 @@
1
- import { CatalogFormatter } 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
- * By default, the po-formatter treats the pair `msgid` + `msgctx` as the source
24
- * for generating an ID by hashing its value.
25
- *
26
- * For messages with explicit IDs, the formatter adds a special comment `js-lingui-explicit-id` as a flag.
27
- * When this flag is present, the formatter will use the `msgid` as-is without any additional processing.
28
- *
29
- * Set this option to true if you exclusively use explicit-ids in your project.
30
- *
31
- * https://lingui.dev/tutorials/explicit-vs-generated-ids#using-custom-id
32
- *
33
- * @default false
34
- */
35
- explicitIdAsDefault?: boolean;
36
- /**
37
- * Custom attributes to append to the PO file header
38
- *
39
- * @default {}
40
- */
41
- customHeaderAttributes?: {
42
- [key: string]: string;
43
- };
44
- /**
45
- * Print values for unnamed placeholders as comments for each message.
46
- *
47
- * This can give more context to translators for better translations.
48
- *
49
- * By default first 3 placeholders are shown.
50
- *
51
- * Example:
52
- *
53
- * ```js
54
- * t`Hello ${user.name} ${value}`
55
- * ```
56
- *
57
- * This will be extracted as
58
- *
59
- * ```po
60
- * #. placeholder {0}: user.name
61
- * msgid "Hello {0} {value}"
62
- * ```
63
- *
64
- * @default true
65
- */
66
- printPlaceholdersInComments?: boolean | {
67
- limit?: number;
68
- };
69
- };
70
- declare function formatter(options?: PoFormatterOptions): CatalogFormatter;
71
-
72
- export { type PoFormatterOptions, formatter };