@vocoder/cli 0.14.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +942 -754
- package/dist/bin.mjs.map +1 -1
- package/dist/{chunk-LLEMSC3X.mjs → chunk-IK4ZCESQ.mjs} +283 -423
- package/dist/chunk-IK4ZCESQ.mjs.map +1 -0
- package/dist/lib.d.mts +50 -27
- package/dist/lib.mjs +159 -2
- package/dist/lib.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-LLEMSC3X.mjs.map +0 -1
|
@@ -3094,14 +3094,14 @@ var require_lib = __commonJS({
|
|
|
3094
3094
|
super.checkParams(node, false, true);
|
|
3095
3095
|
this.scope.exit();
|
|
3096
3096
|
}
|
|
3097
|
-
forwardNoArrowParamsConversionAt(node,
|
|
3097
|
+
forwardNoArrowParamsConversionAt(node, parse5) {
|
|
3098
3098
|
let result;
|
|
3099
3099
|
if (this.state.noArrowParamsConversionAt.includes(this.offsetToSourcePos(node.start))) {
|
|
3100
3100
|
this.state.noArrowParamsConversionAt.push(this.state.start);
|
|
3101
|
-
result =
|
|
3101
|
+
result = parse5();
|
|
3102
3102
|
this.state.noArrowParamsConversionAt.pop();
|
|
3103
3103
|
} else {
|
|
3104
|
-
result =
|
|
3104
|
+
result = parse5();
|
|
3105
3105
|
}
|
|
3106
3106
|
return result;
|
|
3107
3107
|
}
|
|
@@ -14496,7 +14496,7 @@ var require_lib = __commonJS({
|
|
|
14496
14496
|
return result;
|
|
14497
14497
|
}
|
|
14498
14498
|
};
|
|
14499
|
-
function
|
|
14499
|
+
function parse4(input, options) {
|
|
14500
14500
|
var _options;
|
|
14501
14501
|
if (((_options = options) == null ? void 0 : _options.sourceType) === "unambiguous") {
|
|
14502
14502
|
options = Object.assign({}, options);
|
|
@@ -14583,7 +14583,7 @@ var require_lib = __commonJS({
|
|
|
14583
14583
|
}
|
|
14584
14584
|
return cls;
|
|
14585
14585
|
}
|
|
14586
|
-
exports.parse =
|
|
14586
|
+
exports.parse = parse4;
|
|
14587
14587
|
exports.parseExpression = parseExpression;
|
|
14588
14588
|
exports.tokTypes = tokTypes;
|
|
14589
14589
|
}
|
|
@@ -14632,7 +14632,7 @@ var require_ms = __commonJS({
|
|
|
14632
14632
|
options = options || {};
|
|
14633
14633
|
var type = typeof val;
|
|
14634
14634
|
if (type === "string" && val.length > 0) {
|
|
14635
|
-
return
|
|
14635
|
+
return parse4(val);
|
|
14636
14636
|
} else if (type === "number" && isFinite(val)) {
|
|
14637
14637
|
return options.long ? fmtLong(val) : fmtShort(val);
|
|
14638
14638
|
}
|
|
@@ -14640,7 +14640,7 @@ var require_ms = __commonJS({
|
|
|
14640
14640
|
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
14641
14641
|
);
|
|
14642
14642
|
};
|
|
14643
|
-
function
|
|
14643
|
+
function parse4(str) {
|
|
14644
14644
|
str = String(str);
|
|
14645
14645
|
if (str.length > 100) {
|
|
14646
14646
|
return;
|
|
@@ -28425,9 +28425,9 @@ var require_traverse = __commonJS({
|
|
|
28425
28425
|
Object.defineProperty(exports, "__esModule", {
|
|
28426
28426
|
value: true
|
|
28427
28427
|
});
|
|
28428
|
-
exports.default =
|
|
28428
|
+
exports.default = traverse4;
|
|
28429
28429
|
var _index = require_definitions();
|
|
28430
|
-
function
|
|
28430
|
+
function traverse4(node, handlers, state) {
|
|
28431
28431
|
if (typeof handlers === "function") {
|
|
28432
28432
|
handlers = {
|
|
28433
28433
|
enter: handlers
|
|
@@ -32148,11 +32148,11 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
32148
32148
|
function buildNullArray() {
|
|
32149
32149
|
return { __proto__: null };
|
|
32150
32150
|
}
|
|
32151
|
-
function
|
|
32151
|
+
function parse4(map) {
|
|
32152
32152
|
return typeof map === "string" ? JSON.parse(map) : map;
|
|
32153
32153
|
}
|
|
32154
32154
|
var FlattenMap = function(map, mapUrl) {
|
|
32155
|
-
const parsed =
|
|
32155
|
+
const parsed = parse4(map);
|
|
32156
32156
|
if (!("sections" in parsed)) {
|
|
32157
32157
|
return new TraceMap(parsed, mapUrl);
|
|
32158
32158
|
}
|
|
@@ -32216,7 +32216,7 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
32216
32216
|
}
|
|
32217
32217
|
}
|
|
32218
32218
|
function addSection(input, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
|
|
32219
|
-
const parsed =
|
|
32219
|
+
const parsed = parse4(input);
|
|
32220
32220
|
if ("sections" in parsed) return recurse(...arguments);
|
|
32221
32221
|
const map = new TraceMap(parsed, mapUrl);
|
|
32222
32222
|
const sourcesOffset = sources.length;
|
|
@@ -32266,7 +32266,7 @@ var require_trace_mapping_umd = __commonJS({
|
|
|
32266
32266
|
constructor(map, mapUrl) {
|
|
32267
32267
|
const isString = typeof map === "string";
|
|
32268
32268
|
if (!isString && map._decodedMemo) return map;
|
|
32269
|
-
const parsed =
|
|
32269
|
+
const parsed = parse4(map);
|
|
32270
32270
|
const { version, file, names, sourceRoot, sources, sourcesContent } = parsed;
|
|
32271
32271
|
this.version = version;
|
|
32272
32272
|
this.file = file;
|
|
@@ -40637,7 +40637,7 @@ var require_parse = __commonJS({
|
|
|
40637
40637
|
isStatement,
|
|
40638
40638
|
isStringLiteral,
|
|
40639
40639
|
removePropertiesDeep,
|
|
40640
|
-
traverse:
|
|
40640
|
+
traverse: traverse4
|
|
40641
40641
|
} = _t;
|
|
40642
40642
|
var PATTERN = /^[_$A-Z0-9]+$/;
|
|
40643
40643
|
function parseAndBuildMetadata(formatter, code, opts) {
|
|
@@ -40665,7 +40665,7 @@ var require_parse = __commonJS({
|
|
|
40665
40665
|
placeholderPattern,
|
|
40666
40666
|
syntacticPlaceholders
|
|
40667
40667
|
};
|
|
40668
|
-
|
|
40668
|
+
traverse4(ast, placeholderVisitorHandler, state);
|
|
40669
40669
|
return Object.assign({
|
|
40670
40670
|
ast
|
|
40671
40671
|
}, state.syntactic.placeholders.length ? state.syntactic : state.legacy);
|
|
@@ -43309,7 +43309,7 @@ var require_lib8 = __commonJS({
|
|
|
43309
43309
|
removeProperties,
|
|
43310
43310
|
traverseFast
|
|
43311
43311
|
} = _t;
|
|
43312
|
-
function
|
|
43312
|
+
function traverse4(parent, opts = {}, scope, state, parentPath, visitSelf) {
|
|
43313
43313
|
if (!parent) return;
|
|
43314
43314
|
if (!opts.noScope && !scope) {
|
|
43315
43315
|
if (parent.type !== "Program" && parent.type !== "File") {
|
|
@@ -43325,25 +43325,25 @@ var require_lib8 = __commonJS({
|
|
|
43325
43325
|
visitors.explode(opts);
|
|
43326
43326
|
(0, _traverseNode.traverseNode)(parent, opts, scope, state, parentPath, void 0, visitSelf);
|
|
43327
43327
|
}
|
|
43328
|
-
var _default = exports.default =
|
|
43329
|
-
|
|
43330
|
-
|
|
43331
|
-
|
|
43332
|
-
|
|
43328
|
+
var _default = exports.default = traverse4;
|
|
43329
|
+
traverse4.visitors = visitors;
|
|
43330
|
+
traverse4.verify = visitors.verify;
|
|
43331
|
+
traverse4.explode = visitors.explode;
|
|
43332
|
+
traverse4.cheap = function(node, enter) {
|
|
43333
43333
|
traverseFast(node, enter);
|
|
43334
43334
|
return;
|
|
43335
43335
|
};
|
|
43336
|
-
|
|
43336
|
+
traverse4.node = function(node, opts, scope, state, path2, skipKeys) {
|
|
43337
43337
|
(0, _traverseNode.traverseNode)(node, opts, scope, state, path2, skipKeys);
|
|
43338
43338
|
};
|
|
43339
|
-
|
|
43339
|
+
traverse4.clearNode = function(node, opts) {
|
|
43340
43340
|
removeProperties(node, opts);
|
|
43341
43341
|
};
|
|
43342
|
-
|
|
43343
|
-
traverseFast(tree,
|
|
43342
|
+
traverse4.removeProperties = function(tree, opts) {
|
|
43343
|
+
traverseFast(tree, traverse4.clearNode, opts);
|
|
43344
43344
|
return tree;
|
|
43345
43345
|
};
|
|
43346
|
-
|
|
43346
|
+
traverse4.hasType = function(tree, type, denylistTypes) {
|
|
43347
43347
|
if (denylistTypes != null && denylistTypes.includes(tree.type)) return false;
|
|
43348
43348
|
if (tree.type === type) return true;
|
|
43349
43349
|
return traverseFast(tree, function(node) {
|
|
@@ -43355,7 +43355,7 @@ var require_lib8 = __commonJS({
|
|
|
43355
43355
|
}
|
|
43356
43356
|
});
|
|
43357
43357
|
};
|
|
43358
|
-
|
|
43358
|
+
traverse4.cache = cache;
|
|
43359
43359
|
}
|
|
43360
43360
|
});
|
|
43361
43361
|
|
|
@@ -43570,9 +43570,9 @@ var require_brace_expansion = __commonJS({
|
|
|
43570
43570
|
|
|
43571
43571
|
// src/utils/api.ts
|
|
43572
43572
|
function computeStringsHash(input) {
|
|
43573
|
-
const { createHash } = __require("crypto");
|
|
43574
|
-
const sorted = [...input.
|
|
43575
|
-
return
|
|
43573
|
+
const { createHash: createHash2 } = __require("crypto");
|
|
43574
|
+
const sorted = [...input.keys].sort();
|
|
43575
|
+
return createHash2("sha256").update(JSON.stringify({ strings: sorted, industry: input.industry ?? null })).digest("hex");
|
|
43576
43576
|
}
|
|
43577
43577
|
function isLimitErrorResponse(value) {
|
|
43578
43578
|
if (!value || typeof value !== "object") {
|
|
@@ -43716,7 +43716,8 @@ var VocoderAPI = class {
|
|
|
43716
43716
|
}));
|
|
43717
43717
|
}
|
|
43718
43718
|
return entries.map((entry, index) => ({
|
|
43719
|
-
|
|
43719
|
+
// Fall back to stableTextKey only when text is present — id-only entries always have a key.
|
|
43720
|
+
key: entry.key || (entry.text ? this.stableTextKey(`${entry.text}:${index}`) : `_idonly_${index}`),
|
|
43720
43721
|
text: entry.text,
|
|
43721
43722
|
...entry.context ? { context: entry.context } : {},
|
|
43722
43723
|
...entry.formality ? { formality: entry.formality } : {},
|
|
@@ -43724,9 +43725,9 @@ var VocoderAPI = class {
|
|
|
43724
43725
|
}));
|
|
43725
43726
|
}
|
|
43726
43727
|
async submitTranslation(branch, entries, targetLocales, options, repoIdentity) {
|
|
43727
|
-
const
|
|
43728
|
-
const
|
|
43729
|
-
const stringsHash = computeStringsHash({
|
|
43728
|
+
const allEntries = this.normalizeStringEntries(entries);
|
|
43729
|
+
const stringEntries = allEntries.filter((e) => e.text != null);
|
|
43730
|
+
const stringsHash = computeStringsHash({ keys: allEntries.map((e) => e.key), industry: options?.industry ?? null });
|
|
43730
43731
|
return this.request(
|
|
43731
43732
|
"/api/cli/sync",
|
|
43732
43733
|
{
|
|
@@ -43745,7 +43746,7 @@ var VocoderAPI = class {
|
|
|
43745
43746
|
...repoIdentity?.repoCanonical ? { repoCanonical: repoIdentity.repoCanonical } : {},
|
|
43746
43747
|
...repoIdentity?.repoAppDir !== void 0 ? { repoAppDir: repoIdentity.repoAppDir } : {},
|
|
43747
43748
|
...repoIdentity?.commitSha ? { commitSha: repoIdentity.commitSha } : {},
|
|
43748
|
-
...options?.
|
|
43749
|
+
...options?.industry ? { industry: options.industry } : {}
|
|
43749
43750
|
})
|
|
43750
43751
|
},
|
|
43751
43752
|
"Translation submission failed"
|
|
@@ -43951,9 +43952,9 @@ var VocoderAPI = class {
|
|
|
43951
43952
|
});
|
|
43952
43953
|
}
|
|
43953
43954
|
}
|
|
43954
|
-
// ──
|
|
43955
|
-
async
|
|
43956
|
-
const url = new URL(`${this.apiUrl}/api/cli/
|
|
43955
|
+
// ── Organizations ─────────────────────────────────────────────────────────────
|
|
43956
|
+
async listOrganizations(userToken, params) {
|
|
43957
|
+
const url = new URL(`${this.apiUrl}/api/cli/organizations`);
|
|
43957
43958
|
if (params?.repo) url.searchParams.set("repo", params.repo);
|
|
43958
43959
|
const response = await fetch(url.toString(), {
|
|
43959
43960
|
headers: { Authorization: `Bearer ${userToken}` }
|
|
@@ -43963,7 +43964,7 @@ var VocoderAPI = class {
|
|
|
43963
43964
|
throw new VocoderAPIError({
|
|
43964
43965
|
message: extractErrorMessage(
|
|
43965
43966
|
payload,
|
|
43966
|
-
`Failed to list
|
|
43967
|
+
`Failed to list organizations (${response.status})`
|
|
43967
43968
|
),
|
|
43968
43969
|
status: response.status,
|
|
43969
43970
|
payload
|
|
@@ -43972,7 +43973,7 @@ var VocoderAPI = class {
|
|
|
43972
43973
|
return payload;
|
|
43973
43974
|
}
|
|
43974
43975
|
async listApps(userToken, organizationId) {
|
|
43975
|
-
const url = new URL(`${this.apiUrl}/api/cli/
|
|
43976
|
+
const url = new URL(`${this.apiUrl}/api/cli/apps`);
|
|
43976
43977
|
url.searchParams.set("organizationId", organizationId);
|
|
43977
43978
|
const response = await fetch(url.toString(), {
|
|
43978
43979
|
headers: { Authorization: `Bearer ${userToken}` }
|
|
@@ -43982,14 +43983,14 @@ var VocoderAPI = class {
|
|
|
43982
43983
|
throw new VocoderAPIError({
|
|
43983
43984
|
message: extractErrorMessage(
|
|
43984
43985
|
payload,
|
|
43985
|
-
`Failed to list
|
|
43986
|
+
`Failed to list apps (${response.status})`
|
|
43986
43987
|
),
|
|
43987
43988
|
status: response.status,
|
|
43988
43989
|
payload
|
|
43989
43990
|
});
|
|
43990
43991
|
}
|
|
43991
43992
|
const result = payload;
|
|
43992
|
-
return result.
|
|
43993
|
+
return result.apps;
|
|
43993
43994
|
}
|
|
43994
43995
|
async regenerateProjectApiKey(userToken, projectId) {
|
|
43995
43996
|
const response = await fetch(
|
|
@@ -44142,15 +44143,16 @@ var VocoderAPI = class {
|
|
|
44142
44143
|
* @throws {VocoderAPIError} status 422 for invalid/unsupported locale code
|
|
44143
44144
|
* @throws {VocoderAPIError} status 403 with limitError.limitType "target_locales" when plan limit reached
|
|
44144
44145
|
*/
|
|
44145
|
-
async addLocale(locale, repoCanonical) {
|
|
44146
|
+
async addLocale(locale, repoCanonical, appId) {
|
|
44146
44147
|
return this.request(
|
|
44147
|
-
"/api/cli/
|
|
44148
|
+
"/api/cli/app/locales",
|
|
44148
44149
|
{
|
|
44149
44150
|
method: "POST",
|
|
44150
44151
|
headers: { "Content-Type": "application/json" },
|
|
44151
44152
|
body: JSON.stringify({
|
|
44152
44153
|
locale,
|
|
44153
|
-
...repoCanonical ? { repoCanonical } : {}
|
|
44154
|
+
...repoCanonical ? { repoCanonical } : {},
|
|
44155
|
+
...appId ? { appId } : {}
|
|
44154
44156
|
})
|
|
44155
44157
|
},
|
|
44156
44158
|
"Failed to add locale"
|
|
@@ -44163,15 +44165,16 @@ var VocoderAPI = class {
|
|
|
44163
44165
|
*
|
|
44164
44166
|
* @throws {VocoderAPIError} on auth or server errors
|
|
44165
44167
|
*/
|
|
44166
|
-
async removeLocale(locale, repoCanonical) {
|
|
44168
|
+
async removeLocale(locale, repoCanonical, appId) {
|
|
44167
44169
|
return this.request(
|
|
44168
|
-
"/api/cli/
|
|
44170
|
+
"/api/cli/app/locales",
|
|
44169
44171
|
{
|
|
44170
44172
|
method: "DELETE",
|
|
44171
44173
|
headers: { "Content-Type": "application/json" },
|
|
44172
44174
|
body: JSON.stringify({
|
|
44173
44175
|
locale,
|
|
44174
|
-
...repoCanonical ? { repoCanonical } : {}
|
|
44176
|
+
...repoCanonical ? { repoCanonical } : {},
|
|
44177
|
+
...appId ? { appId } : {}
|
|
44175
44178
|
})
|
|
44176
44179
|
},
|
|
44177
44180
|
"Failed to remove locale"
|
|
@@ -44216,7 +44219,7 @@ var VocoderAPI = class {
|
|
|
44216
44219
|
}
|
|
44217
44220
|
// ── Project creation ──────────────────────────────────────────────────────────
|
|
44218
44221
|
async createProject(userToken, params) {
|
|
44219
|
-
const response = await fetch(`${this.apiUrl}/api/cli/
|
|
44222
|
+
const response = await fetch(`${this.apiUrl}/api/cli/apps`, {
|
|
44220
44223
|
method: "POST",
|
|
44221
44224
|
headers: {
|
|
44222
44225
|
"Content-Type": "application/json",
|
|
@@ -44254,16 +44257,17 @@ var VocoderAPI = class {
|
|
|
44254
44257
|
})
|
|
44255
44258
|
});
|
|
44256
44259
|
if (!response.ok) {
|
|
44257
|
-
return { exactMatch: null, existingApps: [], hasWholeRepoApp: false };
|
|
44260
|
+
return { exactMatch: null, existingApps: [], hasWholeRepoApp: false, organizationContext: null };
|
|
44258
44261
|
}
|
|
44259
44262
|
const data = await response.json();
|
|
44260
44263
|
return {
|
|
44261
44264
|
exactMatch: data.exactMatch ?? null,
|
|
44262
44265
|
existingApps: data.existingApps ?? [],
|
|
44263
|
-
hasWholeRepoApp: data.hasWholeRepoApp ?? false
|
|
44266
|
+
hasWholeRepoApp: data.hasWholeRepoApp ?? false,
|
|
44267
|
+
organizationContext: data.organizationContext ?? null
|
|
44264
44268
|
};
|
|
44265
44269
|
} catch {
|
|
44266
|
-
return { exactMatch: null, existingApps: [], hasWholeRepoApp: false };
|
|
44270
|
+
return { exactMatch: null, existingApps: [], hasWholeRepoApp: false, organizationContext: null };
|
|
44267
44271
|
}
|
|
44268
44272
|
}
|
|
44269
44273
|
/**
|
|
@@ -44271,7 +44275,7 @@ var VocoderAPI = class {
|
|
|
44271
44275
|
* Does not check plan limits — no new project is created.
|
|
44272
44276
|
*/
|
|
44273
44277
|
async createApp(userToken, params) {
|
|
44274
|
-
const response = await fetch(`${this.apiUrl}/api/cli/
|
|
44278
|
+
const response = await fetch(`${this.apiUrl}/api/cli/apps`, {
|
|
44275
44279
|
method: "POST",
|
|
44276
44280
|
headers: {
|
|
44277
44281
|
"Content-Type": "application/json",
|
|
@@ -44461,164 +44465,6 @@ function clearAuthData() {
|
|
|
44461
44465
|
}
|
|
44462
44466
|
}
|
|
44463
44467
|
|
|
44464
|
-
// src/utils/setup-snippets.ts
|
|
44465
|
-
function getSetupSnippets(params) {
|
|
44466
|
-
const { framework, ecosystem, sourceLocale } = params;
|
|
44467
|
-
return {
|
|
44468
|
-
pluginStep: getPluginSnippet(framework, ecosystem),
|
|
44469
|
-
providerStep: getProviderSnippet(ecosystem, sourceLocale),
|
|
44470
|
-
wrapStep: getWrapSnippet(ecosystem),
|
|
44471
|
-
whatsNext: "Push to a target branch to trigger translations."
|
|
44472
|
-
};
|
|
44473
|
-
}
|
|
44474
|
-
function getPluginSnippet(framework, ecosystem) {
|
|
44475
|
-
switch (framework) {
|
|
44476
|
-
case "nextjs":
|
|
44477
|
-
return {
|
|
44478
|
-
file: "next.config.ts",
|
|
44479
|
-
code: `import { withVocoder } from '@vocoder/plugin/next';
|
|
44480
|
-
|
|
44481
|
-
export default withVocoder({
|
|
44482
|
-
// your existing Next.js config
|
|
44483
|
-
});`
|
|
44484
|
-
};
|
|
44485
|
-
case "vite":
|
|
44486
|
-
case "remix":
|
|
44487
|
-
return {
|
|
44488
|
-
file: "vite.config.ts",
|
|
44489
|
-
code: `import vocoder from '@vocoder/plugin/vite';
|
|
44490
|
-
|
|
44491
|
-
export default defineConfig({
|
|
44492
|
-
plugins: [
|
|
44493
|
-
vocoder(),
|
|
44494
|
-
// your other plugins
|
|
44495
|
-
],
|
|
44496
|
-
});`
|
|
44497
|
-
};
|
|
44498
|
-
case "nuxt":
|
|
44499
|
-
return {
|
|
44500
|
-
file: "nuxt.config.ts",
|
|
44501
|
-
code: `import vocoder from '@vocoder/plugin/vite';
|
|
44502
|
-
|
|
44503
|
-
export default defineNuxtConfig({
|
|
44504
|
-
vite: {
|
|
44505
|
-
plugins: [vocoder()],
|
|
44506
|
-
},
|
|
44507
|
-
});`
|
|
44508
|
-
};
|
|
44509
|
-
case "sveltekit":
|
|
44510
|
-
return {
|
|
44511
|
-
file: "vite.config.ts",
|
|
44512
|
-
code: `import vocoder from '@vocoder/plugin/vite';
|
|
44513
|
-
import { sveltekit } from '@sveltejs/kit/vite';
|
|
44514
|
-
|
|
44515
|
-
export default defineConfig({
|
|
44516
|
-
plugins: [
|
|
44517
|
-
sveltekit(),
|
|
44518
|
-
vocoder(),
|
|
44519
|
-
],
|
|
44520
|
-
});`
|
|
44521
|
-
};
|
|
44522
|
-
case "gatsby":
|
|
44523
|
-
return {
|
|
44524
|
-
file: "gatsby-node.js",
|
|
44525
|
-
code: `const vocoder = require('@vocoder/plugin/webpack');
|
|
44526
|
-
|
|
44527
|
-
exports.onCreateWebpackConfig = ({ actions }) => {
|
|
44528
|
-
actions.setWebpackConfig({
|
|
44529
|
-
plugins: [vocoder()],
|
|
44530
|
-
});
|
|
44531
|
-
};`
|
|
44532
|
-
};
|
|
44533
|
-
case "angular":
|
|
44534
|
-
return null;
|
|
44535
|
-
// Angular CLI doesn't expose plugin config easily
|
|
44536
|
-
default:
|
|
44537
|
-
if (ecosystem) {
|
|
44538
|
-
return {
|
|
44539
|
-
file: "your bundler config",
|
|
44540
|
-
code: `// Vite
|
|
44541
|
-
import vocoder from '@vocoder/plugin/vite';
|
|
44542
|
-
// Webpack
|
|
44543
|
-
const vocoder = require('@vocoder/plugin/webpack');
|
|
44544
|
-
|
|
44545
|
-
// Add vocoder() to your plugins array`
|
|
44546
|
-
};
|
|
44547
|
-
}
|
|
44548
|
-
return null;
|
|
44549
|
-
}
|
|
44550
|
-
}
|
|
44551
|
-
function getProviderSnippet(ecosystem, sourceLocale) {
|
|
44552
|
-
switch (ecosystem) {
|
|
44553
|
-
case "react":
|
|
44554
|
-
return {
|
|
44555
|
-
file: "your root layout or App component",
|
|
44556
|
-
code: `import { VocoderProvider } from '@vocoder/react';
|
|
44557
|
-
|
|
44558
|
-
<VocoderProvider defaultLocale="${sourceLocale}">
|
|
44559
|
-
{children}
|
|
44560
|
-
</VocoderProvider>`
|
|
44561
|
-
};
|
|
44562
|
-
case "vue":
|
|
44563
|
-
return {
|
|
44564
|
-
file: "your app entry",
|
|
44565
|
-
code: `import { createVocoder } from '@vocoder/vue';
|
|
44566
|
-
|
|
44567
|
-
const vocoder = createVocoder({
|
|
44568
|
-
defaultLocale: '${sourceLocale}',
|
|
44569
|
-
});
|
|
44570
|
-
|
|
44571
|
-
app.use(vocoder);`
|
|
44572
|
-
};
|
|
44573
|
-
case "svelte":
|
|
44574
|
-
return {
|
|
44575
|
-
file: "your root layout",
|
|
44576
|
-
code: `<script>
|
|
44577
|
-
import { VocoderProvider } from '@vocoder/svelte';
|
|
44578
|
-
</script>
|
|
44579
|
-
|
|
44580
|
-
<VocoderProvider defaultLocale="${sourceLocale}">
|
|
44581
|
-
<slot />
|
|
44582
|
-
</VocoderProvider>`
|
|
44583
|
-
};
|
|
44584
|
-
default:
|
|
44585
|
-
return null;
|
|
44586
|
-
}
|
|
44587
|
-
}
|
|
44588
|
-
function getWrapSnippet(ecosystem) {
|
|
44589
|
-
switch (ecosystem) {
|
|
44590
|
-
case "react":
|
|
44591
|
-
return {
|
|
44592
|
-
code: `import { T } from '@vocoder/react';
|
|
44593
|
-
|
|
44594
|
-
<T>Hello, world!</T>`
|
|
44595
|
-
};
|
|
44596
|
-
case "vue":
|
|
44597
|
-
return {
|
|
44598
|
-
code: `<template>
|
|
44599
|
-
<T>Hello, world!</T>
|
|
44600
|
-
</template>
|
|
44601
|
-
|
|
44602
|
-
<script setup>
|
|
44603
|
-
import { T } from '@vocoder/vue';
|
|
44604
|
-
</script>`
|
|
44605
|
-
};
|
|
44606
|
-
case "svelte":
|
|
44607
|
-
return {
|
|
44608
|
-
code: `<script>
|
|
44609
|
-
import { T } from '@vocoder/svelte';
|
|
44610
|
-
</script>
|
|
44611
|
-
|
|
44612
|
-
<T>Hello, world!</T>`
|
|
44613
|
-
};
|
|
44614
|
-
default:
|
|
44615
|
-
return {
|
|
44616
|
-
code: `// Wrap translatable strings with <T>
|
|
44617
|
-
<T>Hello, world!</T>`
|
|
44618
|
-
};
|
|
44619
|
-
}
|
|
44620
|
-
}
|
|
44621
|
-
|
|
44622
44468
|
// ../extractor/src/config.ts
|
|
44623
44469
|
var import_parser = __toESM(require_lib());
|
|
44624
44470
|
var import_traverse = __toESM(require_lib8());
|
|
@@ -44691,8 +44537,11 @@ function extractFromObject(obj) {
|
|
|
44691
44537
|
if (key === "localesPath" && prop.value.type === "StringLiteral") {
|
|
44692
44538
|
config.localesPath = prop.value.value;
|
|
44693
44539
|
}
|
|
44540
|
+
if (key === "industry" && prop.value.type === "StringLiteral") {
|
|
44541
|
+
config.industry = prop.value.value;
|
|
44542
|
+
}
|
|
44694
44543
|
if (key === "appIndustry" && prop.value.type === "StringLiteral") {
|
|
44695
|
-
config.
|
|
44544
|
+
config.industry = prop.value.value;
|
|
44696
44545
|
}
|
|
44697
44546
|
if (key === "formality" && prop.value.type === "StringLiteral") {
|
|
44698
44547
|
config.formality = prop.value.value;
|
|
@@ -44702,8 +44551,7 @@ function extractFromObject(obj) {
|
|
|
44702
44551
|
}
|
|
44703
44552
|
|
|
44704
44553
|
// ../extractor/src/index.ts
|
|
44705
|
-
|
|
44706
|
-
var import_traverse2 = __toESM(require_lib8());
|
|
44554
|
+
import { createHash } from "crypto";
|
|
44707
44555
|
import { readFileSync as readFileSync4 } from "fs";
|
|
44708
44556
|
import { relative as pathRelative } from "path";
|
|
44709
44557
|
|
|
@@ -51077,9 +50925,16 @@ var glob = Object.assign(glob_, {
|
|
|
51077
50925
|
});
|
|
51078
50926
|
glob.glob = glob;
|
|
51079
50927
|
|
|
51080
|
-
// ../extractor/src/
|
|
51081
|
-
|
|
51082
|
-
|
|
50928
|
+
// ../extractor/src/parse/react.ts
|
|
50929
|
+
var import_parser3 = __toESM(require_lib());
|
|
50930
|
+
var import_traverse3 = __toESM(require_lib8());
|
|
50931
|
+
|
|
50932
|
+
// ../core/src/hash.ts
|
|
50933
|
+
function generateMessageHash(text, context, formality) {
|
|
50934
|
+
let input = context ? `${text}${context}` : text;
|
|
50935
|
+
if (formality === "formal" || formality === "informal") {
|
|
50936
|
+
input += `${formality}`;
|
|
50937
|
+
}
|
|
51083
50938
|
let h = 2166136261 >>> 0;
|
|
51084
50939
|
for (let i = 0; i < input.length; i++) {
|
|
51085
50940
|
h = Math.imul(h ^ input.charCodeAt(i), 16777619) >>> 0;
|
|
@@ -51087,10 +50942,10 @@ function generateMessageHash(text, context) {
|
|
|
51087
50942
|
return h.toString(36).padStart(7, "0");
|
|
51088
50943
|
}
|
|
51089
50944
|
|
|
51090
|
-
// ../
|
|
51091
|
-
var traverse2 = import_traverse2.default.default || import_traverse2.default;
|
|
50945
|
+
// ../core/src/icu-builders.ts
|
|
51092
50946
|
var PLURAL_CLDR = /* @__PURE__ */ new Set(["zero", "one", "two", "few", "many"]);
|
|
51093
50947
|
var ALL_CLDR = /* @__PURE__ */ new Set(["zero", "one", "two", "few", "many", "other"]);
|
|
50948
|
+
var DEFAULT_ORDINAL_ICU = "{count, selectordinal, other {#}}";
|
|
51094
50949
|
function buildPluralICU(props, ordinal = false) {
|
|
51095
50950
|
const type = ordinal ? "selectordinal" : "plural";
|
|
51096
50951
|
const exactParts = [];
|
|
@@ -51114,14 +50969,89 @@ function buildSelectICU(props) {
|
|
|
51114
50969
|
cases.push(`other {${text}}`);
|
|
51115
50970
|
} else {
|
|
51116
50971
|
const wordCase = key.match(/^_([a-zA-Z].*)$/);
|
|
51117
|
-
if (wordCase) {
|
|
51118
|
-
cases.push(`${wordCase[1]} {${text}}`);
|
|
51119
|
-
}
|
|
50972
|
+
if (wordCase) cases.push(`${wordCase[1]} {${text}}`);
|
|
51120
50973
|
}
|
|
51121
50974
|
}
|
|
51122
50975
|
if (!hasOther) cases.push("other {other}");
|
|
51123
50976
|
return `{value, select, ${cases.join(" ")}}`;
|
|
51124
50977
|
}
|
|
50978
|
+
|
|
50979
|
+
// ../extractor/src/shared/roles.ts
|
|
50980
|
+
function propNameToUiRole(propName) {
|
|
50981
|
+
switch (propName) {
|
|
50982
|
+
case "placeholder":
|
|
50983
|
+
return "input_placeholder";
|
|
50984
|
+
case "aria-label":
|
|
50985
|
+
case "aria-description":
|
|
50986
|
+
case "label":
|
|
50987
|
+
return "input_label";
|
|
50988
|
+
case "alt":
|
|
50989
|
+
return "image_alt";
|
|
50990
|
+
case "title":
|
|
50991
|
+
return "tooltip";
|
|
50992
|
+
default:
|
|
50993
|
+
return "unknown";
|
|
50994
|
+
}
|
|
50995
|
+
}
|
|
50996
|
+
function elementNameToUiRole(name) {
|
|
50997
|
+
if (!name) return "unknown";
|
|
50998
|
+
switch (name.toLowerCase()) {
|
|
50999
|
+
case "button":
|
|
51000
|
+
return "button_label";
|
|
51001
|
+
case "h1":
|
|
51002
|
+
case "h2":
|
|
51003
|
+
case "h3":
|
|
51004
|
+
case "h4":
|
|
51005
|
+
case "h5":
|
|
51006
|
+
case "h6":
|
|
51007
|
+
return "heading";
|
|
51008
|
+
case "label":
|
|
51009
|
+
return "input_label";
|
|
51010
|
+
case "th":
|
|
51011
|
+
return "table_header";
|
|
51012
|
+
case "option":
|
|
51013
|
+
return "option_label";
|
|
51014
|
+
case "title":
|
|
51015
|
+
return "page_title";
|
|
51016
|
+
case "p":
|
|
51017
|
+
case "li":
|
|
51018
|
+
case "dd":
|
|
51019
|
+
return "body_text";
|
|
51020
|
+
default: {
|
|
51021
|
+
const lower = name.toLowerCase();
|
|
51022
|
+
if (/button|btn|submit|cta/.test(lower)) return "button_label";
|
|
51023
|
+
if (/heading|headline/.test(lower)) return "heading";
|
|
51024
|
+
if (/label/.test(lower)) return "input_label";
|
|
51025
|
+
if (/tooltip|hint|popover/.test(lower)) return "tooltip";
|
|
51026
|
+
if (/badge|chip|tag|pill/.test(lower)) return "badge";
|
|
51027
|
+
if (/toast|snackbar|notification/.test(lower)) return "toast";
|
|
51028
|
+
if (/navitem|menuitem/.test(lower)) return "nav_item";
|
|
51029
|
+
return "unknown";
|
|
51030
|
+
}
|
|
51031
|
+
}
|
|
51032
|
+
}
|
|
51033
|
+
function detectUiRole(path2) {
|
|
51034
|
+
const parent = path2.parent;
|
|
51035
|
+
if (!parent) return "unknown";
|
|
51036
|
+
if (parent.type === "JSXExpressionContainer") {
|
|
51037
|
+
const attrNode = path2.parentPath?.parent;
|
|
51038
|
+
if (attrNode?.type === "JSXAttribute") {
|
|
51039
|
+
const propName = attrNode.name?.type === "JSXNamespacedName" ? `${attrNode.name.namespace.name}-${attrNode.name.name.name}` : attrNode.name?.name ?? "";
|
|
51040
|
+
return propNameToUiRole(propName);
|
|
51041
|
+
}
|
|
51042
|
+
}
|
|
51043
|
+
if (parent.type === "JSXElement") {
|
|
51044
|
+
const opening = parent.openingElement;
|
|
51045
|
+
const tagName = opening?.name?.type === "JSXMemberExpression" ? "unknown" : opening?.name?.name ?? "";
|
|
51046
|
+
return elementNameToUiRole(tagName);
|
|
51047
|
+
}
|
|
51048
|
+
return "unknown";
|
|
51049
|
+
}
|
|
51050
|
+
|
|
51051
|
+
// ../extractor/src/shared/transform.ts
|
|
51052
|
+
var import_parser2 = __toESM(require_lib());
|
|
51053
|
+
var import_traverse2 = __toESM(require_lib8());
|
|
51054
|
+
var traverse2 = import_traverse2.default.default || import_traverse2.default;
|
|
51125
51055
|
function extractTextContentFromNodes(children, ctx) {
|
|
51126
51056
|
let text = "";
|
|
51127
51057
|
for (const child of children) {
|
|
@@ -51185,140 +51115,109 @@ function extractTextContentFromNodes(children, ctx) {
|
|
|
51185
51115
|
}
|
|
51186
51116
|
return text;
|
|
51187
51117
|
}
|
|
51188
|
-
|
|
51189
|
-
|
|
51190
|
-
|
|
51191
|
-
|
|
51192
|
-
|
|
51193
|
-
|
|
51194
|
-
|
|
51195
|
-
|
|
51196
|
-
|
|
51197
|
-
|
|
51198
|
-
|
|
51199
|
-
|
|
51200
|
-
|
|
51201
|
-
|
|
51202
|
-
for (const includePattern of includePatterns) {
|
|
51203
|
-
const files = await glob(includePattern, {
|
|
51204
|
-
cwd: projectRoot,
|
|
51205
|
-
absolute: true,
|
|
51206
|
-
ignore: ignorePatterns
|
|
51207
|
-
});
|
|
51208
|
-
for (const file of files) allFiles.add(file);
|
|
51209
|
-
}
|
|
51210
|
-
const allStrings = [];
|
|
51211
|
-
const sortedFiles = Array.from(allFiles).sort();
|
|
51212
|
-
for (const file of sortedFiles) {
|
|
51213
|
-
try {
|
|
51214
|
-
const code = readFileSync4(file, "utf-8");
|
|
51215
|
-
const relPath = pathRelative(projectRoot, file).split("\\").join("/");
|
|
51216
|
-
const strings = _extractFromContent(relPath, code);
|
|
51217
|
-
allStrings.push(...strings);
|
|
51218
|
-
} catch (error) {
|
|
51219
|
-
console.warn(`Warning: Failed to extract from ${file}:`, error);
|
|
51118
|
+
|
|
51119
|
+
// ../extractor/src/parse/react.ts
|
|
51120
|
+
var traverse3 = import_traverse3.default.default || import_traverse3.default;
|
|
51121
|
+
function extractTemplateText(node) {
|
|
51122
|
+
let text = "";
|
|
51123
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
51124
|
+
const quasi = node.quasis[i];
|
|
51125
|
+
text += quasi.value.raw;
|
|
51126
|
+
if (i < node.expressions.length) {
|
|
51127
|
+
const expr = node.expressions[i];
|
|
51128
|
+
if (expr.type === "Identifier") {
|
|
51129
|
+
text += `{${expr.name}}`;
|
|
51130
|
+
} else {
|
|
51131
|
+
text += "{value}";
|
|
51220
51132
|
}
|
|
51221
51133
|
}
|
|
51222
|
-
return deduplicateStrings(allStrings);
|
|
51223
51134
|
}
|
|
51224
|
-
|
|
51225
|
-
|
|
51226
|
-
|
|
51227
|
-
|
|
51228
|
-
|
|
51229
|
-
|
|
51230
|
-
|
|
51231
|
-
|
|
51232
|
-
|
|
51233
|
-
|
|
51234
|
-
|
|
51235
|
-
|
|
51236
|
-
|
|
51237
|
-
|
|
51238
|
-
return "unknown";
|
|
51135
|
+
return text;
|
|
51136
|
+
}
|
|
51137
|
+
function getStringAttribute(attributes, name) {
|
|
51138
|
+
const attr = attributes.find(
|
|
51139
|
+
(a) => a.type === "JSXAttribute" && a.name.name === name
|
|
51140
|
+
);
|
|
51141
|
+
if (!attr || !attr.value) return void 0;
|
|
51142
|
+
if (attr.value.type === "StringLiteral") {
|
|
51143
|
+
return attr.value.value;
|
|
51144
|
+
}
|
|
51145
|
+
if (attr.value.type === "JSXExpressionContainer") {
|
|
51146
|
+
const expr = attr.value.expression;
|
|
51147
|
+
if (expr.type === "TemplateLiteral") return extractTemplateText(expr);
|
|
51148
|
+
if (expr.type === "StringLiteral") return expr.value;
|
|
51239
51149
|
}
|
|
51150
|
+
return void 0;
|
|
51240
51151
|
}
|
|
51241
|
-
function
|
|
51242
|
-
|
|
51243
|
-
|
|
51244
|
-
|
|
51245
|
-
|
|
51246
|
-
|
|
51247
|
-
|
|
51248
|
-
|
|
51249
|
-
|
|
51250
|
-
|
|
51251
|
-
|
|
51252
|
-
|
|
51253
|
-
|
|
51254
|
-
|
|
51255
|
-
|
|
51256
|
-
|
|
51257
|
-
|
|
51258
|
-
|
|
51259
|
-
|
|
51260
|
-
|
|
51261
|
-
|
|
51262
|
-
|
|
51263
|
-
|
|
51264
|
-
|
|
51265
|
-
|
|
51266
|
-
|
|
51267
|
-
|
|
51268
|
-
|
|
51269
|
-
|
|
51270
|
-
if (/label/.test(lower)) return "input_label";
|
|
51271
|
-
if (/tooltip|hint|popover/.test(lower)) return "tooltip";
|
|
51272
|
-
if (/badge|chip|tag|pill/.test(lower)) return "badge";
|
|
51273
|
-
if (/toast|snackbar|notification/.test(lower)) return "toast";
|
|
51274
|
-
if (/navitem|menuitem/.test(lower)) return "nav_item";
|
|
51275
|
-
return "unknown";
|
|
51152
|
+
function extractPluralSelectICU(attributes) {
|
|
51153
|
+
const pluralProps = {};
|
|
51154
|
+
const selectProps = {};
|
|
51155
|
+
let otherValue;
|
|
51156
|
+
let hasPlural = false;
|
|
51157
|
+
let hasSelect = false;
|
|
51158
|
+
let isOrdinal = false;
|
|
51159
|
+
let hasGender = false;
|
|
51160
|
+
for (const attr of attributes) {
|
|
51161
|
+
if (attr.type !== "JSXAttribute") continue;
|
|
51162
|
+
const name = attr.name.name;
|
|
51163
|
+
if (name === "ordinal") {
|
|
51164
|
+
isOrdinal = true;
|
|
51165
|
+
continue;
|
|
51166
|
+
}
|
|
51167
|
+
if (name === "gender") {
|
|
51168
|
+
hasGender = true;
|
|
51169
|
+
continue;
|
|
51170
|
+
}
|
|
51171
|
+
const value = attr.value?.type === "StringLiteral" ? attr.value.value : null;
|
|
51172
|
+
if (!value) continue;
|
|
51173
|
+
if (PLURAL_CLDR.has(name) || /^_\d+$/.test(name)) {
|
|
51174
|
+
pluralProps[name] = value;
|
|
51175
|
+
hasPlural = true;
|
|
51176
|
+
} else if (name === "other") {
|
|
51177
|
+
otherValue = value;
|
|
51178
|
+
} else if (/^_[a-zA-Z]/.test(name)) {
|
|
51179
|
+
selectProps[name] = value;
|
|
51180
|
+
hasSelect = true;
|
|
51276
51181
|
}
|
|
51277
51182
|
}
|
|
51278
|
-
|
|
51279
|
-
|
|
51280
|
-
|
|
51281
|
-
|
|
51282
|
-
if (parent.type === "JSXExpressionContainer") {
|
|
51283
|
-
const attrNode = path2.parentPath?.parent;
|
|
51284
|
-
if (attrNode?.type === "JSXAttribute") {
|
|
51285
|
-
const propName = attrNode.name?.type === "JSXNamespacedName" ? `${attrNode.name.namespace.name}-${attrNode.name.name.name}` : attrNode.name?.name ?? "";
|
|
51286
|
-
return propNameToUiRole(propName);
|
|
51183
|
+
if (isOrdinal) {
|
|
51184
|
+
const ordinalICU = DEFAULT_ORDINAL_ICU;
|
|
51185
|
+
if (hasGender) {
|
|
51186
|
+
return `{gender, select, masculine {${ordinalICU}} feminine {${ordinalICU}} other {${ordinalICU}}}`;
|
|
51287
51187
|
}
|
|
51188
|
+
return ordinalICU;
|
|
51288
51189
|
}
|
|
51289
|
-
if (
|
|
51290
|
-
|
|
51291
|
-
|
|
51292
|
-
return
|
|
51190
|
+
if (!hasPlural && !hasSelect) return null;
|
|
51191
|
+
if (hasPlural) {
|
|
51192
|
+
if (otherValue !== void 0) pluralProps.other = otherValue;
|
|
51193
|
+
return buildPluralICU(pluralProps, false);
|
|
51293
51194
|
}
|
|
51294
|
-
|
|
51195
|
+
if (hasSelect) {
|
|
51196
|
+
if (otherValue !== void 0) selectProps.other = otherValue;
|
|
51197
|
+
return buildSelectICU(selectProps);
|
|
51198
|
+
}
|
|
51199
|
+
return null;
|
|
51295
51200
|
}
|
|
51296
|
-
function
|
|
51201
|
+
function extractFromContent(filePath, content) {
|
|
51297
51202
|
const strings = [];
|
|
51298
51203
|
try {
|
|
51299
|
-
const ast = (0,
|
|
51204
|
+
const ast = (0, import_parser3.parse)(content, {
|
|
51300
51205
|
sourceType: "module",
|
|
51301
51206
|
plugins: ["jsx", "typescript"]
|
|
51302
51207
|
});
|
|
51303
51208
|
const vocoderImports = /* @__PURE__ */ new Map();
|
|
51304
51209
|
const tFunctionNames = /* @__PURE__ */ new Set();
|
|
51305
|
-
|
|
51210
|
+
traverse3(ast, {
|
|
51306
51211
|
ImportDeclaration: (path2) => {
|
|
51307
|
-
|
|
51308
|
-
|
|
51309
|
-
|
|
51310
|
-
|
|
51311
|
-
|
|
51312
|
-
|
|
51313
|
-
|
|
51314
|
-
|
|
51315
|
-
|
|
51316
|
-
if (imported === "t") {
|
|
51317
|
-
tFunctionNames.add(local);
|
|
51318
|
-
}
|
|
51319
|
-
}
|
|
51320
|
-
});
|
|
51321
|
-
}
|
|
51212
|
+
if (path2.node.source.value !== "@vocoder/react") return;
|
|
51213
|
+
path2.node.specifiers.forEach((spec) => {
|
|
51214
|
+
if (spec.type === "ImportSpecifier") {
|
|
51215
|
+
const imported = spec.imported.type === "Identifier" ? spec.imported.name : null;
|
|
51216
|
+
const local = spec.local.name;
|
|
51217
|
+
if (imported === "T") vocoderImports.set(local, "T");
|
|
51218
|
+
if (imported === "t") tFunctionNames.add(local);
|
|
51219
|
+
}
|
|
51220
|
+
});
|
|
51322
51221
|
},
|
|
51323
51222
|
VariableDeclarator: (path2) => {
|
|
51324
51223
|
const init = path2.node.init;
|
|
@@ -51364,7 +51263,7 @@ function _extractFromContent(filePath, content) {
|
|
|
51364
51263
|
});
|
|
51365
51264
|
}
|
|
51366
51265
|
const line = path2.node.loc?.start.line || 0;
|
|
51367
|
-
const key = explicitKey && explicitKey.length > 0 ? explicitKey : generateMessageHash(text.trim(), context);
|
|
51266
|
+
const key = explicitKey && explicitKey.length > 0 ? explicitKey + (formality === "formal" || formality === "informal" ? `${formality}` : "") : generateMessageHash(text.trim(), context, formality);
|
|
51368
51267
|
const uiRole = detectUiRole(path2);
|
|
51369
51268
|
strings.push({
|
|
51370
51269
|
key,
|
|
@@ -51403,19 +51302,21 @@ function _extractFromContent(filePath, content) {
|
|
|
51403
51302
|
if (extractCtx.bail) return;
|
|
51404
51303
|
}
|
|
51405
51304
|
}
|
|
51406
|
-
if (!text || text.trim().length === 0) return;
|
|
51407
51305
|
const id = getStringAttribute(opening.attributes, "id");
|
|
51408
51306
|
const context = getStringAttribute(opening.attributes, "context");
|
|
51409
51307
|
const formality = getStringAttribute(
|
|
51410
51308
|
opening.attributes,
|
|
51411
51309
|
"formality"
|
|
51412
51310
|
);
|
|
51311
|
+
const trimmedId = id?.trim() || void 0;
|
|
51312
|
+
const trimmedText = text?.trim() || void 0;
|
|
51313
|
+
if (!trimmedText && !trimmedId) return;
|
|
51413
51314
|
const line = path2.node.loc?.start.line || 0;
|
|
51414
|
-
const key =
|
|
51315
|
+
const key = trimmedId ? trimmedId + (formality === "formal" || formality === "informal" ? `${formality}` : "") : generateMessageHash(trimmedText, context, formality);
|
|
51415
51316
|
const uiRole = detectUiRole(path2);
|
|
51416
51317
|
strings.push({
|
|
51417
51318
|
key,
|
|
51418
|
-
text:
|
|
51319
|
+
text: trimmedText ?? null,
|
|
51419
51320
|
file: filePath,
|
|
51420
51321
|
line,
|
|
51421
51322
|
context,
|
|
@@ -51431,90 +51332,49 @@ function _extractFromContent(filePath, content) {
|
|
|
51431
51332
|
}
|
|
51432
51333
|
return strings;
|
|
51433
51334
|
}
|
|
51434
|
-
|
|
51435
|
-
|
|
51436
|
-
|
|
51437
|
-
|
|
51438
|
-
|
|
51439
|
-
let hasSelect = false;
|
|
51440
|
-
let isOrdinal = false;
|
|
51441
|
-
let hasGender = false;
|
|
51442
|
-
for (const attr of attributes) {
|
|
51443
|
-
if (attr.type !== "JSXAttribute") continue;
|
|
51444
|
-
const name = attr.name.name;
|
|
51445
|
-
if (name === "ordinal") {
|
|
51446
|
-
isOrdinal = true;
|
|
51447
|
-
continue;
|
|
51448
|
-
}
|
|
51449
|
-
if (name === "gender") {
|
|
51450
|
-
hasGender = true;
|
|
51451
|
-
continue;
|
|
51452
|
-
}
|
|
51453
|
-
const value = attr.value?.type === "StringLiteral" ? attr.value.value : null;
|
|
51454
|
-
if (!value) continue;
|
|
51455
|
-
if (PLURAL_CLDR.has(name) || /^_\d+$/.test(name)) {
|
|
51456
|
-
pluralProps[name] = value;
|
|
51457
|
-
hasPlural = true;
|
|
51458
|
-
} else if (name === "other") {
|
|
51459
|
-
otherValue = value;
|
|
51460
|
-
} else if (/^_[a-zA-Z]/.test(name)) {
|
|
51461
|
-
selectProps[name] = value;
|
|
51462
|
-
hasSelect = true;
|
|
51463
|
-
}
|
|
51464
|
-
}
|
|
51465
|
-
if (isOrdinal) {
|
|
51466
|
-
const ordinalICU = "{count, selectordinal, other {#}}";
|
|
51467
|
-
if (hasGender) {
|
|
51468
|
-
return `{gender, select, masculine {${ordinalICU}} feminine {${ordinalICU}} other {${ordinalICU}}}`;
|
|
51469
|
-
}
|
|
51470
|
-
return ordinalICU;
|
|
51471
|
-
}
|
|
51472
|
-
if (!hasPlural && !hasSelect) return null;
|
|
51473
|
-
if (hasPlural) {
|
|
51474
|
-
if (otherValue !== void 0) pluralProps.other = otherValue;
|
|
51475
|
-
return buildPluralICU(pluralProps, false);
|
|
51476
|
-
}
|
|
51477
|
-
if (hasSelect) {
|
|
51478
|
-
if (otherValue !== void 0) selectProps.other = otherValue;
|
|
51479
|
-
return buildSelectICU(selectProps);
|
|
51480
|
-
}
|
|
51481
|
-
return null;
|
|
51482
|
-
}
|
|
51483
|
-
function extractTemplateText(node) {
|
|
51484
|
-
let text = "";
|
|
51485
|
-
for (let i = 0; i < node.quasis.length; i++) {
|
|
51486
|
-
const quasi = node.quasis[i];
|
|
51487
|
-
text += quasi.value.raw;
|
|
51488
|
-
if (i < node.expressions.length) {
|
|
51489
|
-
const expr = node.expressions[i];
|
|
51490
|
-
if (expr.type === "Identifier") {
|
|
51491
|
-
text += `{${expr.name}}`;
|
|
51492
|
-
} else {
|
|
51493
|
-
text += "{value}";
|
|
51494
|
-
}
|
|
51495
|
-
}
|
|
51496
|
-
}
|
|
51497
|
-
return text;
|
|
51335
|
+
|
|
51336
|
+
// ../extractor/src/index.ts
|
|
51337
|
+
function computeFingerprint(appShortCode, sourceKeys) {
|
|
51338
|
+
const sorted = [...sourceKeys].sort();
|
|
51339
|
+
return createHash("sha256").update(`${appShortCode}:${sorted.join("\0")}`).digest("hex").slice(0, 12);
|
|
51498
51340
|
}
|
|
51499
|
-
|
|
51500
|
-
|
|
51501
|
-
|
|
51502
|
-
|
|
51503
|
-
|
|
51504
|
-
|
|
51505
|
-
|
|
51506
|
-
|
|
51507
|
-
|
|
51508
|
-
const
|
|
51509
|
-
|
|
51510
|
-
|
|
51341
|
+
var StringExtractor = class {
|
|
51342
|
+
async extractFromProject(pattern, projectRoot = process.cwd(), excludePattern) {
|
|
51343
|
+
const includePatterns = Array.isArray(pattern) ? pattern : [pattern];
|
|
51344
|
+
const defaultIgnore = [
|
|
51345
|
+
"**/node_modules/**",
|
|
51346
|
+
"**/.next/**",
|
|
51347
|
+
"**/dist/**",
|
|
51348
|
+
"**/build/**"
|
|
51349
|
+
];
|
|
51350
|
+
const ignorePatterns = excludePattern ? [
|
|
51351
|
+
...defaultIgnore,
|
|
51352
|
+
...Array.isArray(excludePattern) ? excludePattern : [excludePattern]
|
|
51353
|
+
] : defaultIgnore;
|
|
51354
|
+
const allFiles = /* @__PURE__ */ new Set();
|
|
51355
|
+
for (const includePattern of includePatterns) {
|
|
51356
|
+
const files = await glob(includePattern, {
|
|
51357
|
+
cwd: projectRoot,
|
|
51358
|
+
absolute: true,
|
|
51359
|
+
ignore: ignorePatterns
|
|
51360
|
+
});
|
|
51361
|
+
for (const file of files) allFiles.add(file);
|
|
51511
51362
|
}
|
|
51512
|
-
|
|
51513
|
-
|
|
51363
|
+
const allStrings = [];
|
|
51364
|
+
const sortedFiles = Array.from(allFiles).sort();
|
|
51365
|
+
for (const file of sortedFiles) {
|
|
51366
|
+
try {
|
|
51367
|
+
const code = readFileSync4(file, "utf-8");
|
|
51368
|
+
const relPath = pathRelative(projectRoot, file).split("\\").join("/");
|
|
51369
|
+
const strings = extractFromContent(relPath, code);
|
|
51370
|
+
allStrings.push(...strings);
|
|
51371
|
+
} catch (error) {
|
|
51372
|
+
console.warn(`Warning: Failed to extract from ${file}:`, error);
|
|
51373
|
+
}
|
|
51514
51374
|
}
|
|
51375
|
+
return deduplicateStrings(allStrings);
|
|
51515
51376
|
}
|
|
51516
|
-
|
|
51517
|
-
}
|
|
51377
|
+
};
|
|
51518
51378
|
function deduplicateStrings(strings) {
|
|
51519
51379
|
const seen = /* @__PURE__ */ new Set();
|
|
51520
51380
|
const unique = [];
|
|
@@ -51537,8 +51397,8 @@ export {
|
|
|
51537
51397
|
writeAuthData,
|
|
51538
51398
|
verifyStoredAuth,
|
|
51539
51399
|
clearAuthData,
|
|
51540
|
-
getSetupSnippets,
|
|
51541
51400
|
loadVocoderConfig,
|
|
51401
|
+
computeFingerprint,
|
|
51542
51402
|
StringExtractor
|
|
51543
51403
|
};
|
|
51544
|
-
//# sourceMappingURL=chunk-
|
|
51404
|
+
//# sourceMappingURL=chunk-IK4ZCESQ.mjs.map
|