lingo.dev 0.117.7 → 0.117.9
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/build/cli.cjs +645 -151
- package/build/cli.cjs.map +1 -1
- package/build/cli.mjs +522 -28
- package/build/cli.mjs.map +1 -1
- package/package.json +5 -5
package/build/cli.mjs
CHANGED
|
@@ -2321,9 +2321,119 @@ function _isMetadataKey(key) {
|
|
|
2321
2321
|
return key.startsWith("@");
|
|
2322
2322
|
}
|
|
2323
2323
|
|
|
2324
|
+
// src/cli/loaders/ail.ts
|
|
2325
|
+
import { parseStringPromise, Builder } from "xml2js";
|
|
2326
|
+
function createAilLoader() {
|
|
2327
|
+
return createLoader({
|
|
2328
|
+
async pull(locale, input2) {
|
|
2329
|
+
const result = {};
|
|
2330
|
+
if (!input2 || !input2.trim()) {
|
|
2331
|
+
return result;
|
|
2332
|
+
}
|
|
2333
|
+
try {
|
|
2334
|
+
const parsed = await parseStringPromise(input2, {
|
|
2335
|
+
explicitArray: true,
|
|
2336
|
+
// Always use arrays for consistency
|
|
2337
|
+
mergeAttrs: false,
|
|
2338
|
+
// Keep attributes separate in $
|
|
2339
|
+
trim: true,
|
|
2340
|
+
explicitRoot: true
|
|
2341
|
+
});
|
|
2342
|
+
const dictionary = parsed.DICTIONARY;
|
|
2343
|
+
if (!dictionary) {
|
|
2344
|
+
return result;
|
|
2345
|
+
}
|
|
2346
|
+
const entries = dictionary.ENTRY || [];
|
|
2347
|
+
for (const entry of entries) {
|
|
2348
|
+
const id = entry.$?.id;
|
|
2349
|
+
if (!id) {
|
|
2350
|
+
continue;
|
|
2351
|
+
}
|
|
2352
|
+
const strings = entry.STRING || [];
|
|
2353
|
+
const sourceString = strings.find(
|
|
2354
|
+
(s) => s.$?.lang === locale
|
|
2355
|
+
);
|
|
2356
|
+
if (sourceString?.$.value) {
|
|
2357
|
+
result[id] = sourceString.$.value;
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
return result;
|
|
2361
|
+
} catch (error) {
|
|
2362
|
+
console.error("Failed to parse AIL file:", error);
|
|
2363
|
+
return result;
|
|
2364
|
+
}
|
|
2365
|
+
},
|
|
2366
|
+
async push(locale, data, originalInput) {
|
|
2367
|
+
if (!originalInput || !originalInput.trim()) {
|
|
2368
|
+
const dictionary = {
|
|
2369
|
+
$: { type: "multilanguage" },
|
|
2370
|
+
ENTRY: Object.entries(data).map(([id, value]) => ({
|
|
2371
|
+
$: { id },
|
|
2372
|
+
STRING: [
|
|
2373
|
+
{
|
|
2374
|
+
$: { lang: locale, value }
|
|
2375
|
+
}
|
|
2376
|
+
]
|
|
2377
|
+
}))
|
|
2378
|
+
};
|
|
2379
|
+
const builder = new Builder({
|
|
2380
|
+
xmldec: { version: "1.0", encoding: "UTF-8" },
|
|
2381
|
+
headless: false
|
|
2382
|
+
});
|
|
2383
|
+
return builder.buildObject({ DICTIONARY: dictionary });
|
|
2384
|
+
}
|
|
2385
|
+
try {
|
|
2386
|
+
const parsed = await parseStringPromise(originalInput, {
|
|
2387
|
+
explicitArray: true,
|
|
2388
|
+
mergeAttrs: false,
|
|
2389
|
+
trim: true,
|
|
2390
|
+
explicitRoot: true
|
|
2391
|
+
});
|
|
2392
|
+
const dictionary = parsed.DICTIONARY;
|
|
2393
|
+
if (!dictionary) {
|
|
2394
|
+
throw new Error("No DICTIONARY root element found");
|
|
2395
|
+
}
|
|
2396
|
+
const entries = dictionary.ENTRY || [];
|
|
2397
|
+
for (const [id, value] of Object.entries(data)) {
|
|
2398
|
+
let entry = entries.find((e) => e.$?.id === id);
|
|
2399
|
+
if (!entry) {
|
|
2400
|
+
entry = {
|
|
2401
|
+
$: { id },
|
|
2402
|
+
STRING: []
|
|
2403
|
+
};
|
|
2404
|
+
entries.push(entry);
|
|
2405
|
+
}
|
|
2406
|
+
if (!entry.STRING) {
|
|
2407
|
+
entry.STRING = [];
|
|
2408
|
+
}
|
|
2409
|
+
let targetString = entry.STRING.find(
|
|
2410
|
+
(s) => s.$?.lang === locale
|
|
2411
|
+
);
|
|
2412
|
+
if (targetString) {
|
|
2413
|
+
targetString.$.value = value;
|
|
2414
|
+
} else {
|
|
2415
|
+
entry.STRING.push({
|
|
2416
|
+
$: { lang: locale, value }
|
|
2417
|
+
});
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
dictionary.ENTRY = entries;
|
|
2421
|
+
const builder = new Builder({
|
|
2422
|
+
xmldec: { version: "1.0", encoding: "UTF-8" },
|
|
2423
|
+
headless: false
|
|
2424
|
+
});
|
|
2425
|
+
return builder.buildObject({ DICTIONARY: dictionary });
|
|
2426
|
+
} catch (error) {
|
|
2427
|
+
console.error("Failed to build AIL file:", error);
|
|
2428
|
+
throw error;
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
});
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2324
2434
|
// src/cli/loaders/android.ts
|
|
2325
2435
|
import { createRequire } from "module";
|
|
2326
|
-
import { parseStringPromise } from "xml2js";
|
|
2436
|
+
import { parseStringPromise as parseStringPromise2 } from "xml2js";
|
|
2327
2437
|
var require2 = createRequire(import.meta.url);
|
|
2328
2438
|
var sax = require2("sax");
|
|
2329
2439
|
var defaultAndroidResourcesXml = `<?xml version="1.0" encoding="utf-8"?>
|
|
@@ -2401,7 +2511,7 @@ function resolveXmlDeclaration(xml) {
|
|
|
2401
2511
|
}
|
|
2402
2512
|
async function parseAndroidDocument(input2) {
|
|
2403
2513
|
const xmlToParse = input2 && input2.trim().length > 0 ? input2 : defaultAndroidResourcesXml;
|
|
2404
|
-
const parsed = await
|
|
2514
|
+
const parsed = await parseStringPromise2(xmlToParse, {
|
|
2405
2515
|
explicitArray: true,
|
|
2406
2516
|
explicitChildren: true,
|
|
2407
2517
|
preserveChildrenOrder: true,
|
|
@@ -3403,8 +3513,8 @@ function serializeElement(node) {
|
|
|
3403
3513
|
const attrString = Object.entries(attributes).map(([key, value]) => ` ${key}="${escapeAttributeValue(String(value))}"`).join("");
|
|
3404
3514
|
const children = Array.isArray(node.$$) ? node.$$ : [];
|
|
3405
3515
|
if (children.length === 0) {
|
|
3406
|
-
const
|
|
3407
|
-
return `<${name}${attrString}>${
|
|
3516
|
+
const textContent3 = node._ ?? "";
|
|
3517
|
+
return `<${name}${attrString}>${textContent3}</${name}>`;
|
|
3408
3518
|
}
|
|
3409
3519
|
const childContent = children.map(serializeElement).join("");
|
|
3410
3520
|
return `<${name}${attrString}>${childContent}</${name}>`;
|
|
@@ -4005,7 +4115,7 @@ function applyTranslations(node, path19, data, pathMap) {
|
|
|
4005
4115
|
}
|
|
4006
4116
|
|
|
4007
4117
|
// src/cli/loaders/mjml.ts
|
|
4008
|
-
import { parseStringPromise as
|
|
4118
|
+
import { parseStringPromise as parseStringPromise3 } from "xml2js";
|
|
4009
4119
|
import * as htmlparser22 from "htmlparser2";
|
|
4010
4120
|
import { DomHandler as DomHandler2 } from "domhandler";
|
|
4011
4121
|
var LOCALIZABLE_COMPONENTS = [
|
|
@@ -4037,7 +4147,7 @@ function createMjmlLoader() {
|
|
|
4037
4147
|
async pull(locale, input2) {
|
|
4038
4148
|
const result = {};
|
|
4039
4149
|
try {
|
|
4040
|
-
const parsed = await
|
|
4150
|
+
const parsed = await parseStringPromise3(input2, {
|
|
4041
4151
|
explicitArray: true,
|
|
4042
4152
|
explicitChildren: true,
|
|
4043
4153
|
preserveChildrenOrder: true,
|
|
@@ -4083,7 +4193,7 @@ function createMjmlLoader() {
|
|
|
4083
4193
|
},
|
|
4084
4194
|
async push(locale, data, originalInput) {
|
|
4085
4195
|
try {
|
|
4086
|
-
const parsed = await
|
|
4196
|
+
const parsed = await parseStringPromise3(originalInput || "", {
|
|
4087
4197
|
explicitArray: true,
|
|
4088
4198
|
explicitChildren: true,
|
|
4089
4199
|
preserveChildrenOrder: true,
|
|
@@ -4190,9 +4300,9 @@ function serializeXmlNode(node) {
|
|
|
4190
4300
|
const attrString = Object.entries(attrs).map(([key, value]) => ` ${key}="${escapeAttributeValue2(String(value))}"`).join("");
|
|
4191
4301
|
const children = node.$$ || [];
|
|
4192
4302
|
if (children.length === 0) {
|
|
4193
|
-
const
|
|
4194
|
-
if (
|
|
4195
|
-
return `<${name}${attrString}>${
|
|
4303
|
+
const textContent3 = node._ || "";
|
|
4304
|
+
if (textContent3) {
|
|
4305
|
+
return `<${name}${attrString}>${textContent3}</${name}>`;
|
|
4196
4306
|
}
|
|
4197
4307
|
return `<${name}${attrString} />`;
|
|
4198
4308
|
}
|
|
@@ -4249,9 +4359,9 @@ function serializeElement2(node, indent2 = "") {
|
|
|
4249
4359
|
const attrString = Object.entries(attributes).map(([key, value]) => ` ${key}="${escapeAttributeValue2(String(value))}"`).join("");
|
|
4250
4360
|
const children = Array.isArray(node.$$) ? node.$$ : [];
|
|
4251
4361
|
if (children.length === 0) {
|
|
4252
|
-
const
|
|
4253
|
-
if (
|
|
4254
|
-
return `${indent2}<${name}${attrString}>${
|
|
4362
|
+
const textContent3 = node._ ?? "";
|
|
4363
|
+
if (textContent3) {
|
|
4364
|
+
return `${indent2}<${name}${attrString}>${textContent3}</${name}>`;
|
|
4255
4365
|
}
|
|
4256
4366
|
return `${indent2}<${name}${attrString} />`;
|
|
4257
4367
|
}
|
|
@@ -5810,10 +5920,10 @@ function formatXml(xml) {
|
|
|
5810
5920
|
if (cdataNode) {
|
|
5811
5921
|
return `${indent2}${openTag}<![CDATA[${cdataNode.nodeValue}]]></${tagName}>`;
|
|
5812
5922
|
}
|
|
5813
|
-
const
|
|
5923
|
+
const textContent3 = element.textContent?.trim() || "";
|
|
5814
5924
|
const hasOnlyText = element.childNodes.length === 1 && element.childNodes[0].nodeType === 3;
|
|
5815
|
-
if (hasOnlyText &&
|
|
5816
|
-
return `${indent2}${openTag}${
|
|
5925
|
+
if (hasOnlyText && textContent3) {
|
|
5926
|
+
return `${indent2}${openTag}${textContent3}</${tagName}>`;
|
|
5817
5927
|
}
|
|
5818
5928
|
const children = Array.from(element.children);
|
|
5819
5929
|
if (children.length === 0) {
|
|
@@ -5865,7 +5975,7 @@ function pushNewFile(locale, translations, originalLocale) {
|
|
|
5865
5975
|
}
|
|
5866
5976
|
|
|
5867
5977
|
// src/cli/loaders/xml.ts
|
|
5868
|
-
import { parseStringPromise as
|
|
5978
|
+
import { parseStringPromise as parseStringPromise4, Builder as Builder3 } from "xml2js";
|
|
5869
5979
|
function normalizeXMLString(xmlString) {
|
|
5870
5980
|
return xmlString.replace(/\s+/g, " ").replace(/>\s+</g, "><").replace("\n", "").trim();
|
|
5871
5981
|
}
|
|
@@ -5874,7 +5984,7 @@ function createXmlLoader() {
|
|
|
5874
5984
|
async pull(locale, input2) {
|
|
5875
5985
|
let result = {};
|
|
5876
5986
|
try {
|
|
5877
|
-
const parsed = await
|
|
5987
|
+
const parsed = await parseStringPromise4(input2, {
|
|
5878
5988
|
explicitArray: false,
|
|
5879
5989
|
mergeAttrs: false,
|
|
5880
5990
|
normalize: true,
|
|
@@ -5892,7 +6002,7 @@ function createXmlLoader() {
|
|
|
5892
6002
|
},
|
|
5893
6003
|
async push(locale, data) {
|
|
5894
6004
|
try {
|
|
5895
|
-
const builder = new
|
|
6005
|
+
const builder = new Builder3({ headless: true });
|
|
5896
6006
|
const xmlOutput = builder.buildObject(data);
|
|
5897
6007
|
const expectedOutput = normalizeXMLString(xmlOutput);
|
|
5898
6008
|
return expectedOutput;
|
|
@@ -9133,14 +9243,14 @@ function parseEjsForTranslation(input2) {
|
|
|
9133
9243
|
if (part.type === "ejs") {
|
|
9134
9244
|
template += part.content;
|
|
9135
9245
|
} else {
|
|
9136
|
-
const
|
|
9246
|
+
const textContent3 = part.content;
|
|
9137
9247
|
const htmlTagRegex = /<[^>]+>/g;
|
|
9138
9248
|
const textParts = [];
|
|
9139
9249
|
let lastTextIndex = 0;
|
|
9140
9250
|
let htmlMatch;
|
|
9141
|
-
while ((htmlMatch = htmlTagRegex.exec(
|
|
9251
|
+
while ((htmlMatch = htmlTagRegex.exec(textContent3)) !== null) {
|
|
9142
9252
|
if (htmlMatch.index > lastTextIndex) {
|
|
9143
|
-
const textBefore =
|
|
9253
|
+
const textBefore = textContent3.slice(lastTextIndex, htmlMatch.index);
|
|
9144
9254
|
if (textBefore.trim()) {
|
|
9145
9255
|
textParts.push({ type: "text", content: textBefore });
|
|
9146
9256
|
} else {
|
|
@@ -9150,8 +9260,8 @@ function parseEjsForTranslation(input2) {
|
|
|
9150
9260
|
textParts.push({ type: "html", content: htmlMatch[0] });
|
|
9151
9261
|
lastTextIndex = htmlMatch.index + htmlMatch[0].length;
|
|
9152
9262
|
}
|
|
9153
|
-
if (lastTextIndex <
|
|
9154
|
-
const remainingText =
|
|
9263
|
+
if (lastTextIndex < textContent3.length) {
|
|
9264
|
+
const remainingText = textContent3.slice(lastTextIndex);
|
|
9155
9265
|
if (remainingText.trim()) {
|
|
9156
9266
|
textParts.push({ type: "text", content: remainingText });
|
|
9157
9267
|
} else {
|
|
@@ -9159,11 +9269,11 @@ function parseEjsForTranslation(input2) {
|
|
|
9159
9269
|
}
|
|
9160
9270
|
}
|
|
9161
9271
|
if (textParts.length === 0) {
|
|
9162
|
-
const trimmedContent =
|
|
9272
|
+
const trimmedContent = textContent3.trim();
|
|
9163
9273
|
if (trimmedContent) {
|
|
9164
|
-
textParts.push({ type: "text", content:
|
|
9274
|
+
textParts.push({ type: "text", content: textContent3 });
|
|
9165
9275
|
} else {
|
|
9166
|
-
textParts.push({ type: "html", content:
|
|
9276
|
+
textParts.push({ type: "html", content: textContent3 });
|
|
9167
9277
|
}
|
|
9168
9278
|
}
|
|
9169
9279
|
for (const textPart of textParts) {
|
|
@@ -9232,6 +9342,368 @@ function createEjsLoader() {
|
|
|
9232
9342
|
});
|
|
9233
9343
|
}
|
|
9234
9344
|
|
|
9345
|
+
// src/cli/loaders/twig.ts
|
|
9346
|
+
import * as htmlparser23 from "htmlparser2";
|
|
9347
|
+
import { DomHandler as DomHandler3 } from "domhandler";
|
|
9348
|
+
import * as domutils2 from "domutils";
|
|
9349
|
+
import * as DomSerializer2 from "dom-serializer";
|
|
9350
|
+
function createTwigLoader() {
|
|
9351
|
+
const PHRASING_ELEMENTS = /* @__PURE__ */ new Set([
|
|
9352
|
+
// Text-level semantics
|
|
9353
|
+
"a",
|
|
9354
|
+
"abbr",
|
|
9355
|
+
"b",
|
|
9356
|
+
"bdi",
|
|
9357
|
+
"bdo",
|
|
9358
|
+
"br",
|
|
9359
|
+
"cite",
|
|
9360
|
+
"code",
|
|
9361
|
+
"data",
|
|
9362
|
+
"dfn",
|
|
9363
|
+
"em",
|
|
9364
|
+
"i",
|
|
9365
|
+
"kbd",
|
|
9366
|
+
"mark",
|
|
9367
|
+
"q",
|
|
9368
|
+
"ruby",
|
|
9369
|
+
"s",
|
|
9370
|
+
"samp",
|
|
9371
|
+
"small",
|
|
9372
|
+
"span",
|
|
9373
|
+
"strong",
|
|
9374
|
+
"sub",
|
|
9375
|
+
"sup",
|
|
9376
|
+
"time",
|
|
9377
|
+
"u",
|
|
9378
|
+
"var",
|
|
9379
|
+
"wbr",
|
|
9380
|
+
// Media
|
|
9381
|
+
"audio",
|
|
9382
|
+
"img",
|
|
9383
|
+
"video",
|
|
9384
|
+
"picture",
|
|
9385
|
+
// Interactive
|
|
9386
|
+
"button",
|
|
9387
|
+
"input",
|
|
9388
|
+
"label",
|
|
9389
|
+
"select",
|
|
9390
|
+
"textarea",
|
|
9391
|
+
// Embedded
|
|
9392
|
+
"canvas",
|
|
9393
|
+
"iframe",
|
|
9394
|
+
"object",
|
|
9395
|
+
"svg",
|
|
9396
|
+
"math",
|
|
9397
|
+
// Other
|
|
9398
|
+
"del",
|
|
9399
|
+
"ins",
|
|
9400
|
+
"map",
|
|
9401
|
+
"area"
|
|
9402
|
+
]);
|
|
9403
|
+
const BLOCK_ELEMENTS = /* @__PURE__ */ new Set([
|
|
9404
|
+
"div",
|
|
9405
|
+
"p",
|
|
9406
|
+
"h1",
|
|
9407
|
+
"h2",
|
|
9408
|
+
"h3",
|
|
9409
|
+
"h4",
|
|
9410
|
+
"h5",
|
|
9411
|
+
"h6",
|
|
9412
|
+
"ul",
|
|
9413
|
+
"ol",
|
|
9414
|
+
"li",
|
|
9415
|
+
"dl",
|
|
9416
|
+
"dt",
|
|
9417
|
+
"dd",
|
|
9418
|
+
"blockquote",
|
|
9419
|
+
"pre",
|
|
9420
|
+
"article",
|
|
9421
|
+
"aside",
|
|
9422
|
+
"nav",
|
|
9423
|
+
"section",
|
|
9424
|
+
"header",
|
|
9425
|
+
"footer",
|
|
9426
|
+
"main",
|
|
9427
|
+
"figure",
|
|
9428
|
+
"figcaption",
|
|
9429
|
+
"table",
|
|
9430
|
+
"thead",
|
|
9431
|
+
"tbody",
|
|
9432
|
+
"tfoot",
|
|
9433
|
+
"tr",
|
|
9434
|
+
"td",
|
|
9435
|
+
"th",
|
|
9436
|
+
"caption",
|
|
9437
|
+
"form",
|
|
9438
|
+
"fieldset",
|
|
9439
|
+
"legend",
|
|
9440
|
+
"details",
|
|
9441
|
+
"summary",
|
|
9442
|
+
"address",
|
|
9443
|
+
"hr",
|
|
9444
|
+
"search",
|
|
9445
|
+
"dialog",
|
|
9446
|
+
"noscript",
|
|
9447
|
+
"title"
|
|
9448
|
+
]);
|
|
9449
|
+
const UNLOCALIZABLE_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
|
|
9450
|
+
const LOCALIZABLE_ATTRIBUTES2 = {
|
|
9451
|
+
meta: ["content"],
|
|
9452
|
+
img: ["alt", "title"],
|
|
9453
|
+
input: ["placeholder", "title", "aria-label"],
|
|
9454
|
+
textarea: ["placeholder", "title", "aria-label"],
|
|
9455
|
+
button: ["title", "aria-label"],
|
|
9456
|
+
a: ["title", "aria-label"],
|
|
9457
|
+
abbr: ["title"],
|
|
9458
|
+
link: ["title"]
|
|
9459
|
+
};
|
|
9460
|
+
function preprocessTwig(input2) {
|
|
9461
|
+
const twigBlocks = [];
|
|
9462
|
+
let counter = 0;
|
|
9463
|
+
const processed = input2.replace(/\{%[\s\S]*?%\}/g, (match2) => {
|
|
9464
|
+
twigBlocks.push(match2);
|
|
9465
|
+
return `__TWIG_BLOCK_${counter++}__`;
|
|
9466
|
+
});
|
|
9467
|
+
return {
|
|
9468
|
+
processed: processed.replace(/\{#[\s\S]*?#\}/g, (match2) => {
|
|
9469
|
+
twigBlocks.push(match2);
|
|
9470
|
+
return `__TWIG_BLOCK_${counter++}__`;
|
|
9471
|
+
}),
|
|
9472
|
+
twigBlocks
|
|
9473
|
+
};
|
|
9474
|
+
}
|
|
9475
|
+
function postprocessTwig(text, twigBlocks) {
|
|
9476
|
+
return text.replace(/__TWIG_BLOCK_(\d+)__/g, (_37, index) => {
|
|
9477
|
+
return twigBlocks[parseInt(index, 10)] || "";
|
|
9478
|
+
});
|
|
9479
|
+
}
|
|
9480
|
+
return createLoader({
|
|
9481
|
+
async pull(locale, input2) {
|
|
9482
|
+
const result = {};
|
|
9483
|
+
const { processed, twigBlocks } = preprocessTwig(input2);
|
|
9484
|
+
const handler = new DomHandler3();
|
|
9485
|
+
const parser = new htmlparser23.Parser(handler, {
|
|
9486
|
+
lowerCaseTags: false,
|
|
9487
|
+
lowerCaseAttributeNames: false
|
|
9488
|
+
});
|
|
9489
|
+
parser.write(processed);
|
|
9490
|
+
parser.end();
|
|
9491
|
+
const dom = handler.dom;
|
|
9492
|
+
function isInsideUnlocalizableTag(element) {
|
|
9493
|
+
let current = element.parent;
|
|
9494
|
+
while (current && current.type === "tag") {
|
|
9495
|
+
if (UNLOCALIZABLE_TAGS.has(current.name.toLowerCase())) {
|
|
9496
|
+
return true;
|
|
9497
|
+
}
|
|
9498
|
+
current = current.parent;
|
|
9499
|
+
}
|
|
9500
|
+
return false;
|
|
9501
|
+
}
|
|
9502
|
+
function hasTranslatableContent(element) {
|
|
9503
|
+
const text = domutils2.textContent(element);
|
|
9504
|
+
return text.trim().length > 0;
|
|
9505
|
+
}
|
|
9506
|
+
function isLeafBlock(element) {
|
|
9507
|
+
const childElements = element.children.filter(
|
|
9508
|
+
(child) => child.type === "tag"
|
|
9509
|
+
);
|
|
9510
|
+
for (const child of childElements) {
|
|
9511
|
+
if (BLOCK_ELEMENTS.has(child.name.toLowerCase())) {
|
|
9512
|
+
return false;
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9515
|
+
return hasTranslatableContent(element);
|
|
9516
|
+
}
|
|
9517
|
+
function getInnerHTML2(element) {
|
|
9518
|
+
const html2 = element.children.map((child) => DomSerializer2.default(child, { encodeEntities: false })).join("");
|
|
9519
|
+
return postprocessTwig(html2, twigBlocks);
|
|
9520
|
+
}
|
|
9521
|
+
function extractAttributes(element, path19) {
|
|
9522
|
+
const tagName = element.name.toLowerCase();
|
|
9523
|
+
const attrs = LOCALIZABLE_ATTRIBUTES2[tagName];
|
|
9524
|
+
if (!attrs) return;
|
|
9525
|
+
for (const attr of attrs) {
|
|
9526
|
+
const value = element.attribs?.[attr];
|
|
9527
|
+
if (value && value.trim()) {
|
|
9528
|
+
const restoredValue = postprocessTwig(value.trim(), twigBlocks);
|
|
9529
|
+
result[`${path19}#${attr}`] = restoredValue;
|
|
9530
|
+
}
|
|
9531
|
+
}
|
|
9532
|
+
}
|
|
9533
|
+
function extractFromElement(element, pathParts) {
|
|
9534
|
+
const path19 = pathParts.join("/");
|
|
9535
|
+
if (isInsideUnlocalizableTag(element)) {
|
|
9536
|
+
return;
|
|
9537
|
+
}
|
|
9538
|
+
extractAttributes(element, path19);
|
|
9539
|
+
const tagName = element.name.toLowerCase();
|
|
9540
|
+
if (BLOCK_ELEMENTS.has(tagName) && isLeafBlock(element)) {
|
|
9541
|
+
const content = getInnerHTML2(element).trim();
|
|
9542
|
+
if (content) {
|
|
9543
|
+
result[path19] = content;
|
|
9544
|
+
}
|
|
9545
|
+
return;
|
|
9546
|
+
}
|
|
9547
|
+
if (PHRASING_ELEMENTS.has(tagName) && hasTranslatableContent(element)) {
|
|
9548
|
+
const content = getInnerHTML2(element).trim();
|
|
9549
|
+
if (content) {
|
|
9550
|
+
result[path19] = content;
|
|
9551
|
+
}
|
|
9552
|
+
return;
|
|
9553
|
+
}
|
|
9554
|
+
let childIndex = 0;
|
|
9555
|
+
const childElements = element.children.filter(
|
|
9556
|
+
(child) => child.type === "tag"
|
|
9557
|
+
);
|
|
9558
|
+
for (const child of childElements) {
|
|
9559
|
+
extractFromElement(child, [...pathParts, childIndex++]);
|
|
9560
|
+
}
|
|
9561
|
+
}
|
|
9562
|
+
const html = domutils2.findOne(
|
|
9563
|
+
(elem) => elem.type === "tag" && elem.name.toLowerCase() === "html",
|
|
9564
|
+
dom,
|
|
9565
|
+
true
|
|
9566
|
+
);
|
|
9567
|
+
if (html) {
|
|
9568
|
+
const head = domutils2.findOne(
|
|
9569
|
+
(elem) => elem.type === "tag" && elem.name.toLowerCase() === "head",
|
|
9570
|
+
html.children,
|
|
9571
|
+
true
|
|
9572
|
+
);
|
|
9573
|
+
const body = domutils2.findOne(
|
|
9574
|
+
(elem) => elem.type === "tag" && elem.name.toLowerCase() === "body",
|
|
9575
|
+
html.children,
|
|
9576
|
+
true
|
|
9577
|
+
);
|
|
9578
|
+
if (head) {
|
|
9579
|
+
let headIndex = 0;
|
|
9580
|
+
const headChildren = head.children.filter(
|
|
9581
|
+
(child) => child.type === "tag"
|
|
9582
|
+
);
|
|
9583
|
+
for (const child of headChildren) {
|
|
9584
|
+
extractFromElement(child, ["head", headIndex++]);
|
|
9585
|
+
}
|
|
9586
|
+
}
|
|
9587
|
+
if (body) {
|
|
9588
|
+
let bodyIndex = 0;
|
|
9589
|
+
const bodyChildren = body.children.filter(
|
|
9590
|
+
(child) => child.type === "tag"
|
|
9591
|
+
);
|
|
9592
|
+
for (const child of bodyChildren) {
|
|
9593
|
+
extractFromElement(child, ["body", bodyIndex++]);
|
|
9594
|
+
}
|
|
9595
|
+
}
|
|
9596
|
+
} else {
|
|
9597
|
+
let rootIndex = 0;
|
|
9598
|
+
const rootElements = dom.filter(
|
|
9599
|
+
(child) => child.type === "tag"
|
|
9600
|
+
);
|
|
9601
|
+
for (const child of rootElements) {
|
|
9602
|
+
extractFromElement(child, [rootIndex++]);
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
return result;
|
|
9606
|
+
},
|
|
9607
|
+
async push(locale, data, originalInput) {
|
|
9608
|
+
const { processed, twigBlocks } = preprocessTwig(originalInput || "");
|
|
9609
|
+
const handler = new DomHandler3();
|
|
9610
|
+
const parser = new htmlparser23.Parser(handler, {
|
|
9611
|
+
lowerCaseTags: false,
|
|
9612
|
+
lowerCaseAttributeNames: false
|
|
9613
|
+
});
|
|
9614
|
+
parser.write(processed || "<!DOCTYPE html><html><head></head><body></body></html>");
|
|
9615
|
+
parser.end();
|
|
9616
|
+
const dom = handler.dom;
|
|
9617
|
+
const html = domutils2.findOne(
|
|
9618
|
+
(elem) => elem.type === "tag" && elem.name.toLowerCase() === "html",
|
|
9619
|
+
dom,
|
|
9620
|
+
true
|
|
9621
|
+
);
|
|
9622
|
+
if (html) {
|
|
9623
|
+
html.attribs = html.attribs || {};
|
|
9624
|
+
html.attribs.lang = locale;
|
|
9625
|
+
}
|
|
9626
|
+
function traverseByIndices(element, indices) {
|
|
9627
|
+
let current = element;
|
|
9628
|
+
for (const indexStr of indices) {
|
|
9629
|
+
if (!current) return null;
|
|
9630
|
+
const index = parseInt(indexStr, 10);
|
|
9631
|
+
const children = current.children.filter(
|
|
9632
|
+
(child) => child.type === "tag"
|
|
9633
|
+
);
|
|
9634
|
+
if (index >= children.length) {
|
|
9635
|
+
return null;
|
|
9636
|
+
}
|
|
9637
|
+
current = children[index];
|
|
9638
|
+
}
|
|
9639
|
+
return current;
|
|
9640
|
+
}
|
|
9641
|
+
function resolvePathToElement(path19) {
|
|
9642
|
+
const parts = path19.split("/");
|
|
9643
|
+
const [rootTag, ...indices] = parts;
|
|
9644
|
+
let current = null;
|
|
9645
|
+
if (html) {
|
|
9646
|
+
if (rootTag === "head") {
|
|
9647
|
+
current = domutils2.findOne(
|
|
9648
|
+
(elem) => elem.type === "tag" && elem.name.toLowerCase() === "head",
|
|
9649
|
+
html.children,
|
|
9650
|
+
true
|
|
9651
|
+
);
|
|
9652
|
+
} else if (rootTag === "body") {
|
|
9653
|
+
current = domutils2.findOne(
|
|
9654
|
+
(elem) => elem.type === "tag" && elem.name.toLowerCase() === "body",
|
|
9655
|
+
html.children,
|
|
9656
|
+
true
|
|
9657
|
+
);
|
|
9658
|
+
}
|
|
9659
|
+
if (!current) return null;
|
|
9660
|
+
return traverseByIndices(current, indices);
|
|
9661
|
+
} else {
|
|
9662
|
+
const rootElements = dom.filter(
|
|
9663
|
+
(child) => child.type === "tag"
|
|
9664
|
+
);
|
|
9665
|
+
const rootIndex = parseInt(rootTag, 10);
|
|
9666
|
+
if (rootIndex >= rootElements.length) {
|
|
9667
|
+
return null;
|
|
9668
|
+
}
|
|
9669
|
+
current = rootElements[rootIndex];
|
|
9670
|
+
return traverseByIndices(current, indices);
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
for (const [path19, value] of Object.entries(data)) {
|
|
9674
|
+
const [nodePath, attribute] = path19.split("#");
|
|
9675
|
+
const element = resolvePathToElement(nodePath);
|
|
9676
|
+
if (!element) {
|
|
9677
|
+
console.warn(`Path not found in original template: ${nodePath}`);
|
|
9678
|
+
continue;
|
|
9679
|
+
}
|
|
9680
|
+
if (attribute) {
|
|
9681
|
+
element.attribs = element.attribs || {};
|
|
9682
|
+
element.attribs[attribute] = value;
|
|
9683
|
+
} else {
|
|
9684
|
+
if (value) {
|
|
9685
|
+
const { processed: processedValue, twigBlocks: valueTwigBlocks } = preprocessTwig(value);
|
|
9686
|
+
const valueHandler = new DomHandler3();
|
|
9687
|
+
const valueParser = new htmlparser23.Parser(valueHandler);
|
|
9688
|
+
valueParser.write(processedValue);
|
|
9689
|
+
valueParser.end();
|
|
9690
|
+
element.children = valueHandler.dom;
|
|
9691
|
+
element.children.forEach((child) => {
|
|
9692
|
+
if (child.type === "text" && child.data) {
|
|
9693
|
+
child.data = postprocessTwig(child.data, valueTwigBlocks);
|
|
9694
|
+
}
|
|
9695
|
+
});
|
|
9696
|
+
} else {
|
|
9697
|
+
element.children = [];
|
|
9698
|
+
}
|
|
9699
|
+
}
|
|
9700
|
+
}
|
|
9701
|
+
const serialized = DomSerializer2.default(dom, { encodeEntities: false });
|
|
9702
|
+
return postprocessTwig(serialized, twigBlocks);
|
|
9703
|
+
}
|
|
9704
|
+
});
|
|
9705
|
+
}
|
|
9706
|
+
|
|
9235
9707
|
// src/cli/loaders/ensure-key-order.ts
|
|
9236
9708
|
import _25 from "lodash";
|
|
9237
9709
|
function createEnsureKeyOrderLoader() {
|
|
@@ -9384,6 +9856,18 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
9384
9856
|
switch (bucketType) {
|
|
9385
9857
|
default:
|
|
9386
9858
|
throw new Error(`Unsupported bucket type: ${bucketType}`);
|
|
9859
|
+
case "ail":
|
|
9860
|
+
return composeLoaders(
|
|
9861
|
+
createTextFileLoader(bucketPathPattern),
|
|
9862
|
+
createLockedPatternsLoader(lockedPatterns),
|
|
9863
|
+
createAilLoader(),
|
|
9864
|
+
createEnsureKeyOrderLoader(),
|
|
9865
|
+
createFlatLoader(),
|
|
9866
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
9867
|
+
createIgnoredKeysLoader(ignoredKeys || []),
|
|
9868
|
+
createSyncLoader(),
|
|
9869
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
9870
|
+
);
|
|
9387
9871
|
case "android":
|
|
9388
9872
|
return composeLoaders(
|
|
9389
9873
|
createTextFileLoader(bucketPathPattern),
|
|
@@ -9730,6 +10214,16 @@ function createBucketLoader(bucketType, bucketPathPattern, options, lockedKeys,
|
|
|
9730
10214
|
createIgnoredKeysLoader(ignoredKeys || []),
|
|
9731
10215
|
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
9732
10216
|
);
|
|
10217
|
+
case "twig":
|
|
10218
|
+
return composeLoaders(
|
|
10219
|
+
createTextFileLoader(bucketPathPattern),
|
|
10220
|
+
createLockedPatternsLoader(lockedPatterns),
|
|
10221
|
+
createTwigLoader(),
|
|
10222
|
+
createLockedKeysLoader(lockedKeys || []),
|
|
10223
|
+
createIgnoredKeysLoader(ignoredKeys || []),
|
|
10224
|
+
createSyncLoader(),
|
|
10225
|
+
createUnlocalizableLoader(options.returnUnlocalizedKeys)
|
|
10226
|
+
);
|
|
9733
10227
|
case "txt":
|
|
9734
10228
|
return composeLoaders(
|
|
9735
10229
|
createTextFileLoader(bucketPathPattern),
|
|
@@ -14101,7 +14595,7 @@ async function renderHero2() {
|
|
|
14101
14595
|
// package.json
|
|
14102
14596
|
var package_default = {
|
|
14103
14597
|
name: "lingo.dev",
|
|
14104
|
-
version: "0.117.
|
|
14598
|
+
version: "0.117.9",
|
|
14105
14599
|
description: "Lingo.dev CLI",
|
|
14106
14600
|
private: false,
|
|
14107
14601
|
publishConfig: {
|