generaltranslation 9.0.5 → 9.1.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/CHANGELOG.md +10 -0
- package/dist/{derive-DDwuyrKI.mjs → derive-C7Gc7al2.mjs} +3 -2
- package/dist/derive-C7Gc7al2.mjs.map +1 -0
- package/dist/{derive-Cbl7M1SY.cjs → derive-CM6w3hKI.cjs} +3 -2
- package/dist/derive-CM6w3hKI.cjs.map +1 -0
- package/dist/{derive-VfZjYfIU.d.mts → derive-texIAHzc.d.mts} +1 -1
- package/dist/file-BO51iVUx.cjs +29 -0
- package/dist/file-BO51iVUx.cjs.map +1 -0
- package/dist/file-CY2B-8Wr.mjs +18 -0
- package/dist/file-CY2B-8Wr.mjs.map +1 -0
- package/dist/{id-CJxNTGtQ.mjs → id-BMOKDfiZ.mjs} +2 -2
- package/dist/{id-CJxNTGtQ.mjs.map → id-BMOKDfiZ.mjs.map} +1 -1
- package/dist/{id-CkTE9OaC.cjs → id-BpSNpXZu.cjs} +2 -2
- package/dist/{id-CkTE9OaC.cjs.map → id-BpSNpXZu.cjs.map} +1 -1
- package/dist/id.cjs +1 -1
- package/dist/id.d.cts +1 -1
- package/dist/id.d.mts +1 -1
- package/dist/id.mjs +1 -1
- package/dist/index.cjs +44 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -1
- package/dist/index.d.mts +31 -2
- package/dist/index.d.ts +10 -0
- package/dist/index.js +25 -0
- package/dist/index.mjs +44 -6
- package/dist/index.mjs.map +1 -1
- package/dist/internal.cjs +2 -2
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.mts +2 -2
- package/dist/internal.mjs +2 -2
- package/dist/{isVariable-CSPdMlAF.mjs → isVariable-8-Wy5FnX.mjs} +1 -1
- package/dist/{isVariable-CSPdMlAF.mjs.map → isVariable-8-Wy5FnX.mjs.map} +1 -1
- package/dist/{isVariable-E-vOsD6G.cjs → isVariable-I3nllgeI.cjs} +1 -1
- package/dist/{isVariable-E-vOsD6G.cjs.map → isVariable-I3nllgeI.cjs.map} +1 -1
- package/dist/{runtime-mKpF6P4Q.cjs → runtime-B2Tvrf2B.cjs} +2 -2
- package/dist/{runtime-mKpF6P4Q.cjs.map → runtime-B2Tvrf2B.cjs.map} +1 -1
- package/dist/{runtime-DsKdTOSO.mjs → runtime-kPwGszp1.mjs} +2 -2
- package/dist/{runtime-DsKdTOSO.mjs.map → runtime-kPwGszp1.mjs.map} +1 -1
- package/dist/runtime.cjs +1 -1
- package/dist/runtime.d.cts +1 -1
- package/dist/runtime.d.mts +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/translate/downloadFileBatch.js +4 -1
- package/dist/translate/uploadFonts.d.ts +1 -0
- package/dist/translate/uploadFonts.js +74 -0
- package/dist/translate/uploadSourceFiles.js +4 -1
- package/dist/translate/uploadTranslations.js +7 -2
- package/dist/{types-wj-Dtih8.d.cts → types-BXULfnbQ.d.mts} +14 -3
- package/dist/types-dir/api/file.d.ts +12 -1
- package/dist/types-dir/api/file.js +13 -1
- package/dist/types-dir/api/uploadAssets.d.ts +18 -0
- package/dist/types-dir/api/uploadAssets.js +5 -0
- package/dist/{types-iO493WgK.d.mts → types-i06r567-.d.cts} +14 -3
- package/dist/types.cjs +3 -0
- package/dist/types.d.cts +2 -2
- package/dist/types.d.mts +2 -2
- package/dist/types.d.ts +1 -0
- package/dist/types.js +1 -0
- package/dist/types.mjs +2 -1
- package/dist/utils/isSupportedFileFormatTransform.js +1 -0
- package/package.json +1 -1
- package/dist/derive-Cbl7M1SY.cjs.map +0 -1
- package/dist/derive-DDwuyrKI.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# generaltranslation
|
|
2
2
|
|
|
3
|
+
## 9.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1994](https://github.com/generaltranslation/gt/pull/1994) [`bd961d1`](https://github.com/generaltranslation/gt/commit/bd961d1474547f7c6d470583c1b1190dce0112ca) Thanks [@logflash](https://github.com/logflash)! - Add Lottie file support and project font syncing.
|
|
8
|
+
- Support `.lottie` files as a new `LOTTIE` file format. Lottie bundles are binary (zip), so their content is carried base64-encoded end-to-end — including existing translated `.lottie` targets on `gt upload` — and skips the UTF-8 encode/decode and text merge paths (new `isBinaryFileFormat` / `BINARY_FILE_FORMATS` exports). Lottie translations are processed asynchronously and require the `gt stage` + `gt download` flow, so `gt translate` now exits with an error pointing users there when a project has Lottie files and staging isn't enabled. (As before, enabling staging makes `gt translate` download staged results rather than translating inline.)
|
|
9
|
+
- Reject `.lottie` files that use After Effects expressions (executable code): the upload fails and names every offending file, since expression-driven text can't be translated safely.
|
|
10
|
+
- Add `GT.uploadFonts` and a `fonts` config option (include/exclude globs) so project fonts are synced to the API before translating formats that need them (including during `gt stage`, so async Lottie jobs get the real fonts). Globs resolve from the project root. Font sync is idempotent and non-fatal on failure.
|
|
11
|
+
- Keep staged lock entries staged until every configured locale has downloaded, and only require `_versionId` for `gt download` when an inline GTJSON template is part of the download and config IDs aren't omitted (staged downloads resolve versions from `gt-lock.json`, file-only projects never have a `_versionId`, and `omitConfigIds` projects use the GTJSON's own content-derived version).
|
|
12
|
+
|
|
3
13
|
## 9.0.5
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -12,7 +12,8 @@ const SUPPORTED_TRANSFORMATIONS = {
|
|
|
12
12
|
JS: ["JS"],
|
|
13
13
|
HTML: ["HTML"],
|
|
14
14
|
TXT: ["TXT"],
|
|
15
|
-
TWILIO_CONTENT_JSON: ["TWILIO_CONTENT_JSON"]
|
|
15
|
+
TWILIO_CONTENT_JSON: ["TWILIO_CONTENT_JSON"],
|
|
16
|
+
LOTTIE: ["LOTTIE"]
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
19
|
* This function checks if a file format transformation is supported during translation
|
|
@@ -216,4 +217,4 @@ function derive(content) {
|
|
|
216
217
|
//#endregion
|
|
217
218
|
export { isGTUnindexedSelectElement as a, decode as c, isGTIndexedSelectElement as i, encode as l, declareVar as n, VAR_IDENTIFIER as o, decodeVars as r, traverseIcu as s, derive as t, isSupportedFileFormatTransform as u };
|
|
218
219
|
|
|
219
|
-
//# sourceMappingURL=derive-
|
|
220
|
+
//# sourceMappingURL=derive-C7Gc7al2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive-C7Gc7al2.mjs","names":[],"sources":["../src/utils/isSupportedFileFormatTransform.ts","../src/utils/base64.ts","../src/derive/utils/traverseIcu.ts","../src/derive/utils/constants.ts","../src/derive/utils/regex.ts","../src/derive/utils/traverseHelpers.ts","../src/derive/decodeVars.ts","../src/derive/utils/sanitizeVar.ts","../src/derive/declareVar.ts","../src/derive/derive.ts"],"sourcesContent":["import type { FileFormat } from '../types-dir/api/file';\n\nconst SUPPORTED_TRANSFORMATIONS = {\n GTJSON: ['GTJSON'],\n JSON: ['JSON'],\n PO: ['PO'],\n // POT templates can produce translated PO catalog files.\n POT: ['POT', 'PO'],\n YAML: ['YAML'],\n MDX: ['MDX'],\n MD: ['MD'],\n TS: ['TS'],\n JS: ['JS'],\n HTML: ['HTML'],\n TXT: ['TXT'],\n TWILIO_CONTENT_JSON: ['TWILIO_CONTENT_JSON'],\n LOTTIE: ['LOTTIE'],\n} as const satisfies Record<FileFormat, FileFormat[]>;\n\n/**\n * This function checks if a file format transformation is supported during translation\n * @param from - The source file format.\n * @param to - The target file format.\n * @returns True if the transformation is supported, false otherwise\n */\nexport function isSupportedFileFormatTransform(\n from: FileFormat,\n to: FileFormat\n): boolean {\n const toFormats: FileFormat[] | undefined = SUPPORTED_TRANSFORMATIONS[from];\n return toFormats?.includes(to) ?? false;\n}\n","// Encode a string to base64\nexport function encode(data: string): string {\n if (typeof Buffer !== 'undefined') {\n // Node.js path.\n return Buffer.from(data, 'utf8').toString('base64');\n }\n // Browser path.\n const bytes = new TextEncoder().encode(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n// Decode a base64 string to a string\nexport function decode(base64: string): string {\n if (typeof Buffer !== 'undefined') {\n // Node.js path.\n return Buffer.from(base64, 'base64').toString('utf8');\n }\n // Browser path.\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n","import {\n parse,\n TYPE,\n type MessageFormatElement,\n type ParserOptions,\n} from '@generaltranslation/icu';\n\ntype TraverseIcuOptions = ParserOptions & {\n recurseIntoVisited?: boolean;\n};\n\n/**\n * Given an ICU string, traverse the AST and call the visitor function for each element that matches the type T\n * @param icu - The ICU string to traverse\n * @param shouldVisit - A function that returns true if the element should be visited\n * @param visitor - A function that is called for each element that matches the type T\n * @returns The modified AST of the ICU string.\n *\n * @note This function is a heavy operation, use sparingly\n */\nexport function traverseIcu<T extends MessageFormatElement>({\n icuString,\n shouldVisit,\n visitor,\n options: { recurseIntoVisited = true, ...otherOptions },\n}: {\n icuString: string;\n shouldVisit: (element: MessageFormatElement) => element is T;\n visitor: (element: T) => void;\n options: TraverseIcuOptions;\n}): MessageFormatElement[] {\n const ast = parse(icuString, otherOptions);\n handleChildren(ast);\n return ast;\n\n function handleChildren(children: MessageFormatElement[]): void {\n children.map(handleChild);\n }\n\n function handleChild(child: MessageFormatElement) {\n // handle select var\n let visited = false;\n if (shouldVisit(child)) {\n visitor(child);\n visited = true;\n }\n // recurse on children\n if (!visited || recurseIntoVisited) {\n if (child.type === TYPE.select || child.type === TYPE.plural) {\n Object.values(child.options)\n .map((option) => option.value)\n .map(handleChildren);\n } else if (child.type === TYPE.tag) {\n handleChildren(child.children);\n }\n }\n }\n}\n","export const VAR_IDENTIFIER = '_gt_';\nexport const VAR_NAME_IDENTIFIER = '_gt_var_name';\n","import { VAR_IDENTIFIER } from './constants';\n\n// Regex for _gt_# select\nexport const GT_INDEXED_IDENTIFIER_REGEX = new RegExp(\n `^${VAR_IDENTIFIER}\\\\d+$`\n);\n\nexport const GT_UNINDEXED_IDENTIFIER_REGEX = new RegExp(`^${VAR_IDENTIFIER}$`);\n","import {\n GT_INDEXED_IDENTIFIER_REGEX,\n GT_UNINDEXED_IDENTIFIER_REGEX,\n} from './regex';\nimport { GTIndexedSelectElement, GTUnindexedSelectElement } from './types';\nimport { TYPE, type MessageFormatElement } from '@generaltranslation/icu';\n\n// Visit any _gt_# select\nexport function isGTIndexedSelectElement(\n child: MessageFormatElement\n): child is GTIndexedSelectElement {\n return (\n child.type === TYPE.select &&\n GT_INDEXED_IDENTIFIER_REGEX.test(child.value) &&\n !!child.options.other &&\n (child.options.other.value.length === 0 ||\n (child.options.other.value.length > 0 &&\n child.options.other.value[0]?.type === TYPE.literal))\n );\n}\n\n// Visit any _gt_ select\nexport function isGTUnindexedSelectElement(\n child: MessageFormatElement\n): child is GTUnindexedSelectElement {\n return (\n child.type === TYPE.select &&\n GT_UNINDEXED_IDENTIFIER_REGEX.test(child.value) &&\n !!child.options.other &&\n (child.options.other.value.length === 0 ||\n (child.options.other.value.length > 0 &&\n child.options.other.value[0]?.type === TYPE.literal))\n );\n}\n","import { traverseIcu } from './utils/traverseIcu';\nimport { VAR_IDENTIFIER } from './utils/constants';\nimport { GTUnindexedSelectElement } from './utils/types';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\n\ntype Location = {\n start: number;\n end: number;\n value: string;\n};\n\n/**\n * Given an encoded ICU string, interpolate only _gt_ variables that have been marked with declareVar()\n * @example\n * const encodedIcu = \"Hi\" + declareVar(\"Brian\") + \", my name is {name}\"\n * // 'Hi {_gt_, select, other {Brian}}, my name is {name}'\n * decodeVars(encodedIcu)\n * // 'Hi Brian, my name is {name}'\n */\nexport function decodeVars(icuString: string): string {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return icuString;\n }\n\n // Record the location of the variable\n const variableLocations: Location[] = [];\n function visitor(child: GTUnindexedSelectElement): void {\n variableLocations.push({\n start: child.location?.start.offset ?? 0,\n end: child.location?.end.offset ?? 0,\n value:\n child.options.other.value.length > 0\n ? child.options.other.value[0].value\n : '',\n });\n }\n\n // Find all variable identifiers.\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: {\n recurseIntoVisited: false,\n captureLocation: true,\n },\n });\n\n // Construct output string\n let previousIndex = 0;\n const outputList = [];\n for (let i = 0; i < variableLocations.length; i++) {\n outputList.push(icuString.slice(previousIndex, variableLocations[i].start));\n outputList.push(variableLocations[i].value);\n previousIndex = variableLocations[i].end;\n }\n if (previousIndex < icuString.length) {\n outputList.push(icuString.slice(previousIndex));\n }\n const outputString = outputList.join('');\n\n return outputString;\n}\n","/**\n * Sanitizes string by escaping ICU syntax\n *\n * Sanitize arbitrary string so it does not break the following ICU message syntax:\n * {_gt_, select, other {string_here}}\n *\n * Escapes ICU special characters by:\n * 1. Doubling all single quotes (U+0027 ')\n * 2. Adding a single quote before the first special character ({}<>)\n * 3. Adding a single quote after the last special character ({}<>)\n */\nexport function sanitizeVar(string: string): string {\n // First, double all single quotes (both ASCII and Unicode).\n let result = string.replace(/'/g, \"''\");\n\n // Find first and last positions of special characters\n const specialChars = /[{}<>]/;\n const firstSpecialIndex = result.search(specialChars);\n\n if (firstSpecialIndex === -1) {\n // No special characters; return with just doubled quotes.\n return result;\n }\n\n // Find last special character position\n let lastSpecialIndex = -1;\n for (let i = result.length - 1; i >= 0; i--) {\n if (specialChars.test(result[i])) {\n lastSpecialIndex = i;\n break;\n }\n }\n\n // Insert quotes around the special character region.\n result =\n result.slice(0, firstSpecialIndex) +\n \"'\" +\n result.slice(firstSpecialIndex, lastSpecialIndex + 1) +\n \"'\" +\n result.slice(lastSpecialIndex + 1);\n\n return result;\n}\n","import { VAR_IDENTIFIER, VAR_NAME_IDENTIFIER } from './utils/constants';\nimport { sanitizeVar } from './utils/sanitizeVar';\n\n/**\n * Mark as a non-translatable string. Use within a derive() call to mark content as not derivable (e.g., not possible to statically analyze).\n *\n * @example\n * function nonDerivableFunction() {\n * return Math.random();\n * }\n *\n * function derivableFunction() {\n * if (condition) {\n * return declareVar(nonDerivableFunction())\n * }\n * return 'John Doe';\n * }\n *\n * const gt = useGT();\n * gt(`My name is ${derive(derivableFunction())}`);\n *\n * @param {string | number | boolean | null | undefined} variable - The variable to sanitize.\n * @param {Object} [options] - The options for the sanitization.\n * @param {string} [options.$name] - The name of the variable.\n * @returns {string} The sanitized value.\n */\nexport function declareVar(\n variable: string | number | boolean | null | undefined,\n options?: { $name?: string }\n): string {\n // Variable section.\n const sanitizedVariable = sanitizeVar(String(variable ?? ''));\n const variableSection = ` other {${sanitizedVariable}}`;\n\n // Name section.\n let nameSection = '';\n if (options?.$name) {\n const sanitizedName = sanitizeVar(options.$name);\n nameSection = ` ${VAR_NAME_IDENTIFIER} {${sanitizedName}}`;\n }\n\n // interpolate\n return `{${VAR_IDENTIFIER}, select,${variableSection}${nameSection}}`;\n}\n","/**\n * Marks content as derivable by the GT compiler and CLI.\n *\n * Use `derive()` when a translation string or context needs content that is\n * computed from source code, but should still be discovered during extraction\n * instead of treated as a runtime interpolation variable. The CLI attempts to\n * resolve the derivable expression into every possible static value and\n * includes those values in the source content that gets translated.\n *\n * `derive()` returns its argument unchanged at runtime.\n *\n * Run `gt validate` after adding or changing `derive()` calls to verify that\n * each derivable expression can be resolved by the CLI before translating or\n * building.\n *\n * @example\n * ```jsx\n * function getSubject() {\n * return (Math.random() > 0.5) ? \"Alice\" : \"Brian\";\n * }\n * ...\n * gt(`My name is ${derive(getSubject())}`);\n * ```\n *\n * @param {T extends string | boolean | number | null | undefined} content - Content to derive for translation extraction.\n * @returns {T} The same content, unchanged at runtime.\n */\nexport function derive<T extends string | boolean | number | null | undefined>(\n content: T\n): T {\n return content;\n}\n"],"mappings":"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"}
|
|
@@ -12,7 +12,8 @@ const SUPPORTED_TRANSFORMATIONS = {
|
|
|
12
12
|
JS: ["JS"],
|
|
13
13
|
HTML: ["HTML"],
|
|
14
14
|
TXT: ["TXT"],
|
|
15
|
-
TWILIO_CONTENT_JSON: ["TWILIO_CONTENT_JSON"]
|
|
15
|
+
TWILIO_CONTENT_JSON: ["TWILIO_CONTENT_JSON"],
|
|
16
|
+
LOTTIE: ["LOTTIE"]
|
|
16
17
|
};
|
|
17
18
|
/**
|
|
18
19
|
* This function checks if a file format transformation is supported during translation
|
|
@@ -275,4 +276,4 @@ Object.defineProperty(exports, "traverseIcu", {
|
|
|
275
276
|
}
|
|
276
277
|
});
|
|
277
278
|
|
|
278
|
-
//# sourceMappingURL=derive-
|
|
279
|
+
//# sourceMappingURL=derive-CM6w3hKI.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive-CM6w3hKI.cjs","names":["TYPE","TYPE"],"sources":["../src/utils/isSupportedFileFormatTransform.ts","../src/utils/base64.ts","../src/derive/utils/traverseIcu.ts","../src/derive/utils/constants.ts","../src/derive/utils/regex.ts","../src/derive/utils/traverseHelpers.ts","../src/derive/decodeVars.ts","../src/derive/utils/sanitizeVar.ts","../src/derive/declareVar.ts","../src/derive/derive.ts"],"sourcesContent":["import type { FileFormat } from '../types-dir/api/file';\n\nconst SUPPORTED_TRANSFORMATIONS = {\n GTJSON: ['GTJSON'],\n JSON: ['JSON'],\n PO: ['PO'],\n // POT templates can produce translated PO catalog files.\n POT: ['POT', 'PO'],\n YAML: ['YAML'],\n MDX: ['MDX'],\n MD: ['MD'],\n TS: ['TS'],\n JS: ['JS'],\n HTML: ['HTML'],\n TXT: ['TXT'],\n TWILIO_CONTENT_JSON: ['TWILIO_CONTENT_JSON'],\n LOTTIE: ['LOTTIE'],\n} as const satisfies Record<FileFormat, FileFormat[]>;\n\n/**\n * This function checks if a file format transformation is supported during translation\n * @param from - The source file format.\n * @param to - The target file format.\n * @returns True if the transformation is supported, false otherwise\n */\nexport function isSupportedFileFormatTransform(\n from: FileFormat,\n to: FileFormat\n): boolean {\n const toFormats: FileFormat[] | undefined = SUPPORTED_TRANSFORMATIONS[from];\n return toFormats?.includes(to) ?? false;\n}\n","// Encode a string to base64\nexport function encode(data: string): string {\n if (typeof Buffer !== 'undefined') {\n // Node.js path.\n return Buffer.from(data, 'utf8').toString('base64');\n }\n // Browser path.\n const bytes = new TextEncoder().encode(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n// Decode a base64 string to a string\nexport function decode(base64: string): string {\n if (typeof Buffer !== 'undefined') {\n // Node.js path.\n return Buffer.from(base64, 'base64').toString('utf8');\n }\n // Browser path.\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n","import {\n parse,\n TYPE,\n type MessageFormatElement,\n type ParserOptions,\n} from '@generaltranslation/icu';\n\ntype TraverseIcuOptions = ParserOptions & {\n recurseIntoVisited?: boolean;\n};\n\n/**\n * Given an ICU string, traverse the AST and call the visitor function for each element that matches the type T\n * @param icu - The ICU string to traverse\n * @param shouldVisit - A function that returns true if the element should be visited\n * @param visitor - A function that is called for each element that matches the type T\n * @returns The modified AST of the ICU string.\n *\n * @note This function is a heavy operation, use sparingly\n */\nexport function traverseIcu<T extends MessageFormatElement>({\n icuString,\n shouldVisit,\n visitor,\n options: { recurseIntoVisited = true, ...otherOptions },\n}: {\n icuString: string;\n shouldVisit: (element: MessageFormatElement) => element is T;\n visitor: (element: T) => void;\n options: TraverseIcuOptions;\n}): MessageFormatElement[] {\n const ast = parse(icuString, otherOptions);\n handleChildren(ast);\n return ast;\n\n function handleChildren(children: MessageFormatElement[]): void {\n children.map(handleChild);\n }\n\n function handleChild(child: MessageFormatElement) {\n // handle select var\n let visited = false;\n if (shouldVisit(child)) {\n visitor(child);\n visited = true;\n }\n // recurse on children\n if (!visited || recurseIntoVisited) {\n if (child.type === TYPE.select || child.type === TYPE.plural) {\n Object.values(child.options)\n .map((option) => option.value)\n .map(handleChildren);\n } else if (child.type === TYPE.tag) {\n handleChildren(child.children);\n }\n }\n }\n}\n","export const VAR_IDENTIFIER = '_gt_';\nexport const VAR_NAME_IDENTIFIER = '_gt_var_name';\n","import { VAR_IDENTIFIER } from './constants';\n\n// Regex for _gt_# select\nexport const GT_INDEXED_IDENTIFIER_REGEX = new RegExp(\n `^${VAR_IDENTIFIER}\\\\d+$`\n);\n\nexport const GT_UNINDEXED_IDENTIFIER_REGEX = new RegExp(`^${VAR_IDENTIFIER}$`);\n","import {\n GT_INDEXED_IDENTIFIER_REGEX,\n GT_UNINDEXED_IDENTIFIER_REGEX,\n} from './regex';\nimport { GTIndexedSelectElement, GTUnindexedSelectElement } from './types';\nimport { TYPE, type MessageFormatElement } from '@generaltranslation/icu';\n\n// Visit any _gt_# select\nexport function isGTIndexedSelectElement(\n child: MessageFormatElement\n): child is GTIndexedSelectElement {\n return (\n child.type === TYPE.select &&\n GT_INDEXED_IDENTIFIER_REGEX.test(child.value) &&\n !!child.options.other &&\n (child.options.other.value.length === 0 ||\n (child.options.other.value.length > 0 &&\n child.options.other.value[0]?.type === TYPE.literal))\n );\n}\n\n// Visit any _gt_ select\nexport function isGTUnindexedSelectElement(\n child: MessageFormatElement\n): child is GTUnindexedSelectElement {\n return (\n child.type === TYPE.select &&\n GT_UNINDEXED_IDENTIFIER_REGEX.test(child.value) &&\n !!child.options.other &&\n (child.options.other.value.length === 0 ||\n (child.options.other.value.length > 0 &&\n child.options.other.value[0]?.type === TYPE.literal))\n );\n}\n","import { traverseIcu } from './utils/traverseIcu';\nimport { VAR_IDENTIFIER } from './utils/constants';\nimport { GTUnindexedSelectElement } from './utils/types';\nimport { isGTUnindexedSelectElement } from './utils/traverseHelpers';\n\ntype Location = {\n start: number;\n end: number;\n value: string;\n};\n\n/**\n * Given an encoded ICU string, interpolate only _gt_ variables that have been marked with declareVar()\n * @example\n * const encodedIcu = \"Hi\" + declareVar(\"Brian\") + \", my name is {name}\"\n * // 'Hi {_gt_, select, other {Brian}}, my name is {name}'\n * decodeVars(encodedIcu)\n * // 'Hi Brian, my name is {name}'\n */\nexport function decodeVars(icuString: string): string {\n // Check if the string contains _gt_\n if (!icuString.includes(VAR_IDENTIFIER)) {\n return icuString;\n }\n\n // Record the location of the variable\n const variableLocations: Location[] = [];\n function visitor(child: GTUnindexedSelectElement): void {\n variableLocations.push({\n start: child.location?.start.offset ?? 0,\n end: child.location?.end.offset ?? 0,\n value:\n child.options.other.value.length > 0\n ? child.options.other.value[0].value\n : '',\n });\n }\n\n // Find all variable identifiers.\n traverseIcu({\n icuString,\n shouldVisit: isGTUnindexedSelectElement,\n visitor,\n options: {\n recurseIntoVisited: false,\n captureLocation: true,\n },\n });\n\n // Construct output string\n let previousIndex = 0;\n const outputList = [];\n for (let i = 0; i < variableLocations.length; i++) {\n outputList.push(icuString.slice(previousIndex, variableLocations[i].start));\n outputList.push(variableLocations[i].value);\n previousIndex = variableLocations[i].end;\n }\n if (previousIndex < icuString.length) {\n outputList.push(icuString.slice(previousIndex));\n }\n const outputString = outputList.join('');\n\n return outputString;\n}\n","/**\n * Sanitizes string by escaping ICU syntax\n *\n * Sanitize arbitrary string so it does not break the following ICU message syntax:\n * {_gt_, select, other {string_here}}\n *\n * Escapes ICU special characters by:\n * 1. Doubling all single quotes (U+0027 ')\n * 2. Adding a single quote before the first special character ({}<>)\n * 3. Adding a single quote after the last special character ({}<>)\n */\nexport function sanitizeVar(string: string): string {\n // First, double all single quotes (both ASCII and Unicode).\n let result = string.replace(/'/g, \"''\");\n\n // Find first and last positions of special characters\n const specialChars = /[{}<>]/;\n const firstSpecialIndex = result.search(specialChars);\n\n if (firstSpecialIndex === -1) {\n // No special characters; return with just doubled quotes.\n return result;\n }\n\n // Find last special character position\n let lastSpecialIndex = -1;\n for (let i = result.length - 1; i >= 0; i--) {\n if (specialChars.test(result[i])) {\n lastSpecialIndex = i;\n break;\n }\n }\n\n // Insert quotes around the special character region.\n result =\n result.slice(0, firstSpecialIndex) +\n \"'\" +\n result.slice(firstSpecialIndex, lastSpecialIndex + 1) +\n \"'\" +\n result.slice(lastSpecialIndex + 1);\n\n return result;\n}\n","import { VAR_IDENTIFIER, VAR_NAME_IDENTIFIER } from './utils/constants';\nimport { sanitizeVar } from './utils/sanitizeVar';\n\n/**\n * Mark as a non-translatable string. Use within a derive() call to mark content as not derivable (e.g., not possible to statically analyze).\n *\n * @example\n * function nonDerivableFunction() {\n * return Math.random();\n * }\n *\n * function derivableFunction() {\n * if (condition) {\n * return declareVar(nonDerivableFunction())\n * }\n * return 'John Doe';\n * }\n *\n * const gt = useGT();\n * gt(`My name is ${derive(derivableFunction())}`);\n *\n * @param {string | number | boolean | null | undefined} variable - The variable to sanitize.\n * @param {Object} [options] - The options for the sanitization.\n * @param {string} [options.$name] - The name of the variable.\n * @returns {string} The sanitized value.\n */\nexport function declareVar(\n variable: string | number | boolean | null | undefined,\n options?: { $name?: string }\n): string {\n // Variable section.\n const sanitizedVariable = sanitizeVar(String(variable ?? ''));\n const variableSection = ` other {${sanitizedVariable}}`;\n\n // Name section.\n let nameSection = '';\n if (options?.$name) {\n const sanitizedName = sanitizeVar(options.$name);\n nameSection = ` ${VAR_NAME_IDENTIFIER} {${sanitizedName}}`;\n }\n\n // interpolate\n return `{${VAR_IDENTIFIER}, select,${variableSection}${nameSection}}`;\n}\n","/**\n * Marks content as derivable by the GT compiler and CLI.\n *\n * Use `derive()` when a translation string or context needs content that is\n * computed from source code, but should still be discovered during extraction\n * instead of treated as a runtime interpolation variable. The CLI attempts to\n * resolve the derivable expression into every possible static value and\n * includes those values in the source content that gets translated.\n *\n * `derive()` returns its argument unchanged at runtime.\n *\n * Run `gt validate` after adding or changing `derive()` calls to verify that\n * each derivable expression can be resolved by the CLI before translating or\n * building.\n *\n * @example\n * ```jsx\n * function getSubject() {\n * return (Math.random() > 0.5) ? \"Alice\" : \"Brian\";\n * }\n * ...\n * gt(`My name is ${derive(getSubject())}`);\n * ```\n *\n * @param {T extends string | boolean | number | null | undefined} content - Content to derive for translation extraction.\n * @returns {T} The same content, unchanged at runtime.\n */\nexport function derive<T extends string | boolean | number | null | undefined>(\n content: T\n): T {\n return content;\n}\n"],"mappings":"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"}
|
|
@@ -68,4 +68,4 @@ declare function declareVar(variable: string | number | boolean | null | undefin
|
|
|
68
68
|
declare function derive<T extends string | boolean | number | null | undefined>(content: T): T;
|
|
69
69
|
//#endregion
|
|
70
70
|
export { declareVar as n, decodeVars as r, derive as t };
|
|
71
|
-
//# sourceMappingURL=derive-
|
|
71
|
+
//# sourceMappingURL=derive-texIAHzc.d.mts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/types-dir/api/file.ts
|
|
2
|
+
/**
|
|
3
|
+
* File formats whose content is binary (e.g. zip bundles) rather than text.
|
|
4
|
+
* Their content travels through the pipeline already base64-encoded, so the
|
|
5
|
+
* usual UTF-8 encode/decode steps must be skipped to avoid corrupting bytes.
|
|
6
|
+
*/
|
|
7
|
+
const BINARY_FILE_FORMATS = new Set(["LOTTIE"]);
|
|
8
|
+
/**
|
|
9
|
+
* Whether a file format's content is binary (carried as base64 end-to-end)
|
|
10
|
+
* rather than a UTF-8 text string.
|
|
11
|
+
*/
|
|
12
|
+
function isBinaryFileFormat(fileFormat) {
|
|
13
|
+
return BINARY_FILE_FORMATS.has(fileFormat);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
Object.defineProperty(exports, "BINARY_FILE_FORMATS", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function() {
|
|
19
|
+
return BINARY_FILE_FORMATS;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(exports, "isBinaryFileFormat", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function() {
|
|
25
|
+
return isBinaryFileFormat;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=file-BO51iVUx.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-BO51iVUx.cjs","names":[],"sources":["../src/types-dir/api/file.ts"],"sourcesContent":["import type { DataFormat } from '@generaltranslation/format/types';\nimport { Updates } from './enqueueFiles';\nimport type { JsonObject } from './json';\n\nexport type FileFormat =\n | 'GTJSON'\n | 'JSON'\n | 'PO'\n | 'POT'\n | 'YAML'\n | 'MDX'\n | 'MD'\n | 'TS'\n | 'JS'\n | 'HTML'\n | 'TXT'\n | 'TWILIO_CONTENT_JSON'\n | 'LOTTIE';\n\n/**\n * File formats whose content is binary (e.g. zip bundles) rather than text.\n * Their content travels through the pipeline already base64-encoded, so the\n * usual UTF-8 encode/decode steps must be skipped to avoid corrupting bytes.\n */\nexport const BINARY_FILE_FORMATS: ReadonlySet<FileFormat> = new Set<FileFormat>(\n ['LOTTIE']\n);\n\n/**\n * Whether a file format's content is binary (carried as base64 end-to-end)\n * rather than a UTF-8 text string.\n */\nexport function isBinaryFileFormat(fileFormat: FileFormat): boolean {\n return BINARY_FILE_FORMATS.has(fileFormat);\n}\n\n/**\n * Metadata for files or entries.\n */\nexport type FormatMetadata = JsonObject | Updates[number]['metadata'];\n\n/**\n * File object structure for uploading files.\n * @see {@link FileReferenceOptionalBranchId}\n * @property {string} content - Content of the file.\n * @property {string} locale - The locale of the file (e.g. 'en', 'de', 'es', etc.)\n * @property {FormatMetadata} [formatMetadata] - Optional metadata for the file, specific to the format of the file\n * @property {string} [incomingBranchId] - The ID of the incoming branch of the file.\n * @property {string} [checkedOutBranchId] - The ID of the checked-out branch of the file.\n */\nexport type FileToUpload = Omit<FileReference, 'branchId'> & {\n content: string;\n locale: string;\n // Optional output format requested for generated translations.\n transformFormat?: FileFormat;\n formatMetadata?: FormatMetadata;\n branchId?: string;\n incomingBranchId?: string;\n checkedOutBranchId?: string;\n};\n\n/**\n * File object structure for referencing files.\n * @property {string} fileId - The ID of the file.\n * @property {string} versionId - The ID of the version of the file\n * @property {string} branchId - The ID of the branch of the file\n * @property {string} locale - The locale of the file (e.g. 'en', 'de', 'es', etc.)\n * @property {string} fileName - The name of the file.\n * @property {FileFormat} fileFormat - The format of the file (JSON, MDX, MD, etc.).\n * @property {DataFormat} [dataFormat] - Optional format of the data within the file.\n */\nexport type FileReference = {\n fileId: string;\n versionId: string;\n branchId: string;\n fileName: string;\n fileFormat: FileFormat;\n // Optional output format requested for generated translations.\n transformFormat?: FileFormat;\n dataFormat?: DataFormat;\n};\n\n/**\n * File reference object structure for referencing files.\n * @see {@link FileReference}\n * @property {string} [branchId] - The ID of the branch of the file\n */\nexport type FileReferenceIds = Omit<\n FileReference,\n 'branchId' | 'fileName' | 'fileFormat' | 'dataFormat'\n> & {\n branchId?: string;\n fileName?: string;\n fileFormat?: FileFormat;\n transformFormat?: FileFormat;\n dataFormat?: DataFormat;\n};\n"],"mappings":";;;;;;AAwBA,MAAa,sBAA+C,IAAI,IAC9D,CAAC,SAAS,CACX;;;;;AAMD,SAAgB,mBAAmB,YAAiC;AAClE,QAAO,oBAAoB,IAAI,WAAW"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/types-dir/api/file.ts
|
|
2
|
+
/**
|
|
3
|
+
* File formats whose content is binary (e.g. zip bundles) rather than text.
|
|
4
|
+
* Their content travels through the pipeline already base64-encoded, so the
|
|
5
|
+
* usual UTF-8 encode/decode steps must be skipped to avoid corrupting bytes.
|
|
6
|
+
*/
|
|
7
|
+
const BINARY_FILE_FORMATS = new Set(["LOTTIE"]);
|
|
8
|
+
/**
|
|
9
|
+
* Whether a file format's content is binary (carried as base64 end-to-end)
|
|
10
|
+
* rather than a UTF-8 text string.
|
|
11
|
+
*/
|
|
12
|
+
function isBinaryFileFormat(fileFormat) {
|
|
13
|
+
return BINARY_FILE_FORMATS.has(fileFormat);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { isBinaryFileFormat as n, BINARY_FILE_FORMATS as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=file-CY2B-8Wr.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-CY2B-8Wr.mjs","names":[],"sources":["../src/types-dir/api/file.ts"],"sourcesContent":["import type { DataFormat } from '@generaltranslation/format/types';\nimport { Updates } from './enqueueFiles';\nimport type { JsonObject } from './json';\n\nexport type FileFormat =\n | 'GTJSON'\n | 'JSON'\n | 'PO'\n | 'POT'\n | 'YAML'\n | 'MDX'\n | 'MD'\n | 'TS'\n | 'JS'\n | 'HTML'\n | 'TXT'\n | 'TWILIO_CONTENT_JSON'\n | 'LOTTIE';\n\n/**\n * File formats whose content is binary (e.g. zip bundles) rather than text.\n * Their content travels through the pipeline already base64-encoded, so the\n * usual UTF-8 encode/decode steps must be skipped to avoid corrupting bytes.\n */\nexport const BINARY_FILE_FORMATS: ReadonlySet<FileFormat> = new Set<FileFormat>(\n ['LOTTIE']\n);\n\n/**\n * Whether a file format's content is binary (carried as base64 end-to-end)\n * rather than a UTF-8 text string.\n */\nexport function isBinaryFileFormat(fileFormat: FileFormat): boolean {\n return BINARY_FILE_FORMATS.has(fileFormat);\n}\n\n/**\n * Metadata for files or entries.\n */\nexport type FormatMetadata = JsonObject | Updates[number]['metadata'];\n\n/**\n * File object structure for uploading files.\n * @see {@link FileReferenceOptionalBranchId}\n * @property {string} content - Content of the file.\n * @property {string} locale - The locale of the file (e.g. 'en', 'de', 'es', etc.)\n * @property {FormatMetadata} [formatMetadata] - Optional metadata for the file, specific to the format of the file\n * @property {string} [incomingBranchId] - The ID of the incoming branch of the file.\n * @property {string} [checkedOutBranchId] - The ID of the checked-out branch of the file.\n */\nexport type FileToUpload = Omit<FileReference, 'branchId'> & {\n content: string;\n locale: string;\n // Optional output format requested for generated translations.\n transformFormat?: FileFormat;\n formatMetadata?: FormatMetadata;\n branchId?: string;\n incomingBranchId?: string;\n checkedOutBranchId?: string;\n};\n\n/**\n * File object structure for referencing files.\n * @property {string} fileId - The ID of the file.\n * @property {string} versionId - The ID of the version of the file\n * @property {string} branchId - The ID of the branch of the file\n * @property {string} locale - The locale of the file (e.g. 'en', 'de', 'es', etc.)\n * @property {string} fileName - The name of the file.\n * @property {FileFormat} fileFormat - The format of the file (JSON, MDX, MD, etc.).\n * @property {DataFormat} [dataFormat] - Optional format of the data within the file.\n */\nexport type FileReference = {\n fileId: string;\n versionId: string;\n branchId: string;\n fileName: string;\n fileFormat: FileFormat;\n // Optional output format requested for generated translations.\n transformFormat?: FileFormat;\n dataFormat?: DataFormat;\n};\n\n/**\n * File reference object structure for referencing files.\n * @see {@link FileReference}\n * @property {string} [branchId] - The ID of the branch of the file\n */\nexport type FileReferenceIds = Omit<\n FileReference,\n 'branchId' | 'fileName' | 'fileFormat' | 'dataFormat'\n> & {\n branchId?: string;\n fileName?: string;\n fileFormat?: FileFormat;\n transformFormat?: FileFormat;\n dataFormat?: DataFormat;\n};\n"],"mappings":";;;;;;AAwBA,MAAa,sBAA+C,IAAI,IAC9D,CAAC,SAAS,CACX;;;;;AAMD,SAAgB,mBAAmB,YAAiC;AAClE,QAAO,oBAAoB,IAAI,WAAW"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as isVariable } from "./isVariable-
|
|
1
|
+
import { t as isVariable } from "./isVariable-8-Wy5FnX.mjs";
|
|
2
2
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
3
3
|
import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
4
4
|
//#region src/utils/stableStringify.ts
|
|
@@ -101,4 +101,4 @@ function sanitizeJsxChildren(childrenAsObjects) {
|
|
|
101
101
|
//#endregion
|
|
102
102
|
export { hashString as n, hashSource as t };
|
|
103
103
|
|
|
104
|
-
//# sourceMappingURL=id-
|
|
104
|
+
//# sourceMappingURL=id-BMOKDfiZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"id-
|
|
1
|
+
{"version":3,"file":"id-BMOKDfiZ.mjs","names":["stringify"],"sources":["../src/utils/stableStringify.ts","../src/id/hashSource.ts"],"sourcesContent":["/**\n * Deterministic JSON stringification with sorted object keys.\n * Drop-in replacement for `fast-json-stable-stringify` for plain\n * JSON-compatible data (no toJSON, no circular references).\n */\nfunction _stringify(node: unknown): string | undefined {\n if (node === undefined) return undefined;\n if (node === null) return 'null';\n if (typeof node === 'number') return isFinite(node) ? '' + node : 'null';\n if (typeof node !== 'object') return JSON.stringify(node);\n\n if (Array.isArray(node)) {\n let out = '[';\n for (let i = 0; i < node.length; i++) {\n if (i) out += ',';\n out += _stringify(node[i]) || 'null';\n }\n return out + ']';\n }\n\n const keys = Object.keys(node as Record<string, unknown>).sort();\n let out = '';\n for (const key of keys) {\n const value = _stringify((node as Record<string, unknown>)[key]);\n if (!value) continue;\n if (out) out += ',';\n out += JSON.stringify(key) + ':' + value;\n }\n return '{' + out + '}';\n}\n\nexport function stableStringify(data: unknown): string {\n return _stringify(data) ?? '';\n}\n","// Functions provided to other GT libraries\n\nimport { JsxChild, JsxChildren, Variable } from '../types';\nimport { stableStringify as stringify } from '../utils/stableStringify';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { bytesToHex, utf8ToBytes } from '@noble/hashes/utils.js';\nimport { isVariable } from '../utils/isVariable';\nimport { HashMetadata } from './types';\n\n// ----- FUNCTIONS ----- //\n/**\n * Calculates a unique hash for a given string using SHA-256.\n *\n * First 16 characters of hash, hex encoded.\n *\n * @param {string} string - The string to be hashed.\n * @returns {string} The resulting hash as a hexadecimal string.\n */\nexport function hashString(string: string): string {\n return bytesToHex(sha256(utf8ToBytes(string))).slice(0, 16);\n}\n\n/**\n * Calculates a unique ID for the given children objects by hashing their sanitized JSON string representation.\n *\n * @param {any} childrenAsObjects - The children objects to be hashed.\n * @param {string} [context] - The context for the children.\n * @param {string} [id] - Deprecated custom ID. It remains part of the hash for\n * backward compatibility, but will be removed in the next major version.\n * @param {number} [maxChars] - The maxChars limit for the JSX children object.\n * @param {string} [dataFormat] - The data format of the sources.\n * @param {function} [hashFunction] - Custom hash function.\n * @returns {string} - The unique hash of the children.\n */\nexport function hashSource(\n {\n source,\n context,\n id,\n maxChars,\n requiresReview,\n dataFormat,\n }: {\n source: JsxChildren | string;\n } & HashMetadata,\n hashFunction: (string: string) => string = hashString\n): string {\n let sanitizedSource: SanitizedChildren | string;\n if (dataFormat === 'JSX') {\n sanitizedSource = sanitizeJsxChildren(source);\n } else {\n sanitizedSource = source as string;\n }\n const sanitizedData: {\n source?: SanitizedChildren;\n } & HashMetadata = {\n source: sanitizedSource,\n ...(id && { id }),\n ...(context && { context }),\n ...(maxChars != null && { maxChars: Math.abs(maxChars) }),\n // Only mixed in when true: false/absent must hash identically to\n // pre-requiresReview versions so existing projects keep their hashes\n ...(requiresReview === true && { requiresReview: true }),\n ...(dataFormat && { dataFormat }),\n };\n const stringifiedData = stringify(sanitizedData);\n return hashFunction(stringifiedData);\n}\n\ntype SanitizedVariable = Omit<Variable, 'i'>;\n\ntype SanitizedElement = {\n b?: {\n [k: string]: SanitizedChildren; // Branches\n };\n c?: SanitizedChildren; // Children\n t?: string; // Branch Transformation\n};\ntype SanitizedChild = SanitizedElement | SanitizedVariable | string;\ntype SanitizedChildren = SanitizedChild | SanitizedChild[];\n\n/**\n * Sanitizes a child object by removing the data-_gt attribute and its branches.\n *\n * @param child - The child object to sanitize.\n * @returns The sanitized child object.\n *\n */\nconst sanitizeChild = (child: JsxChild): SanitizedChild => {\n if (child && typeof child === 'object') {\n const newChild: SanitizedChild = {};\n if ('c' in child && child.c) {\n newChild.c = sanitizeJsxChildren(child.c);\n }\n if ('d' in child) {\n const generaltranslation = child?.d;\n if (generaltranslation?.b) {\n // The only thing that prevents sanitizeJsx from being stable is\n // the order of the keys in the branches object.\n // We don't sort them because stable-stringify sorts them anyways\n newChild.b = Object.fromEntries(\n Object.entries(generaltranslation.b).map(([key, value]) => [\n key,\n sanitizeJsxChildren(value as JsxChildren),\n ])\n );\n }\n if (generaltranslation?.t) {\n newChild.t = generaltranslation.t;\n }\n }\n if (isVariable(child)) {\n return {\n k: child.k,\n ...(child.v && {\n v: child.v,\n }),\n };\n }\n return newChild;\n }\n return child;\n};\n\nfunction sanitizeJsxChildren(\n childrenAsObjects: JsxChildren\n): SanitizedChildren {\n return Array.isArray(childrenAsObjects)\n ? childrenAsObjects.map(sanitizeChild)\n : sanitizeChild(childrenAsObjects);\n}\n"],"mappings":";;;;;;;;;AAKA,SAAS,WAAW,MAAmC;AACrD,KAAI,SAAS,KAAA,EAAW,QAAO,KAAA;AAC/B,KAAI,SAAS,KAAM,QAAO;AAC1B,KAAI,OAAO,SAAS,SAAU,QAAO,SAAS,KAAK,GAAG,KAAK,OAAO;AAClE,KAAI,OAAO,SAAS,SAAU,QAAO,KAAK,UAAU,KAAK;AAEzD,KAAI,MAAM,QAAQ,KAAK,EAAE;EACvB,IAAI,MAAM;AACV,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,OAAI,EAAG,QAAO;AACd,UAAO,WAAW,KAAK,GAAG,IAAI;;AAEhC,SAAO,MAAM;;CAGf,MAAM,OAAO,OAAO,KAAK,KAAgC,CAAC,MAAM;CAChE,IAAI,MAAM;AACV,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,WAAY,KAAiC,KAAK;AAChE,MAAI,CAAC,MAAO;AACZ,MAAI,IAAK,QAAO;AAChB,SAAO,KAAK,UAAU,IAAI,GAAG,MAAM;;AAErC,QAAO,MAAM,MAAM;;AAGrB,SAAgB,gBAAgB,MAAuB;AACrD,QAAO,WAAW,KAAK,IAAI;;;;;;;;;;;;ACd7B,SAAgB,WAAW,QAAwB;AACjD,QAAO,WAAW,OAAO,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG;;;;;;;;;;;;;;AAe7D,SAAgB,WACd,EACE,QACA,SACA,IACA,UACA,gBACA,cAIF,eAA2C,YACnC;CACR,IAAI;AACJ,KAAI,eAAe,MACjB,mBAAkB,oBAAoB,OAAO;KAE7C,mBAAkB;AAepB,QAAO,aADiBA,gBAAU;EAThC,QAAQ;EACR,GAAI,MAAM,EAAE,IAAI;EAChB,GAAI,WAAW,EAAE,SAAS;EAC1B,GAAI,YAAY,QAAQ,EAAE,UAAU,KAAK,IAAI,SAAS,EAAE;EAGxD,GAAI,mBAAmB,QAAQ,EAAE,gBAAgB,MAAM;EACvD,GAAI,cAAc,EAAE,YAAY;EAEa,CACZ,CAAC;;;;;;;;;AAsBtC,MAAM,iBAAiB,UAAoC;AACzD,KAAI,SAAS,OAAO,UAAU,UAAU;EACtC,MAAM,WAA2B,EAAE;AACnC,MAAI,OAAO,SAAS,MAAM,EACxB,UAAS,IAAI,oBAAoB,MAAM,EAAE;AAE3C,MAAI,OAAO,OAAO;GAChB,MAAM,qBAAqB,OAAO;AAClC,OAAI,oBAAoB,EAItB,UAAS,IAAI,OAAO,YAClB,OAAO,QAAQ,mBAAmB,EAAE,CAAC,KAAK,CAAC,KAAK,WAAW,CACzD,KACA,oBAAoB,MAAqB,CAC1C,CAAC,CACH;AAEH,OAAI,oBAAoB,EACtB,UAAS,IAAI,mBAAmB;;AAGpC,MAAI,WAAW,MAAM,CACnB,QAAO;GACL,GAAG,MAAM;GACT,GAAI,MAAM,KAAK,EACb,GAAG,MAAM,GACV;GACF;AAEH,SAAO;;AAET,QAAO;;AAGT,SAAS,oBACP,mBACmB;AACnB,QAAO,MAAM,QAAQ,kBAAkB,GACnC,kBAAkB,IAAI,cAAc,GACpC,cAAc,kBAAkB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_isVariable = require("./isVariable-
|
|
1
|
+
const require_isVariable = require("./isVariable-I3nllgeI.cjs");
|
|
2
2
|
//#region src/utils/stableStringify.ts
|
|
3
3
|
/**
|
|
4
4
|
* Deterministic JSON stringification with sorted object keys.
|
|
@@ -775,4 +775,4 @@ Object.defineProperty(exports, "hashString", {
|
|
|
775
775
|
}
|
|
776
776
|
});
|
|
777
777
|
|
|
778
|
-
//# sourceMappingURL=id-
|
|
778
|
+
//# sourceMappingURL=id-BpSNpXZu.cjs.map
|