next-intl 4.5.2 → 4.5.4
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 +3 -3
- package/dist/esm/development/extractor/ExtractionCompiler.js +1 -1
- package/dist/esm/development/extractor/catalog/CatalogManager.js +2 -1
- package/dist/esm/development/extractor/extractionLoader.js +3 -2
- package/dist/esm/development/extractor/extractor/MessageExtractor.js +35 -373
- package/dist/esm/development/extractor/formatters/POFormatter.js +1 -1
- package/dist/esm/development/extractor/formatters/utils.js +6 -6
- package/dist/esm/production/extractor/ExtractionCompiler.js +1 -1
- package/dist/esm/production/extractor/catalog/CatalogManager.js +1 -1
- package/dist/esm/production/extractor/extractionLoader.js +1 -1
- package/dist/esm/production/extractor/extractor/MessageExtractor.js +1 -1
- package/dist/esm/production/extractor/formatters/POFormatter.js +1 -1
- package/dist/esm/production/extractor/formatters/utils.js +1 -1
- package/dist/types/extractor/ExtractionCompiler.d.ts +7 -1
- package/dist/types/extractor/catalog/CatalogManager.d.ts +3 -1
- package/dist/types/extractor/extractor/MessageExtractor.bench.d.ts +1 -0
- package/dist/types/extractor/extractor/MessageExtractor.d.ts +4 -3
- package/dist/types/navigation/react-client/createNavigation.d.ts +6 -6
- package/dist/types/navigation/react-server/createNavigation.d.ts +6 -6
- package/dist/types/navigation/shared/createSharedNavigationFns.d.ts +6 -6
- package/package.json +6 -4
- package/dist/esm/development/extractor/extractor/ASTScope.js +0 -18
- package/dist/esm/development/extractor/extractor/KeyGenerator.js +0 -11
- package/dist/esm/development/extractor/utils/POParser.js +0 -222
- package/dist/esm/production/extractor/extractor/ASTScope.js +0 -1
- package/dist/esm/production/extractor/extractor/KeyGenerator.js +0 -1
- package/dist/esm/production/extractor/utils/POParser.js +0 -1
- package/dist/types/extractor/utils/POParser.d.ts +0 -24
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<
|
|
1
|
+
<p align="center">
|
|
2
2
|
<br>
|
|
3
3
|
<a href="https://next-intl.dev">
|
|
4
4
|
<picture>
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
</a>
|
|
10
10
|
<br>
|
|
11
11
|
<br>
|
|
12
|
-
</
|
|
12
|
+
</p>
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Internationalization for Next.js.
|
|
15
15
|
|
|
16
16
|
## Features
|
|
17
17
|
|
|
@@ -31,7 +31,8 @@ class CatalogManager {
|
|
|
31
31
|
this.isDevelopment = opts.isDevelopment ?? false;
|
|
32
32
|
this.messageExtractor = new MessageExtractor({
|
|
33
33
|
isDevelopment: this.isDevelopment,
|
|
34
|
-
projectRoot: this.projectRoot
|
|
34
|
+
projectRoot: this.projectRoot,
|
|
35
|
+
sourceMap: opts.sourceMap
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
38
|
async getFormatter() {
|
|
@@ -11,11 +11,12 @@ function extractionLoader(source) {
|
|
|
11
11
|
if (!compiler) {
|
|
12
12
|
compiler = new ExtractionCompiler(options, {
|
|
13
13
|
// Avoid rollup's `replace` plugin to compile this away
|
|
14
|
-
isDevelopment: process.env['NODE_ENV'.trim()] === 'development'
|
|
14
|
+
isDevelopment: process.env['NODE_ENV'.trim()] === 'development',
|
|
15
|
+
sourceMap: this.sourceMap
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
18
|
compiler.compile(this.resourcePath, source).then(result => {
|
|
18
|
-
callback(null, result);
|
|
19
|
+
callback(null, result.code, result.map);
|
|
19
20
|
}).catch(callback);
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
1
2
|
import path from 'path';
|
|
2
|
-
import {
|
|
3
|
-
import { warn } from '../../plugin/utils.js';
|
|
4
|
-
import ASTScope from './ASTScope.js';
|
|
5
|
-
import KeyGenerator from './KeyGenerator.js';
|
|
3
|
+
import { transform } from '@swc/core';
|
|
6
4
|
import LRUCache from './LRUCache.js';
|
|
7
5
|
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
8
7
|
class MessageExtractor {
|
|
9
|
-
static NAMESPACE_SEPARATOR = '.';
|
|
10
8
|
compileCache = (() => new LRUCache(750))();
|
|
11
9
|
constructor(opts) {
|
|
12
10
|
this.isDevelopment = opts.isDevelopment;
|
|
13
11
|
this.projectRoot = opts.projectRoot;
|
|
12
|
+
this.sourceMap = opts.sourceMap ?? false;
|
|
14
13
|
}
|
|
15
14
|
async processFileContent(absoluteFilePath, source) {
|
|
16
15
|
const cacheKey = source;
|
|
@@ -23,379 +22,42 @@ class MessageExtractor {
|
|
|
23
22
|
if (!source.includes('useExtracted') && !source.includes('getExtracted')) {
|
|
24
23
|
return {
|
|
25
24
|
messages: [],
|
|
26
|
-
source
|
|
25
|
+
code: source
|
|
27
26
|
};
|
|
28
27
|
}
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const results = [];
|
|
46
|
-
let hookLocalName = null;
|
|
47
|
-
let hookType = null;
|
|
48
|
-
const isDevelopment = this.isDevelopment;
|
|
49
|
-
const scopeStack = [new ASTScope()];
|
|
50
|
-
function currentScope() {
|
|
51
|
-
return scopeStack[scopeStack.length - 1];
|
|
52
|
-
}
|
|
53
|
-
function createUndefinedArgument() {
|
|
54
|
-
return {
|
|
55
|
-
expression: {
|
|
56
|
-
type: 'Identifier',
|
|
57
|
-
value: 'undefined',
|
|
58
|
-
optional: false,
|
|
59
|
-
ctxt: 1,
|
|
60
|
-
span: {
|
|
61
|
-
start: 0,
|
|
62
|
-
end: 0,
|
|
63
|
-
ctxt: 0
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function extractStaticString(value) {
|
|
69
|
-
if (value.type === 'StringLiteral') {
|
|
70
|
-
return value.value;
|
|
71
|
-
} else if (value.type === 'TemplateLiteral') {
|
|
72
|
-
const templateLiteral = value;
|
|
73
|
-
// Only handle simple template literals without expressions
|
|
74
|
-
if (templateLiteral.expressions.length === 0 && templateLiteral.quasis.length === 1) {
|
|
75
|
-
return templateLiteral.quasis[0].cooked || templateLiteral.quasis[0].raw;
|
|
28
|
+
const filePath = path.relative(this.projectRoot, absoluteFilePath);
|
|
29
|
+
const result = await transform(source, {
|
|
30
|
+
jsc: {
|
|
31
|
+
target: 'esnext',
|
|
32
|
+
parser: {
|
|
33
|
+
syntax: 'typescript',
|
|
34
|
+
tsx: true,
|
|
35
|
+
decorators: true
|
|
36
|
+
},
|
|
37
|
+
experimental: {
|
|
38
|
+
disableBuiltinTransformsForInternalTesting: true,
|
|
39
|
+
disableAllLints: true,
|
|
40
|
+
plugins: [[require.resolve('next-intl-swc-plugin-extractor'), {
|
|
41
|
+
isDevelopment: this.isDevelopment,
|
|
42
|
+
filePath
|
|
43
|
+
}]]
|
|
76
44
|
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
switch (node.type) {
|
|
83
|
-
case 'ImportDeclaration':
|
|
84
|
-
{
|
|
85
|
-
const decl = node;
|
|
86
|
-
if (decl.source.value === 'next-intl') {
|
|
87
|
-
for (const spec of decl.specifiers) {
|
|
88
|
-
if (spec.type === 'ImportSpecifier') {
|
|
89
|
-
const importedName = spec.imported?.value;
|
|
90
|
-
const localName = spec.local.value;
|
|
91
|
-
if (importedName === 'useExtracted' || localName === 'useExtracted') {
|
|
92
|
-
hookLocalName = localName;
|
|
93
|
-
hookType = 'useTranslations';
|
|
94
|
-
|
|
95
|
-
// Transform import to useTranslations
|
|
96
|
-
spec.imported = undefined;
|
|
97
|
-
spec.local.value = 'useTranslations';
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
} else if (decl.source.value === 'next-intl/server') {
|
|
102
|
-
for (const spec of decl.specifiers) {
|
|
103
|
-
if (spec.type === 'ImportSpecifier') {
|
|
104
|
-
const importedName = spec.imported?.value;
|
|
105
|
-
const localName = spec.local.value;
|
|
106
|
-
if (importedName === 'getExtracted' || localName === 'getExtracted') {
|
|
107
|
-
hookLocalName = localName;
|
|
108
|
-
hookType = 'getTranslations';
|
|
109
|
-
|
|
110
|
-
// Transform import to getTranslations
|
|
111
|
-
spec.imported = undefined;
|
|
112
|
-
spec.local.value = 'getTranslations';
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
case 'VariableDeclarator':
|
|
120
|
-
{
|
|
121
|
-
const decl = node;
|
|
122
|
-
let callExpr = null;
|
|
123
|
-
|
|
124
|
-
// Handle direct CallExpression: const t = useExtracted();
|
|
125
|
-
if (decl.init?.type === 'CallExpression' && decl.init.callee.type === 'Identifier' && decl.init.callee.value === hookLocalName) {
|
|
126
|
-
callExpr = decl.init;
|
|
127
|
-
}
|
|
128
|
-
// Handle AwaitExpression: const t = await getExtracted();
|
|
129
|
-
else if (decl.init?.type === 'AwaitExpression' && decl.init.argument.type === 'CallExpression' && decl.init.argument.callee.type === 'Identifier' && decl.init.argument.callee.value === hookLocalName) {
|
|
130
|
-
callExpr = decl.init.argument;
|
|
131
|
-
}
|
|
132
|
-
if (callExpr && decl.id.type === 'Identifier') {
|
|
133
|
-
// Extract namespace from first argument if present
|
|
134
|
-
let namespace;
|
|
135
|
-
if (callExpr.arguments.length > 0) {
|
|
136
|
-
const firstArg = callExpr.arguments[0].expression;
|
|
137
|
-
if (firstArg.type === 'StringLiteral') {
|
|
138
|
-
namespace = firstArg.value;
|
|
139
|
-
} else if (firstArg.type === 'ObjectExpression') {
|
|
140
|
-
const objectExpression = firstArg;
|
|
141
|
-
for (const prop of objectExpression.properties) {
|
|
142
|
-
if (prop.type === 'KeyValueProperty') {
|
|
143
|
-
const key = prop.key;
|
|
144
|
-
if (key.type === 'Identifier' && key.value === 'namespace') {
|
|
145
|
-
const staticNamespace = extractStaticString(prop.value);
|
|
146
|
-
if (staticNamespace != null) {
|
|
147
|
-
namespace = staticNamespace;
|
|
148
|
-
}
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
currentScope().define(decl.id.value, 'translator', namespace);
|
|
156
|
-
|
|
157
|
-
// Transform the call based on the hook type
|
|
158
|
-
if (hookType) {
|
|
159
|
-
callExpr.callee.value = hookType;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
case 'CallExpression':
|
|
165
|
-
{
|
|
166
|
-
const call = node;
|
|
167
|
-
let isTranslatorCall = false;
|
|
168
|
-
let namespace;
|
|
169
|
-
|
|
170
|
-
// Handle Identifier case: t("message")
|
|
171
|
-
if (call.callee.type === 'Identifier') {
|
|
172
|
-
const name = call.callee.value;
|
|
173
|
-
const resolved = currentScope().lookup(name);
|
|
174
|
-
isTranslatorCall = resolved?.kind === 'translator';
|
|
175
|
-
namespace = resolved?.namespace;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Handle MemberExpression case: t.rich, t.markup, or t.has
|
|
179
|
-
else if (call.callee.type === 'MemberExpression') {
|
|
180
|
-
const memberExpr = call.callee;
|
|
181
|
-
if (memberExpr.object.type === 'Identifier' && memberExpr.property.type === 'Identifier') {
|
|
182
|
-
const objectName = memberExpr.object.value;
|
|
183
|
-
const propertyName = memberExpr.property.value;
|
|
184
|
-
const resolved = currentScope().lookup(objectName);
|
|
185
|
-
isTranslatorCall = resolved?.kind === 'translator' && (propertyName === 'rich' || propertyName === 'markup' || propertyName === 'has');
|
|
186
|
-
namespace = resolved?.namespace;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (isTranslatorCall) {
|
|
190
|
-
const arg0 = call.arguments[0]?.expression;
|
|
191
|
-
let messageText = null;
|
|
192
|
-
let explicitId = null;
|
|
193
|
-
let description = null;
|
|
194
|
-
let valuesNode = null;
|
|
195
|
-
let formatsNode = null;
|
|
196
|
-
function warnDynamicExpression(expressionNode) {
|
|
197
|
-
const hasSpan = 'span' in expressionNode && expressionNode.span && typeof expressionNode.span === 'object' && 'start' in expressionNode.span;
|
|
198
|
-
const location = hasSpan ? path.basename(filePath) : undefined;
|
|
199
|
-
warn((location ? `${location}: ` : '') + 'Cannot extract message from dynamic expression, messages need to be statically analyzable. If you need to provide runtime values, pass them as a separate argument.');
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
203
|
-
if (arg0) {
|
|
204
|
-
// Handle object syntax: t({id: 'key', message: 'text'})
|
|
205
|
-
if (arg0.type === 'ObjectExpression') {
|
|
206
|
-
const objectExpression = arg0;
|
|
207
|
-
|
|
208
|
-
// Look for id, message, values, and formats properties
|
|
209
|
-
for (const prop of objectExpression.properties) {
|
|
210
|
-
if (prop.type === 'KeyValueProperty') {
|
|
211
|
-
const key = prop.key;
|
|
212
|
-
if (key.type === 'Identifier' && key.value === 'id') {
|
|
213
|
-
const staticId = extractStaticString(prop.value);
|
|
214
|
-
if (staticId !== null) {
|
|
215
|
-
explicitId = staticId;
|
|
216
|
-
}
|
|
217
|
-
} else if (key.type === 'Identifier' && key.value === 'message') {
|
|
218
|
-
const staticMessage = extractStaticString(prop.value);
|
|
219
|
-
if (staticMessage != null) {
|
|
220
|
-
messageText = staticMessage;
|
|
221
|
-
} else {
|
|
222
|
-
warnDynamicExpression(prop.value);
|
|
223
|
-
}
|
|
224
|
-
} else if (key.type === 'Identifier' && key.value === 'description') {
|
|
225
|
-
const staticDescription = extractStaticString(prop.value);
|
|
226
|
-
if (staticDescription != null) {
|
|
227
|
-
description = staticDescription;
|
|
228
|
-
} else {
|
|
229
|
-
warnDynamicExpression(prop.value);
|
|
230
|
-
}
|
|
231
|
-
} else if (key.type === 'Identifier' && key.value === 'values') {
|
|
232
|
-
valuesNode = prop.value;
|
|
233
|
-
} else if (key.type === 'Identifier' && key.value === 'formats') {
|
|
234
|
-
formatsNode = prop.value;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Handle string syntax: t('text') or t(`text`)
|
|
241
|
-
else {
|
|
242
|
-
const staticString = extractStaticString(arg0);
|
|
243
|
-
if (staticString != null) {
|
|
244
|
-
messageText = staticString;
|
|
245
|
-
} else {
|
|
246
|
-
// Dynamic expression (Identifier, CallExpression, BinaryExpression, etc.)
|
|
247
|
-
warnDynamicExpression(arg0);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (messageText) {
|
|
252
|
-
const callKey = explicitId || KeyGenerator.generate(messageText);
|
|
253
|
-
const fullKey = namespace ? [namespace, callKey].join(MessageExtractor.NAMESPACE_SEPARATOR) : callKey;
|
|
254
|
-
const message = {
|
|
255
|
-
id: fullKey,
|
|
256
|
-
message: messageText,
|
|
257
|
-
references: [{
|
|
258
|
-
path: filePath
|
|
259
|
-
}]
|
|
260
|
-
};
|
|
261
|
-
if (description) {
|
|
262
|
-
message.description = description;
|
|
263
|
-
}
|
|
264
|
-
results.push(message);
|
|
265
|
-
|
|
266
|
-
// Transform the argument based on type
|
|
267
|
-
if (arg0.type === 'StringLiteral') {
|
|
268
|
-
arg0.value = callKey;
|
|
269
|
-
arg0.raw = undefined;
|
|
270
|
-
} else if (arg0.type === 'TemplateLiteral') {
|
|
271
|
-
// Replace template literal with string literal
|
|
272
|
-
Object.assign(arg0, {
|
|
273
|
-
type: 'StringLiteral',
|
|
274
|
-
value: callKey,
|
|
275
|
-
raw: undefined
|
|
276
|
-
});
|
|
277
|
-
} else if (arg0.type === 'ObjectExpression') {
|
|
278
|
-
// Transform object expression to individual parameters
|
|
279
|
-
// Replace the object with the key as first argument
|
|
280
|
-
Object.assign(arg0, {
|
|
281
|
-
type: 'StringLiteral',
|
|
282
|
-
value: callKey,
|
|
283
|
-
raw: undefined
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// Add values as second argument if present
|
|
287
|
-
if (valuesNode) {
|
|
288
|
-
if (call.arguments.length < 2) {
|
|
289
|
-
call.arguments.push({
|
|
290
|
-
// @ts-expect-error -- Node type compatible with Expression
|
|
291
|
-
expression: valuesNode
|
|
292
|
-
});
|
|
293
|
-
} else {
|
|
294
|
-
// @ts-expect-error -- Node type compatible with Expression
|
|
295
|
-
call.arguments[1].expression = valuesNode;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Add formats as third argument if present
|
|
300
|
-
if (formatsNode) {
|
|
301
|
-
// Ensure we have a second argument (values or undefined)
|
|
302
|
-
while (call.arguments.length < 2) {
|
|
303
|
-
call.arguments.push(createUndefinedArgument());
|
|
304
|
-
}
|
|
305
|
-
if (call.arguments.length < 3) {
|
|
306
|
-
// Append argument
|
|
307
|
-
call.arguments.push({
|
|
308
|
-
// @ts-expect-error -- Node type compatible with Expression
|
|
309
|
-
expression: formatsNode
|
|
310
|
-
});
|
|
311
|
-
} else {
|
|
312
|
-
// Replace argument
|
|
313
|
-
// @ts-expect-error -- Node type compatible with Expression
|
|
314
|
-
call.arguments[2].expression = formatsNode;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Check if this is a t.has call (which doesn't need fallback)
|
|
320
|
-
const isHasCall = call.callee.type === 'MemberExpression' && call.callee.property.type === 'Identifier' && call.callee.property.value === 'has';
|
|
321
|
-
|
|
322
|
-
// Add fallback message as fourth parameter in development mode (except for t.has)
|
|
323
|
-
if (isDevelopment && !isHasCall) {
|
|
324
|
-
// Ensure we have at least 3 arguments
|
|
325
|
-
while (call.arguments.length < 3) {
|
|
326
|
-
call.arguments.push(createUndefinedArgument());
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Add fallback message
|
|
330
|
-
call.arguments.push({
|
|
331
|
-
expression: {
|
|
332
|
-
type: 'StringLiteral',
|
|
333
|
-
value: messageText,
|
|
334
|
-
raw: JSON.stringify(messageText),
|
|
335
|
-
// @ts-expect-error -- Seems required
|
|
336
|
-
ctxt: 1,
|
|
337
|
-
span: {
|
|
338
|
-
start: 0,
|
|
339
|
-
end: 0,
|
|
340
|
-
ctxt: 0
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
case 'FunctionDeclaration':
|
|
350
|
-
case 'FunctionExpression':
|
|
351
|
-
case 'ArrowFunctionExpression':
|
|
352
|
-
case 'BlockStatement':
|
|
353
|
-
{
|
|
354
|
-
scopeStack.push(new ASTScope(currentScope()));
|
|
355
|
-
for (const key of Object.keys(node)) {
|
|
356
|
-
const child = node[key];
|
|
357
|
-
if (Array.isArray(child)) {
|
|
358
|
-
child.forEach(item => {
|
|
359
|
-
if (item && typeof item === 'object') {
|
|
360
|
-
if ('expression' in item && typeof item.expression === 'object' && 'type' in item.expression) {
|
|
361
|
-
visit(item.expression);
|
|
362
|
-
} else if ('type' in item) {
|
|
363
|
-
visit(item);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
} else if (child && typeof child === 'object' && 'type' in child) {
|
|
368
|
-
visit(child);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
scopeStack.pop();
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
45
|
+
},
|
|
46
|
+
sourceMaps: this.sourceMap,
|
|
47
|
+
sourceFileName: filePath,
|
|
48
|
+
filename: filePath
|
|
49
|
+
});
|
|
375
50
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
visit(item.expression);
|
|
384
|
-
} else if ('type' in item) {
|
|
385
|
-
visit(item);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
} else if (child && typeof child === 'object' && 'type' in child) {
|
|
390
|
-
visit(child);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
visit(ast);
|
|
395
|
-
return {
|
|
396
|
-
messages: results,
|
|
397
|
-
source: (await print(ast)).code
|
|
51
|
+
// TODO: Improve the typing of @swc/core
|
|
52
|
+
const output = result.output;
|
|
53
|
+
const messages = JSON.parse(JSON.parse(output).results);
|
|
54
|
+
const extractionResult = {
|
|
55
|
+
code: result.code,
|
|
56
|
+
map: result.map,
|
|
57
|
+
messages
|
|
398
58
|
};
|
|
59
|
+
this.compileCache.set(cacheKey, extractionResult);
|
|
60
|
+
return extractionResult;
|
|
399
61
|
}
|
|
400
62
|
}
|
|
401
63
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
function getSortedMessages(messages) {
|
|
2
|
-
return messages.toSorted((
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
if (
|
|
6
|
-
return
|
|
2
|
+
return messages.toSorted((messageA, messageB) => {
|
|
3
|
+
const pathA = messageA.references?.[0]?.path ?? '';
|
|
4
|
+
const pathB = messageB.references?.[0]?.path ?? '';
|
|
5
|
+
if (pathA === pathB) {
|
|
6
|
+
return messageA.id.localeCompare(messageB.id);
|
|
7
7
|
} else {
|
|
8
|
-
return
|
|
8
|
+
return pathA.localeCompare(pathB);
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import a from"./catalog/CatalogManager.js";class i{isDevelopment=!1;constructor(i,
|
|
1
|
+
import a from"./catalog/CatalogManager.js";class i{isDevelopment=!1;constructor(i,t={}){this.manager=new a(i,t),this.isDevelopment=t.isDevelopment??!1,this.initialScanPromise=this.performInitialScan()}async compile(a,i){this.initialScanPromise&&(await this.initialScanPromise,this.initialScanPromise=void 0);const t=await this.manager.extractFileMessages(a,i);return this.isDevelopment&&t.changed&&this.manager.save(),t}async performInitialScan(){await this.manager.loadMessages(),await this.manager.save()}async extract(){await this.initialScanPromise}[Symbol.dispose](){this.manager.destroy()}}export{i as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"fs/promises";import s from"path";import t from"../extractor/MessageExtractor.js";import a from"../formatters/index.js";import o from"../source/SourceFileScanner.js";import r from"./CatalogLocales.js";import i from"./CatalogPersister.js";import c from"./SaveScheduler.js";class n{messagesByFile=(()=>new Map)();messagesById=(()=>new Map)();translationsByTargetLocale=(()=>new Map)();lastWriteByLocale=(()=>new Map)();constructor(e,s={}){this.config=e,this.saveScheduler=new c(50),this.projectRoot=s.projectRoot||process.cwd(),this.isDevelopment=s.isDevelopment??!1,this.messageExtractor=new t({isDevelopment:this.isDevelopment,projectRoot:this.projectRoot})}async getFormatter(){if(this.formatter)return this.formatter;{const e=(await a[this.config.messages.format]()).default;return this.formatter=new e,this.formatter}}async getPersister(){return this.persister||(this.persister=new i(this.config.messages.path,await this.getFormatter())),this.persister}async getCatalogLocales(){if(this.catalogLocales)return this.catalogLocales;{const e=s.join(this.projectRoot,this.config.messages.path),t=await this.getFormatter();return this.catalogLocales=new r({messagesDir:e,sourceLocale:this.config.sourceLocale,extension:t.EXTENSION,locales:this.config.messages.locales}),this.catalogLocales}}async getTargetLocales(){return(await this.getCatalogLocales()).getTargetLocales()}getSrcPaths(){return(Array.isArray(this.config.srcPath)?this.config.srcPath:[this.config.srcPath]).map((e=>s.join(this.projectRoot,e)))}getFileMessages(e){return this.messagesByFile.get(e)}async loadMessages(){if(await this.loadSourceMessages(),await this.loadTargetMessages(),this.isDevelopment){(await this.getCatalogLocales()).subscribeLocalesChange(this.onLocalesChange)}}async loadSourceMessages(){await this.loadLocaleMessages(this.config.sourceLocale);const s=await o.getSourceFiles(this.getSrcPaths());await Promise.all(s.map((async s=>this.extractFileMessages(s,await e.readFile(s,"utf8")))))}async loadLocaleMessages(e){const s=await this.getPersister();try{const t=await s.read(e),a=await s.getLastModified(e);return this.lastWriteByLocale.set(e,a),t}catch{return[]}}async loadTargetMessages(){const e=await this.getTargetLocales();await Promise.all(e.map((async e=>{this.translationsByTargetLocale.set(e,new Map);const s=await this.loadLocaleMessages(e);for(const t of s){this.translationsByTargetLocale.get(e).set(t.id,t.message)}})))}async extractFileMessages(e,t){const a=await this.messageExtractor.processFileContent(e,t),o=this.messagesByFile.get(e),r=Array.from(o?.keys()??[]),i=new Map;for(let e of a.messages){const s=this.messagesById.get(e.id);if(s){const t=[...s.references??[]];e.references.forEach((e=>{t.some((s=>s.path===e.path))||t.push(e)})),t.sort(((e,s)=>e.path.localeCompare(s.path))),e={...e,references:t},s.description&&!e.description&&(e={...e,description:s.description})}this.messagesById.set(e.id,e),i.set(e.id,e);const t=r.indexOf(e.id);-1!==t&&r.splice(t,1)}const c=s.relative(this.projectRoot,e);r.filter((e=>{const s=this.messagesById.get(e);return!s?.references?.some((e=>e.path!==c))})).forEach((e=>{this.messagesById.delete(e)}));a.messages.length>0?this.messagesByFile.set(e,i):this.messagesByFile.delete(e);const n=this.haveMessagesChanged(o,i);return{...a,changed:n}}haveMessagesChanged(e,s){if(!e)return s.size>0;if(e.size!==s.size)return!0;for(const[t,a]of e){const e=s.get(t);if(!e||!this.areMessagesEqual(a,e))return!0}return!1}areMessagesEqual(e,s){return e.id===s.id&&e.message===s.message&&e.description===s.description&&this.areReferencesEqual(e.references,s.references)}areReferencesEqual(e,s){if(!e&&!s)return!0;if(!e||!s)return!1;if(e.length!==s.length)return!1;for(let t=0;t<e.length;t++)if(e[t].path!==s[t].path)return!1;return!0}async save(){return this.saveScheduler.schedule((()=>this.saveImpl()))}async saveImpl(){const e=Array.from(this.messagesById.values()),s=await this.getPersister();await s.write(this.config.sourceLocale,e);for(const e of await this.getTargetLocales())await this.saveLocale(e);return e.length}async saveLocale(e){const s=Array.from(this.messagesById.values()),t=await this.getPersister(),a=this.lastWriteByLocale.get(e),o=await t.getLastModified(e);if(o&&a&&o>a){const s=await t.read(e),a=this.translationsByTargetLocale.get(e);for(const e of s)a.set(e.id,e.message)}const r=this.translationsByTargetLocale.get(e),i=s.map((e=>({...e,message:r.get(e.id)||""})));await t.write(e,i);const c=await t.getLastModified(e);this.lastWriteByLocale.set(e,c)}onLocalesChange=async e=>{for(const s of e.added){const e=new Map;this.translationsByTargetLocale.set(s,e);const t=await this.loadLocaleMessages(s);for(const s of t)e.set(s.id,s.message);await this.saveLocale(s)}for(const s of e.removed)this.translationsByTargetLocale.delete(s),this.lastWriteByLocale.delete(s)};destroy(){this.saveScheduler.destroy(),this.catalogLocales&&this.isDevelopment&&this.catalogLocales.unsubscribeLocalesChange(this.onLocalesChange)}}export{n as default};
|
|
1
|
+
import e from"fs/promises";import s from"path";import t from"../extractor/MessageExtractor.js";import a from"../formatters/index.js";import o from"../source/SourceFileScanner.js";import r from"./CatalogLocales.js";import i from"./CatalogPersister.js";import c from"./SaveScheduler.js";class n{messagesByFile=(()=>new Map)();messagesById=(()=>new Map)();translationsByTargetLocale=(()=>new Map)();lastWriteByLocale=(()=>new Map)();constructor(e,s={}){this.config=e,this.saveScheduler=new c(50),this.projectRoot=s.projectRoot||process.cwd(),this.isDevelopment=s.isDevelopment??!1,this.messageExtractor=new t({isDevelopment:this.isDevelopment,projectRoot:this.projectRoot,sourceMap:s.sourceMap})}async getFormatter(){if(this.formatter)return this.formatter;{const e=(await a[this.config.messages.format]()).default;return this.formatter=new e,this.formatter}}async getPersister(){return this.persister||(this.persister=new i(this.config.messages.path,await this.getFormatter())),this.persister}async getCatalogLocales(){if(this.catalogLocales)return this.catalogLocales;{const e=s.join(this.projectRoot,this.config.messages.path),t=await this.getFormatter();return this.catalogLocales=new r({messagesDir:e,sourceLocale:this.config.sourceLocale,extension:t.EXTENSION,locales:this.config.messages.locales}),this.catalogLocales}}async getTargetLocales(){return(await this.getCatalogLocales()).getTargetLocales()}getSrcPaths(){return(Array.isArray(this.config.srcPath)?this.config.srcPath:[this.config.srcPath]).map((e=>s.join(this.projectRoot,e)))}getFileMessages(e){return this.messagesByFile.get(e)}async loadMessages(){if(await this.loadSourceMessages(),await this.loadTargetMessages(),this.isDevelopment){(await this.getCatalogLocales()).subscribeLocalesChange(this.onLocalesChange)}}async loadSourceMessages(){await this.loadLocaleMessages(this.config.sourceLocale);const s=await o.getSourceFiles(this.getSrcPaths());await Promise.all(s.map((async s=>this.extractFileMessages(s,await e.readFile(s,"utf8")))))}async loadLocaleMessages(e){const s=await this.getPersister();try{const t=await s.read(e),a=await s.getLastModified(e);return this.lastWriteByLocale.set(e,a),t}catch{return[]}}async loadTargetMessages(){const e=await this.getTargetLocales();await Promise.all(e.map((async e=>{this.translationsByTargetLocale.set(e,new Map);const s=await this.loadLocaleMessages(e);for(const t of s){this.translationsByTargetLocale.get(e).set(t.id,t.message)}})))}async extractFileMessages(e,t){const a=await this.messageExtractor.processFileContent(e,t),o=this.messagesByFile.get(e),r=Array.from(o?.keys()??[]),i=new Map;for(let e of a.messages){const s=this.messagesById.get(e.id);if(s){const t=[...s.references??[]];e.references.forEach((e=>{t.some((s=>s.path===e.path))||t.push(e)})),t.sort(((e,s)=>e.path.localeCompare(s.path))),e={...e,references:t},s.description&&!e.description&&(e={...e,description:s.description})}this.messagesById.set(e.id,e),i.set(e.id,e);const t=r.indexOf(e.id);-1!==t&&r.splice(t,1)}const c=s.relative(this.projectRoot,e);r.filter((e=>{const s=this.messagesById.get(e);return!s?.references?.some((e=>e.path!==c))})).forEach((e=>{this.messagesById.delete(e)}));a.messages.length>0?this.messagesByFile.set(e,i):this.messagesByFile.delete(e);const n=this.haveMessagesChanged(o,i);return{...a,changed:n}}haveMessagesChanged(e,s){if(!e)return s.size>0;if(e.size!==s.size)return!0;for(const[t,a]of e){const e=s.get(t);if(!e||!this.areMessagesEqual(a,e))return!0}return!1}areMessagesEqual(e,s){return e.id===s.id&&e.message===s.message&&e.description===s.description&&this.areReferencesEqual(e.references,s.references)}areReferencesEqual(e,s){if(!e&&!s)return!0;if(!e||!s)return!1;if(e.length!==s.length)return!1;for(let t=0;t<e.length;t++)if(e[t].path!==s[t].path)return!1;return!0}async save(){return this.saveScheduler.schedule((()=>this.saveImpl()))}async saveImpl(){const e=Array.from(this.messagesById.values()),s=await this.getPersister();await s.write(this.config.sourceLocale,e);for(const e of await this.getTargetLocales())await this.saveLocale(e);return e.length}async saveLocale(e){const s=Array.from(this.messagesById.values()),t=await this.getPersister(),a=this.lastWriteByLocale.get(e),o=await t.getLastModified(e);if(o&&a&&o>a){const s=await t.read(e),a=this.translationsByTargetLocale.get(e);for(const e of s)a.set(e.id,e.message)}const r=this.translationsByTargetLocale.get(e),i=s.map((e=>({...e,message:r.get(e.id)||""})));await t.write(e,i);const c=await t.getLastModified(e);this.lastWriteByLocale.set(e,c)}onLocalesChange=async e=>{for(const s of e.added){const e=new Map;this.translationsByTargetLocale.set(s,e);const t=await this.loadLocaleMessages(s);for(const s of t)e.set(s.id,s.message);await this.saveLocale(s)}for(const s of e.removed)this.translationsByTargetLocale.delete(s),this.lastWriteByLocale.delete(s)};destroy(){this.saveScheduler.destroy(),this.catalogLocales&&this.isDevelopment&&this.catalogLocales.unsubscribeLocalesChange(this.onLocalesChange)}}export{n as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"./ExtractionCompiler.js";let t;function o(o){const s=this.getOptions(),c=this.async();t||(t=new e(s,{isDevelopment:"development"===process.env["NODE_ENV".trim()],sourceMap:this.sourceMap})),t.compile(this.resourcePath,o).then((e=>{c(null,e.code,e.map)})).catch(c)}export{o as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e
|
|
1
|
+
import{createRequire as e}from"module";import t from"path";import{transform as s}from"@swc/core";import o from"./LRUCache.js";const r=e(import.meta.url);class i{compileCache=(()=>new o(750))();constructor(e){this.isDevelopment=e.isDevelopment,this.projectRoot=e.projectRoot,this.sourceMap=e.sourceMap??!1}async processFileContent(e,o){const i=o,a=this.compileCache.get(i);if(a)return a;if(!o.includes("useExtracted")&&!o.includes("getExtracted"))return{messages:[],code:o};const c=t.relative(this.projectRoot,e),p=await s(o,{jsc:{target:"esnext",parser:{syntax:"typescript",tsx:!0,decorators:!0},experimental:{disableBuiltinTransformsForInternalTesting:!0,disableAllLints:!0,plugins:[[r.resolve("next-intl-swc-plugin-extractor"),{isDevelopment:this.isDevelopment,filePath:c}]]}},sourceMaps:this.sourceMap,sourceFileName:c,filename:c}),n=p.output,l=JSON.parse(JSON.parse(n).results),m={code:p.code,map:p.map,messages:l};return this.compileCache.set(i,m),m}}export{i as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import t from"po-parser";import{setNestedProperty as e}from"../utils/ObjectUtils.js";import a from"./Formatter.js";import{getSortedMessages as s}from"./utils.js";class r extends a{static DEFAULT_METADATA={"Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"8bit","X-Generator":"next-intl","X-Crowdin-SourceKey":"msgstr"};EXTENSION=".po";metadataByLocale=(()=>new Map)();parse(e,a){const s=t.parse(e);return s.meta&&this.metadataByLocale.set(a.locale,s.meta),s.messages||[]}serialize(e,a){const o={Language:a.locale,...r.DEFAULT_METADATA,...this.metadataByLocale.get(a.locale)};return t.serialize({meta:o,messages:s(e)})}toJSONString(t,a){const s=this.parse(t,a),r={};for(const t of s)e(r,t.id,t.message);return JSON.stringify(r,null,2)}}export{r as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(e){return e.toSorted(((e,r)=>{const
|
|
1
|
+
function e(e){return e.toSorted(((e,r)=>{const o=e.references?.[0]?.path??"",t=r.references?.[0]?.path??"";return o===t?e.id.localeCompare(r.id):o.localeCompare(t)}))}export{e as getSortedMessages};
|
|
@@ -6,8 +6,14 @@ export default class ExtractionCompiler implements Disposable {
|
|
|
6
6
|
constructor(config: ExtractorConfig, opts?: {
|
|
7
7
|
isDevelopment?: boolean;
|
|
8
8
|
projectRoot?: string;
|
|
9
|
+
sourceMap?: boolean;
|
|
9
10
|
});
|
|
10
|
-
compile(resourcePath: string, source: string): Promise<
|
|
11
|
+
compile(resourcePath: string, source: string): Promise<{
|
|
12
|
+
messages: Array<import("./types.js").ExtractedMessage>;
|
|
13
|
+
code: string;
|
|
14
|
+
changed: boolean;
|
|
15
|
+
map?: string;
|
|
16
|
+
}>;
|
|
11
17
|
private performInitialScan;
|
|
12
18
|
extract(): Promise<void>;
|
|
13
19
|
[Symbol.dispose](): void;
|
|
@@ -19,6 +19,7 @@ export default class CatalogManager {
|
|
|
19
19
|
constructor(config: ExtractorConfig, opts?: {
|
|
20
20
|
projectRoot?: string;
|
|
21
21
|
isDevelopment?: boolean;
|
|
22
|
+
sourceMap?: boolean;
|
|
22
23
|
});
|
|
23
24
|
private getFormatter;
|
|
24
25
|
private getPersister;
|
|
@@ -32,8 +33,9 @@ export default class CatalogManager {
|
|
|
32
33
|
private loadTargetMessages;
|
|
33
34
|
extractFileMessages(absoluteFilePath: string, source: string): Promise<{
|
|
34
35
|
messages: Array<ExtractedMessage>;
|
|
35
|
-
|
|
36
|
+
code: string;
|
|
36
37
|
changed: boolean;
|
|
38
|
+
map?: string;
|
|
37
39
|
}>;
|
|
38
40
|
private haveMessagesChanged;
|
|
39
41
|
private areMessagesEqual;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,18 +3,19 @@ type StrictExtractedMessage = ExtractedMessage & {
|
|
|
3
3
|
references: NonNullable<ExtractedMessage['references']>;
|
|
4
4
|
};
|
|
5
5
|
export default class MessageExtractor {
|
|
6
|
-
private static readonly NAMESPACE_SEPARATOR;
|
|
7
6
|
private isDevelopment;
|
|
8
7
|
private projectRoot;
|
|
8
|
+
private sourceMap;
|
|
9
9
|
private compileCache;
|
|
10
10
|
constructor(opts: {
|
|
11
11
|
isDevelopment: boolean;
|
|
12
12
|
projectRoot: string;
|
|
13
|
+
sourceMap?: boolean;
|
|
13
14
|
});
|
|
14
15
|
processFileContent(absoluteFilePath: string, source: string): Promise<{
|
|
15
16
|
messages: Array<StrictExtractedMessage>;
|
|
16
|
-
|
|
17
|
+
code: string;
|
|
18
|
+
map?: string;
|
|
17
19
|
}>;
|
|
18
|
-
private processAST;
|
|
19
20
|
}
|
|
20
21
|
export {};
|
|
@@ -4,19 +4,17 @@ import type { DomainsConfig, LocalePrefixMode, Locales, Pathnames } from '../../
|
|
|
4
4
|
export default function createNavigation<const AppLocales extends Locales, const AppLocalePrefixMode extends LocalePrefixMode = 'always', const AppPathnames extends Pathnames<AppLocales> = never, const AppDomains extends DomainsConfig<AppLocales> = never>(routing?: [AppPathnames] extends [never] ? RoutingConfigSharedNavigation<AppLocales, AppLocalePrefixMode, AppDomains> | undefined : RoutingConfigLocalizedNavigation<AppLocales, AppLocalePrefixMode, AppPathnames, AppDomains>): {
|
|
5
5
|
Link: import("react").ForwardRefExoticComponent<Omit<{
|
|
6
6
|
target?: import("react").HTMLAttributeAnchorTarget | undefined;
|
|
7
|
-
type?: string | undefined | undefined;
|
|
8
|
-
id?: string | undefined | undefined;
|
|
9
|
-
prefix?: string | undefined | undefined;
|
|
10
|
-
property?: string | undefined | undefined;
|
|
11
|
-
children?: import("react").ReactNode;
|
|
12
|
-
key?: import("react").Key | null | undefined;
|
|
13
7
|
replace?: boolean | undefined;
|
|
8
|
+
id?: string | undefined | undefined;
|
|
14
9
|
slot?: string | undefined | undefined;
|
|
15
10
|
style?: import("react").CSSProperties | undefined;
|
|
16
11
|
title?: string | undefined | undefined;
|
|
17
12
|
locale?: Locale | undefined;
|
|
18
13
|
onError?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
14
|
+
children?: import("react").ReactNode;
|
|
19
15
|
ref?: import("react").Ref<HTMLAnchorElement> | undefined;
|
|
16
|
+
prefix?: string | undefined | undefined;
|
|
17
|
+
key?: import("react").Key | null | undefined;
|
|
20
18
|
as?: (string | import("url").UrlObject) | undefined;
|
|
21
19
|
scroll?: boolean | undefined;
|
|
22
20
|
shallow?: boolean | undefined;
|
|
@@ -33,6 +31,7 @@ export default function createNavigation<const AppLocales extends Locales, const
|
|
|
33
31
|
hrefLang?: string | undefined | undefined;
|
|
34
32
|
media?: string | undefined | undefined;
|
|
35
33
|
ping?: string | undefined | undefined;
|
|
34
|
+
type?: string | undefined | undefined;
|
|
36
35
|
referrerPolicy?: import("react").HTMLAttributeReferrerPolicy | undefined;
|
|
37
36
|
defaultChecked?: boolean | undefined | undefined;
|
|
38
37
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
@@ -59,6 +58,7 @@ export default function createNavigation<const AppLocales extends Locales, const
|
|
|
59
58
|
content?: string | undefined | undefined;
|
|
60
59
|
datatype?: string | undefined | undefined;
|
|
61
60
|
inlist?: any;
|
|
61
|
+
property?: string | undefined | undefined;
|
|
62
62
|
rel?: string | undefined | undefined;
|
|
63
63
|
resource?: string | undefined | undefined;
|
|
64
64
|
rev?: string | undefined | undefined;
|
|
@@ -5,19 +5,17 @@ export default function createNavigation<const AppLocales extends Locales, const
|
|
|
5
5
|
useRouter: () => never;
|
|
6
6
|
Link: import("react").ForwardRefExoticComponent<Omit<{
|
|
7
7
|
target?: import("react").HTMLAttributeAnchorTarget | undefined;
|
|
8
|
-
type?: string | undefined | undefined;
|
|
9
|
-
id?: string | undefined | undefined;
|
|
10
|
-
prefix?: string | undefined | undefined;
|
|
11
|
-
property?: string | undefined | undefined;
|
|
12
|
-
children?: import("react").ReactNode;
|
|
13
|
-
key?: import("react").Key | null | undefined;
|
|
14
8
|
replace?: boolean | undefined;
|
|
9
|
+
id?: string | undefined | undefined;
|
|
15
10
|
slot?: string | undefined | undefined;
|
|
16
11
|
style?: import("react").CSSProperties | undefined;
|
|
17
12
|
title?: string | undefined | undefined;
|
|
18
13
|
locale?: import("use-intl").Locale | undefined;
|
|
19
14
|
onError?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
15
|
+
children?: import("react").ReactNode;
|
|
20
16
|
ref?: import("react").Ref<HTMLAnchorElement> | undefined;
|
|
17
|
+
prefix?: string | undefined | undefined;
|
|
18
|
+
key?: import("react").Key | null | undefined;
|
|
21
19
|
as?: (string | import("url").UrlObject) | undefined;
|
|
22
20
|
scroll?: boolean | undefined;
|
|
23
21
|
shallow?: boolean | undefined;
|
|
@@ -34,6 +32,7 @@ export default function createNavigation<const AppLocales extends Locales, const
|
|
|
34
32
|
hrefLang?: string | undefined | undefined;
|
|
35
33
|
media?: string | undefined | undefined;
|
|
36
34
|
ping?: string | undefined | undefined;
|
|
35
|
+
type?: string | undefined | undefined;
|
|
37
36
|
referrerPolicy?: import("react").HTMLAttributeReferrerPolicy | undefined;
|
|
38
37
|
defaultChecked?: boolean | undefined | undefined;
|
|
39
38
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
@@ -60,6 +59,7 @@ export default function createNavigation<const AppLocales extends Locales, const
|
|
|
60
59
|
content?: string | undefined | undefined;
|
|
61
60
|
datatype?: string | undefined | undefined;
|
|
62
61
|
inlist?: any;
|
|
62
|
+
property?: string | undefined | undefined;
|
|
63
63
|
rel?: string | undefined | undefined;
|
|
64
64
|
resource?: string | undefined | undefined;
|
|
65
65
|
rev?: string | undefined | undefined;
|
|
@@ -23,19 +23,17 @@ export default function createSharedNavigationFns<const AppLocales extends Local
|
|
|
23
23
|
};
|
|
24
24
|
Link: import("react").ForwardRefExoticComponent<Omit<{
|
|
25
25
|
target?: import("react").HTMLAttributeAnchorTarget | undefined;
|
|
26
|
-
type?: string | undefined | undefined;
|
|
27
|
-
id?: string | undefined | undefined;
|
|
28
|
-
prefix?: string | undefined | undefined;
|
|
29
|
-
property?: string | undefined | undefined;
|
|
30
|
-
children?: import("react").ReactNode;
|
|
31
|
-
key?: import("react").Key | null | undefined;
|
|
32
26
|
replace?: boolean | undefined;
|
|
27
|
+
id?: string | undefined | undefined;
|
|
33
28
|
slot?: string | undefined | undefined;
|
|
34
29
|
style?: import("react").CSSProperties | undefined;
|
|
35
30
|
title?: string | undefined | undefined;
|
|
36
31
|
locale?: Locale | undefined;
|
|
37
32
|
onError?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined;
|
|
33
|
+
children?: import("react").ReactNode;
|
|
38
34
|
ref?: import("react").Ref<HTMLAnchorElement> | undefined;
|
|
35
|
+
prefix?: string | undefined | undefined;
|
|
36
|
+
key?: import("react").Key | null | undefined;
|
|
39
37
|
as?: (string | import("url").UrlObject) | undefined;
|
|
40
38
|
scroll?: boolean | undefined;
|
|
41
39
|
shallow?: boolean | undefined;
|
|
@@ -52,6 +50,7 @@ export default function createSharedNavigationFns<const AppLocales extends Local
|
|
|
52
50
|
hrefLang?: string | undefined | undefined;
|
|
53
51
|
media?: string | undefined | undefined;
|
|
54
52
|
ping?: string | undefined | undefined;
|
|
53
|
+
type?: string | undefined | undefined;
|
|
55
54
|
referrerPolicy?: import("react").HTMLAttributeReferrerPolicy | undefined;
|
|
56
55
|
defaultChecked?: boolean | undefined | undefined;
|
|
57
56
|
defaultValue?: string | number | readonly string[] | undefined;
|
|
@@ -78,6 +77,7 @@ export default function createSharedNavigationFns<const AppLocales extends Local
|
|
|
78
77
|
content?: string | undefined | undefined;
|
|
79
78
|
datatype?: string | undefined | undefined;
|
|
80
79
|
inlist?: any;
|
|
80
|
+
property?: string | undefined | undefined;
|
|
81
81
|
rel?: string | undefined | undefined;
|
|
82
82
|
resource?: string | undefined | undefined;
|
|
83
83
|
rev?: string | undefined | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-intl",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.4",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"author": "Jan Amann <jan@amann.work>",
|
|
6
6
|
"funding": [
|
|
@@ -125,9 +125,11 @@
|
|
|
125
125
|
],
|
|
126
126
|
"dependencies": {
|
|
127
127
|
"@formatjs/intl-localematcher": "^0.5.4",
|
|
128
|
-
"@swc/core": "^1.
|
|
128
|
+
"@swc/core": "^1.15.2",
|
|
129
129
|
"negotiator": "^1.0.0",
|
|
130
|
-
"
|
|
130
|
+
"next-intl-swc-plugin-extractor": "^4.5.4",
|
|
131
|
+
"po-parser": "^0.1.2",
|
|
132
|
+
"use-intl": "^4.5.4"
|
|
131
133
|
},
|
|
132
134
|
"peerDependencies": {
|
|
133
135
|
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
@@ -139,5 +141,5 @@
|
|
|
139
141
|
"optional": true
|
|
140
142
|
}
|
|
141
143
|
},
|
|
142
|
-
"gitHead": "
|
|
144
|
+
"gitHead": "32b170cc341cc847d4a6f4ae353c53d941f626f2"
|
|
143
145
|
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
class ASTScope {
|
|
2
|
-
vars = (() => new Map())();
|
|
3
|
-
constructor(parent) {
|
|
4
|
-
this.parent = parent;
|
|
5
|
-
}
|
|
6
|
-
define(name, kind, namespace) {
|
|
7
|
-
this.vars.set(name, {
|
|
8
|
-
kind,
|
|
9
|
-
namespace
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
lookup(name) {
|
|
13
|
-
if (this.vars.has(name)) return this.vars.get(name);
|
|
14
|
-
return this.parent?.lookup(name);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export { ASTScope as default };
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import crypto from 'crypto';
|
|
2
|
-
|
|
3
|
-
class KeyGenerator {
|
|
4
|
-
static generate(message) {
|
|
5
|
-
const hash = crypto.createHash('sha512').update(message).digest();
|
|
6
|
-
const base64 = hash.toString('base64');
|
|
7
|
-
return base64.slice(0, 6);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export { KeyGenerator as default };
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
class POParser {
|
|
2
|
-
static KEYWORDS = (() => ({
|
|
3
|
-
MSGID: 'msgid',
|
|
4
|
-
MSGSTR: 'msgstr',
|
|
5
|
-
MSGCTXT: 'msgctxt',
|
|
6
|
-
MSGID_PLURAL: 'msgid_plural'
|
|
7
|
-
}))();
|
|
8
|
-
static COMMENTS = (() => ({
|
|
9
|
-
REFERENCE: '#:',
|
|
10
|
-
EXTRACTED: '#.',
|
|
11
|
-
TRANSLATOR: '#',
|
|
12
|
-
FLAG: '#,',
|
|
13
|
-
PREVIOUS: '#|'
|
|
14
|
-
}))();
|
|
15
|
-
static NAMESPACE_SEPARATOR = '.';
|
|
16
|
-
static QUOTE = '"';
|
|
17
|
-
static NEWLINE = '\\n';
|
|
18
|
-
static FILE_COLUMN_SEPARATOR = ':';
|
|
19
|
-
static META_SEPARATOR = ':';
|
|
20
|
-
static parse(content) {
|
|
21
|
-
const lines = POParser.splitLines(content);
|
|
22
|
-
const messages = [];
|
|
23
|
-
const meta = {};
|
|
24
|
-
let state = 'entry';
|
|
25
|
-
let entry;
|
|
26
|
-
for (let i = 0; i < lines.length; i++) {
|
|
27
|
-
const line = lines[i].trim();
|
|
28
|
-
|
|
29
|
-
// An empty line indicates the end of an entry
|
|
30
|
-
if (!line) {
|
|
31
|
-
if (state === 'entry' && entry) {
|
|
32
|
-
messages.push(POParser.finishEntry(entry));
|
|
33
|
-
entry = undefined;
|
|
34
|
-
}
|
|
35
|
-
state = 'entry';
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
if (state === 'meta') {
|
|
39
|
-
if (line.startsWith(POParser.QUOTE)) {
|
|
40
|
-
const metaLine = POParser.extractQuotedString(line, state);
|
|
41
|
-
const cleaned = metaLine.endsWith(POParser.NEWLINE) ? metaLine.slice(0, -2) : metaLine;
|
|
42
|
-
const separatorIndex = cleaned.indexOf(POParser.META_SEPARATOR);
|
|
43
|
-
if (separatorIndex > 0) {
|
|
44
|
-
const key = cleaned.substring(0, separatorIndex).trim();
|
|
45
|
-
const value = cleaned.substring(separatorIndex + 1).trim();
|
|
46
|
-
meta[key] = value;
|
|
47
|
-
}
|
|
48
|
-
} else {
|
|
49
|
-
POParser.throwWithLine('Encountered unexpected non-quoted metadata line', line);
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
52
|
-
// Unsupported comment types
|
|
53
|
-
if (POParser.lineStartsWithPrefix(line, POParser.COMMENTS.TRANSLATOR)) {
|
|
54
|
-
POParser.throwWithLine('Translator comments (#) are not supported, use inline descriptions instead', line);
|
|
55
|
-
}
|
|
56
|
-
if (POParser.lineStartsWithPrefix(line, POParser.COMMENTS.FLAG)) {
|
|
57
|
-
POParser.throwWithLine('Flag comments (#,) are not supported', line);
|
|
58
|
-
}
|
|
59
|
-
if (POParser.lineStartsWithPrefix(line, POParser.COMMENTS.PREVIOUS)) {
|
|
60
|
-
POParser.throwWithLine('Previous string key comments (#|) are not supported', line);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Reference comments
|
|
64
|
-
if (POParser.lineStartsWithPrefix(line, POParser.COMMENTS.REFERENCE)) {
|
|
65
|
-
entry = POParser.ensureEntry(entry);
|
|
66
|
-
// Only use the path part, ignore line and column numbers
|
|
67
|
-
const path = line.substring(POParser.COMMENTS.REFERENCE.length).trim().split(POParser.FILE_COLUMN_SEPARATOR).at(0);
|
|
68
|
-
entry.references ??= [];
|
|
69
|
-
entry.references.push({
|
|
70
|
-
path
|
|
71
|
-
});
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Extracted comments
|
|
76
|
-
if (POParser.lineStartsWithPrefix(line, POParser.COMMENTS.EXTRACTED)) {
|
|
77
|
-
entry = POParser.ensureEntry(entry);
|
|
78
|
-
entry.description = line.substring(POParser.COMMENTS.EXTRACTED.length).trim();
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Check for unsupported features
|
|
83
|
-
if (POParser.lineStartsWithPrefix(line, POParser.KEYWORDS.MSGID_PLURAL)) {
|
|
84
|
-
POParser.throwWithLine('Plural forms (msgid_plural) are not supported, use ICU pluralization instead', line);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// msgctxt
|
|
88
|
-
if (POParser.lineStartsWithPrefix(line, POParser.KEYWORDS.MSGCTXT)) {
|
|
89
|
-
entry = POParser.ensureEntry(entry);
|
|
90
|
-
entry.msgctxt = POParser.extractQuotedString(line.substring(POParser.KEYWORDS.MSGCTXT.length + 1), state);
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// msgid
|
|
95
|
-
if (POParser.lineStartsWithPrefix(line, POParser.KEYWORDS.MSGID)) {
|
|
96
|
-
entry = POParser.ensureEntry(entry);
|
|
97
|
-
entry.msgid = POParser.extractQuotedString(line.substring(POParser.KEYWORDS.MSGID.length + 1), state);
|
|
98
|
-
if (POParser.isMetaEntry(entry, messages)) {
|
|
99
|
-
state = 'meta';
|
|
100
|
-
entry = undefined;
|
|
101
|
-
}
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// msgstr
|
|
106
|
-
if (POParser.lineStartsWithPrefix(line, POParser.KEYWORDS.MSGSTR)) {
|
|
107
|
-
entry = POParser.ensureEntry(entry);
|
|
108
|
-
entry.msgstr = POParser.extractQuotedString(line.substring(POParser.KEYWORDS.MSGSTR.length + 1), state);
|
|
109
|
-
if (POParser.isMetaEntry(entry, messages)) {
|
|
110
|
-
state = 'meta';
|
|
111
|
-
entry = undefined;
|
|
112
|
-
}
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Multi-line strings are not supported in entry mode
|
|
117
|
-
if (line.startsWith(POParser.QUOTE)) {
|
|
118
|
-
POParser.throwWithLine('Multi-line strings are not supported, use single-line strings instead', line);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Finish any remaining entry
|
|
124
|
-
if (state === 'entry' && entry) {
|
|
125
|
-
messages.push(POParser.finishEntry(entry));
|
|
126
|
-
}
|
|
127
|
-
return {
|
|
128
|
-
meta: Object.keys(meta).length > 0 ? meta : undefined,
|
|
129
|
-
messages: messages.length > 0 ? messages : undefined
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
static isMetaEntry(entry, messages) {
|
|
133
|
-
return messages.length === 0 && entry.msgid === '' && entry.msgstr === '';
|
|
134
|
-
}
|
|
135
|
-
static serialize(catalog) {
|
|
136
|
-
const lines = [];
|
|
137
|
-
|
|
138
|
-
// Metadata
|
|
139
|
-
if (catalog.meta) {
|
|
140
|
-
lines.push(`${POParser.KEYWORDS.MSGID} ${POParser.QUOTE}${POParser.QUOTE}`);
|
|
141
|
-
lines.push(`${POParser.KEYWORDS.MSGSTR} ${POParser.QUOTE}${POParser.QUOTE}`);
|
|
142
|
-
for (const [key, value] of Object.entries(catalog.meta)) {
|
|
143
|
-
lines.push(`${POParser.QUOTE}${key}${POParser.META_SEPARATOR} ${value}${POParser.NEWLINE}${POParser.QUOTE}`);
|
|
144
|
-
}
|
|
145
|
-
lines.push('');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Messages
|
|
149
|
-
if (catalog.messages) {
|
|
150
|
-
for (const message of catalog.messages) {
|
|
151
|
-
if (message.description) {
|
|
152
|
-
lines.push(`${POParser.COMMENTS.EXTRACTED} ${message.description}`);
|
|
153
|
-
}
|
|
154
|
-
if (message.references && message.references.length > 0) {
|
|
155
|
-
for (const ref of message.references) {
|
|
156
|
-
lines.push(`${POParser.COMMENTS.REFERENCE} ${ref.path}`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
let msgctxt;
|
|
160
|
-
let msgid;
|
|
161
|
-
const lastDotIndex = message.id.lastIndexOf(POParser.NAMESPACE_SEPARATOR);
|
|
162
|
-
if (lastDotIndex > 0) {
|
|
163
|
-
msgctxt = message.id.substring(0, lastDotIndex);
|
|
164
|
-
msgid = message.id.substring(lastDotIndex + 1);
|
|
165
|
-
} else {
|
|
166
|
-
msgid = message.id;
|
|
167
|
-
}
|
|
168
|
-
if (msgctxt) {
|
|
169
|
-
lines.push(`${POParser.KEYWORDS.MSGCTXT} ${POParser.QUOTE}${msgctxt}${POParser.QUOTE}`);
|
|
170
|
-
}
|
|
171
|
-
lines.push(`${POParser.KEYWORDS.MSGID} ${POParser.QUOTE}${msgid}${POParser.QUOTE}`);
|
|
172
|
-
lines.push(`${POParser.KEYWORDS.MSGSTR} ${POParser.QUOTE}${message.message}${POParser.QUOTE}`);
|
|
173
|
-
lines.push('');
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return lines.join('\n');
|
|
177
|
-
}
|
|
178
|
-
static lineStartsWithPrefix(line, prefix) {
|
|
179
|
-
return line.startsWith(prefix + ' ');
|
|
180
|
-
}
|
|
181
|
-
static throwWithLine(message, line) {
|
|
182
|
-
throw new Error(`${message}:\n> ${line}`);
|
|
183
|
-
}
|
|
184
|
-
static splitLines(content) {
|
|
185
|
-
// Avoid overhead for Unix newlines only
|
|
186
|
-
if (content.includes('\r')) {
|
|
187
|
-
content = content.replace(/\r\n/g, '\n');
|
|
188
|
-
}
|
|
189
|
-
return content.split('\n');
|
|
190
|
-
}
|
|
191
|
-
static ensureEntry(entry) {
|
|
192
|
-
return entry || {};
|
|
193
|
-
}
|
|
194
|
-
static finishEntry(entry) {
|
|
195
|
-
if (entry.msgid == null || entry.msgstr == null) {
|
|
196
|
-
throw new Error('Incomplete message entry: both msgid and msgstr are required');
|
|
197
|
-
}
|
|
198
|
-
let fullId = entry.msgid;
|
|
199
|
-
if (entry.msgctxt) {
|
|
200
|
-
fullId = entry.msgctxt + POParser.NAMESPACE_SEPARATOR + entry.msgid;
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
id: fullId,
|
|
204
|
-
message: entry.msgstr,
|
|
205
|
-
description: entry.description,
|
|
206
|
-
references: entry.references
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
static extractQuotedString(line, state) {
|
|
210
|
-
const trimmed = line.trim();
|
|
211
|
-
const endIndex = trimmed.indexOf(POParser.QUOTE, POParser.QUOTE.length);
|
|
212
|
-
if (endIndex === -1) {
|
|
213
|
-
if (state === 'meta') {
|
|
214
|
-
return trimmed.substring(POParser.QUOTE.length);
|
|
215
|
-
}
|
|
216
|
-
POParser.throwWithLine('Incomplete quoted string', line);
|
|
217
|
-
}
|
|
218
|
-
return trimmed.substring(POParser.QUOTE.length, endIndex);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
export { POParser as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
class s{vars=(()=>new Map)();constructor(s){this.parent=s}define(s,t,a){this.vars.set(s,{kind:t,namespace:a})}lookup(s){return this.vars.has(s)?this.vars.get(s):this.parent?.lookup(s)}}export{s as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import t from"crypto";class e{static generate(e){return t.createHash("sha512").update(e).digest().toString("base64").slice(0,6)}}export{e as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
class t{static KEYWORDS={MSGID:"msgid",MSGSTR:"msgstr",MSGCTXT:"msgctxt",MSGID_PLURAL:"msgid_plural"};static COMMENTS={REFERENCE:"#:",EXTRACTED:"#.",TRANSLATOR:"#",FLAG:"#,",PREVIOUS:"#|"};static NAMESPACE_SEPARATOR=".";static QUOTE='"';static NEWLINE="\\n";static FILE_COLUMN_SEPARATOR=":";static META_SEPARATOR=":";static parse(e){const s=t.splitLines(e),i=[],r={};let n,E="entry";for(let e=0;e<s.length;e++){const a=s[e].trim();if(a)if("meta"===E)if(a.startsWith(t.QUOTE)){const e=t.extractQuotedString(a,E),s=e.endsWith(t.NEWLINE)?e.slice(0,-2):e,i=s.indexOf(t.META_SEPARATOR);if(i>0){const t=s.substring(0,i).trim(),e=s.substring(i+1).trim();r[t]=e}}else t.throwWithLine("Encountered unexpected non-quoted metadata line",a);else{if(t.lineStartsWithPrefix(a,t.COMMENTS.TRANSLATOR)&&t.throwWithLine("Translator comments (#) are not supported, use inline descriptions instead",a),t.lineStartsWithPrefix(a,t.COMMENTS.FLAG)&&t.throwWithLine("Flag comments (#,) are not supported",a),t.lineStartsWithPrefix(a,t.COMMENTS.PREVIOUS)&&t.throwWithLine("Previous string key comments (#|) are not supported",a),t.lineStartsWithPrefix(a,t.COMMENTS.REFERENCE)){n=t.ensureEntry(n);const e=a.substring(t.COMMENTS.REFERENCE.length).trim().split(t.FILE_COLUMN_SEPARATOR).at(0);n.references??=[],n.references.push({path:e});continue}if(t.lineStartsWithPrefix(a,t.COMMENTS.EXTRACTED)){n=t.ensureEntry(n),n.description=a.substring(t.COMMENTS.EXTRACTED.length).trim();continue}if(t.lineStartsWithPrefix(a,t.KEYWORDS.MSGID_PLURAL)&&t.throwWithLine("Plural forms (msgid_plural) are not supported, use ICU pluralization instead",a),t.lineStartsWithPrefix(a,t.KEYWORDS.MSGCTXT)){n=t.ensureEntry(n),n.msgctxt=t.extractQuotedString(a.substring(t.KEYWORDS.MSGCTXT.length+1),E);continue}if(t.lineStartsWithPrefix(a,t.KEYWORDS.MSGID)){n=t.ensureEntry(n),n.msgid=t.extractQuotedString(a.substring(t.KEYWORDS.MSGID.length+1),E),t.isMetaEntry(n,i)&&(E="meta",n=void 0);continue}if(t.lineStartsWithPrefix(a,t.KEYWORDS.MSGSTR)){n=t.ensureEntry(n),n.msgstr=t.extractQuotedString(a.substring(t.KEYWORDS.MSGSTR.length+1),E),t.isMetaEntry(n,i)&&(E="meta",n=void 0);continue}a.startsWith(t.QUOTE)&&t.throwWithLine("Multi-line strings are not supported, use single-line strings instead",a)}else"entry"===E&&n&&(i.push(t.finishEntry(n)),n=void 0),E="entry"}return"entry"===E&&n&&i.push(t.finishEntry(n)),{meta:Object.keys(r).length>0?r:void 0,messages:i.length>0?i:void 0}}static isMetaEntry(t,e){return 0===e.length&&""===t.msgid&&""===t.msgstr}static serialize(e){const s=[];if(e.meta){s.push(`${t.KEYWORDS.MSGID} ${t.QUOTE}${t.QUOTE}`),s.push(`${t.KEYWORDS.MSGSTR} ${t.QUOTE}${t.QUOTE}`);for(const[i,r]of Object.entries(e.meta))s.push(`${t.QUOTE}${i}${t.META_SEPARATOR} ${r}${t.NEWLINE}${t.QUOTE}`);s.push("")}if(e.messages)for(const i of e.messages){if(i.description&&s.push(`${t.COMMENTS.EXTRACTED} ${i.description}`),i.references&&i.references.length>0)for(const e of i.references)s.push(`${t.COMMENTS.REFERENCE} ${e.path}`);let e,r;const n=i.id.lastIndexOf(t.NAMESPACE_SEPARATOR);n>0?(e=i.id.substring(0,n),r=i.id.substring(n+1)):r=i.id,e&&s.push(`${t.KEYWORDS.MSGCTXT} ${t.QUOTE}${e}${t.QUOTE}`),s.push(`${t.KEYWORDS.MSGID} ${t.QUOTE}${r}${t.QUOTE}`),s.push(`${t.KEYWORDS.MSGSTR} ${t.QUOTE}${i.message}${t.QUOTE}`),s.push("")}return s.join("\n")}static lineStartsWithPrefix(t,e){return t.startsWith(e+" ")}static throwWithLine(t,e){throw new Error(`${t}:\n> ${e}`)}static splitLines(t){return t.includes("\r")&&(t=t.replace(/\r\n/g,"\n")),t.split("\n")}static ensureEntry(t){return t||{}}static finishEntry(e){if(null==e.msgid||null==e.msgstr)throw new Error("Incomplete message entry: both msgid and msgstr are required");let s=e.msgid;return e.msgctxt&&(s=e.msgctxt+t.NAMESPACE_SEPARATOR+e.msgid),{id:s,message:e.msgstr,description:e.description,references:e.references}}static extractQuotedString(e,s){const i=e.trim(),r=i.indexOf(t.QUOTE,t.QUOTE.length);if(-1===r){if("meta"===s)return i.substring(t.QUOTE.length);t.throwWithLine("Incomplete quoted string",e)}return i.substring(t.QUOTE.length,r)}}export{t as default};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { ExtractedMessage } from '../types.js';
|
|
2
|
-
type Catalog = {
|
|
3
|
-
meta?: Record<string, string>;
|
|
4
|
-
messages?: Array<ExtractedMessage>;
|
|
5
|
-
};
|
|
6
|
-
export default class POParser {
|
|
7
|
-
private static readonly KEYWORDS;
|
|
8
|
-
private static readonly COMMENTS;
|
|
9
|
-
private static readonly NAMESPACE_SEPARATOR;
|
|
10
|
-
private static readonly QUOTE;
|
|
11
|
-
private static readonly NEWLINE;
|
|
12
|
-
private static readonly FILE_COLUMN_SEPARATOR;
|
|
13
|
-
private static readonly META_SEPARATOR;
|
|
14
|
-
static parse(content: string): Catalog;
|
|
15
|
-
private static isMetaEntry;
|
|
16
|
-
static serialize(catalog: Catalog): string;
|
|
17
|
-
private static lineStartsWithPrefix;
|
|
18
|
-
private static throwWithLine;
|
|
19
|
-
private static splitLines;
|
|
20
|
-
private static ensureEntry;
|
|
21
|
-
private static finishEntry;
|
|
22
|
-
private static extractQuotedString;
|
|
23
|
-
}
|
|
24
|
-
export {};
|