wuchale 0.23.3 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-utils/mixed-visitor.d.ts +21 -14
- package/dist/adapter-utils/mixed-visitor.js +110 -101
- package/dist/adapter-vanilla/index.js +8 -6
- package/dist/adapter-vanilla/inertvisitors.d.ts +31 -0
- package/dist/adapter-vanilla/inertvisitors.js +86 -0
- package/dist/adapter-vanilla/transformer.d.ts +67 -95
- package/dist/adapter-vanilla/transformer.js +292 -240
- package/dist/adapters.d.ts +18 -12
- package/dist/adapters.js +33 -13
- package/dist/ai/gemini.js +1 -1
- package/dist/ai/index.js +3 -1
- package/dist/bundlers/vite.d.ts +1 -1
- package/dist/bundlers/vite.js +3 -3
- package/dist/cli/check.js +1 -1
- package/dist/cli/index.js +12 -5
- package/dist/cli/status.js +1 -1
- package/dist/config.d.ts +2 -1
- package/dist/config.js +2 -2
- package/dist/handler/files.d.ts +11 -13
- package/dist/handler/files.js +37 -44
- package/dist/handler/index.d.ts +7 -4
- package/dist/handler/index.js +85 -62
- package/dist/handler/state.d.ts +10 -11
- package/dist/handler/state.js +40 -28
- package/dist/handler/url.d.ts +10 -13
- package/dist/handler/url.js +51 -80
- package/dist/hub.d.ts +1 -1
- package/dist/hub.js +16 -14
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/load-utils/index.d.ts +6 -8
- package/dist/load-utils/index.js +11 -11
- package/dist/load-utils/pure.d.ts +2 -2
- package/dist/load-utils/server.d.ts +3 -3
- package/dist/load-utils/server.js +4 -7
- package/dist/pofile.d.ts +5 -5
- package/dist/pofile.js +23 -35
- package/dist/storage.d.ts +6 -3
- package/dist/storage.js +98 -0
- package/dist/url.d.ts +12 -10
- package/dist/url.js +206 -31
- package/package.json +4 -5
- package/src/adapter-vanilla/loaders/bundle.js +1 -1
- package/src/adapter-vanilla/loaders/server.js +3 -3
- package/src/adapter-vanilla/loaders/vite.js +2 -2
- package/src/adapter-vanilla/loaders/vite.ssr.js +3 -3
package/dist/handler/url.js
CHANGED
|
@@ -1,34 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
2
|
import { getKey } from '../adapters.js';
|
|
3
|
-
import { compileTranslation } from '../compile.js';
|
|
4
3
|
import { newItem } from '../storage.js';
|
|
5
|
-
|
|
6
|
-
const compiledTranslatedPatt = compileTranslation(patternTranslated, patternTranslated);
|
|
7
|
-
if (typeof compiledTranslatedPatt === 'string') {
|
|
8
|
-
return compiledTranslatedPatt;
|
|
9
|
-
}
|
|
10
|
-
const urlTokens = compiledTranslatedPatt.map(part => {
|
|
11
|
-
if (typeof part === 'number') {
|
|
12
|
-
return keys[part];
|
|
13
|
-
}
|
|
14
|
-
return { type: 'text', value: part };
|
|
15
|
-
});
|
|
16
|
-
return stringify({ tokens: urlTokens });
|
|
17
|
-
}
|
|
18
|
-
export function patternToTranslate(pattern) {
|
|
19
|
-
const { keys } = pathToRegexp(pattern);
|
|
20
|
-
const compile = compileUrlPattern(pattern, { encode: false });
|
|
21
|
-
const paramsReplace = {};
|
|
22
|
-
for (const [i, { name }] of keys.entries()) {
|
|
23
|
-
paramsReplace[name] = `{${i}}`;
|
|
24
|
-
}
|
|
25
|
-
return compile(paramsReplace);
|
|
26
|
-
}
|
|
4
|
+
import { compilePattern, matchPattern, stringifyPattern } from '../url.js';
|
|
27
5
|
export class URLHandler {
|
|
28
|
-
patternKeys = new Map();
|
|
29
6
|
locales;
|
|
30
7
|
sourceLocale;
|
|
31
8
|
patterns = [];
|
|
9
|
+
compiledPatterns = [];
|
|
32
10
|
constructor(locales, sourceLocale, urlConf) {
|
|
33
11
|
this.locales = locales;
|
|
34
12
|
this.sourceLocale = sourceLocale;
|
|
@@ -36,43 +14,33 @@ export class URLHandler {
|
|
|
36
14
|
this.patterns = urlConf.patterns;
|
|
37
15
|
}
|
|
38
16
|
}
|
|
39
|
-
buildManifest = (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (transl) {
|
|
50
|
-
const patternTranslated = transl[0] || item.translations.get(this.sourceLocale)[0];
|
|
51
|
-
pattern = patternFromTranslate(patternTranslated, keys);
|
|
17
|
+
buildManifest = () => {
|
|
18
|
+
// order of catalogs should be based on locales
|
|
19
|
+
const manifest = [];
|
|
20
|
+
for (let i = 0; i < this.patterns.length; i++) {
|
|
21
|
+
const locPatterns = [];
|
|
22
|
+
const compiledPatts = this.compiledPatterns[i];
|
|
23
|
+
const compiledPattBase = compiledPatts.get(this.sourceLocale);
|
|
24
|
+
for (const loc of this.locales) {
|
|
25
|
+
const locCompiledPatt = compiledPatts.get(loc);
|
|
26
|
+
locPatterns.push(locCompiledPatt);
|
|
52
27
|
}
|
|
53
|
-
locPatterns.
|
|
54
|
-
|
|
55
|
-
if (locPatterns.some(p => p !== patt)) {
|
|
56
|
-
return [patt, locPatterns];
|
|
28
|
+
const notAllSame = locPatterns.some(p => !isDeepStrictEqual(p, compiledPattBase));
|
|
29
|
+
manifest.push(notAllSame ? [compiledPattBase, locPatterns] : [compiledPattBase]);
|
|
57
30
|
}
|
|
58
|
-
return
|
|
59
|
-
}
|
|
60
|
-
initPatterns = async (adapterKey, catalog, aiQueue) => {
|
|
61
|
-
const urlPatternsForTranslate = this.patterns.map(patternToTranslate);
|
|
31
|
+
return manifest;
|
|
32
|
+
};
|
|
33
|
+
initPatterns = async (adapterKey, catalog, fallbackChains, aiQueue) => {
|
|
62
34
|
const urlPatternCatKeys = [];
|
|
63
35
|
const toTranslate = [];
|
|
64
36
|
let needWriteCatalog = false;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
context = `original: ${this.patterns[i]}`;
|
|
69
|
-
}
|
|
70
|
-
const key = getKey([locPattern], context);
|
|
37
|
+
const toCompile = [];
|
|
38
|
+
for (const [i, pattern] of this.patterns.entries()) {
|
|
39
|
+
const key = getKey([pattern]);
|
|
71
40
|
urlPatternCatKeys[i] = key;
|
|
72
|
-
this.patternKeys.set(this.patterns[i], key); // save for href translate
|
|
73
41
|
let item = catalog.get(key);
|
|
74
42
|
if (!item) {
|
|
75
|
-
item = newItem({ id: [
|
|
43
|
+
item = newItem({ id: [pattern] }, this.locales);
|
|
76
44
|
catalog.set(key, item);
|
|
77
45
|
needWriteCatalog = true;
|
|
78
46
|
}
|
|
@@ -80,11 +48,12 @@ export class URLHandler {
|
|
|
80
48
|
item.urlAdapters.push(adapterKey);
|
|
81
49
|
needWriteCatalog = true;
|
|
82
50
|
}
|
|
83
|
-
item.translations.set(this.sourceLocale, [
|
|
84
|
-
|
|
51
|
+
item.translations.set(this.sourceLocale, [pattern]);
|
|
52
|
+
toCompile.push(item);
|
|
53
|
+
if (pattern.search(/\p{L}/u) === -1) {
|
|
85
54
|
for (const loc of this.locales) {
|
|
86
55
|
if (loc !== this.sourceLocale) {
|
|
87
|
-
item.translations.set(loc, [
|
|
56
|
+
item.translations.set(loc, [pattern]);
|
|
88
57
|
}
|
|
89
58
|
}
|
|
90
59
|
continue;
|
|
@@ -103,41 +72,43 @@ export class URLHandler {
|
|
|
103
72
|
aiQueue.add(toTranslate);
|
|
104
73
|
await aiQueue.running;
|
|
105
74
|
}
|
|
75
|
+
// for matching hrefs
|
|
76
|
+
for (const item of toCompile) {
|
|
77
|
+
const compiled = new Map();
|
|
78
|
+
for (const locale of this.locales) {
|
|
79
|
+
for (const loc of fallbackChains.get(locale) ?? [locale, this.sourceLocale]) {
|
|
80
|
+
const pattern = item.translations.get(loc)?.[0];
|
|
81
|
+
if (pattern) {
|
|
82
|
+
compiled.set(locale, compilePattern(pattern));
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.compiledPatterns.push(compiled);
|
|
88
|
+
}
|
|
106
89
|
return needWriteCatalog;
|
|
107
90
|
};
|
|
108
91
|
match = (url) => {
|
|
109
|
-
for (const pattern of this.
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
for (const [i, pattern] of this.compiledPatterns.entries()) {
|
|
93
|
+
const dynamics = matchPattern(pattern.get(this.sourceLocale), url);
|
|
94
|
+
if (dynamics) {
|
|
95
|
+
return [i, dynamics];
|
|
112
96
|
}
|
|
113
97
|
}
|
|
114
98
|
return null;
|
|
115
99
|
};
|
|
116
|
-
matchToCompile = (key,
|
|
100
|
+
matchToCompile = (key, locale) => {
|
|
117
101
|
// e.g. key: /items/foo/{0}
|
|
118
102
|
const toCompile = key;
|
|
119
103
|
const relevantPattern = this.match(key);
|
|
120
104
|
if (relevantPattern == null) {
|
|
121
105
|
return toCompile;
|
|
122
106
|
}
|
|
123
|
-
// e.g. relevantPattern: /items
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
// e.g.
|
|
129
|
-
const matchedUrl = matchUrlPattern(relevantPattern, { decode: false })(key);
|
|
130
|
-
// e.g. matchUrl.params: {rest: 'foo/{0}'}
|
|
131
|
-
if (!matchedUrl) {
|
|
132
|
-
return toCompile;
|
|
133
|
-
}
|
|
134
|
-
const translatedPattern = patternItem.translations.get(locale)[0] || patternItem.translations.get(this.sourceLocale)[0];
|
|
135
|
-
// e.g. translatedPattern: /elementos/{0}
|
|
136
|
-
const { keys } = pathToRegexp(relevantPattern);
|
|
137
|
-
const translatedPattUrl = patternFromTranslate(translatedPattern, keys);
|
|
138
|
-
// e.g. translatedPattUrl: /elementos/:rest
|
|
139
|
-
const compileTranslated = compileUrlPattern(translatedPattUrl, { encode: false });
|
|
140
|
-
return compileTranslated(matchedUrl.params);
|
|
141
|
-
// e.g. return /elementos/foo/{0}
|
|
107
|
+
// e.g. relevantPattern: [index of /items/**, [foo/{0}]]
|
|
108
|
+
const [i, dynamics] = relevantPattern;
|
|
109
|
+
const translatedCompiled = this.compiledPatterns[i].get(locale);
|
|
110
|
+
// e.g. translatedCompiled: [/elementos, 0]
|
|
111
|
+
return stringifyPattern(translatedCompiled, dynamics);
|
|
112
|
+
// e.g. /elementos/foo/{0}
|
|
142
113
|
};
|
|
143
114
|
}
|
package/dist/hub.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ type TransformErrFormatter = (e: Error, adapterKey: string, filename: string) =>
|
|
|
47
47
|
export declare class Hub {
|
|
48
48
|
#private;
|
|
49
49
|
private constructor();
|
|
50
|
-
static create: (mode: Mode, loadConfig: ConfigLoader, root: string, hmrDelayThreshold?: number, fs?: FS, formatTransformErr?: TransformErrFormatter) => Promise<Hub>;
|
|
50
|
+
static create: (mode: Mode, loadConfig: ConfigLoader, root: string, modifyAdapters?: string[], hmrDelayThreshold?: number, fs?: FS, formatTransformErr?: TransformErrFormatter) => Promise<Hub>;
|
|
51
51
|
onFileChange: (file: string, read: () => string | Promise<string>) => Promise<FileChangeInfo | undefined>;
|
|
52
52
|
transform: (code: string, filePath: string, forServer?: boolean) => ReturnType<AdapterHandler["transform"]>;
|
|
53
53
|
directVisit(clean: boolean, watch: boolean, sync: boolean): Promise<void>;
|
package/dist/hub.js
CHANGED
|
@@ -7,7 +7,7 @@ import { glob } from 'tinyglobby';
|
|
|
7
7
|
import { compileTranslation, isEquivalent } from './compile.js';
|
|
8
8
|
import { defaultFS } from './fs.js';
|
|
9
9
|
import { dataFileName, generatedDir, getLoaderPath, globConfToArgs, normalizeSep } from './handler/files.js';
|
|
10
|
-
import { AdapterHandler, getLoadIDs } from './handler/index.js';
|
|
10
|
+
import { AdapterHandler, getLoadIDs, newItemsAllowed } from './handler/index.js';
|
|
11
11
|
import { SharedState } from './handler/state.js';
|
|
12
12
|
import { color, Logger } from './log.js';
|
|
13
13
|
import { itemIsObsolete, itemIsUrl } from './storage.js';
|
|
@@ -25,22 +25,21 @@ async function initGenDirWithData(config, fs, root) {
|
|
|
25
25
|
// data file
|
|
26
26
|
await fs.write(resolve(localesDirAbs, dataFileName), [
|
|
27
27
|
`/** @typedef {('${config.locales.join("'|'")}')} Locale */`,
|
|
28
|
-
`/** @type {Locale[]} */`,
|
|
28
|
+
`/** @type {[Locale, ...Locale[]]} */`,
|
|
29
29
|
`export const locales = ['${config.locales.join("','")}']`,
|
|
30
30
|
].join('\n'));
|
|
31
31
|
}
|
|
32
|
-
async function getSharedState(sharedStates, config, fs, root, adapter, key, sourceLocale) {
|
|
32
|
+
async function getSharedState(sharedStates, config, fs, root, adapter, key, sourceLocale, allowNewItems) {
|
|
33
33
|
const storage = await adapter.storage({
|
|
34
34
|
locales: config.locales,
|
|
35
35
|
root,
|
|
36
36
|
localesDir: config.localesDir,
|
|
37
37
|
sourceLocale: sourceLocale,
|
|
38
|
-
haveUrl: adapter.url != null,
|
|
39
38
|
fs,
|
|
40
39
|
});
|
|
41
40
|
let sharedState = sharedStates.get(storage.key);
|
|
42
41
|
if (sharedState == null) {
|
|
43
|
-
sharedState = new SharedState(storage, key, sourceLocale);
|
|
42
|
+
sharedState = new SharedState(storage, key, sourceLocale, allowNewItems);
|
|
44
43
|
sharedStates.set(storage.key, sharedState);
|
|
45
44
|
}
|
|
46
45
|
else {
|
|
@@ -69,7 +68,7 @@ export class Hub {
|
|
|
69
68
|
this.#lastSourceTriggeredCatalogWrite = performance.now();
|
|
70
69
|
};
|
|
71
70
|
const adapter = handler.adapter;
|
|
72
|
-
if (adapter.
|
|
71
|
+
if (adapter.loading.granular) {
|
|
73
72
|
this.#granularLoadHandlers.push(handler);
|
|
74
73
|
}
|
|
75
74
|
else {
|
|
@@ -106,7 +105,7 @@ export class Hub {
|
|
|
106
105
|
}
|
|
107
106
|
}
|
|
108
107
|
}
|
|
109
|
-
static create = async (mode, loadConfig, root, hmrDelayThreshold = 1000, fs = defaultFS, formatTransformErr = e => e) => {
|
|
108
|
+
static create = async (mode, loadConfig, root, modifyAdapters = [], hmrDelayThreshold = 1000, fs = defaultFS, formatTransformErr = e => e) => {
|
|
110
109
|
const config = await loadConfig();
|
|
111
110
|
const adaptersData = Object.entries(config.adapters);
|
|
112
111
|
if (adaptersData.length === 0) {
|
|
@@ -124,7 +123,9 @@ export class Hub {
|
|
|
124
123
|
adapter,
|
|
125
124
|
key,
|
|
126
125
|
sourceLocale,
|
|
127
|
-
sharedState: await getSharedState(sharedStates, config, fs, root, adapter, key, sourceLocale),
|
|
126
|
+
sharedState: await getSharedState(sharedStates, config, fs, root, adapter, key, sourceLocale, newItemsAllowed(mode, config.dev)),
|
|
127
|
+
devMode: config.dev,
|
|
128
|
+
modifyInplace: modifyAdapters.includes(key),
|
|
128
129
|
});
|
|
129
130
|
handlers.set(key, handler);
|
|
130
131
|
}
|
|
@@ -144,12 +145,12 @@ export class Hub {
|
|
|
144
145
|
const updateTxt = await read();
|
|
145
146
|
const update = JSON.parse(updateTxt);
|
|
146
147
|
this.#opts.log.info(`${logPrefix} config update received: ${color.cyan(updateTxt)}`);
|
|
147
|
-
if (update.
|
|
148
|
-
this.#opts.config.
|
|
148
|
+
if (update.dev !== undefined) {
|
|
149
|
+
this.#opts.config.dev = update.dev;
|
|
149
150
|
}
|
|
150
151
|
return ignoreChange;
|
|
151
152
|
}
|
|
152
|
-
if (!this.#opts.config.
|
|
153
|
+
if (!this.#opts.config.dev) {
|
|
153
154
|
return;
|
|
154
155
|
}
|
|
155
156
|
// This is mainly to make sure that catalog file changes result in a page reload with new catalogs
|
|
@@ -183,7 +184,7 @@ export class Hub {
|
|
|
183
184
|
await handler.loadStorage();
|
|
184
185
|
await handler.compile(this.#hmrVersion);
|
|
185
186
|
}
|
|
186
|
-
const
|
|
187
|
+
const loadIDs = getLoadIDs(handler.adapter, handler.granularState.byID.values(), handler.sourceLocale);
|
|
187
188
|
for (const loc of this.#opts.config.locales) {
|
|
188
189
|
for (const loadID of loadIDs) {
|
|
189
190
|
changeInfo.invalidate.add(normalizeSep(handler.files.getCompiledFilePath(loc, loadID)));
|
|
@@ -193,7 +194,7 @@ export class Hub {
|
|
|
193
194
|
return changeInfo;
|
|
194
195
|
};
|
|
195
196
|
transform = async (code, filePath, forServer = false) => {
|
|
196
|
-
if (this.#opts.mode === 'dev' && !this.#opts.config.
|
|
197
|
+
if (this.#opts.mode === 'dev' && !this.#opts.config.dev) {
|
|
197
198
|
return [{}, false];
|
|
198
199
|
}
|
|
199
200
|
const filename = normalizeSep(relative(this.#opts.root, filePath));
|
|
@@ -224,7 +225,8 @@ export class Hub {
|
|
|
224
225
|
return updated;
|
|
225
226
|
};
|
|
226
227
|
async #directVisitHandler(handler, clean, sync, existingFilesByOwner) {
|
|
227
|
-
const
|
|
228
|
+
const [patterns, ignore] = globConfToArgs(handler.adapter.files, this.#opts.config.localesDir);
|
|
229
|
+
const filePaths = await glob(patterns, { ignore, cwd: this.#opts.root });
|
|
228
230
|
let existingFiles = existingFilesByOwner.get(handler.sharedState.ownerKey);
|
|
229
231
|
if (existingFiles) {
|
|
230
232
|
for (const file of filePaths) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { Adapter, AdapterArgs, AdapterPassThruOpts, CodePattern, CreateHeuristicOpts, DecideReactiveDetails, HeuristicDetails, HeuristicDetailsBase, HeuristicFunc, HeuristicResult, LoaderChoice, Message, MessageType, RuntimeConf, RuntimeExpr
|
|
2
|
-
export { createHeuristic,
|
|
1
|
+
export type { Adapter, AdapterArgs, AdapterPassThruOpts, CodePattern, CreateHeuristicOpts, DecideReactiveDetails, HeuristicDetails, HeuristicDetailsBase, HeuristicFunc, HeuristicResult, LoaderChoice, LoadGroupPatt, Message, MessageType, RuntimeConf, RuntimeExpr, TransformCtx, TransformOutput, TransformOutputCode, URLConf, UrlMatcher, } from './adapters.js';
|
|
2
|
+
export { createHeuristic, defaultHeuristic, defaultHeuristicOpts, getKey, IndexTracker, } from './adapters.js';
|
|
3
3
|
export { gemini } from './ai/gemini.js';
|
|
4
4
|
export type { CompiledElement, Composite, CompositePayload, Mixed, } from './compile.js';
|
|
5
5
|
export { type Config, type DeepPartial, defaultConfig, defineConfig, fillDefaults, getConfig, } from './config.js';
|
|
@@ -12,4 +12,4 @@ export { Hub } from './hub.js';
|
|
|
12
12
|
export { Logger } from './log.js';
|
|
13
13
|
export { pofile } from './pofile.js';
|
|
14
14
|
export type { Catalog, CatalogStorage, FileRef, FileRefEntry, Item, LoadData, PluralRule, PluralRules, SaveData, StorageFactory, StorageFactoryOpts, } from './storage.js';
|
|
15
|
-
export { defaultPluralRule, migrateStorage } from './storage.js';
|
|
15
|
+
export { defaultPluralRule, mergeItemsByKey, migrateStorage, storageByLocale, storageByType } from './storage.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createHeuristic,
|
|
1
|
+
export { createHeuristic, defaultHeuristic, defaultHeuristicOpts, getKey, IndexTracker, } from './adapters.js';
|
|
2
2
|
export { gemini } from './ai/gemini.js';
|
|
3
3
|
export { defaultConfig, defineConfig, fillDefaults, getConfig, } from './config.js';
|
|
4
4
|
export { generatedDir, normalizeSep } from './handler/files.js';
|
|
@@ -7,4 +7,4 @@ export { URLHandler } from './handler/url.js';
|
|
|
7
7
|
export { Hub } from './hub.js';
|
|
8
8
|
export { Logger } from './log.js';
|
|
9
9
|
export { pofile } from './pofile.js';
|
|
10
|
-
export { defaultPluralRule, migrateStorage } from './storage.js';
|
|
10
|
+
export { defaultPluralRule, mergeItemsByKey, migrateStorage, storageByLocale, storageByType } from './storage.js';
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { type CatalogModule, type Runtime } from '../runtime.js';
|
|
2
|
-
export type LoaderFunc = (loadID:
|
|
2
|
+
export type LoaderFunc = (loadID: number, locale: string) => CatalogModule | Promise<CatalogModule>;
|
|
3
3
|
export type RuntimeCollection = {
|
|
4
|
-
get: (loadID:
|
|
5
|
-
set: (loadID:
|
|
4
|
+
get: (loadID: number) => Runtime;
|
|
5
|
+
set: (loadID: number, runtime: Runtime) => void;
|
|
6
6
|
};
|
|
7
7
|
export type LoaderState = {
|
|
8
8
|
load: LoaderFunc;
|
|
9
|
-
catalogs:
|
|
10
|
-
[loadID: string]: CatalogModule | undefined;
|
|
11
|
-
};
|
|
9
|
+
catalogs: (CatalogModule | undefined)[];
|
|
12
10
|
collection: RuntimeCollection;
|
|
13
11
|
};
|
|
14
|
-
export declare function defaultCollection(store:
|
|
12
|
+
export declare function defaultCollection(store: Runtime[]): RuntimeCollection;
|
|
15
13
|
/**
|
|
16
14
|
* - `key` is a unique identifier for the group
|
|
17
15
|
* - `loadIDs` and `load` MUST be imported from the loader virtual modules or proxies.
|
|
18
16
|
*/
|
|
19
|
-
export declare function registerLoaders(key: string, load: LoaderFunc,
|
|
17
|
+
export declare function registerLoaders(key: string, load: LoaderFunc, loadCount: number, collection?: RuntimeCollection): (loadID?: number) => Runtime;
|
|
20
18
|
export declare function commitLocale(locale: string): void;
|
|
21
19
|
/**
|
|
22
20
|
* Loads catalogs using registered async loaders.
|
package/dist/load-utils/index.js
CHANGED
|
@@ -14,21 +14,21 @@ const emptyRuntime = toRuntime();
|
|
|
14
14
|
* - `key` is a unique identifier for the group
|
|
15
15
|
* - `loadIDs` and `load` MUST be imported from the loader virtual modules or proxies.
|
|
16
16
|
*/
|
|
17
|
-
export function registerLoaders(key, load,
|
|
17
|
+
export function registerLoaders(key, load, loadCount, collection) {
|
|
18
18
|
states[key] = {
|
|
19
19
|
load,
|
|
20
|
-
catalogs:
|
|
21
|
-
collection: collection ?? defaultCollection(
|
|
20
|
+
catalogs: Array(loadCount).fill(undefined),
|
|
21
|
+
collection: collection ?? defaultCollection([]),
|
|
22
22
|
};
|
|
23
|
-
for (
|
|
23
|
+
for (let id = 0; id < loadCount; id++) {
|
|
24
24
|
states[key].collection.set(id, emptyRuntime);
|
|
25
25
|
}
|
|
26
|
-
return loadID => states[key].collection.get(loadID);
|
|
26
|
+
return (loadID = 0) => states[key].collection.get(loadID);
|
|
27
27
|
}
|
|
28
28
|
/* Sets the most recently loaded locale as the current one */
|
|
29
29
|
export function commitLocale(locale) {
|
|
30
30
|
for (const state of Object.values(states)) {
|
|
31
|
-
for (const [loadID, catalog] of
|
|
31
|
+
for (const [loadID, catalog] of state.catalogs.entries()) {
|
|
32
32
|
state.collection.set(loadID, toRuntime(catalog, locale));
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -42,9 +42,9 @@ export async function loadLocale(locale, commit = true) {
|
|
|
42
42
|
const promises = [];
|
|
43
43
|
const statesArr = [];
|
|
44
44
|
for (const state of Object.values(states)) {
|
|
45
|
-
for (
|
|
46
|
-
promises.push(state.load(
|
|
47
|
-
statesArr.push([
|
|
45
|
+
for (let id = 0; id < state.catalogs.length; id++) {
|
|
46
|
+
promises.push(state.load(id, locale));
|
|
47
|
+
statesArr.push([id, state]);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
for (const [i, loaded] of (await Promise.all(promises)).entries()) {
|
|
@@ -61,8 +61,8 @@ export async function loadLocale(locale, commit = true) {
|
|
|
61
61
|
*/
|
|
62
62
|
export function loadLocaleSync(locale, commit = true) {
|
|
63
63
|
for (const state of Object.values(states)) {
|
|
64
|
-
for (
|
|
65
|
-
state.catalogs[
|
|
64
|
+
for (let id = 0; id < state.catalogs.length; id++) {
|
|
65
|
+
state.catalogs[id] = state.load(id, locale);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
commit && commitLocale(locale);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CatalogModule } from '../runtime.js';
|
|
2
2
|
import type { LoaderFunc } from './index.js';
|
|
3
|
-
export type CatalogsByID = Record<
|
|
3
|
+
export type CatalogsByID = Record<number, CatalogModule>;
|
|
4
4
|
/** No-side effect way to load catalogs. Can be used for multiple file IDs. */
|
|
5
|
-
export declare function loadCatalogs(locale: string, loadIDs:
|
|
5
|
+
export declare function loadCatalogs(locale: string, loadIDs: number[], loadCatalog: LoaderFunc): Promise<CatalogsByID>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { type Runtime } from '../runtime.js';
|
|
3
3
|
import type { LoaderFunc } from './index.js';
|
|
4
|
-
type LoadedRuntimes = Record<string,
|
|
4
|
+
type LoadedRuntimes = Record<string, Runtime[]>;
|
|
5
5
|
export declare const runtimeCtx: AsyncLocalStorage<LoadedRuntimes>;
|
|
6
|
-
export declare function currentRuntime(key: string, loadID:
|
|
7
|
-
export declare function loadLocales(key: string,
|
|
6
|
+
export declare function currentRuntime(key: string, loadID: number): Runtime;
|
|
7
|
+
export declare function loadLocales(key: string, loadCount: number, load: LoaderFunc, locales: string[]): Promise<(loadID?: number) => Runtime>;
|
|
8
8
|
export declare function runWithLocale<T>(locale: string, func: () => T): Promise<T>;
|
|
9
9
|
export {};
|
|
@@ -19,23 +19,20 @@ export function currentRuntime(key, loadID) {
|
|
|
19
19
|
warningShown[warnKey] = true;
|
|
20
20
|
return emptyRuntime;
|
|
21
21
|
}
|
|
22
|
-
export async function loadLocales(key,
|
|
23
|
-
if (loadIDs == null) {
|
|
24
|
-
loadIDs = [key];
|
|
25
|
-
}
|
|
22
|
+
export async function loadLocales(key, loadCount, load, locales) {
|
|
26
23
|
for (const locale of locales) {
|
|
27
24
|
if (!(locale in runtimes)) {
|
|
28
25
|
runtimes[locale] = {};
|
|
29
26
|
}
|
|
30
27
|
const loaded = runtimes[locale];
|
|
31
28
|
if (!(key in loaded)) {
|
|
32
|
-
loaded[key] =
|
|
29
|
+
loaded[key] = [];
|
|
33
30
|
}
|
|
34
|
-
for (
|
|
31
|
+
for (let id = 0; id < loadCount; id++) {
|
|
35
32
|
loaded[key][id] = toRuntime(await load(id, locale), locale);
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
|
-
return (loadID) => currentRuntime(key, loadID);
|
|
35
|
+
return (loadID = 0) => currentRuntime(key, loadID);
|
|
39
36
|
}
|
|
40
37
|
export async function runWithLocale(locale, func) {
|
|
41
38
|
return await runtimeCtx.run(runtimes[locale], func);
|
package/dist/pofile.d.ts
CHANGED
|
@@ -2,21 +2,21 @@ import PO from 'pofile';
|
|
|
2
2
|
import { type PluralRule, type SaveData, type StorageFactory, type StorageFactoryOpts } from './storage.js';
|
|
3
3
|
export type POItem = InstanceType<typeof PO.Item>;
|
|
4
4
|
export type POFileOptions = {
|
|
5
|
-
dir
|
|
6
|
-
|
|
5
|
+
/** in the form like 'path/to/dir/{locale}.po' */
|
|
6
|
+
location: string;
|
|
7
7
|
};
|
|
8
8
|
export declare const defaultOpts: POFileOptions;
|
|
9
9
|
type POHeaders = Record<string, string | undefined>;
|
|
10
10
|
export declare class POFile {
|
|
11
11
|
key: string;
|
|
12
12
|
opts: StorageFactoryOpts & POFileOptions;
|
|
13
|
-
filesByLoc: Map<string,
|
|
13
|
+
filesByLoc: Map<string, string>;
|
|
14
14
|
files: string[];
|
|
15
15
|
fileExistsCache: Map<string, boolean>;
|
|
16
16
|
constructor(opts: StorageFactoryOpts & POFileOptions);
|
|
17
|
-
loadRaw(locale: string
|
|
17
|
+
loadRaw(locale: string): Promise<PO | null>;
|
|
18
18
|
load(): Promise<SaveData>;
|
|
19
|
-
saveRaw(items: POItem[], headers: POHeaders, locale: string
|
|
19
|
+
saveRaw(items: POItem[], headers: POHeaders, locale: string): Promise<void>;
|
|
20
20
|
save(data: SaveData): Promise<void>;
|
|
21
21
|
getHeaders(locale: string, pluralRule: PluralRule): POHeaders;
|
|
22
22
|
}
|
package/dist/pofile.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
1
|
+
import { dirname, resolve } from 'node:path';
|
|
2
2
|
import PO from 'pofile';
|
|
3
3
|
import { getKey } from './adapters.js';
|
|
4
4
|
import { fillDefaults } from './config.js';
|
|
5
|
-
import { itemIsObsolete,
|
|
5
|
+
import { itemIsObsolete, } from './storage.js';
|
|
6
6
|
const urlAdapterFlagPrefix = 'url:';
|
|
7
7
|
function join(parts, sep) {
|
|
8
8
|
return parts.map(s => s.replaceAll('\\', '\\\\').replaceAll(sep, `\\${sep}`)).join(sep);
|
|
@@ -79,7 +79,7 @@ function poitemToItemCommons(poi) {
|
|
|
79
79
|
}
|
|
80
80
|
for (const c of commSp.slice(phStart)) {
|
|
81
81
|
const [i, ph] = split(c, ': ', 2);
|
|
82
|
-
refEnt.placeholders.push([
|
|
82
|
+
refEnt.placeholders.push([i, ph]);
|
|
83
83
|
}
|
|
84
84
|
lastRef.refs.push(refEnt);
|
|
85
85
|
}
|
|
@@ -124,8 +124,7 @@ function poitemsToItems(poItems, locales, sourceLocale) {
|
|
|
124
124
|
return items;
|
|
125
125
|
}
|
|
126
126
|
export const defaultOpts = {
|
|
127
|
-
|
|
128
|
-
separateUrls: true,
|
|
127
|
+
location: 'src/locales/{locale}.po',
|
|
129
128
|
};
|
|
130
129
|
export class POFile {
|
|
131
130
|
key;
|
|
@@ -135,16 +134,16 @@ export class POFile {
|
|
|
135
134
|
fileExistsCache = new Map();
|
|
136
135
|
constructor(opts) {
|
|
137
136
|
this.opts = opts;
|
|
138
|
-
opts.
|
|
139
|
-
this.key = opts.
|
|
137
|
+
opts.location = resolve(opts.root, opts.location);
|
|
138
|
+
this.key = opts.location;
|
|
140
139
|
for (const locale of opts.locales) {
|
|
141
|
-
const
|
|
142
|
-
this.filesByLoc.set(locale,
|
|
143
|
-
this.files.push(
|
|
140
|
+
const location = opts.location.replace('{locale}', locale);
|
|
141
|
+
this.filesByLoc.set(locale, location);
|
|
142
|
+
this.files.push(location);
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
|
-
async loadRaw(locale
|
|
147
|
-
const filename = this.filesByLoc.get(locale)
|
|
145
|
+
async loadRaw(locale) {
|
|
146
|
+
const filename = this.filesByLoc.get(locale);
|
|
148
147
|
const content = await this.opts.fs.read(filename);
|
|
149
148
|
this.fileExistsCache.set(filename, content != null);
|
|
150
149
|
return content == null ? null : PO.parse(content);
|
|
@@ -155,7 +154,7 @@ export class POFile {
|
|
|
155
154
|
const poItems = new Map();
|
|
156
155
|
// first, group by key
|
|
157
156
|
for (const locale of this.opts.locales) {
|
|
158
|
-
const po = await this.loadRaw(locale
|
|
157
|
+
const po = await this.loadRaw(locale);
|
|
159
158
|
if (po == null) {
|
|
160
159
|
continue;
|
|
161
160
|
}
|
|
@@ -165,10 +164,6 @@ export class POFile {
|
|
|
165
164
|
pluralRule.nplurals = Number(pluralRule.nplurals);
|
|
166
165
|
pluralRules.set(locale, pluralRule);
|
|
167
166
|
}
|
|
168
|
-
if (this.opts.separateUrls && this.opts.haveUrl) {
|
|
169
|
-
const poUrl = await this.loadRaw(locale, true);
|
|
170
|
-
poUrl && po.items.push(...poUrl.items);
|
|
171
|
-
}
|
|
172
167
|
for (const poItem of po.items) {
|
|
173
168
|
const key = getKey(getItemId(poItem), poItem.msgctxt);
|
|
174
169
|
if (!poItems.has(key)) {
|
|
@@ -182,8 +177,8 @@ export class POFile {
|
|
|
182
177
|
pluralRules,
|
|
183
178
|
};
|
|
184
179
|
}
|
|
185
|
-
async saveRaw(items, headers, locale
|
|
186
|
-
const filename = this.filesByLoc.get(locale)
|
|
180
|
+
async saveRaw(items, headers, locale) {
|
|
181
|
+
const filename = this.filesByLoc.get(locale);
|
|
187
182
|
if (items.length === 0) {
|
|
188
183
|
if (this.fileExistsCache.get(filename) === false) {
|
|
189
184
|
return;
|
|
@@ -199,25 +194,14 @@ export class POFile {
|
|
|
199
194
|
this.fileExistsCache.set(filename, true);
|
|
200
195
|
}
|
|
201
196
|
async save(data) {
|
|
202
|
-
|
|
203
|
-
await Promise.all(this.opts.locales.flatMap(locale => {
|
|
197
|
+
await Promise.all(this.opts.locales.map(locale => {
|
|
204
198
|
const poItems = [];
|
|
205
|
-
const poItemsUrl = [];
|
|
206
199
|
for (const item of data.items) {
|
|
207
200
|
const poItem = itemToPOItem(item, locale, this.opts.sourceLocale);
|
|
208
|
-
|
|
209
|
-
poItemsUrl.push(poItem);
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
poItems.push(poItem);
|
|
213
|
-
}
|
|
201
|
+
poItems.push(poItem);
|
|
214
202
|
}
|
|
215
203
|
const headers = this.getHeaders(locale, data.pluralRules.get(locale));
|
|
216
|
-
|
|
217
|
-
if (useSeparateUrls) {
|
|
218
|
-
saveJobs.push(this.saveRaw(poItemsUrl, headers, locale, true));
|
|
219
|
-
}
|
|
220
|
-
return saveJobs;
|
|
204
|
+
return this.saveRaw(poItems, headers, locale);
|
|
221
205
|
}));
|
|
222
206
|
}
|
|
223
207
|
getHeaders(locale, pluralRule) {
|
|
@@ -238,8 +222,12 @@ export class POFile {
|
|
|
238
222
|
}
|
|
239
223
|
export function pofile(pofOpts = {}) {
|
|
240
224
|
return async (opts) => {
|
|
241
|
-
const
|
|
242
|
-
|
|
225
|
+
const defaultLocation = resolve(opts.root, opts.localesDir, '{locale}.po');
|
|
226
|
+
const fullOpts = fillDefaults(pofOpts, { ...defaultOpts, location: defaultLocation });
|
|
227
|
+
await opts.fs.mkdir(dirname(resolve(opts.root, fullOpts.location))); // create once
|
|
228
|
+
if (!fullOpts.location.includes('{locale}')) {
|
|
229
|
+
throw new Error('PO file `location` config has to include `{locale}`');
|
|
230
|
+
}
|
|
243
231
|
return new POFile({ ...opts, ...fullOpts });
|
|
244
232
|
};
|
|
245
233
|
}
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FS } from './fs.js';
|
|
2
2
|
export type FileRefEntry = {
|
|
3
3
|
link?: string | undefined;
|
|
4
|
-
placeholders: [
|
|
4
|
+
placeholders: [string, string][];
|
|
5
5
|
};
|
|
6
6
|
export type FileRef = {
|
|
7
7
|
file: string;
|
|
@@ -54,10 +54,13 @@ export type StorageFactoryOpts = {
|
|
|
54
54
|
root: string;
|
|
55
55
|
/** shared locale artifacts directory from the top-level config */
|
|
56
56
|
localesDir: string;
|
|
57
|
-
/** whether the url is configured, can use to load separate url files */
|
|
58
|
-
haveUrl: boolean;
|
|
59
57
|
sourceLocale: string;
|
|
60
58
|
fs: FS;
|
|
61
59
|
};
|
|
62
60
|
export type StorageFactory = (opts: StorageFactoryOpts) => CatalogStorage | Promise<CatalogStorage>;
|
|
63
61
|
export declare function migrateStorage(fromStorages: StorageFactory[], toStorage: StorageFactory): StorageFactory;
|
|
62
|
+
type ItemType = 'message' | 'url';
|
|
63
|
+
export declare function storageByType(storages: Record<ItemType, StorageFactory>): StorageFactory;
|
|
64
|
+
export declare function mergeItemsByKey(allItems: Item[][], sourceLocale: string): Item[];
|
|
65
|
+
export declare function storageByLocale(storages: [string[], StorageFactory][]): StorageFactory;
|
|
66
|
+
export {};
|