@x18n/builtins 0.0.2 → 0.0.3
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/checks.d.mts +19 -0
- package/dist/checks.mjs +329 -0
- package/dist/extractors.d.mts +51 -0
- package/dist/extractors.mjs +269 -0
- package/dist/finders-CqTGh4OJ.mjs +197 -0
- package/dist/finders.d.mts +31 -0
- package/dist/finders.mjs +3 -0
- package/dist/formats-BAogSrvw.mjs +1331 -0
- package/dist/formats.d.mts +34 -0
- package/dist/formats.mjs +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +38 -0
- package/dist/manifests.d.mts +10 -0
- package/dist/manifests.mjs +49 -0
- package/dist/placeholders.d.mts +27 -0
- package/dist/placeholders.mjs +131 -0
- package/dist/presets-DNnE_2MQ.mjs +1124 -0
- package/dist/presets.d.mts +58 -0
- package/dist/presets.mjs +1 -0
- package/dist/regex-B9TBGgXC.mjs +97 -0
- package/dist/reporters.d.mts +14 -0
- package/dist/reporters.mjs +203 -0
- package/dist/scanners-B27IEH4_.mjs +119 -0
- package/dist/scanners.d.mts +49 -0
- package/dist/scanners.mjs +4 -0
- package/dist/sfc-blocks-BwJwCUka.mjs +161 -0
- package/dist/vue-5GFR5hft.mjs +727 -0
- package/dist/yaml-plugin.d.mts +8 -0
- package/dist/yaml-plugin.mjs +68 -0
- package/package.json +2 -2
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
//#region src/finders/pattern.ts
|
|
2
|
+
const localeLike = /^[a-z]{2,3}(?:[-_][a-z\d]{2,8})*$/i;
|
|
3
|
+
function isLocaleCode(text) {
|
|
4
|
+
if (!localeLike.test(text)) return false;
|
|
5
|
+
try {
|
|
6
|
+
return Intl.getCanonicalLocales(text.replace(/_/g, "-")).length === 1;
|
|
7
|
+
} catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function escapeRegExp(text) {
|
|
12
|
+
return text.replace(/[.+^$()|[\]\\]/g, "\\$&");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Compiles a resource pattern. Tokens: `{locale}`, `{locale?}`, `{namespace}`,
|
|
16
|
+
* `{namespaces}` (several segments, joined with `.`), `{ext}`; plus `*` and `**`.
|
|
17
|
+
*/
|
|
18
|
+
function compilePattern(pattern, extensions) {
|
|
19
|
+
const normalized = pattern.replace(/^\.\//, "");
|
|
20
|
+
const ext = `(?<ext>${extensions.map(escapeRegExp).join("|")})`;
|
|
21
|
+
let source = "";
|
|
22
|
+
let glob = "";
|
|
23
|
+
const tokens = /\{[^}]*\}|\*\*\/|\*\*|\*|\?/g;
|
|
24
|
+
let last = 0;
|
|
25
|
+
for (const match of normalized.matchAll(tokens)) {
|
|
26
|
+
const literal = normalized.slice(last, match.index);
|
|
27
|
+
source += escapeRegExp(literal);
|
|
28
|
+
glob += literal;
|
|
29
|
+
last = match.index + match[0].length;
|
|
30
|
+
switch (match[0]) {
|
|
31
|
+
case "{locale}":
|
|
32
|
+
source += "(?<locale>[\\w-]+)";
|
|
33
|
+
glob += "*";
|
|
34
|
+
break;
|
|
35
|
+
case "{locale?}":
|
|
36
|
+
source += "(?<locale>[\\w-]+)?";
|
|
37
|
+
glob += "*";
|
|
38
|
+
break;
|
|
39
|
+
case "{namespace}":
|
|
40
|
+
source += "(?<namespace>[^/]+)";
|
|
41
|
+
glob += "*";
|
|
42
|
+
break;
|
|
43
|
+
case "{namespaces}":
|
|
44
|
+
source += "(?<namespace>.+)";
|
|
45
|
+
glob += "**";
|
|
46
|
+
break;
|
|
47
|
+
case "{ext}":
|
|
48
|
+
source += ext;
|
|
49
|
+
glob += extensions.length === 1 ? extensions[0] : `{${extensions.join(",")}}`;
|
|
50
|
+
break;
|
|
51
|
+
case "**/":
|
|
52
|
+
source += "(?:.*/)?";
|
|
53
|
+
glob += "**/";
|
|
54
|
+
break;
|
|
55
|
+
case "**":
|
|
56
|
+
source += ".*";
|
|
57
|
+
glob += "**";
|
|
58
|
+
break;
|
|
59
|
+
case "*":
|
|
60
|
+
source += "[^/]*";
|
|
61
|
+
glob += "*";
|
|
62
|
+
break;
|
|
63
|
+
case "?":
|
|
64
|
+
source += "[^/]";
|
|
65
|
+
glob += "?";
|
|
66
|
+
break;
|
|
67
|
+
default: {
|
|
68
|
+
const options = match[0].slice(1, -1).split(",");
|
|
69
|
+
source += `(?:${options.map(escapeRegExp).join("|")})`;
|
|
70
|
+
glob += match[0];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
source += escapeRegExp(normalized.slice(last));
|
|
75
|
+
glob += normalized.slice(last);
|
|
76
|
+
const regex = new RegExp(`^${source}$`);
|
|
77
|
+
return {
|
|
78
|
+
glob,
|
|
79
|
+
match(path) {
|
|
80
|
+
const found = regex.exec(path);
|
|
81
|
+
if (!found) return void 0;
|
|
82
|
+
const groups = found.groups ?? {};
|
|
83
|
+
const extension = groups.ext ?? path.slice(path.lastIndexOf(".") + 1);
|
|
84
|
+
return {
|
|
85
|
+
locale: groups.locale,
|
|
86
|
+
namespace: groups.namespace,
|
|
87
|
+
ext: extension
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const localeDirNames = [
|
|
93
|
+
"locales",
|
|
94
|
+
"locale",
|
|
95
|
+
"i18n",
|
|
96
|
+
"lang",
|
|
97
|
+
"langs",
|
|
98
|
+
"language",
|
|
99
|
+
"languages",
|
|
100
|
+
"translations",
|
|
101
|
+
"messages",
|
|
102
|
+
"_locales",
|
|
103
|
+
"l10n"
|
|
104
|
+
];
|
|
105
|
+
/** Guesses resource patterns from directories named like `locales`, as i18n-ally did without `localesPaths`. */
|
|
106
|
+
async function guessResources(ctx) {
|
|
107
|
+
const exts = ctx.extensions.length === 1 ? ctx.extensions[0] : `{${ctx.extensions.join(",")}}`;
|
|
108
|
+
const files = await ctx.host.glob([`**/{${localeDirNames.join(",")}}/**/*.${exts}`], {
|
|
109
|
+
ignore: [
|
|
110
|
+
"**/node_modules/**",
|
|
111
|
+
"**/dist/**",
|
|
112
|
+
"**/.git/**",
|
|
113
|
+
"**/.nuxt/**",
|
|
114
|
+
"**/.output/**",
|
|
115
|
+
"**/build/**"
|
|
116
|
+
],
|
|
117
|
+
gitignore: true
|
|
118
|
+
});
|
|
119
|
+
const dirs = /* @__PURE__ */ new Map();
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
const segments = file.split("/");
|
|
122
|
+
const index = segments.findLastIndex((segment) => localeDirNames.includes(segment));
|
|
123
|
+
const dir = segments.slice(0, index + 1).join("/");
|
|
124
|
+
const list = dirs.get(dir) ?? [];
|
|
125
|
+
dirs.set(dir, list);
|
|
126
|
+
list.push(segments.slice(index + 1).join("/"));
|
|
127
|
+
}
|
|
128
|
+
const specs = [];
|
|
129
|
+
for (const [dir, rest] of dirs) {
|
|
130
|
+
const stem = (file) => file.slice(0, file.lastIndexOf("."));
|
|
131
|
+
const fileLayout = rest.filter((file) => !file.includes("/") && isLocaleCode(stem(file))).length;
|
|
132
|
+
const dirLayout = rest.filter((file) => file.includes("/") && isLocaleCode(file.split("/")[0])).length;
|
|
133
|
+
if (fileLayout === 0 && dirLayout === 0) continue;
|
|
134
|
+
specs.push({ pattern: fileLayout >= dirLayout ? `${dir}/{locale}.{ext}` : `${dir}/{locale}/{namespaces}.{ext}` });
|
|
135
|
+
}
|
|
136
|
+
return specs;
|
|
137
|
+
}
|
|
138
|
+
/** A namespace from a path in the style of `namespace.fromPath`. Transloco camelCases scope folders, as its `toCamelCase`. */
|
|
139
|
+
function namespaceFromPath(path, style) {
|
|
140
|
+
if (style === "slash") return path;
|
|
141
|
+
if (style === "camel") return path.replace(/[-_/\s]+(.)/g, (_, c) => c.toUpperCase()).replace(/^./, (c) => c.toLowerCase());
|
|
142
|
+
return path.replace(/\//g, ".");
|
|
143
|
+
}
|
|
144
|
+
async function findBySpecs(ctx, specs, strictLocales) {
|
|
145
|
+
const out = [];
|
|
146
|
+
for (const spec of specs) {
|
|
147
|
+
const compiled = compilePattern(spec.pattern, ctx.extensions);
|
|
148
|
+
const fixed = spec.locale ?? (spec.pattern.includes("{locale") ? void 0 : ctx.config.sourceLocale);
|
|
149
|
+
const paths = await ctx.host.glob([compiled.glob], {
|
|
150
|
+
ignore: ["**/node_modules/**"],
|
|
151
|
+
gitignore: false
|
|
152
|
+
});
|
|
153
|
+
for (const path of paths) {
|
|
154
|
+
const matched = compiled.match(path);
|
|
155
|
+
if (!matched) continue;
|
|
156
|
+
const locale = fixed ?? matched.locale ?? (spec.pattern.includes("{locale?}") ? ctx.config.sourceLocale : void 0);
|
|
157
|
+
if (!locale || strictLocales && !isLocaleCode(locale)) continue;
|
|
158
|
+
const namespace = spec.namespace ?? (matched.namespace === void 0 ? void 0 : namespaceFromPath(matched.namespace, ctx.config.namespace.fromPath));
|
|
159
|
+
out.push({
|
|
160
|
+
path,
|
|
161
|
+
locale,
|
|
162
|
+
namespace,
|
|
163
|
+
format: spec.format,
|
|
164
|
+
readonly: spec.execute === true
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
const patternFinder = {
|
|
171
|
+
id: "pattern",
|
|
172
|
+
resolveNew(target, ctx) {
|
|
173
|
+
const style = ctx.config.namespace.fromPath;
|
|
174
|
+
for (const spec of ctx.config.resources) {
|
|
175
|
+
const wantsNamespace = /\{namespaces?\}/.test(spec.pattern);
|
|
176
|
+
if (wantsNamespace !== (target.namespace !== void 0) || wantsNamespace && style === "camel" || spec.execute || !spec.pattern.includes("{locale")) continue;
|
|
177
|
+
const path = spec.pattern.replace(/^\.\//, "").replace(/\{locale\??\}/g, target.locale).replace("{namespaces}", style === "slash" ? target.namespace ?? "" : (target.namespace ?? "").replace(/\./g, "/")).replace("{namespace}", target.namespace ?? "").replace("{ext}", spec.format === "yaml" ? "yml" : spec.format ?? "json");
|
|
178
|
+
if (!/[*?{}[\]]/.test(path)) return path;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
async find(ctx) {
|
|
182
|
+
const configured = ctx.config.resources;
|
|
183
|
+
const fromUser = ctx.config.origins.resources === "user" || ctx.config.origins.resources === "parent";
|
|
184
|
+
const found = configured.length > 0 ? await findBySpecs(ctx, configured, !fromUser) : [];
|
|
185
|
+
if (found.length > 0 || fromUser) return found;
|
|
186
|
+
return findBySpecs(ctx, await guessResources(ctx), true);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
/** The `pattern` locale finder: files that match `resources[].pattern`, or guessed locale directories. */
|
|
190
|
+
function pattern() {
|
|
191
|
+
return {
|
|
192
|
+
name: "x18n:finder-pattern",
|
|
193
|
+
localeFinders: [patternFinder]
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
//#endregion
|
|
197
|
+
export { patternFinder as a, pattern as i, guessResources as n, namespaceFromPath as r, compilePattern as t };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FinderContext, LocaleFinder, NamespaceFromPath, Plugin, ResourceSpec } from "@x18n/core";
|
|
2
|
+
//#region src/finders/pattern.d.ts
|
|
3
|
+
interface CompiledPattern {
|
|
4
|
+
/** Glob for the host. */
|
|
5
|
+
readonly glob: string;
|
|
6
|
+
readonly match: (path: string) => {
|
|
7
|
+
locale: string | undefined;
|
|
8
|
+
namespace: string | undefined;
|
|
9
|
+
ext: string;
|
|
10
|
+
} | undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Compiles a resource pattern. Tokens: `{locale}`, `{locale?}`, `{namespace}`,
|
|
14
|
+
* `{namespaces}` (several segments, joined with `.`), `{ext}`; plus `*` and `**`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function compilePattern(pattern: string, extensions: readonly string[]): CompiledPattern;
|
|
17
|
+
/** Guesses resource patterns from directories named like `locales`, as i18n-ally did without `localesPaths`. */
|
|
18
|
+
export declare function guessResources(ctx: FinderContext): Promise<ResourceSpec[]>;
|
|
19
|
+
/** A namespace from a path in the style of `namespace.fromPath`. Transloco camelCases scope folders, as its `toCamelCase`. */
|
|
20
|
+
export declare function namespaceFromPath(path: string, style: NamespaceFromPath): string;
|
|
21
|
+
export declare const patternFinder: LocaleFinder;
|
|
22
|
+
/** The `pattern` locale finder: files that match `resources[].pattern`, or guessed locale directories. */
|
|
23
|
+
export declare function pattern(): Plugin;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/finders/sfc-blocks.d.ts
|
|
26
|
+
/** Vue `<i18n>` blocks: one resource per block and locale (`locale="en"`, or every top-level locale key). */
|
|
27
|
+
export declare function sfcBlocks(): Plugin;
|
|
28
|
+
/** fluent-vue `<fluent locale="en">` blocks in Vue SFCs, read with the `ftl` format. */
|
|
29
|
+
export declare function sfcFluentBlocks(): Plugin;
|
|
30
|
+
//#endregion
|
|
31
|
+
export type { CompiledPattern };
|
package/dist/finders.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { a as patternFinder, i as pattern, n as guessResources, r as namespaceFromPath, t as compilePattern } from "./finders-CqTGh4OJ.mjs";
|
|
2
|
+
import { n as sfcFluentBlocks, t as sfcBlocks } from "./sfc-blocks-BwJwCUka.mjs";
|
|
3
|
+
export { compilePattern, guessResources, namespaceFromPath, pattern, patternFinder, sfcBlocks, sfcFluentBlocks };
|