@worldware/msg-cli 0.0.4 → 0.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/dist/chunk-4Q2252JQ.mjs +50 -0
- package/dist/chunk-DBC2Y6VQ.mjs +167 -0
- package/dist/chunk-KKYCVD5M.mjs +136 -0
- package/dist/commands/create/project.cjs +293 -0
- package/dist/commands/create/project.d.mts +22 -0
- package/dist/commands/create/project.d.ts +22 -0
- package/dist/commands/create/project.mjs +151 -0
- package/dist/commands/create/resource.cjs +355 -0
- package/dist/commands/create/resource.d.mts +22 -0
- package/dist/commands/create/resource.d.ts +22 -0
- package/dist/commands/create/resource.mjs +143 -0
- package/dist/commands/init.cjs +259 -0
- package/dist/commands/init.d.mts +20 -0
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/init.mjs +133 -0
- package/dist/lib/create-project-helpers.cjs +163 -0
- package/dist/lib/create-project-helpers.d.mts +50 -0
- package/dist/lib/create-project-helpers.d.ts +50 -0
- package/dist/lib/create-project-helpers.mjs +14 -0
- package/dist/lib/create-resource-helpers.cjs +225 -0
- package/dist/lib/create-resource-helpers.d.mts +55 -0
- package/dist/lib/create-resource-helpers.d.ts +55 -0
- package/dist/lib/create-resource-helpers.mjs +15 -0
- package/dist/lib/init-helpers.cjs +203 -0
- package/dist/lib/init-helpers.d.mts +100 -0
- package/dist/lib/init-helpers.d.ts +100 -0
- package/dist/lib/init-helpers.mjs +30 -0
- package/dist/lib/utilities.cjs +203 -0
- package/dist/lib/utilities.d.mts +59 -0
- package/dist/lib/utilities.d.ts +59 -0
- package/dist/lib/utilities.mjs +172 -0
- package/package.json +7 -4
- package/dist/commands/create/project.js +0 -160
- package/dist/commands/create/resource.js +0 -169
- package/dist/commands/init.js +0 -131
- package/dist/lib/create-project-helpers.js +0 -112
- package/dist/lib/create-resource-helpers.js +0 -178
- package/dist/lib/init-helpers.js +0 -219
- package/dist/lib/utilities.js +0 -286
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** Default relative path for the i18n directory. */
|
|
2
|
+
declare const DEFAULT_I18N_DIR = "src/i18n";
|
|
3
|
+
/** Default relative path for the l10n directory. */
|
|
4
|
+
declare const DEFAULT_L10N_DIR = "res/l10n";
|
|
5
|
+
/** Minimal type for package.json fields we read/write. */
|
|
6
|
+
interface PackageJson {
|
|
7
|
+
name?: string;
|
|
8
|
+
directories?: Record<string, string>;
|
|
9
|
+
imports?: Record<string, string>;
|
|
10
|
+
scripts?: Record<string, string>;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Finds package.json by walking up from the given directory.
|
|
15
|
+
* @param cwd - Directory to start from (e.g. process.cwd())
|
|
16
|
+
* @returns Absolute path to package.json, or null if not found
|
|
17
|
+
*/
|
|
18
|
+
declare function findPackageJsonPath(cwd: string): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Reads and parses package.json.
|
|
21
|
+
* @param pkgPath - Absolute path to package.json
|
|
22
|
+
* @returns Parsed package.json object
|
|
23
|
+
* @throws Error if file is unreadable or invalid JSON
|
|
24
|
+
*/
|
|
25
|
+
declare function readPackageJson(pkgPath: string): PackageJson;
|
|
26
|
+
/** Result of loadPackageJsonForMsg - shared package.json context for msg commands. */
|
|
27
|
+
interface MsgPackageContext {
|
|
28
|
+
pkgPath: string;
|
|
29
|
+
rootDir: string;
|
|
30
|
+
pkg: PackageJson;
|
|
31
|
+
i18nDir: string;
|
|
32
|
+
l10nDir?: string;
|
|
33
|
+
isEsm: boolean;
|
|
34
|
+
useTypeScript: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Loads package.json for msg commands (create project, create resource, etc.).
|
|
38
|
+
* Finds package.json from cwd, validates directories, and derives module info.
|
|
39
|
+
* @param cwd - Directory to start from (e.g. process.cwd())
|
|
40
|
+
* @param options - requireL10n: if true, directories.l10n must exist (default: false)
|
|
41
|
+
* @returns Package context with pkgPath, rootDir, pkg, i18nDir, l10nDir?, isEsm, useTypeScript
|
|
42
|
+
* @throws Error if package.json not found or required directories missing
|
|
43
|
+
*/
|
|
44
|
+
declare function loadPackageJsonForMsg(cwd: string, options?: {
|
|
45
|
+
requireL10n?: boolean;
|
|
46
|
+
}): MsgPackageContext;
|
|
47
|
+
/**
|
|
48
|
+
* Writes package.json to disk with trailing newline.
|
|
49
|
+
* @param pkgPath - Absolute path to package.json
|
|
50
|
+
* @param pkg - Object to serialize
|
|
51
|
+
*/
|
|
52
|
+
declare function writePackageJson(pkgPath: string, pkg: PackageJson): void;
|
|
53
|
+
/**
|
|
54
|
+
* Validates i18n and l10n paths (relative, non-empty, no absolute segments).
|
|
55
|
+
* @param rootDir - Project root (absolute)
|
|
56
|
+
* @param i18nDir - Relative i18n path
|
|
57
|
+
* @param l10nDir - Relative l10n path
|
|
58
|
+
* @returns Object with valid: boolean and optional error message
|
|
59
|
+
*/
|
|
60
|
+
declare function validatePaths(rootDir: string, i18nDir: string, l10nDir: string): {
|
|
61
|
+
valid: true;
|
|
62
|
+
} | {
|
|
63
|
+
valid: false;
|
|
64
|
+
error: string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Ensures i18n and l10n directory trees exist and adds .gitkeep to leaf dirs.
|
|
68
|
+
* Leaf dirs: i18n/projects, i18n/resources, l10n/translations, l10n/xliff.
|
|
69
|
+
* @param rootDir - Project root (absolute)
|
|
70
|
+
* @param i18nDir - Relative i18n path
|
|
71
|
+
* @param l10nDir - Relative l10n path
|
|
72
|
+
* @param force - If true, overwrite/recreate even when dirs exist or are non-empty
|
|
73
|
+
*/
|
|
74
|
+
declare function ensureDirectoriesWithGitkeep(rootDir: string, i18nDir: string, l10nDir: string, force: boolean): void;
|
|
75
|
+
/**
|
|
76
|
+
* Returns true if package.json already has msg directories and they exist on disk.
|
|
77
|
+
*/
|
|
78
|
+
declare function isAlreadyInitialized(pkg: PackageJson, rootDir: string, i18nDir: string, l10nDir: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Adds or overwrites directories.i18n, directories.l10n, directories.root in package.json.
|
|
81
|
+
*/
|
|
82
|
+
declare function addDirectoriesToPackageJson(pkg: PackageJson, i18nDir: string, l10nDir: string): PackageJson;
|
|
83
|
+
/**
|
|
84
|
+
* Adds import aliases #i18n/*, #l10n/*, #root/* to package.json imports.
|
|
85
|
+
*/
|
|
86
|
+
declare function addImportAliasesToPackageJson(pkg: PackageJson, i18nDir: string, l10nDir: string): PackageJson;
|
|
87
|
+
/**
|
|
88
|
+
* Adds i18n-export and l10n-import scripts to package.json.
|
|
89
|
+
*/
|
|
90
|
+
declare function addScriptsToPackageJson(pkg: PackageJson): PackageJson;
|
|
91
|
+
/**
|
|
92
|
+
* Reads tsconfig.json, adds baseUrl and paths for #i18n/*, #l10n/*, #root/*, and writes it back.
|
|
93
|
+
* Merges into existing compilerOptions.paths and compilerOptions.baseUrl if present.
|
|
94
|
+
* @param tsconfigPath - Absolute path to tsconfig.json
|
|
95
|
+
* @param i18nDir - Relative i18n path
|
|
96
|
+
* @param l10nDir - Relative l10n path
|
|
97
|
+
*/
|
|
98
|
+
declare function addTsconfigPaths(tsconfigPath: string, i18nDir: string, l10nDir: string): void;
|
|
99
|
+
|
|
100
|
+
export { DEFAULT_I18N_DIR, DEFAULT_L10N_DIR, type MsgPackageContext, type PackageJson, addDirectoriesToPackageJson, addImportAliasesToPackageJson, addScriptsToPackageJson, addTsconfigPaths, ensureDirectoriesWithGitkeep, findPackageJsonPath, isAlreadyInitialized, loadPackageJsonForMsg, readPackageJson, validatePaths, writePackageJson };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** Default relative path for the i18n directory. */
|
|
2
|
+
declare const DEFAULT_I18N_DIR = "src/i18n";
|
|
3
|
+
/** Default relative path for the l10n directory. */
|
|
4
|
+
declare const DEFAULT_L10N_DIR = "res/l10n";
|
|
5
|
+
/** Minimal type for package.json fields we read/write. */
|
|
6
|
+
interface PackageJson {
|
|
7
|
+
name?: string;
|
|
8
|
+
directories?: Record<string, string>;
|
|
9
|
+
imports?: Record<string, string>;
|
|
10
|
+
scripts?: Record<string, string>;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Finds package.json by walking up from the given directory.
|
|
15
|
+
* @param cwd - Directory to start from (e.g. process.cwd())
|
|
16
|
+
* @returns Absolute path to package.json, or null if not found
|
|
17
|
+
*/
|
|
18
|
+
declare function findPackageJsonPath(cwd: string): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Reads and parses package.json.
|
|
21
|
+
* @param pkgPath - Absolute path to package.json
|
|
22
|
+
* @returns Parsed package.json object
|
|
23
|
+
* @throws Error if file is unreadable or invalid JSON
|
|
24
|
+
*/
|
|
25
|
+
declare function readPackageJson(pkgPath: string): PackageJson;
|
|
26
|
+
/** Result of loadPackageJsonForMsg - shared package.json context for msg commands. */
|
|
27
|
+
interface MsgPackageContext {
|
|
28
|
+
pkgPath: string;
|
|
29
|
+
rootDir: string;
|
|
30
|
+
pkg: PackageJson;
|
|
31
|
+
i18nDir: string;
|
|
32
|
+
l10nDir?: string;
|
|
33
|
+
isEsm: boolean;
|
|
34
|
+
useTypeScript: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Loads package.json for msg commands (create project, create resource, etc.).
|
|
38
|
+
* Finds package.json from cwd, validates directories, and derives module info.
|
|
39
|
+
* @param cwd - Directory to start from (e.g. process.cwd())
|
|
40
|
+
* @param options - requireL10n: if true, directories.l10n must exist (default: false)
|
|
41
|
+
* @returns Package context with pkgPath, rootDir, pkg, i18nDir, l10nDir?, isEsm, useTypeScript
|
|
42
|
+
* @throws Error if package.json not found or required directories missing
|
|
43
|
+
*/
|
|
44
|
+
declare function loadPackageJsonForMsg(cwd: string, options?: {
|
|
45
|
+
requireL10n?: boolean;
|
|
46
|
+
}): MsgPackageContext;
|
|
47
|
+
/**
|
|
48
|
+
* Writes package.json to disk with trailing newline.
|
|
49
|
+
* @param pkgPath - Absolute path to package.json
|
|
50
|
+
* @param pkg - Object to serialize
|
|
51
|
+
*/
|
|
52
|
+
declare function writePackageJson(pkgPath: string, pkg: PackageJson): void;
|
|
53
|
+
/**
|
|
54
|
+
* Validates i18n and l10n paths (relative, non-empty, no absolute segments).
|
|
55
|
+
* @param rootDir - Project root (absolute)
|
|
56
|
+
* @param i18nDir - Relative i18n path
|
|
57
|
+
* @param l10nDir - Relative l10n path
|
|
58
|
+
* @returns Object with valid: boolean and optional error message
|
|
59
|
+
*/
|
|
60
|
+
declare function validatePaths(rootDir: string, i18nDir: string, l10nDir: string): {
|
|
61
|
+
valid: true;
|
|
62
|
+
} | {
|
|
63
|
+
valid: false;
|
|
64
|
+
error: string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Ensures i18n and l10n directory trees exist and adds .gitkeep to leaf dirs.
|
|
68
|
+
* Leaf dirs: i18n/projects, i18n/resources, l10n/translations, l10n/xliff.
|
|
69
|
+
* @param rootDir - Project root (absolute)
|
|
70
|
+
* @param i18nDir - Relative i18n path
|
|
71
|
+
* @param l10nDir - Relative l10n path
|
|
72
|
+
* @param force - If true, overwrite/recreate even when dirs exist or are non-empty
|
|
73
|
+
*/
|
|
74
|
+
declare function ensureDirectoriesWithGitkeep(rootDir: string, i18nDir: string, l10nDir: string, force: boolean): void;
|
|
75
|
+
/**
|
|
76
|
+
* Returns true if package.json already has msg directories and they exist on disk.
|
|
77
|
+
*/
|
|
78
|
+
declare function isAlreadyInitialized(pkg: PackageJson, rootDir: string, i18nDir: string, l10nDir: string): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Adds or overwrites directories.i18n, directories.l10n, directories.root in package.json.
|
|
81
|
+
*/
|
|
82
|
+
declare function addDirectoriesToPackageJson(pkg: PackageJson, i18nDir: string, l10nDir: string): PackageJson;
|
|
83
|
+
/**
|
|
84
|
+
* Adds import aliases #i18n/*, #l10n/*, #root/* to package.json imports.
|
|
85
|
+
*/
|
|
86
|
+
declare function addImportAliasesToPackageJson(pkg: PackageJson, i18nDir: string, l10nDir: string): PackageJson;
|
|
87
|
+
/**
|
|
88
|
+
* Adds i18n-export and l10n-import scripts to package.json.
|
|
89
|
+
*/
|
|
90
|
+
declare function addScriptsToPackageJson(pkg: PackageJson): PackageJson;
|
|
91
|
+
/**
|
|
92
|
+
* Reads tsconfig.json, adds baseUrl and paths for #i18n/*, #l10n/*, #root/*, and writes it back.
|
|
93
|
+
* Merges into existing compilerOptions.paths and compilerOptions.baseUrl if present.
|
|
94
|
+
* @param tsconfigPath - Absolute path to tsconfig.json
|
|
95
|
+
* @param i18nDir - Relative i18n path
|
|
96
|
+
* @param l10nDir - Relative l10n path
|
|
97
|
+
*/
|
|
98
|
+
declare function addTsconfigPaths(tsconfigPath: string, i18nDir: string, l10nDir: string): void;
|
|
99
|
+
|
|
100
|
+
export { DEFAULT_I18N_DIR, DEFAULT_L10N_DIR, type MsgPackageContext, type PackageJson, addDirectoriesToPackageJson, addImportAliasesToPackageJson, addScriptsToPackageJson, addTsconfigPaths, ensureDirectoriesWithGitkeep, findPackageJsonPath, isAlreadyInitialized, loadPackageJsonForMsg, readPackageJson, validatePaths, writePackageJson };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_I18N_DIR,
|
|
3
|
+
DEFAULT_L10N_DIR,
|
|
4
|
+
addDirectoriesToPackageJson,
|
|
5
|
+
addImportAliasesToPackageJson,
|
|
6
|
+
addScriptsToPackageJson,
|
|
7
|
+
addTsconfigPaths,
|
|
8
|
+
ensureDirectoriesWithGitkeep,
|
|
9
|
+
findPackageJsonPath,
|
|
10
|
+
isAlreadyInitialized,
|
|
11
|
+
loadPackageJsonForMsg,
|
|
12
|
+
readPackageJson,
|
|
13
|
+
validatePaths,
|
|
14
|
+
writePackageJson
|
|
15
|
+
} from "../chunk-DBC2Y6VQ.mjs";
|
|
16
|
+
export {
|
|
17
|
+
DEFAULT_I18N_DIR,
|
|
18
|
+
DEFAULT_L10N_DIR,
|
|
19
|
+
addDirectoriesToPackageJson,
|
|
20
|
+
addImportAliasesToPackageJson,
|
|
21
|
+
addScriptsToPackageJson,
|
|
22
|
+
addTsconfigPaths,
|
|
23
|
+
ensureDirectoriesWithGitkeep,
|
|
24
|
+
findPackageJsonPath,
|
|
25
|
+
isAlreadyInitialized,
|
|
26
|
+
loadPackageJsonForMsg,
|
|
27
|
+
readPackageJson,
|
|
28
|
+
validatePaths,
|
|
29
|
+
writePackageJson
|
|
30
|
+
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/utilities.ts
|
|
21
|
+
var utilities_exports = {};
|
|
22
|
+
__export(utilities_exports, {
|
|
23
|
+
findMsgResourceFiles: () => findMsgResourceFiles,
|
|
24
|
+
importMsgResources: () => importMsgResources,
|
|
25
|
+
parseXliff: () => parseXliff,
|
|
26
|
+
readXliff: () => readXliff,
|
|
27
|
+
resourcesToXliffString: () => resourcesToXliffString,
|
|
28
|
+
writeTranslationData: () => writeTranslationData,
|
|
29
|
+
writeXliff: () => writeXliff,
|
|
30
|
+
xliffDataToResourceTranslationData: () => xliffDataToResourceTranslationData,
|
|
31
|
+
xliffToTranslationData: () => xliffToTranslationData
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(utilities_exports);
|
|
34
|
+
var import_msg = require("@worldware/msg");
|
|
35
|
+
var import_promises = require("fs/promises");
|
|
36
|
+
var import_path = require("path");
|
|
37
|
+
var import_url = require("url");
|
|
38
|
+
var import_fast_xml_parser = require("fast-xml-parser");
|
|
39
|
+
var MSG_PATTERN = /\.msg\.(ts|js)$/i;
|
|
40
|
+
async function findMsgResourceFiles(directory) {
|
|
41
|
+
const result = [];
|
|
42
|
+
const entries = await (0, import_promises.readdir)(directory, { withFileTypes: true });
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const fullPath = (0, import_path.join)(directory, entry.name);
|
|
45
|
+
if (entry.isFile() && MSG_PATTERN.test(entry.name)) {
|
|
46
|
+
result.push(fullPath);
|
|
47
|
+
} else if (entry.isDirectory()) {
|
|
48
|
+
result.push(...await findMsgResourceFiles(fullPath));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
async function importMsgResources(filePaths) {
|
|
54
|
+
const byProjectName = /* @__PURE__ */ new Map();
|
|
55
|
+
for (const filePath of filePaths) {
|
|
56
|
+
if (!MSG_PATTERN.test(filePath)) {
|
|
57
|
+
throw new Error(`File does not have .msg. in filename: ${filePath}`);
|
|
58
|
+
}
|
|
59
|
+
const url = (0, import_url.pathToFileURL)(filePath).href;
|
|
60
|
+
const mod = await import(url);
|
|
61
|
+
const resource = mod.default ?? mod.resource ?? mod.MsgResource;
|
|
62
|
+
if (!resource || !(resource instanceof import_msg.MsgResource)) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Failed to import MsgResource from ${filePath}: no valid export found`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const project = resource.getProject();
|
|
68
|
+
const projectName = project.project.name;
|
|
69
|
+
let group = byProjectName.get(projectName);
|
|
70
|
+
if (!group) {
|
|
71
|
+
group = { project, resources: [] };
|
|
72
|
+
byProjectName.set(projectName, group);
|
|
73
|
+
}
|
|
74
|
+
group.resources.push(resource);
|
|
75
|
+
}
|
|
76
|
+
const result = /* @__PURE__ */ new Map();
|
|
77
|
+
for (const { project, resources } of byProjectName.values()) {
|
|
78
|
+
result.set(project, resources);
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
async function resourcesToXliffString(resources) {
|
|
83
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
84
|
+
for (const resource of resources) {
|
|
85
|
+
const project = resource.getProject();
|
|
86
|
+
let arr = byProject.get(project);
|
|
87
|
+
if (!arr) {
|
|
88
|
+
arr = [];
|
|
89
|
+
byProject.set(project, arr);
|
|
90
|
+
}
|
|
91
|
+
arr.push(resource);
|
|
92
|
+
}
|
|
93
|
+
const result = /* @__PURE__ */ new Map();
|
|
94
|
+
for (const [project, arr] of byProject) {
|
|
95
|
+
const xliff = serializeResourcesToXliff(arr);
|
|
96
|
+
result.set(project, xliff);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
function serializeResourcesToXliff(resources) {
|
|
101
|
+
const xmlns = "urn:oasis:names:tc:xliff:document:1.2";
|
|
102
|
+
const parts = [
|
|
103
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
104
|
+
`<xliff version="1.2" xmlns="${xmlns}">`
|
|
105
|
+
];
|
|
106
|
+
for (const resource of resources) {
|
|
107
|
+
const orig = `${resource.title}.json`;
|
|
108
|
+
const sourceLang = resource.attributes.lang || "en";
|
|
109
|
+
const data = resource.getData(false);
|
|
110
|
+
parts.push(
|
|
111
|
+
` <file original="${escapeXml(orig)}" source-language="${escapeXml(sourceLang)}" datatype="plaintext">`
|
|
112
|
+
);
|
|
113
|
+
parts.push(" <body>");
|
|
114
|
+
for (const msg of data.messages || []) {
|
|
115
|
+
const key = msg.key;
|
|
116
|
+
const value = msg.value;
|
|
117
|
+
const attrs = [`id="${escapeXml(key)}"`, `resname="${escapeXml(key)}"`];
|
|
118
|
+
parts.push(` <trans-unit ${attrs.join(" ")}>`);
|
|
119
|
+
parts.push(` <source>${escapeXml(value)}</source>`);
|
|
120
|
+
parts.push(` </trans-unit>`);
|
|
121
|
+
}
|
|
122
|
+
parts.push(" </body>");
|
|
123
|
+
parts.push(" </file>");
|
|
124
|
+
}
|
|
125
|
+
parts.push("</xliff>");
|
|
126
|
+
return parts.join("\n");
|
|
127
|
+
}
|
|
128
|
+
function escapeXml(s) {
|
|
129
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
130
|
+
}
|
|
131
|
+
async function writeXliff(filePath, xliff) {
|
|
132
|
+
await (0, import_promises.writeFile)(filePath, xliff, "utf-8");
|
|
133
|
+
}
|
|
134
|
+
async function readXliff(filePath) {
|
|
135
|
+
return (0, import_promises.readFile)(filePath, "utf-8");
|
|
136
|
+
}
|
|
137
|
+
var xmlParser = new import_fast_xml_parser.XMLParser({
|
|
138
|
+
ignoreAttributes: false,
|
|
139
|
+
attributeNamePrefix: "@_"
|
|
140
|
+
});
|
|
141
|
+
async function parseXliff(xliff) {
|
|
142
|
+
try {
|
|
143
|
+
const parsed = xmlParser.parse(xliff);
|
|
144
|
+
if (!parsed || typeof parsed !== "object") {
|
|
145
|
+
throw new Error("Invalid XLIFF: failed to parse");
|
|
146
|
+
}
|
|
147
|
+
return parsed;
|
|
148
|
+
} catch (err) {
|
|
149
|
+
const message = err instanceof Error ? err.message : "Failed to parse XLIFF";
|
|
150
|
+
throw new Error(`Invalid XLIFF 1.2: ${message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function xliffDataToResourceTranslationData(parsedXliff) {
|
|
154
|
+
const result = [];
|
|
155
|
+
const xliff = parsedXliff;
|
|
156
|
+
const fileEl = xliff?.xliff?.file;
|
|
157
|
+
if (!fileEl) return result;
|
|
158
|
+
const files = Array.isArray(fileEl) ? fileEl : [fileEl];
|
|
159
|
+
for (const file of files) {
|
|
160
|
+
const f = file;
|
|
161
|
+
const orig = f["@_original"] ?? "unknown";
|
|
162
|
+
const title = (0, import_path.basename)(orig, (0, import_path.extname)(orig)) || orig;
|
|
163
|
+
const targetLang = f["@_target-language"] ?? f["@_source-language"] ?? "";
|
|
164
|
+
const transUnits = f.body?.["trans-unit"];
|
|
165
|
+
const units = Array.isArray(transUnits) ? transUnits : transUnits ? [transUnits] : [];
|
|
166
|
+
const messages = [];
|
|
167
|
+
for (const tu of units) {
|
|
168
|
+
const t = tu;
|
|
169
|
+
const translate = (t["@_translate"] ?? "yes").toLowerCase();
|
|
170
|
+
if (translate === "no" || translate === "false") continue;
|
|
171
|
+
const key = t["@_resname"] ?? t["@_id"] ?? "";
|
|
172
|
+
const targetEl = t.target;
|
|
173
|
+
const value = (typeof targetEl === "object" && targetEl && "#text" in targetEl ? targetEl["#text"] : typeof targetEl === "string" ? targetEl : "") ?? "";
|
|
174
|
+
messages.push({ key, value });
|
|
175
|
+
}
|
|
176
|
+
result.push({
|
|
177
|
+
title,
|
|
178
|
+
attributes: { lang: targetLang, dir: "", dnt: false },
|
|
179
|
+
messages
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
async function xliffToTranslationData(xliff) {
|
|
185
|
+
const parsed = await parseXliff(xliff);
|
|
186
|
+
return xliffDataToResourceTranslationData(parsed);
|
|
187
|
+
}
|
|
188
|
+
async function writeTranslationData(filePath, data) {
|
|
189
|
+
const json = JSON.stringify(data, null, 2);
|
|
190
|
+
await (0, import_promises.writeFile)(filePath, json, "utf-8");
|
|
191
|
+
}
|
|
192
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
193
|
+
0 && (module.exports = {
|
|
194
|
+
findMsgResourceFiles,
|
|
195
|
+
importMsgResources,
|
|
196
|
+
parseXliff,
|
|
197
|
+
readXliff,
|
|
198
|
+
resourcesToXliffString,
|
|
199
|
+
writeTranslationData,
|
|
200
|
+
writeXliff,
|
|
201
|
+
xliffDataToResourceTranslationData,
|
|
202
|
+
xliffToTranslationData
|
|
203
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { MsgProject, MsgResource, MsgResourceData } from '@worldware/msg';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Recursively finds all javascript and typescript files in a directory that have
|
|
5
|
+
* an `.msg.` substring in their filename just before the file extension.
|
|
6
|
+
* @param directory - The directory path to search
|
|
7
|
+
* @returns Promise resolving to array of file paths
|
|
8
|
+
*/
|
|
9
|
+
declare function findMsgResourceFiles(directory: string): Promise<string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Dynamically imports MsgResource objects from .msg. files and groups them by project.
|
|
12
|
+
* @param filePaths - Array of paths to .msg. files
|
|
13
|
+
* @returns Promise resolving to Map of MsgProject keys and MsgResource array values
|
|
14
|
+
*/
|
|
15
|
+
declare function importMsgResources(filePaths: string[]): Promise<Map<MsgProject, MsgResource[]>>;
|
|
16
|
+
/**
|
|
17
|
+
* Serializes MsgResource arrays into monolingual XLIFF 1.2 strings per project.
|
|
18
|
+
* @param resources - Array of MsgResource objects
|
|
19
|
+
* @returns Promise resolving to Map of MsgProject keys and xliff string values
|
|
20
|
+
*/
|
|
21
|
+
declare function resourcesToXliffString(resources: MsgResource[]): Promise<Map<MsgProject, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* Writes an XLIFF 1.2 string to a file with appropriate indentation.
|
|
24
|
+
* @param filePath - The destination file path
|
|
25
|
+
* @param xliff - The serialized XLIFF 1.2 string
|
|
26
|
+
*/
|
|
27
|
+
declare function writeXliff(filePath: string, xliff: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Reads XLIFF 1.2 content from a file.
|
|
30
|
+
* @param filePath - The path to the XLIFF file
|
|
31
|
+
* @returns Promise resolving to the XLIFF string content
|
|
32
|
+
*/
|
|
33
|
+
declare function readXliff(filePath: string): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Parses an XLIFF 1.2 string into a javascript object, preserving notes and attributes.
|
|
36
|
+
* @param xliff - Valid XLIFF 1.2 string
|
|
37
|
+
* @returns Promise resolving to parsed object
|
|
38
|
+
*/
|
|
39
|
+
declare function parseXliff(xliff: string): Promise<object>;
|
|
40
|
+
/**
|
|
41
|
+
* Extracts MsgResourceData from parsed XLIFF 1.2 object.
|
|
42
|
+
* @param parsedXliff - Parsed XLIFF 1.2 javascript object
|
|
43
|
+
* @returns Promise resolving to array of MsgResourceData objects
|
|
44
|
+
*/
|
|
45
|
+
declare function xliffDataToResourceTranslationData(parsedXliff: object): Promise<MsgResourceData[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Parses XLIFF 1.2 string and extracts translation data to MsgResourceData objects.
|
|
48
|
+
* @param xliff - Valid XLIFF 1.2 string
|
|
49
|
+
* @returns Promise resolving to array of MsgResourceData objects
|
|
50
|
+
*/
|
|
51
|
+
declare function xliffToTranslationData(xliff: string): Promise<MsgResourceData[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Serializes MsgResourceData to JSON and writes it to a file.
|
|
54
|
+
* @param filePath - The destination file path
|
|
55
|
+
* @param data - MsgResourceData object to serialize
|
|
56
|
+
*/
|
|
57
|
+
declare function writeTranslationData(filePath: string, data: MsgResourceData): Promise<void>;
|
|
58
|
+
|
|
59
|
+
export { findMsgResourceFiles, importMsgResources, parseXliff, readXliff, resourcesToXliffString, writeTranslationData, writeXliff, xliffDataToResourceTranslationData, xliffToTranslationData };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { MsgProject, MsgResource, MsgResourceData } from '@worldware/msg';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Recursively finds all javascript and typescript files in a directory that have
|
|
5
|
+
* an `.msg.` substring in their filename just before the file extension.
|
|
6
|
+
* @param directory - The directory path to search
|
|
7
|
+
* @returns Promise resolving to array of file paths
|
|
8
|
+
*/
|
|
9
|
+
declare function findMsgResourceFiles(directory: string): Promise<string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Dynamically imports MsgResource objects from .msg. files and groups them by project.
|
|
12
|
+
* @param filePaths - Array of paths to .msg. files
|
|
13
|
+
* @returns Promise resolving to Map of MsgProject keys and MsgResource array values
|
|
14
|
+
*/
|
|
15
|
+
declare function importMsgResources(filePaths: string[]): Promise<Map<MsgProject, MsgResource[]>>;
|
|
16
|
+
/**
|
|
17
|
+
* Serializes MsgResource arrays into monolingual XLIFF 1.2 strings per project.
|
|
18
|
+
* @param resources - Array of MsgResource objects
|
|
19
|
+
* @returns Promise resolving to Map of MsgProject keys and xliff string values
|
|
20
|
+
*/
|
|
21
|
+
declare function resourcesToXliffString(resources: MsgResource[]): Promise<Map<MsgProject, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* Writes an XLIFF 1.2 string to a file with appropriate indentation.
|
|
24
|
+
* @param filePath - The destination file path
|
|
25
|
+
* @param xliff - The serialized XLIFF 1.2 string
|
|
26
|
+
*/
|
|
27
|
+
declare function writeXliff(filePath: string, xliff: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Reads XLIFF 1.2 content from a file.
|
|
30
|
+
* @param filePath - The path to the XLIFF file
|
|
31
|
+
* @returns Promise resolving to the XLIFF string content
|
|
32
|
+
*/
|
|
33
|
+
declare function readXliff(filePath: string): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Parses an XLIFF 1.2 string into a javascript object, preserving notes and attributes.
|
|
36
|
+
* @param xliff - Valid XLIFF 1.2 string
|
|
37
|
+
* @returns Promise resolving to parsed object
|
|
38
|
+
*/
|
|
39
|
+
declare function parseXliff(xliff: string): Promise<object>;
|
|
40
|
+
/**
|
|
41
|
+
* Extracts MsgResourceData from parsed XLIFF 1.2 object.
|
|
42
|
+
* @param parsedXliff - Parsed XLIFF 1.2 javascript object
|
|
43
|
+
* @returns Promise resolving to array of MsgResourceData objects
|
|
44
|
+
*/
|
|
45
|
+
declare function xliffDataToResourceTranslationData(parsedXliff: object): Promise<MsgResourceData[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Parses XLIFF 1.2 string and extracts translation data to MsgResourceData objects.
|
|
48
|
+
* @param xliff - Valid XLIFF 1.2 string
|
|
49
|
+
* @returns Promise resolving to array of MsgResourceData objects
|
|
50
|
+
*/
|
|
51
|
+
declare function xliffToTranslationData(xliff: string): Promise<MsgResourceData[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Serializes MsgResourceData to JSON and writes it to a file.
|
|
54
|
+
* @param filePath - The destination file path
|
|
55
|
+
* @param data - MsgResourceData object to serialize
|
|
56
|
+
*/
|
|
57
|
+
declare function writeTranslationData(filePath: string, data: MsgResourceData): Promise<void>;
|
|
58
|
+
|
|
59
|
+
export { findMsgResourceFiles, importMsgResources, parseXliff, readXliff, resourcesToXliffString, writeTranslationData, writeXliff, xliffDataToResourceTranslationData, xliffToTranslationData };
|