@lingui/babel-plugin-extract-messages 3.14.0 → 3.16.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/CHANGELOG.md +344 -0
- package/build/LICENSE +21 -0
- package/build/index.js +416 -0
- package/package.json +11 -5
- package/index.js +0 -397
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
# [3.16.0](https://github.com/lingui/js-lingui/compare/v3.15.0...v3.16.0) (2023-01-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* allow extract to work with i18n._ calls not created from macro ([#1309](https://github.com/lingui/js-lingui/issues/1309)) ([90be171](https://github.com/lingui/js-lingui/commit/90be1719becc4710c910ea16928b7ce41ef9ab19))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [3.15.0](https://github.com/lingui/js-lingui/compare/v3.14.0...v3.15.0) (2022-11-07)
|
|
18
|
+
|
|
19
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# [3.14.0](https://github.com/lingui/js-lingui/compare/v3.13.3...v3.14.0) (2022-06-22)
|
|
26
|
+
|
|
27
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## [3.13.3](https://github.com/lingui/js-lingui/compare/v3.13.2...v3.13.3) (2022-04-24)
|
|
34
|
+
|
|
35
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
## [3.13.2](https://github.com/lingui/js-lingui/compare/v3.13.1...v3.13.2) (2022-01-24)
|
|
42
|
+
|
|
43
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## [3.13.1](https://github.com/lingui/js-lingui/compare/v3.13.0...v3.13.1) (2022-01-21)
|
|
50
|
+
|
|
51
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# [3.13.0](https://github.com/lingui/js-lingui/compare/v3.12.1...v3.13.0) (2021-11-26)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### Features
|
|
61
|
+
|
|
62
|
+
* add the ability to extract concatenated comments ([#1152](https://github.com/lingui/js-lingui/issues/1152)) ([0e553cf](https://github.com/lingui/js-lingui/commit/0e553cf14f5f6dce87839abed76fd21f351a2eae))
|
|
63
|
+
* msgctxt support ([#1094](https://github.com/lingui/js-lingui/issues/1094)) ([8ee42cb](https://github.com/lingui/js-lingui/commit/8ee42cbfe26bc6d055748dcf2713ab8ade7ec827))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## [3.12.1](https://github.com/lingui/js-lingui/compare/v3.12.0...v3.12.1) (2021-09-28)
|
|
70
|
+
|
|
71
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# [3.12.0](https://github.com/lingui/js-lingui/compare/v3.11.1...v3.12.0) (2021-09-28)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
### Bug Fixes
|
|
81
|
+
|
|
82
|
+
* **#1137:** configPath is passed through babel-plugin-extract-messages ([#1140](https://github.com/lingui/js-lingui/issues/1140)) ([8921156](https://github.com/lingui/js-lingui/commit/89211567632733cf9955cafc9c92bd87c6154852)), closes [#1137](https://github.com/lingui/js-lingui/issues/1137)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## [3.11.1](https://github.com/lingui/js-lingui/compare/v3.11.0...v3.11.1) (2021-09-07)
|
|
89
|
+
|
|
90
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# [3.11.0](https://github.com/lingui/js-lingui/compare/v3.10.4...v3.11.0) (2021-09-07)
|
|
97
|
+
|
|
98
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
## [3.10.4](https://github.com/lingui/js-lingui/compare/v3.10.3...v3.10.4) (2021-06-16)
|
|
105
|
+
|
|
106
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## [3.10.3](https://github.com/lingui/js-lingui/compare/v3.10.2...v3.10.3) (2021-06-14)
|
|
113
|
+
|
|
114
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
## [3.10.2](https://github.com/lingui/js-lingui/compare/v3.10.1...v3.10.2) (2021-06-08)
|
|
121
|
+
|
|
122
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## [3.10.1](https://github.com/lingui/js-lingui/compare/v3.10.0...v3.10.1) (2021-06-08)
|
|
129
|
+
|
|
130
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# [3.10.0](https://github.com/lingui/js-lingui/compare/v3.9.0...v3.10.0) (2021-06-08)
|
|
137
|
+
|
|
138
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# [3.9.0](https://github.com/lingui/js-lingui/compare/v3.8.10...v3.9.0) (2021-05-18)
|
|
145
|
+
|
|
146
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
## [3.8.10](https://github.com/lingui/js-lingui/compare/v3.8.9...v3.8.10) (2021-04-19)
|
|
153
|
+
|
|
154
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
## [3.8.9](https://github.com/lingui/js-lingui/compare/v3.8.8...v3.8.9) (2021-04-09)
|
|
161
|
+
|
|
162
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
## [3.8.8](https://github.com/lingui/js-lingui/compare/v3.8.7...v3.8.8) (2021-04-09)
|
|
169
|
+
|
|
170
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
## [3.8.7](https://github.com/lingui/js-lingui/compare/v3.8.6...v3.8.7) (2021-04-09)
|
|
177
|
+
|
|
178
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
## [3.8.6](https://github.com/lingui/js-lingui/compare/v3.8.5...v3.8.6) (2021-04-08)
|
|
185
|
+
|
|
186
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
## [3.8.5](https://github.com/lingui/js-lingui/compare/v3.8.4...v3.8.5) (2021-04-08)
|
|
193
|
+
|
|
194
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
## [3.8.4](https://github.com/lingui/js-lingui/compare/v3.8.3...v3.8.4) (2021-04-08)
|
|
201
|
+
|
|
202
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
## [3.8.3](https://github.com/lingui/js-lingui/compare/v3.8.2...v3.8.3) (2021-04-05)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
### Bug Fixes
|
|
212
|
+
|
|
213
|
+
* extract works with template string id's ([#1027](https://github.com/lingui/js-lingui/issues/1027)) ([a17d629](https://github.com/lingui/js-lingui/commit/a17d629d82395cd86cc080648ef2ebe2a9653225))
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
## [3.8.2](https://github.com/lingui/js-lingui/compare/v3.8.1...v3.8.2) (2021-03-31)
|
|
220
|
+
|
|
221
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
## [3.8.1](https://github.com/lingui/js-lingui/compare/v3.8.0...v3.8.1) (2021-03-23)
|
|
228
|
+
|
|
229
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# [3.8.0](https://github.com/lingui/js-lingui/compare/v3.7.2...v3.8.0) (2021-03-23)
|
|
236
|
+
|
|
237
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
## [3.7.2](https://github.com/lingui/js-lingui/compare/v3.7.1...v3.7.2) (2021-03-14)
|
|
244
|
+
|
|
245
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
## [3.7.1](https://github.com/lingui/js-lingui/compare/v3.7.0...v3.7.1) (2021-03-07)
|
|
252
|
+
|
|
253
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# [3.7.0](https://github.com/lingui/js-lingui/compare/v3.6.0...v3.7.0) (2021-03-04)
|
|
260
|
+
|
|
261
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# [3.6.0](https://github.com/lingui/js-lingui/compare/v3.5.1...v3.6.0) (2021-02-23)
|
|
268
|
+
|
|
269
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
## [3.5.1](https://github.com/lingui/js-lingui/compare/v3.5.0...v3.5.1) (2021-02-09)
|
|
276
|
+
|
|
277
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# [3.5.0](https://github.com/lingui/js-lingui/compare/v3.4.0...v3.5.0) (2021-02-02)
|
|
284
|
+
|
|
285
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# [3.4.0](https://github.com/lingui/js-lingui/compare/v3.3.0...v3.4.0) (2021-01-13)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
### Bug Fixes
|
|
295
|
+
|
|
296
|
+
* prevent adding undefined msgid to messages ([#915](https://github.com/lingui/js-lingui/issues/915)) ([3afacec](https://github.com/lingui/js-lingui/commit/3afaceccb669b59ee2f5b42ee2e138646ccdb79d))
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
# [3.3.0](https://github.com/lingui/js-lingui/compare/v3.2.3...v3.3.0) (2020-12-08)
|
|
303
|
+
|
|
304
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
## [3.2.3](https://github.com/lingui/js-lingui/compare/v3.2.2...v3.2.3) (2020-11-22)
|
|
311
|
+
|
|
312
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
## [3.2.2](https://github.com/lingui/js-lingui/compare/v3.2.1...v3.2.2) (2020-11-20)
|
|
319
|
+
|
|
320
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# [3.2.0](https://github.com/lingui/js-lingui/compare/v3.1.0...v3.2.0) (2020-11-12)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
### Bug Fixes
|
|
330
|
+
|
|
331
|
+
* t macro as function not extracting ([#846](https://github.com/lingui/js-lingui/issues/846)) ([d819bfc](https://github.com/lingui/js-lingui/commit/d819bfc74707a8766bfe1b1a3d43edce97f8f265))
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
### Features
|
|
335
|
+
|
|
336
|
+
* extract multiple comments per translation ID ([#854](https://github.com/lingui/js-lingui/issues/854)) ([c849c9c](https://github.com/lingui/js-lingui/commit/c849c9c024832aa7b07e5f837791e287c3aebe29))
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
# [3.1.0](https://github.com/lingui/js-lingui/compare/v3.0.3...v3.1.0) (2020-11-10)
|
|
343
|
+
|
|
344
|
+
**Note:** Version bump only for package @lingui/babel-plugin-extract-messages
|
package/build/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Tomáš Ehrlich
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/build/index.js
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = _default;
|
|
7
|
+
|
|
8
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
+
|
|
10
|
+
var _path = _interopRequireDefault(require("path"));
|
|
11
|
+
|
|
12
|
+
var _mkdirp = _interopRequireDefault(require("mkdirp"));
|
|
13
|
+
|
|
14
|
+
var _generator = _interopRequireDefault(require("@babel/generator"));
|
|
15
|
+
|
|
16
|
+
var _conf = require("@lingui/conf");
|
|
17
|
+
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
|
|
20
|
+
const CONFIG = Symbol("I18nConfig"); // Map of messages
|
|
21
|
+
|
|
22
|
+
const MESSAGES = Symbol("I18nMessages"); // We need to remember all processed nodes. When JSX expressions are
|
|
23
|
+
// replaced with CallExpressions, all children are traversed for each CallExpression.
|
|
24
|
+
// Then, i18n._ methods are visited multiple times for each parent CallExpression.
|
|
25
|
+
|
|
26
|
+
const VISITED = Symbol("I18nVisited");
|
|
27
|
+
|
|
28
|
+
function addMessage(path, messages, {
|
|
29
|
+
id,
|
|
30
|
+
message: newDefault,
|
|
31
|
+
origin,
|
|
32
|
+
comment,
|
|
33
|
+
context,
|
|
34
|
+
...props
|
|
35
|
+
}) {
|
|
36
|
+
// prevent from adding undefined msgid
|
|
37
|
+
if (id === undefined) return;
|
|
38
|
+
const extractedComments = comment ? [comment] : [];
|
|
39
|
+
|
|
40
|
+
if (context) {
|
|
41
|
+
if (messages.has(context)) {
|
|
42
|
+
const existingContext = messages.get(context);
|
|
43
|
+
|
|
44
|
+
if (existingContext.has(id)) {
|
|
45
|
+
const message = messages.get(id); // only set/check default language when it's defined.
|
|
46
|
+
|
|
47
|
+
if (message.message && newDefault && message.message !== newDefault) {
|
|
48
|
+
throw path.buildCodeFrameError("Different defaults for the same message ID.");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (newDefault) {
|
|
52
|
+
message.message = newDefault;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
;
|
|
56
|
+
[].push.apply(message.origin, origin);
|
|
57
|
+
|
|
58
|
+
if (comment) {
|
|
59
|
+
;
|
|
60
|
+
[].push.apply(message.extractedComments, [comment]);
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
existingContext.set(id, { ...props,
|
|
64
|
+
message: newDefault,
|
|
65
|
+
origin,
|
|
66
|
+
extractedComments
|
|
67
|
+
});
|
|
68
|
+
messages.set(context, existingContext);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
const newContext = new Map();
|
|
72
|
+
newContext.set(id, { ...props,
|
|
73
|
+
message: newDefault,
|
|
74
|
+
origin,
|
|
75
|
+
extractedComments
|
|
76
|
+
});
|
|
77
|
+
messages.set(context, newContext);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
if (messages.has(id)) {
|
|
81
|
+
const message = messages.get(id); // only set/check default language when it's defined.
|
|
82
|
+
|
|
83
|
+
if (message.message && newDefault && message.message !== newDefault) {
|
|
84
|
+
throw path.buildCodeFrameError("Different defaults for the same message ID.");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (newDefault) {
|
|
88
|
+
message.message = newDefault;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
;
|
|
92
|
+
[].push.apply(message.origin, origin);
|
|
93
|
+
|
|
94
|
+
if (comment) {
|
|
95
|
+
;
|
|
96
|
+
[].push.apply(message.extractedComments, [comment]);
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
messages.set(id, { ...props,
|
|
100
|
+
message: newDefault,
|
|
101
|
+
origin,
|
|
102
|
+
extractedComments
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* An ES6 Map type is not possible to encode with JSON.stringify,
|
|
109
|
+
* so we can instead use a replacer function as an argument to
|
|
110
|
+
* tell the JSON parser how to serialize / deserialize the Maps
|
|
111
|
+
* it encounters.
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
function mapReplacer(key, value) {
|
|
116
|
+
if (value instanceof Map) {
|
|
117
|
+
const object = {};
|
|
118
|
+
value.forEach((v, k) => {
|
|
119
|
+
return object[k] = v;
|
|
120
|
+
});
|
|
121
|
+
return object;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function extractStringContatentation(t, node, error) {
|
|
128
|
+
if (t.isStringLiteral(node)) {
|
|
129
|
+
return node.value;
|
|
130
|
+
} else if (t.isBinaryExpression(node)) {
|
|
131
|
+
return extractStringContatentation(t, node.left, error) + extractStringContatentation(t, node.right, error);
|
|
132
|
+
} else {
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function extractCommentString(t, path, valuePath, valueObj) {
|
|
138
|
+
if (t.isStringLiteral(valueObj)) {
|
|
139
|
+
// Comment is a single line string
|
|
140
|
+
return valueObj.value;
|
|
141
|
+
} // Comment is a multi-line string.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
const errorIfNotAString = path.get(valuePath).buildCodeFrameError("Only strings are supported as comments.");
|
|
145
|
+
|
|
146
|
+
if (t.isBinaryExpression(valueObj)) {
|
|
147
|
+
return extractStringContatentation(t, valueObj, errorIfNotAString);
|
|
148
|
+
} else {
|
|
149
|
+
throw errorIfNotAString;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _default({
|
|
154
|
+
types: t
|
|
155
|
+
}) {
|
|
156
|
+
let localTransComponentName;
|
|
157
|
+
|
|
158
|
+
function isTransComponent(node) {
|
|
159
|
+
return t.isJSXElement(node) && t.isJSXIdentifier(node.openingElement.name, {
|
|
160
|
+
name: localTransComponentName
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const isI18nMethod = node => t.isMemberExpression(node) && t.isIdentifier(node.object, {
|
|
165
|
+
name: "i18n"
|
|
166
|
+
}) && t.isIdentifier(node.property, {
|
|
167
|
+
name: "_"
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
function collectMessage(path, file, props) {
|
|
171
|
+
const messages = file.get(MESSAGES);
|
|
172
|
+
const rootDir = file.get(CONFIG).rootDir;
|
|
173
|
+
|
|
174
|
+
const filename = _path.default.relative(rootDir, file.opts.filename).replace(/\\/g, "/");
|
|
175
|
+
|
|
176
|
+
const line = path.node.loc ? path.node.loc.start.line : null;
|
|
177
|
+
props.origin = [[filename, line]];
|
|
178
|
+
addMessage(path, messages, props);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
visitor: {
|
|
183
|
+
// Get the local name of Trans component. Usually it's just `Trans`, but
|
|
184
|
+
// it might be different when the import is aliased:
|
|
185
|
+
// import { Trans as T } from '@lingui/react';
|
|
186
|
+
ImportDeclaration(path) {
|
|
187
|
+
const {
|
|
188
|
+
node
|
|
189
|
+
} = path;
|
|
190
|
+
const moduleName = node.source.value;
|
|
191
|
+
if (!["@lingui/react", "@lingui/macro", "@lingui/core"].includes(moduleName)) return;
|
|
192
|
+
const importDeclarations = {};
|
|
193
|
+
|
|
194
|
+
if (moduleName === "@lingui/react" || moduleName === "@lingui/macro") {
|
|
195
|
+
node.specifiers.forEach(specifier => {
|
|
196
|
+
importDeclarations[specifier.imported.name] = specifier.local.name;
|
|
197
|
+
}); // Trans import might be missing if there's just Plural or similar macro.
|
|
198
|
+
// If there's no alias, consider it was imported as Trans.
|
|
199
|
+
|
|
200
|
+
localTransComponentName = importDeclarations["Trans"] || "Trans";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!node.specifiers.length) {
|
|
204
|
+
path.remove();
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// Extract translation from <Trans /> component.
|
|
209
|
+
JSXElement(path, {
|
|
210
|
+
file
|
|
211
|
+
}) {
|
|
212
|
+
const {
|
|
213
|
+
node
|
|
214
|
+
} = path;
|
|
215
|
+
if (!localTransComponentName || !isTransComponent(node)) return;
|
|
216
|
+
const attrs = node.openingElement.attributes || [];
|
|
217
|
+
const props = attrs.reduce((acc, item) => {
|
|
218
|
+
const key = item.name.name;
|
|
219
|
+
|
|
220
|
+
if (key === "id" || key === "message" || key === "comment" || key === "context") {
|
|
221
|
+
if (item.value.value) {
|
|
222
|
+
acc[key] = item.value.value;
|
|
223
|
+
} else if (item.value.expression && t.isStringLiteral(item.value.expression)) {
|
|
224
|
+
acc[key] = item.value.expression.value;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return acc;
|
|
229
|
+
}, {});
|
|
230
|
+
|
|
231
|
+
if (!props.id) {
|
|
232
|
+
// <Trans id={message} /> is valid, don't raise warning
|
|
233
|
+
const idProp = attrs.filter(item => item.name.name === "id")[0];
|
|
234
|
+
|
|
235
|
+
if (idProp === undefined || t.isLiteral(props.id)) {
|
|
236
|
+
console.warn("Missing message ID, skipping.");
|
|
237
|
+
console.warn((0, _generator.default)(node).code);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
collectMessage(path, file, props);
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
CallExpression(path, {
|
|
247
|
+
file
|
|
248
|
+
}) {
|
|
249
|
+
const visited = file.get(VISITED);
|
|
250
|
+
if (visited.has(path.node)) return;
|
|
251
|
+
const hasComment = [path.node, path.parent].find(({
|
|
252
|
+
leadingComments
|
|
253
|
+
}) => {
|
|
254
|
+
return leadingComments && leadingComments.filter(node => node.value.match(/^\s*i18n\s*$/))[0];
|
|
255
|
+
});
|
|
256
|
+
const isNonMacroI18n = isI18nMethod(path.node.callee) && !hasComment && path.node.arguments[0] && !path.node.arguments[0].leadingComments;
|
|
257
|
+
if (!hasComment && !isNonMacroI18n) return;
|
|
258
|
+
const props = {
|
|
259
|
+
id: path.node.arguments[0].value
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
if (!props.id) {
|
|
263
|
+
console.warn("Missing message ID, skipping.");
|
|
264
|
+
console.warn((0, _generator.default)(path.node).code);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const copyOptions = ["message", "comment", "context"];
|
|
269
|
+
|
|
270
|
+
if (t.isObjectExpression(path.node.arguments[2])) {
|
|
271
|
+
path.node.arguments[2].properties.forEach(({
|
|
272
|
+
key,
|
|
273
|
+
value
|
|
274
|
+
}, i) => {
|
|
275
|
+
if (!copyOptions.includes(key.name)) return;
|
|
276
|
+
let valueToExtract = value.value;
|
|
277
|
+
|
|
278
|
+
if (key.name === "comment") {
|
|
279
|
+
valueToExtract = extractCommentString(t, path, `arguments.2.properties.${i}.value`, value);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
props[key.name] = valueToExtract;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
visited.add(path.node);
|
|
287
|
+
collectMessage(path, file, props);
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
StringLiteral(path, {
|
|
291
|
+
file
|
|
292
|
+
}) {
|
|
293
|
+
const visited = file.get(VISITED);
|
|
294
|
+
const comment = path.node.leadingComments && path.node.leadingComments.filter(node => node.value.match(/^\s*i18n/))[0];
|
|
295
|
+
|
|
296
|
+
if (!comment || visited.has(path.node)) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
visited.add(path.node);
|
|
301
|
+
const props = {
|
|
302
|
+
id: path.node.value
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
if (!props.id) {
|
|
306
|
+
console.warn("Missing message ID, skipping.");
|
|
307
|
+
console.warn((0, _generator.default)(path.node).code);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
collectMessage(path, file, props);
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
// Extract message descriptors
|
|
315
|
+
ObjectExpression(path, {
|
|
316
|
+
file
|
|
317
|
+
}) {
|
|
318
|
+
const visited = file.get(VISITED);
|
|
319
|
+
const comment = path.node.leadingComments && path.node.leadingComments.filter(node => node.value.match(/^\s*i18n/))[0];
|
|
320
|
+
|
|
321
|
+
if (!comment || visited.has(path.node)) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
visited.add(path.node);
|
|
326
|
+
const props = {};
|
|
327
|
+
const copyProps = ["id", "message", "comment", "context"];
|
|
328
|
+
path.node.properties.filter(({
|
|
329
|
+
key
|
|
330
|
+
}) => copyProps.indexOf(key.name) !== -1).forEach(({
|
|
331
|
+
key,
|
|
332
|
+
value
|
|
333
|
+
}, i) => {
|
|
334
|
+
// By default, the value is just the string value of the object property.
|
|
335
|
+
let valueToExtract = value.value;
|
|
336
|
+
|
|
337
|
+
if (key.name === "comment") {
|
|
338
|
+
valueToExtract = extractCommentString(t, path, `properties.${i}.value`, value);
|
|
339
|
+
} else if (key.name === "id") {
|
|
340
|
+
const isIdLiteral = !value.value && t.isTemplateLiteral(value);
|
|
341
|
+
|
|
342
|
+
if (isIdLiteral) {
|
|
343
|
+
valueToExtract = value?.quasis[0]?.value?.cooked;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
props[key.name] = valueToExtract;
|
|
348
|
+
});
|
|
349
|
+
collectMessage(path, file, props);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
},
|
|
353
|
+
|
|
354
|
+
pre(file) {
|
|
355
|
+
localTransComponentName = null; // Skip validation because config is loaded for each file.
|
|
356
|
+
// Config was already validated in CLI.
|
|
357
|
+
|
|
358
|
+
file.set(CONFIG, (0, _conf.getConfig)({
|
|
359
|
+
cwd: file.opts.filename,
|
|
360
|
+
skipValidation: true,
|
|
361
|
+
configPath: this.opts.configPath
|
|
362
|
+
})); // Ignore else path for now. Collision is possible if other plugin is
|
|
363
|
+
// using the same Symbol('I18nMessages').
|
|
364
|
+
// istanbul ignore else
|
|
365
|
+
|
|
366
|
+
if (!file.has(MESSAGES)) {
|
|
367
|
+
file.set(MESSAGES, new Map());
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
file.set(VISITED, new WeakSet());
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
post(file) {
|
|
374
|
+
/* Write catalog to directory `localeDir`/_build/`path.to.file`/`filename`.json
|
|
375
|
+
* e.g: if file is src/components/App.js (relative to package.json), then
|
|
376
|
+
* catalog will be in locale/_build/src/components/App.json
|
|
377
|
+
*/
|
|
378
|
+
const config = file.get(CONFIG);
|
|
379
|
+
const localeDir = this.opts.localeDir || config.localeDir;
|
|
380
|
+
const {
|
|
381
|
+
filename
|
|
382
|
+
} = file.opts;
|
|
383
|
+
const rootDir = config.rootDir;
|
|
384
|
+
|
|
385
|
+
const baseDir = _path.default.dirname(_path.default.relative(rootDir, filename));
|
|
386
|
+
|
|
387
|
+
const targetDir = _path.default.join(localeDir, "_build", baseDir);
|
|
388
|
+
|
|
389
|
+
const messages = file.get(MESSAGES);
|
|
390
|
+
const catalog = {};
|
|
391
|
+
|
|
392
|
+
const baseName = _path.default.basename(filename);
|
|
393
|
+
|
|
394
|
+
const catalogFilename = _path.default.join(targetDir, `${baseName}.json`);
|
|
395
|
+
|
|
396
|
+
_mkdirp.default.sync(targetDir); // no messages, skip file
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
if (!messages.size) {
|
|
400
|
+
// clean any existing catalog
|
|
401
|
+
if (_fs.default.existsSync(catalogFilename)) {
|
|
402
|
+
_fs.default.writeFileSync(catalogFilename, JSON.stringify({}));
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
messages.forEach((value, key) => {
|
|
409
|
+
catalog[key] = value;
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
_fs.default.writeFileSync(catalogFilename, JSON.stringify(catalog, mapReplacer, 2));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
};
|
|
416
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lingui/babel-plugin-extract-messages",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.0",
|
|
4
4
|
"description": "Babel plugin for collecting messages from source code for internationalization",
|
|
5
|
-
"main": "index.js",
|
|
5
|
+
"main": "./build/index.js",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Tomáš Ehrlich",
|
|
8
8
|
"email": "tomas.ehrlich@gmail.com"
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
"i9n",
|
|
18
18
|
"translation"
|
|
19
19
|
],
|
|
20
|
+
"files": [
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"README.md",
|
|
23
|
+
"build/"
|
|
24
|
+
],
|
|
20
25
|
"repository": {
|
|
21
26
|
"type": "git",
|
|
22
27
|
"url": "https://github.com/lingui/js-lingui.git"
|
|
@@ -25,12 +30,13 @@
|
|
|
25
30
|
"url": "https://github.com/lingui/js-lingui/issues"
|
|
26
31
|
},
|
|
27
32
|
"engines": {
|
|
28
|
-
"node": ">=
|
|
33
|
+
"node": ">=14.0.0"
|
|
29
34
|
},
|
|
30
35
|
"dependencies": {
|
|
31
36
|
"@babel/generator": "^7.11.6",
|
|
32
37
|
"@babel/runtime": "^7.11.2",
|
|
33
|
-
"@lingui/conf": "
|
|
38
|
+
"@lingui/conf": "3.16.0",
|
|
34
39
|
"mkdirp": "^1.0.4"
|
|
35
|
-
}
|
|
40
|
+
},
|
|
41
|
+
"gitHead": "e8c1f518b988f45f3f6da84333550b215dcde94b"
|
|
36
42
|
}
|
package/index.js
DELETED
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = _default;
|
|
9
|
-
|
|
10
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
-
|
|
12
|
-
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
|
|
13
|
-
|
|
14
|
-
var _fs = _interopRequireDefault(require("fs"));
|
|
15
|
-
|
|
16
|
-
var _path = _interopRequireDefault(require("path"));
|
|
17
|
-
|
|
18
|
-
var _mkdirp = _interopRequireDefault(require("mkdirp"));
|
|
19
|
-
|
|
20
|
-
var _generator = _interopRequireDefault(require("@babel/generator"));
|
|
21
|
-
|
|
22
|
-
var _conf = require("@lingui/conf");
|
|
23
|
-
|
|
24
|
-
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
25
|
-
|
|
26
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
27
|
-
|
|
28
|
-
var CONFIG = Symbol("I18nConfig"); // Map of messages
|
|
29
|
-
|
|
30
|
-
var MESSAGES = Symbol("I18nMessages"); // We need to remember all processed nodes. When JSX expressions are
|
|
31
|
-
// replaced with CallExpressions, all children are traversed for each CallExpression.
|
|
32
|
-
// Then, i18n._ methods are visited multiple times for each parent CallExpression.
|
|
33
|
-
|
|
34
|
-
var VISITED = Symbol("I18nVisited");
|
|
35
|
-
|
|
36
|
-
function addMessage(path, messages, _ref) {
|
|
37
|
-
var id = _ref.id,
|
|
38
|
-
newDefault = _ref.message,
|
|
39
|
-
origin = _ref.origin,
|
|
40
|
-
comment = _ref.comment,
|
|
41
|
-
context = _ref.context,
|
|
42
|
-
props = (0, _objectWithoutProperties2.default)(_ref, ["id", "message", "origin", "comment", "context"]);
|
|
43
|
-
// prevent from adding undefined msgid
|
|
44
|
-
if (id === undefined) return;
|
|
45
|
-
var extractedComments = comment ? [comment] : [];
|
|
46
|
-
|
|
47
|
-
if (context) {
|
|
48
|
-
if (messages.has(context)) {
|
|
49
|
-
var existingContext = messages.get(context);
|
|
50
|
-
|
|
51
|
-
if (existingContext.has(id)) {
|
|
52
|
-
var message = messages.get(id); // only set/check default language when it's defined.
|
|
53
|
-
|
|
54
|
-
if (message.message && newDefault && message.message !== newDefault) {
|
|
55
|
-
throw path.buildCodeFrameError("Different defaults for the same message ID.");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (newDefault) {
|
|
59
|
-
message.message = newDefault;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
;
|
|
63
|
-
[].push.apply(message.origin, origin);
|
|
64
|
-
|
|
65
|
-
if (comment) {
|
|
66
|
-
;
|
|
67
|
-
[].push.apply(message.extractedComments, [comment]);
|
|
68
|
-
}
|
|
69
|
-
} else {
|
|
70
|
-
existingContext.set(id, _objectSpread(_objectSpread({}, props), {}, {
|
|
71
|
-
message: newDefault,
|
|
72
|
-
origin: origin,
|
|
73
|
-
extractedComments: extractedComments
|
|
74
|
-
}));
|
|
75
|
-
messages.set(context, existingContext);
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
var newContext = new Map();
|
|
79
|
-
newContext.set(id, _objectSpread(_objectSpread({}, props), {}, {
|
|
80
|
-
message: newDefault,
|
|
81
|
-
origin: origin,
|
|
82
|
-
extractedComments: extractedComments
|
|
83
|
-
}));
|
|
84
|
-
messages.set(context, newContext);
|
|
85
|
-
}
|
|
86
|
-
} else {
|
|
87
|
-
if (messages.has(id)) {
|
|
88
|
-
var _message = messages.get(id); // only set/check default language when it's defined.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (_message.message && newDefault && _message.message !== newDefault) {
|
|
92
|
-
throw path.buildCodeFrameError("Different defaults for the same message ID.");
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (newDefault) {
|
|
96
|
-
_message.message = newDefault;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
;
|
|
100
|
-
[].push.apply(_message.origin, origin);
|
|
101
|
-
|
|
102
|
-
if (comment) {
|
|
103
|
-
;
|
|
104
|
-
[].push.apply(_message.extractedComments, [comment]);
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
messages.set(id, _objectSpread(_objectSpread({}, props), {}, {
|
|
108
|
-
message: newDefault,
|
|
109
|
-
origin: origin,
|
|
110
|
-
extractedComments: extractedComments
|
|
111
|
-
}));
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* An ES6 Map type is not possible to encode with JSON.stringify,
|
|
117
|
-
* so we can instead use a replacer function as an argument to
|
|
118
|
-
* tell the JSON parser how to serialize / deserialize the Maps
|
|
119
|
-
* it encounters.
|
|
120
|
-
*/
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
function mapReplacer(key, value) {
|
|
124
|
-
if (value instanceof Map) {
|
|
125
|
-
var object = {};
|
|
126
|
-
value.forEach(function (v, k) {
|
|
127
|
-
return object[k] = v;
|
|
128
|
-
});
|
|
129
|
-
return object;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return value;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function extractStringContatentation(t, node, error) {
|
|
136
|
-
if (t.isStringLiteral(node)) {
|
|
137
|
-
return node.value;
|
|
138
|
-
} else if (t.isBinaryExpression(node)) {
|
|
139
|
-
return extractStringContatentation(t, node.left, error) + extractStringContatentation(t, node.right, error);
|
|
140
|
-
} else {
|
|
141
|
-
throw error;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function _default(_ref2) {
|
|
146
|
-
var t = _ref2.types;
|
|
147
|
-
var localTransComponentName;
|
|
148
|
-
|
|
149
|
-
function isTransComponent(node) {
|
|
150
|
-
return t.isJSXElement(node) && t.isJSXIdentifier(node.openingElement.name, {
|
|
151
|
-
name: localTransComponentName
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
var isI18nMethod = function isI18nMethod(node) {
|
|
156
|
-
return t.isMemberExpression(node) && t.isIdentifier(node.object, {
|
|
157
|
-
name: "i18n"
|
|
158
|
-
}) && t.isIdentifier(node.property, {
|
|
159
|
-
name: "_"
|
|
160
|
-
});
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
function collectMessage(path, file, props) {
|
|
164
|
-
var messages = file.get(MESSAGES);
|
|
165
|
-
var rootDir = file.get(CONFIG).rootDir;
|
|
166
|
-
|
|
167
|
-
var filename = _path.default.relative(rootDir, file.opts.filename).replace(/\\/g, "/");
|
|
168
|
-
|
|
169
|
-
var line = path.node.loc ? path.node.loc.start.line : null;
|
|
170
|
-
props.origin = [[filename, line]];
|
|
171
|
-
addMessage(path, messages, props);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
visitor: {
|
|
176
|
-
// Get the local name of Trans component. Usually it's just `Trans`, but
|
|
177
|
-
// it might be different when the import is aliased:
|
|
178
|
-
// import { Trans as T } from '@lingui/react';
|
|
179
|
-
ImportDeclaration: function ImportDeclaration(path) {
|
|
180
|
-
var node = path.node;
|
|
181
|
-
var moduleName = node.source.value;
|
|
182
|
-
if (!["@lingui/react", "@lingui/macro", "@lingui/core"].includes(moduleName)) return;
|
|
183
|
-
var importDeclarations = {};
|
|
184
|
-
|
|
185
|
-
if (moduleName === "@lingui/react" || moduleName === "@lingui/macro") {
|
|
186
|
-
node.specifiers.forEach(function (specifier) {
|
|
187
|
-
importDeclarations[specifier.imported.name] = specifier.local.name;
|
|
188
|
-
}); // Trans import might be missing if there's just Plural or similar macro.
|
|
189
|
-
// If there's no alias, consider it was imported as Trans.
|
|
190
|
-
|
|
191
|
-
localTransComponentName = importDeclarations["Trans"] || "Trans";
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (!node.specifiers.length) {
|
|
195
|
-
path.remove();
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
// Extract translation from <Trans /> component.
|
|
199
|
-
JSXElement: function JSXElement(path, _ref3) {
|
|
200
|
-
var file = _ref3.file;
|
|
201
|
-
var node = path.node;
|
|
202
|
-
if (!localTransComponentName || !isTransComponent(node)) return;
|
|
203
|
-
var attrs = node.openingElement.attributes || [];
|
|
204
|
-
var props = attrs.reduce(function (acc, item) {
|
|
205
|
-
var key = item.name.name;
|
|
206
|
-
|
|
207
|
-
if (key === "id" || key === "message" || key === "comment" || key === "context") {
|
|
208
|
-
if (item.value.value) {
|
|
209
|
-
acc[key] = item.value.value;
|
|
210
|
-
} else if (item.value.expression && t.isStringLiteral(item.value.expression)) {
|
|
211
|
-
acc[key] = item.value.expression.value;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return acc;
|
|
216
|
-
}, {});
|
|
217
|
-
|
|
218
|
-
if (!props.id) {
|
|
219
|
-
// <Trans id={message} /> is valid, don't raise warning
|
|
220
|
-
var idProp = attrs.filter(function (item) {
|
|
221
|
-
return item.name.name === "id";
|
|
222
|
-
})[0];
|
|
223
|
-
|
|
224
|
-
if (idProp === undefined || t.isLiteral(props.id)) {
|
|
225
|
-
console.warn("Missing message ID, skipping.");
|
|
226
|
-
console.warn((0, _generator.default)(node).code);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
collectMessage(path, file, props);
|
|
233
|
-
},
|
|
234
|
-
CallExpression: function CallExpression(path, _ref4) {
|
|
235
|
-
var file = _ref4.file;
|
|
236
|
-
var visited = file.get(VISITED);
|
|
237
|
-
if (visited.has(path.node)) return;
|
|
238
|
-
var hasComment = [path.node, path.parent].find(function (_ref5) {
|
|
239
|
-
var leadingComments = _ref5.leadingComments;
|
|
240
|
-
return leadingComments && leadingComments.filter(function (node) {
|
|
241
|
-
return node.value.match(/^\s*i18n\s*$/);
|
|
242
|
-
})[0];
|
|
243
|
-
});
|
|
244
|
-
if (!hasComment) return;
|
|
245
|
-
var props = {
|
|
246
|
-
id: path.node.arguments[0].value
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
if (!props.id) {
|
|
250
|
-
console.warn("Missing message ID, skipping.");
|
|
251
|
-
console.warn((0, _generator.default)(path.node).code);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
var copyOptions = ["message", "comment", "context"];
|
|
256
|
-
|
|
257
|
-
if (t.isObjectExpression(path.node.arguments[2])) {
|
|
258
|
-
path.node.arguments[2].properties.forEach(function (property) {
|
|
259
|
-
if (!copyOptions.includes(property.key.name)) return;
|
|
260
|
-
props[property.key.name] = property.value.value;
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
visited.add(path.node);
|
|
265
|
-
collectMessage(path, file, props);
|
|
266
|
-
},
|
|
267
|
-
StringLiteral: function StringLiteral(path, _ref6) {
|
|
268
|
-
var file = _ref6.file;
|
|
269
|
-
var visited = file.get(VISITED);
|
|
270
|
-
var comment = path.node.leadingComments && path.node.leadingComments.filter(function (node) {
|
|
271
|
-
return node.value.match(/^\s*i18n/);
|
|
272
|
-
})[0];
|
|
273
|
-
|
|
274
|
-
if (!comment || visited.has(path.node)) {
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
visited.add(path.node);
|
|
279
|
-
var props = {
|
|
280
|
-
id: path.node.value
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
if (!props.id) {
|
|
284
|
-
console.warn("Missing message ID, skipping.");
|
|
285
|
-
console.warn((0, _generator.default)(path.node).code);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
collectMessage(path, file, props);
|
|
290
|
-
},
|
|
291
|
-
// Extract message descriptors
|
|
292
|
-
ObjectExpression: function ObjectExpression(path, _ref7) {
|
|
293
|
-
var file = _ref7.file;
|
|
294
|
-
var visited = file.get(VISITED);
|
|
295
|
-
var comment = path.node.leadingComments && path.node.leadingComments.filter(function (node) {
|
|
296
|
-
return node.value.match(/^\s*i18n/);
|
|
297
|
-
})[0];
|
|
298
|
-
|
|
299
|
-
if (!comment || visited.has(path.node)) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
visited.add(path.node);
|
|
304
|
-
var props = {};
|
|
305
|
-
var copyProps = ["id", "message", "comment", "context"];
|
|
306
|
-
path.node.properties.filter(function (_ref8) {
|
|
307
|
-
var key = _ref8.key;
|
|
308
|
-
return copyProps.indexOf(key.name) !== -1;
|
|
309
|
-
}).forEach(function (_ref9, i) {
|
|
310
|
-
var key = _ref9.key,
|
|
311
|
-
value = _ref9.value;
|
|
312
|
-
// By default, the value is just the string value of the object property.
|
|
313
|
-
var valueToExtract = value.value;
|
|
314
|
-
|
|
315
|
-
if (key.name === "comment" && !t.isStringLiteral(value)) {
|
|
316
|
-
// Comments can be single or multi-line strings.
|
|
317
|
-
var errorIfNotAString = path.get("properties.".concat(i, ".value")).buildCodeFrameError("Only strings are supported as comments.");
|
|
318
|
-
|
|
319
|
-
if (t.isBinaryExpression(value)) {
|
|
320
|
-
valueToExtract = extractStringContatentation(t, value, errorIfNotAString);
|
|
321
|
-
} else {
|
|
322
|
-
throw errorIfNotAString;
|
|
323
|
-
}
|
|
324
|
-
} else if (key.name === "id") {
|
|
325
|
-
var isIdLiteral = !value.value && t.isTemplateLiteral(value);
|
|
326
|
-
|
|
327
|
-
if (isIdLiteral) {
|
|
328
|
-
var _value$quasis$, _value$quasis$$value;
|
|
329
|
-
|
|
330
|
-
valueToExtract = value === null || value === void 0 ? void 0 : (_value$quasis$ = value.quasis[0]) === null || _value$quasis$ === void 0 ? void 0 : (_value$quasis$$value = _value$quasis$.value) === null || _value$quasis$$value === void 0 ? void 0 : _value$quasis$$value.cooked;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
props[key.name] = valueToExtract;
|
|
335
|
-
});
|
|
336
|
-
collectMessage(path, file, props);
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
|
-
pre: function pre(file) {
|
|
340
|
-
localTransComponentName = null; // Skip validation because config is loaded for each file.
|
|
341
|
-
// Config was already validated in CLI.
|
|
342
|
-
|
|
343
|
-
file.set(CONFIG, (0, _conf.getConfig)({
|
|
344
|
-
cwd: file.opts.filename,
|
|
345
|
-
skipValidation: true,
|
|
346
|
-
configPath: this.opts.configPath
|
|
347
|
-
})); // Ignore else path for now. Collision is possible if other plugin is
|
|
348
|
-
// using the same Symbol('I18nMessages').
|
|
349
|
-
// istanbul ignore else
|
|
350
|
-
|
|
351
|
-
if (!file.has(MESSAGES)) {
|
|
352
|
-
file.set(MESSAGES, new Map());
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
file.set(VISITED, new WeakSet());
|
|
356
|
-
},
|
|
357
|
-
post: function post(file) {
|
|
358
|
-
/* Write catalog to directory `localeDir`/_build/`path.to.file`/`filename`.json
|
|
359
|
-
* e.g: if file is src/components/App.js (relative to package.json), then
|
|
360
|
-
* catalog will be in locale/_build/src/components/App.json
|
|
361
|
-
*/
|
|
362
|
-
var config = file.get(CONFIG);
|
|
363
|
-
var localeDir = this.opts.localeDir || config.localeDir;
|
|
364
|
-
var filename = file.opts.filename;
|
|
365
|
-
var rootDir = config.rootDir;
|
|
366
|
-
|
|
367
|
-
var baseDir = _path.default.dirname(_path.default.relative(rootDir, filename));
|
|
368
|
-
|
|
369
|
-
var targetDir = _path.default.join(localeDir, "_build", baseDir);
|
|
370
|
-
|
|
371
|
-
var messages = file.get(MESSAGES);
|
|
372
|
-
var catalog = {};
|
|
373
|
-
|
|
374
|
-
var baseName = _path.default.basename(filename);
|
|
375
|
-
|
|
376
|
-
var catalogFilename = _path.default.join(targetDir, "".concat(baseName, ".json"));
|
|
377
|
-
|
|
378
|
-
_mkdirp.default.sync(targetDir); // no messages, skip file
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (!messages.size) {
|
|
382
|
-
// clean any existing catalog
|
|
383
|
-
if (_fs.default.existsSync(catalogFilename)) {
|
|
384
|
-
_fs.default.writeFileSync(catalogFilename, JSON.stringify({}));
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
messages.forEach(function (value, key) {
|
|
391
|
-
catalog[key] = value;
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
_fs.default.writeFileSync(catalogFilename, JSON.stringify(catalog, mapReplacer, 2));
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
}
|