next-intl 4.5.5 → 4.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/development/extractor/catalog/CatalogManager.js +92 -68
- package/dist/esm/development/extractor/formatters/JSONFormatter.js +1 -1
- package/dist/esm/development/extractor/formatters/POFormatter.js +1 -1
- package/dist/esm/development/extractor/formatters/utils.js +4 -2
- package/dist/esm/development/extractor/{utils/ObjectUtils.js → utils.js} +4 -1
- package/dist/esm/development/middleware/syncCookie.js +9 -2
- package/dist/esm/production/extractor/catalog/CatalogManager.js +1 -1
- package/dist/esm/production/extractor/formatters/JSONFormatter.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/esm/production/extractor/utils.js +1 -0
- package/dist/esm/production/middleware/syncCookie.js +1 -1
- package/dist/types/extractor/catalog/CatalogManager.d.ts +4 -4
- package/dist/types/extractor/types.d.ts +2 -0
- package/dist/types/extractor/{utils/ObjectUtils.d.ts → utils.d.ts} +1 -0
- package/dist/types/navigation/react-client/createNavigation.d.ts +1 -1
- package/dist/types/navigation/react-server/createNavigation.d.ts +1 -1
- package/dist/types/navigation/shared/createSharedNavigationFns.d.ts +1 -1
- package/package.json +5 -5
- package/dist/esm/production/extractor/utils/ObjectUtils.js +0 -1
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import MessageExtractor from '../extractor/MessageExtractor.js';
|
|
4
4
|
import formatters from '../formatters/index.js';
|
|
5
5
|
import SourceFileScanner from '../source/SourceFileScanner.js';
|
|
6
|
+
import { localeCompare } from '../utils.js';
|
|
6
7
|
import CatalogLocales from './CatalogLocales.js';
|
|
7
8
|
import CatalogPersister from './CatalogPersister.js';
|
|
8
9
|
import SaveScheduler from './SaveScheduler.js';
|
|
@@ -24,6 +25,9 @@ class CatalogManager {
|
|
|
24
25
|
|
|
25
26
|
// Cached instances
|
|
26
27
|
|
|
28
|
+
// Resolves when all catalogs are loaded
|
|
29
|
+
// (but doesn't indicate that project scan is done)
|
|
30
|
+
|
|
27
31
|
constructor(config, opts = {}) {
|
|
28
32
|
this.config = config;
|
|
29
33
|
this.saveScheduler = new SaveScheduler(50);
|
|
@@ -74,24 +78,41 @@ class CatalogManager {
|
|
|
74
78
|
getSrcPaths() {
|
|
75
79
|
return (Array.isArray(this.config.srcPath) ? this.config.srcPath : [this.config.srcPath]).map(srcPath => path.join(this.projectRoot, srcPath));
|
|
76
80
|
}
|
|
77
|
-
getFileMessages(absoluteFilePath) {
|
|
78
|
-
return this.messagesByFile.get(absoluteFilePath);
|
|
79
|
-
}
|
|
80
81
|
async loadMessages() {
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
this.loadCatalogsPromise = Promise.all([this.loadSourceMessages(), this.loadTargetMessages()]);
|
|
83
|
+
|
|
84
|
+
// Ensure catalogs are loaded before scanning source files.
|
|
85
|
+
// Otherwise, `loadSourceMessages` might overwrite extracted
|
|
86
|
+
// messages if it finishes after source file extraction.
|
|
87
|
+
await this.loadCatalogsPromise;
|
|
83
88
|
if (this.isDevelopment) {
|
|
84
89
|
const catalogLocales = await this.getCatalogLocales();
|
|
85
90
|
catalogLocales.subscribeLocalesChange(this.onLocalesChange);
|
|
86
91
|
}
|
|
92
|
+
const sourceFiles = await SourceFileScanner.getSourceFiles(this.getSrcPaths());
|
|
93
|
+
await Promise.all(sourceFiles.map(async filePath => this.extractFileMessages(filePath, await fs.readFile(filePath, 'utf8'))));
|
|
87
94
|
}
|
|
88
95
|
async loadSourceMessages() {
|
|
89
96
|
// First hydrate from source locale file to potentially init metadata
|
|
90
|
-
await this.loadLocaleMessages(this.config.sourceLocale);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
97
|
+
const messages = await this.loadLocaleMessages(this.config.sourceLocale);
|
|
98
|
+
const messagesById = new Map();
|
|
99
|
+
const messagesByFile = new Map();
|
|
100
|
+
for (const message of messages) {
|
|
101
|
+
messagesById.set(message.id, message);
|
|
102
|
+
if (message.references) {
|
|
103
|
+
for (const ref of message.references) {
|
|
104
|
+
const absoluteFilePath = path.join(this.projectRoot, ref.path);
|
|
105
|
+
let fileMessages = messagesByFile.get(absoluteFilePath);
|
|
106
|
+
if (!fileMessages) {
|
|
107
|
+
fileMessages = new Map();
|
|
108
|
+
messagesByFile.set(absoluteFilePath, fileMessages);
|
|
109
|
+
}
|
|
110
|
+
fileMessages.set(message.id, message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this.messagesById = messagesById;
|
|
115
|
+
this.messagesByFile = messagesByFile;
|
|
95
116
|
}
|
|
96
117
|
async loadLocaleMessages(locale) {
|
|
97
118
|
const persister = await this.getPersister();
|
|
@@ -106,14 +127,34 @@ class CatalogManager {
|
|
|
106
127
|
}
|
|
107
128
|
async loadTargetMessages() {
|
|
108
129
|
const targetLocales = await this.getTargetLocales();
|
|
109
|
-
await Promise.all(targetLocales.map(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
130
|
+
await Promise.all(targetLocales.map(locale => this.reloadLocaleCatalog(locale)));
|
|
131
|
+
}
|
|
132
|
+
async reloadLocaleCatalog(locale) {
|
|
133
|
+
const diskMessages = await this.loadLocaleMessages(locale);
|
|
134
|
+
if (locale === this.config.sourceLocale) {
|
|
135
|
+
// For source: Merge additional properties like flags
|
|
136
|
+
for (const diskMessage of diskMessages) {
|
|
137
|
+
const prev = this.messagesById.get(diskMessage.id);
|
|
138
|
+
if (prev) {
|
|
139
|
+
// Unknown properties (like flags): disk wins
|
|
140
|
+
// Known properties: existing (from extraction) wins
|
|
141
|
+
this.messagesById.set(diskMessage.id, {
|
|
142
|
+
...diskMessage,
|
|
143
|
+
id: prev.id,
|
|
144
|
+
message: prev.message,
|
|
145
|
+
description: prev.description,
|
|
146
|
+
references: prev.references
|
|
147
|
+
});
|
|
148
|
+
}
|
|
115
149
|
}
|
|
116
|
-
}
|
|
150
|
+
} else {
|
|
151
|
+
// For target: disk wins completely
|
|
152
|
+
const translations = new Map();
|
|
153
|
+
for (const message of diskMessages) {
|
|
154
|
+
translations.set(message.id, message);
|
|
155
|
+
}
|
|
156
|
+
this.translationsByTargetLocale.set(locale, translations);
|
|
157
|
+
}
|
|
117
158
|
}
|
|
118
159
|
async extractFileMessages(absoluteFilePath, source) {
|
|
119
160
|
const result = await this.messageExtractor.processFileContent(absoluteFilePath, source);
|
|
@@ -138,18 +179,18 @@ class CatalogManager {
|
|
|
138
179
|
references.push(ref);
|
|
139
180
|
}
|
|
140
181
|
});
|
|
141
|
-
references.sort((referenceA, referenceB) => referenceA.path
|
|
182
|
+
references.sort((referenceA, referenceB) => localeCompare(referenceA.path, referenceB.path));
|
|
142
183
|
message = {
|
|
143
184
|
...message,
|
|
144
185
|
references
|
|
145
186
|
};
|
|
146
187
|
|
|
147
|
-
//
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
188
|
+
// Merge other properties like description, or unknown
|
|
189
|
+
// attributes like flags that are opaque to us
|
|
190
|
+
for (const key of Object.keys(prevMessage)) {
|
|
191
|
+
if (message[key] == null) {
|
|
192
|
+
message[key] = prevMessage[key];
|
|
193
|
+
}
|
|
153
194
|
}
|
|
154
195
|
}
|
|
155
196
|
this.messagesById.set(message.id, message);
|
|
@@ -179,13 +220,13 @@ class CatalogManager {
|
|
|
179
220
|
} else {
|
|
180
221
|
this.messagesByFile.delete(absoluteFilePath);
|
|
181
222
|
}
|
|
182
|
-
const changed = this.
|
|
223
|
+
const changed = this.haveMessagesChangedForFile(prevFileMessages, fileMessages);
|
|
183
224
|
return {
|
|
184
225
|
...result,
|
|
185
226
|
changed
|
|
186
227
|
};
|
|
187
228
|
}
|
|
188
|
-
|
|
229
|
+
haveMessagesChangedForFile(beforeMessages, afterMessages) {
|
|
189
230
|
// If one exists and the other doesn't, there's a change
|
|
190
231
|
if (!beforeMessages) {
|
|
191
232
|
return afterMessages.size > 0;
|
|
@@ -206,56 +247,43 @@ class CatalogManager {
|
|
|
206
247
|
return false;
|
|
207
248
|
}
|
|
208
249
|
areMessagesEqual(msg1, msg2) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (!refs1 && !refs2) return true;
|
|
214
|
-
if (!refs1 || !refs2) return false;
|
|
215
|
-
if (refs1.length !== refs2.length) return false;
|
|
216
|
-
|
|
217
|
-
// Compare each reference
|
|
218
|
-
for (let i = 0; i < refs1.length; i++) {
|
|
219
|
-
if (refs1[i].path !== refs2[i].path) {
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return true;
|
|
250
|
+
// Note: We intentionally don't compare references here.
|
|
251
|
+
// References are aggregated metadata from multiple files and comparing
|
|
252
|
+
// them would cause false positives due to parallel extraction order.
|
|
253
|
+
return msg1.id === msg2.id && msg1.message === msg2.message && msg1.description === msg2.description;
|
|
224
254
|
}
|
|
225
255
|
async save() {
|
|
226
256
|
return this.saveScheduler.schedule(() => this.saveImpl());
|
|
227
257
|
}
|
|
228
258
|
async saveImpl() {
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
await
|
|
232
|
-
for (const locale of await this.getTargetLocales()) {
|
|
233
|
-
await this.saveLocale(locale);
|
|
234
|
-
}
|
|
235
|
-
return messages.length;
|
|
259
|
+
await this.saveLocale(this.config.sourceLocale);
|
|
260
|
+
const targetLocales = await this.getTargetLocales();
|
|
261
|
+
await Promise.all(targetLocales.map(locale => this.saveLocale(locale)));
|
|
236
262
|
}
|
|
237
263
|
async saveLocale(locale) {
|
|
264
|
+
await this.loadCatalogsPromise;
|
|
238
265
|
const messages = Array.from(this.messagesById.values());
|
|
239
266
|
const persister = await this.getPersister();
|
|
267
|
+
const isSourceLocale = locale === this.config.sourceLocale;
|
|
240
268
|
|
|
241
|
-
// Check if file was modified externally
|
|
269
|
+
// Check if file was modified externally (poll-at-save is cheaper than
|
|
270
|
+
// watchers here since stat() is fast and avoids continuous overhead)
|
|
242
271
|
const lastWriteTime = this.lastWriteByLocale.get(locale);
|
|
243
272
|
const currentFileTime = await persister.getLastModified(locale);
|
|
244
|
-
|
|
245
|
-
// If file was modified externally, read and merge
|
|
246
273
|
if (currentFileTime && lastWriteTime && currentFileTime > lastWriteTime) {
|
|
247
|
-
|
|
248
|
-
const translations = this.translationsByTargetLocale.get(locale);
|
|
249
|
-
for (const diskMessage of diskMessages) {
|
|
250
|
-
// Disk wins: preserve manual edits
|
|
251
|
-
translations.set(diskMessage.id, diskMessage.message);
|
|
252
|
-
}
|
|
274
|
+
await this.reloadLocaleCatalog(locale);
|
|
253
275
|
}
|
|
254
|
-
const
|
|
255
|
-
const localeMessages = messages.map(message =>
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
276
|
+
const prevMessages = isSourceLocale ? this.messagesById : this.translationsByTargetLocale.get(locale);
|
|
277
|
+
const localeMessages = messages.map(message => {
|
|
278
|
+
const prev = prevMessages?.get(message.id);
|
|
279
|
+
return {
|
|
280
|
+
...prev,
|
|
281
|
+
id: message.id,
|
|
282
|
+
description: message.description,
|
|
283
|
+
references: message.references,
|
|
284
|
+
message: isSourceLocale ? message.message : prev?.message ?? ''
|
|
285
|
+
};
|
|
286
|
+
});
|
|
259
287
|
await persister.write(locale, localeMessages);
|
|
260
288
|
|
|
261
289
|
// Update timestamps
|
|
@@ -263,13 +291,9 @@ class CatalogManager {
|
|
|
263
291
|
this.lastWriteByLocale.set(locale, newTime);
|
|
264
292
|
}
|
|
265
293
|
onLocalesChange = async params => {
|
|
294
|
+
// Chain to existing promise
|
|
295
|
+
this.loadCatalogsPromise = Promise.all([this.loadCatalogsPromise, ...params.added.map(locale => this.reloadLocaleCatalog(locale))]);
|
|
266
296
|
for (const locale of params.added) {
|
|
267
|
-
const translations = new Map();
|
|
268
|
-
this.translationsByTargetLocale.set(locale, translations);
|
|
269
|
-
const messages = await this.loadLocaleMessages(locale);
|
|
270
|
-
for (const message of messages) {
|
|
271
|
-
translations.set(message.id, message.message);
|
|
272
|
-
}
|
|
273
297
|
await this.saveLocale(locale);
|
|
274
298
|
}
|
|
275
299
|
for (const locale of params.removed) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { localeCompare } from '../utils.js';
|
|
2
|
+
|
|
1
3
|
function getSortedMessages(messages) {
|
|
2
4
|
return messages.toSorted((messageA, messageB) => {
|
|
3
5
|
const pathA = messageA.references?.[0]?.path ?? '';
|
|
4
6
|
const pathB = messageB.references?.[0]?.path ?? '';
|
|
5
7
|
if (pathA === pathB) {
|
|
6
|
-
return messageA.id
|
|
8
|
+
return localeCompare(messageA.id, messageB.id);
|
|
7
9
|
} else {
|
|
8
|
-
return
|
|
10
|
+
return localeCompare(pathA, pathB);
|
|
9
11
|
}
|
|
10
12
|
});
|
|
11
13
|
}
|
|
@@ -10,5 +10,8 @@ function setNestedProperty(obj, keyPath, value) {
|
|
|
10
10
|
}
|
|
11
11
|
current[keys[keys.length - 1]] = value;
|
|
12
12
|
}
|
|
13
|
+
function localeCompare(a, b) {
|
|
14
|
+
return a.localeCompare(b, 'en');
|
|
15
|
+
}
|
|
13
16
|
|
|
14
|
-
export { setNestedProperty };
|
|
17
|
+
export { localeCompare, setNestedProperty };
|
|
@@ -6,14 +6,21 @@ function syncCookie(request, response, locale, routing, domain) {
|
|
|
6
6
|
name,
|
|
7
7
|
...rest
|
|
8
8
|
} = routing.localeCookie;
|
|
9
|
-
const acceptLanguageLocale = getAcceptLanguageLocale(request.headers, domain?.locales || routing.locales, routing.defaultLocale);
|
|
10
9
|
const hasLocaleCookie = request.cookies.has(name);
|
|
11
10
|
const hasOutdatedCookie = hasLocaleCookie && request.cookies.get(name)?.value !== locale;
|
|
12
|
-
if (
|
|
11
|
+
if (hasOutdatedCookie) {
|
|
13
12
|
response.cookies.set(name, locale, {
|
|
14
13
|
path: request.nextUrl.basePath || undefined,
|
|
15
14
|
...rest
|
|
16
15
|
});
|
|
16
|
+
} else if (!hasLocaleCookie) {
|
|
17
|
+
const acceptLanguageLocale = getAcceptLanguageLocale(request.headers, domain?.locales || routing.locales, routing.defaultLocale);
|
|
18
|
+
if (acceptLanguageLocale !== locale) {
|
|
19
|
+
response.cookies.set(name, locale, {
|
|
20
|
+
path: request.nextUrl.basePath || undefined,
|
|
21
|
+
...rest
|
|
22
|
+
});
|
|
23
|
+
}
|
|
17
24
|
}
|
|
18
25
|
}
|
|
19
26
|
|
|
@@ -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
|
|
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{localeCompare as i}from"../utils.js";import r from"./CatalogLocales.js";import c from"./CatalogPersister.js";import l 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 l(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 c(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)))}async loadMessages(){if(this.loadCatalogsPromise=Promise.all([this.loadSourceMessages(),this.loadTargetMessages()]),await this.loadCatalogsPromise,this.isDevelopment){(await this.getCatalogLocales()).subscribeLocalesChange(this.onLocalesChange)}const s=await o.getSourceFiles(this.getSrcPaths());await Promise.all(s.map((async s=>this.extractFileMessages(s,await e.readFile(s,"utf8")))))}async loadSourceMessages(){const e=await this.loadLocaleMessages(this.config.sourceLocale),t=new Map,a=new Map;for(const o of e)if(t.set(o.id,o),o.references)for(const e of o.references){const t=s.join(this.projectRoot,e.path);let i=a.get(t);i||(i=new Map,a.set(t,i)),i.set(o.id,o)}this.messagesById=t,this.messagesByFile=a}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((e=>this.reloadLocaleCatalog(e))))}async reloadLocaleCatalog(e){const s=await this.loadLocaleMessages(e);if(e===this.config.sourceLocale)for(const e of s){const s=this.messagesById.get(e.id);s&&this.messagesById.set(e.id,{...e,id:s.id,message:s.message,description:s.description,references:s.references})}else{const t=new Map;for(const e of s)t.set(e.id,e);this.translationsByTargetLocale.set(e,t)}}async extractFileMessages(e,t){const a=await this.messageExtractor.processFileContent(e,t),o=this.messagesByFile.get(e),r=Array.from(o?.keys()??[]),c=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)=>i(e.path,s.path))),e={...e,references:t};for(const t of Object.keys(s))null==e[t]&&(e[t]=s[t])}this.messagesById.set(e.id,e),c.set(e.id,e);const t=r.indexOf(e.id);-1!==t&&r.splice(t,1)}const l=s.relative(this.projectRoot,e);r.filter((e=>{const s=this.messagesById.get(e);return!s?.references?.some((e=>e.path!==l))})).forEach((e=>{this.messagesById.delete(e)}));a.messages.length>0?this.messagesByFile.set(e,c):this.messagesByFile.delete(e);const n=this.haveMessagesChangedForFile(o,c);return{...a,changed:n}}haveMessagesChangedForFile(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}async save(){return this.saveScheduler.schedule((()=>this.saveImpl()))}async saveImpl(){await this.saveLocale(this.config.sourceLocale);const e=await this.getTargetLocales();await Promise.all(e.map((e=>this.saveLocale(e))))}async saveLocale(e){await this.loadCatalogsPromise;const s=Array.from(this.messagesById.values()),t=await this.getPersister(),a=e===this.config.sourceLocale,o=this.lastWriteByLocale.get(e),i=await t.getLastModified(e);i&&o&&i>o&&await this.reloadLocaleCatalog(e);const r=a?this.messagesById:this.translationsByTargetLocale.get(e),c=s.map((e=>{const s=r?.get(e.id);return{...s,id:e.id,description:e.description,references:e.references,message:a?e.message:s?.message??""}}));await t.write(e,c);const l=await t.getLastModified(e);this.lastWriteByLocale.set(e,l)}onLocalesChange=async e=>{this.loadCatalogsPromise=Promise.all([this.loadCatalogsPromise,...e.added.map((e=>this.reloadLocaleCatalog(e)))]);for(const s of e.added)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{setNestedProperty as s}from"../utils
|
|
1
|
+
import{setNestedProperty as s}from"../utils.js";import e from"./Formatter.js";import{getSortedMessages as t}from"./utils.js";class r extends e{static NAMESPACE_SEPARATOR=".";EXTENSION=".json";parse(s){const e=JSON.parse(s),t=[];return this.traverseMessages(e,((s,e)=>{t.push({id:e,message:s})})),t}serialize(e){const r={};for(const o of t(e))s(r,o.id,o.message);return JSON.stringify(r,null,2)}toJSONString(s){return s}traverseMessages(s,e,t=""){for(const o of Object.keys(s)){const a=t?t+r.NAMESPACE_SEPARATOR+o:o,i=s[o];"string"==typeof i?e(i,a):"object"==typeof i&&this.traverseMessages(i,e,a)}}}export{r as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import t from"po-parser";import{setNestedProperty as e}from"../utils
|
|
1
|
+
import t from"po-parser";import{setNestedProperty as e}from"../utils.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
|
|
1
|
+
import{localeCompare as e}from"../utils.js";function r(r){return r.toSorted(((r,t)=>{const n=r.references?.[0]?.path??"",o=t.references?.[0]?.path??"";return n===o?e(r.id,t.id):e(n,o)}))}export{r as getSortedMessages};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(t,n,e){const o=n.split(".");let l=t;for(let t=0;t<o.length-1;t++){const n=o[t];n in l&&"object"==typeof l[n]&&null!==l[n]||(l[n]={}),l=l[n]}l[o[o.length-1]]=e}function n(t,n){return t.localeCompare(n,"en")}export{n as localeCompare,t as setNestedProperty};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAcceptLanguageLocale as e}from"./resolveLocale.js";function o(o,a,l,s,t){if(!s.localeCookie)return;const{name:c
|
|
1
|
+
import{getAcceptLanguageLocale as e}from"./resolveLocale.js";function o(o,a,l,s,t){if(!s.localeCookie)return;const{name:i,...c}=s.localeCookie,r=o.cookies.has(i);if(r&&o.cookies.get(i)?.value!==l)a.cookies.set(i,l,{path:o.nextUrl.basePath||void 0,...c});else if(!r){e(o.headers,t?.locales||s.locales,s.defaultLocale)!==l&&a.cookies.set(i,l,{path:o.nextUrl.basePath||void 0,...c})}}export{o as default};
|
|
@@ -16,6 +16,7 @@ export default class CatalogManager {
|
|
|
16
16
|
private formatter?;
|
|
17
17
|
private catalogLocales?;
|
|
18
18
|
private messageExtractor;
|
|
19
|
+
loadCatalogsPromise?: Promise<unknown>;
|
|
19
20
|
constructor(config: ExtractorConfig, opts?: {
|
|
20
21
|
projectRoot?: string;
|
|
21
22
|
isDevelopment?: boolean;
|
|
@@ -26,21 +27,20 @@ export default class CatalogManager {
|
|
|
26
27
|
private getCatalogLocales;
|
|
27
28
|
private getTargetLocales;
|
|
28
29
|
getSrcPaths(): Array<string>;
|
|
29
|
-
getFileMessages(absoluteFilePath: string): Map<string, ExtractedMessage> | undefined;
|
|
30
30
|
loadMessages(): Promise<void>;
|
|
31
31
|
private loadSourceMessages;
|
|
32
32
|
private loadLocaleMessages;
|
|
33
33
|
private loadTargetMessages;
|
|
34
|
+
private reloadLocaleCatalog;
|
|
34
35
|
extractFileMessages(absoluteFilePath: string, source: string): Promise<{
|
|
35
36
|
messages: Array<ExtractedMessage>;
|
|
36
37
|
code: string;
|
|
37
38
|
changed: boolean;
|
|
38
39
|
map?: string;
|
|
39
40
|
}>;
|
|
40
|
-
private
|
|
41
|
+
private haveMessagesChangedForFile;
|
|
41
42
|
private areMessagesEqual;
|
|
42
|
-
|
|
43
|
-
save(): Promise<number>;
|
|
43
|
+
save(): Promise<void>;
|
|
44
44
|
private saveImpl;
|
|
45
45
|
private saveLocale;
|
|
46
46
|
private onLocalesChange;
|
|
@@ -3,9 +3,9 @@ import type { RoutingConfigLocalizedNavigation, RoutingConfigSharedNavigation }
|
|
|
3
3
|
import type { DomainsConfig, LocalePrefixMode, Locales, Pathnames } from '../../routing/types.js';
|
|
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
|
+
id?: string | undefined | undefined;
|
|
6
7
|
target?: import("react").HTMLAttributeAnchorTarget | undefined;
|
|
7
8
|
replace?: boolean | undefined;
|
|
8
|
-
id?: string | undefined | undefined;
|
|
9
9
|
slot?: string | undefined | undefined;
|
|
10
10
|
style?: import("react").CSSProperties | undefined;
|
|
11
11
|
title?: string | undefined | undefined;
|
|
@@ -4,9 +4,9 @@ export default function createNavigation<const AppLocales extends Locales, const
|
|
|
4
4
|
usePathname: () => never;
|
|
5
5
|
useRouter: () => never;
|
|
6
6
|
Link: import("react").ForwardRefExoticComponent<Omit<{
|
|
7
|
+
id?: string | undefined | undefined;
|
|
7
8
|
target?: import("react").HTMLAttributeAnchorTarget | undefined;
|
|
8
9
|
replace?: boolean | undefined;
|
|
9
|
-
id?: string | undefined | undefined;
|
|
10
10
|
slot?: string | undefined | undefined;
|
|
11
11
|
style?: import("react").CSSProperties | undefined;
|
|
12
12
|
title?: string | undefined | undefined;
|
|
@@ -22,9 +22,9 @@ export default function createSharedNavigationFns<const AppLocales extends Local
|
|
|
22
22
|
alternateLinks: NonNullable<boolean | undefined>;
|
|
23
23
|
};
|
|
24
24
|
Link: import("react").ForwardRefExoticComponent<Omit<{
|
|
25
|
+
id?: string | undefined | undefined;
|
|
25
26
|
target?: import("react").HTMLAttributeAnchorTarget | undefined;
|
|
26
27
|
replace?: boolean | undefined;
|
|
27
|
-
id?: string | undefined | undefined;
|
|
28
28
|
slot?: string | undefined | undefined;
|
|
29
29
|
style?: import("react").CSSProperties | undefined;
|
|
30
30
|
title?: 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.7",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"author": "Jan Amann <jan@amann.work>",
|
|
6
6
|
"funding": [
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"@formatjs/intl-localematcher": "^0.5.4",
|
|
128
128
|
"@swc/core": "^1.15.2",
|
|
129
129
|
"negotiator": "^1.0.0",
|
|
130
|
-
"next-intl-swc-plugin-extractor": "^4.5.
|
|
131
|
-
"po-parser": "^0.
|
|
132
|
-
"use-intl": "^4.5.
|
|
130
|
+
"next-intl-swc-plugin-extractor": "^4.5.7",
|
|
131
|
+
"po-parser": "^1.0.2",
|
|
132
|
+
"use-intl": "^4.5.7"
|
|
133
133
|
},
|
|
134
134
|
"peerDependencies": {
|
|
135
135
|
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
|
@@ -141,5 +141,5 @@
|
|
|
141
141
|
"optional": true
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
|
-
"gitHead": "
|
|
144
|
+
"gitHead": "2ccc147b68227b32ea451935718c3eb5e73d6e2f"
|
|
145
145
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function t(t,n,e){const l=n.split(".");let o=t;for(let t=0;t<l.length-1;t++){const n=l[t];n in o&&"object"==typeof o[n]&&null!==o[n]||(o[n]={}),o=o[n]}o[l[l.length-1]]=e}export{t as setNestedProperty};
|