@gjsify/vite-plugin-gettext 0.3.21 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +60 -57
- package/src/gettext.ts +0 -104
- package/src/index.ts +0 -11
- package/src/msgfmt.ts +0 -248
- package/src/po2json.ts +0 -281
- package/src/types.ts +0 -138
- package/src/utils.ts +0 -119
- package/src/xgettext.ts +0 -525
- package/tsconfig.json +0 -15
package/package.json
CHANGED
|
@@ -1,60 +1,63 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
2
|
+
"name": "@gjsify/vite-plugin-gettext",
|
|
3
|
+
"version": "0.4.3",
|
|
4
|
+
"description": "Gettext PO/MO/JSON pipeline for Vite / Rollup / Rolldown — extract via xgettext, compile via msgfmt, JSON for browser targets.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"module": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./lib/index.d.ts",
|
|
12
|
+
"default": "./lib/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"clear": "rm -rf lib tsconfig.tsbuildinfo || exit 0",
|
|
20
|
+
"check": "tsc --noEmit",
|
|
21
|
+
"build": "tsc"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/gjsify/gjsify.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/gjsify/gjsify/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/gjsify/gjsify/tree/main/packages/infra/vite-plugin-gettext#readme",
|
|
31
|
+
"keywords": [
|
|
32
|
+
"vite",
|
|
33
|
+
"rollup",
|
|
34
|
+
"rolldown",
|
|
35
|
+
"gettext",
|
|
36
|
+
"i18n",
|
|
37
|
+
"gnome"
|
|
38
|
+
],
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"execa": "^9.6.1",
|
|
42
|
+
"fast-glob": "^3.3.3",
|
|
43
|
+
"gettext-parser": "^9.0.2"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"rolldown": "^1.0.0-rc.18",
|
|
47
|
+
"vite": "^8.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"rolldown": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"vite": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
49
56
|
},
|
|
50
|
-
"
|
|
51
|
-
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/gettext-parser": "^9.0.0",
|
|
59
|
+
"@types/node": "^25.6.2",
|
|
60
|
+
"typescript": "^6.0.3",
|
|
61
|
+
"vite": "^8.0.11"
|
|
52
62
|
}
|
|
53
|
-
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"@types/gettext-parser": "^9.0.0",
|
|
56
|
-
"@types/node": "^25.6.2",
|
|
57
|
-
"typescript": "^6.0.3",
|
|
58
|
-
"vite": "^8.0.11"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
63
|
+
}
|
package/src/gettext.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { type Plugin } from "vite";
|
|
2
|
-
import { execa } from "execa";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import type { GettextPluginOptions } from "./types.js";
|
|
5
|
-
import {
|
|
6
|
-
checkDependencies,
|
|
7
|
-
findAvailableLanguages,
|
|
8
|
-
generateLinguasFile,
|
|
9
|
-
ensureDirectory,
|
|
10
|
-
} from "./utils.js";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Creates a Vite plugin that compiles PO translation files to binary MO format
|
|
14
|
-
* The MO files are placed in the standard gettext directory structure:
|
|
15
|
-
* {moDirectory}/locale/{lang}/LC_MESSAGES/messages.mo
|
|
16
|
-
* @param options Configuration options for the plugin
|
|
17
|
-
* @returns A Vite plugin that handles PO compilation
|
|
18
|
-
*/
|
|
19
|
-
export function gettextPlugin(options: GettextPluginOptions): Plugin {
|
|
20
|
-
const {
|
|
21
|
-
poDirectory,
|
|
22
|
-
moDirectory,
|
|
23
|
-
filename = "messages.mo",
|
|
24
|
-
verbose = false,
|
|
25
|
-
} = options;
|
|
26
|
-
|
|
27
|
-
const pluginName = "vite-plugin-gettext";
|
|
28
|
-
|
|
29
|
-
async function compileMoFiles() {
|
|
30
|
-
try {
|
|
31
|
-
// Check if PO directory exists
|
|
32
|
-
try {
|
|
33
|
-
await ensureDirectory(poDirectory);
|
|
34
|
-
} catch {
|
|
35
|
-
if (verbose) {
|
|
36
|
-
console.log(
|
|
37
|
-
`[${pluginName}] PO directory ${poDirectory} does not exist yet, skipping compilation`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Find available languages
|
|
44
|
-
const languages = await findAvailableLanguages(
|
|
45
|
-
poDirectory,
|
|
46
|
-
pluginName,
|
|
47
|
-
verbose
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
if (languages.length === 0) {
|
|
51
|
-
if (verbose) {
|
|
52
|
-
console.log(`[${pluginName}] No translation files found`);
|
|
53
|
-
}
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Generate LINGUAS file
|
|
58
|
-
await generateLinguasFile(languages, poDirectory, verbose);
|
|
59
|
-
|
|
60
|
-
// Create MO directory
|
|
61
|
-
await ensureDirectory(path.join(moDirectory, "locale"));
|
|
62
|
-
|
|
63
|
-
for (const lang of languages) {
|
|
64
|
-
const poFile = path.join(poDirectory, `${lang}.po`);
|
|
65
|
-
const moPath = path.join(moDirectory, "locale", lang, "LC_MESSAGES");
|
|
66
|
-
const moFile = path.join(moPath, filename);
|
|
67
|
-
|
|
68
|
-
await ensureDirectory(moPath);
|
|
69
|
-
|
|
70
|
-
if (verbose) {
|
|
71
|
-
console.log(`[${pluginName}] Compiling ${poFile} to ${moFile}`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
await execa("msgfmt", ["--output-file=" + moFile, poFile]);
|
|
75
|
-
}
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw new Error(`Failed to compile MO files: ${error}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
name: pluginName,
|
|
83
|
-
|
|
84
|
-
async buildStart() {
|
|
85
|
-
await checkDependencies("msgfmt", pluginName, verbose);
|
|
86
|
-
await compileMoFiles();
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
configureServer(server) {
|
|
90
|
-
server.watcher.add(poDirectory);
|
|
91
|
-
|
|
92
|
-
server.watcher.on("change", async (file) => {
|
|
93
|
-
if (file.endsWith(".po")) {
|
|
94
|
-
if (verbose) {
|
|
95
|
-
console.log(
|
|
96
|
-
`[${pluginName}] PO file changed: ${file}, recompiling`
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
await compileMoFiles();
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
},
|
|
103
|
-
};
|
|
104
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { gettextPlugin } from "./gettext.js";
|
|
2
|
-
export { msgfmtPlugin } from "./msgfmt.js";
|
|
3
|
-
export { xgettextPlugin } from "./xgettext.js";
|
|
4
|
-
export { po2jsonPlugin } from "./po2json.js";
|
|
5
|
-
export type {
|
|
6
|
-
GettextPluginOptions,
|
|
7
|
-
MsgfmtPluginOptions,
|
|
8
|
-
MsgfmtFormat,
|
|
9
|
-
XGettextPluginOptions,
|
|
10
|
-
} from "./types.js";
|
|
11
|
-
export * from "./utils.js";
|
package/src/msgfmt.ts
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { type Plugin } from "vite";
|
|
2
|
-
import { execa } from "execa";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import fs from "node:fs/promises";
|
|
5
|
-
import type { MsgfmtPluginOptions, MsgfmtFormat } from "./types.js";
|
|
6
|
-
import {
|
|
7
|
-
checkDependencies,
|
|
8
|
-
findAvailableLanguages,
|
|
9
|
-
ensureDirectory,
|
|
10
|
-
} from "./utils.js";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Remove XML comments from a file content
|
|
14
|
-
* @param content The XML content as string
|
|
15
|
-
* @returns The content with comments removed
|
|
16
|
-
*/
|
|
17
|
-
function removeXmlComments(content: string): string {
|
|
18
|
-
// Remove XML comments <!-- ... -->
|
|
19
|
-
return content.replace(/<!--[\s\S]*?-->/g, '');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Build msgfmt command arguments
|
|
24
|
-
* @param baseArgs Base arguments for msgfmt
|
|
25
|
-
* @param options Plugin options
|
|
26
|
-
* @returns Complete argument array
|
|
27
|
-
*/
|
|
28
|
-
function buildMsgfmtArgs(baseArgs: string[], options: { msgfmtOptions?: string[] }): string[] {
|
|
29
|
-
const args = [...baseArgs];
|
|
30
|
-
|
|
31
|
-
if (options.msgfmtOptions && options.msgfmtOptions.length > 0) {
|
|
32
|
-
args.push(...options.msgfmtOptions);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return args;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get output file extension based on the format
|
|
40
|
-
* @param format The output format
|
|
41
|
-
* @returns The file extension for the given format
|
|
42
|
-
*/
|
|
43
|
-
function getOutputExtension(format: MsgfmtFormat): string {
|
|
44
|
-
switch (format) {
|
|
45
|
-
case "mo":
|
|
46
|
-
return ".mo";
|
|
47
|
-
case "java":
|
|
48
|
-
case "java2":
|
|
49
|
-
return ".class";
|
|
50
|
-
case "csharp":
|
|
51
|
-
return ".dll";
|
|
52
|
-
case "csharp-resources":
|
|
53
|
-
return ".resources.dll";
|
|
54
|
-
case "tcl":
|
|
55
|
-
return ".msg";
|
|
56
|
-
case "desktop":
|
|
57
|
-
return ".desktop";
|
|
58
|
-
case "xml":
|
|
59
|
-
return ".xml";
|
|
60
|
-
case "json":
|
|
61
|
-
return ".json";
|
|
62
|
-
case "qt":
|
|
63
|
-
return ".qm";
|
|
64
|
-
default:
|
|
65
|
-
return ".mo";
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Creates a Vite plugin that compiles PO translation files to various formats
|
|
71
|
-
* Supports metainfo files with special processing
|
|
72
|
-
* @param options Configuration options for the plugin
|
|
73
|
-
* @returns A Vite plugin that handles PO compilation
|
|
74
|
-
*/
|
|
75
|
-
export function msgfmtPlugin(options: MsgfmtPluginOptions): Plugin {
|
|
76
|
-
const {
|
|
77
|
-
poDirectory,
|
|
78
|
-
outputDirectory,
|
|
79
|
-
domain = "messages",
|
|
80
|
-
format = "mo",
|
|
81
|
-
templateFile,
|
|
82
|
-
verbose = false,
|
|
83
|
-
msgfmtOptions = [],
|
|
84
|
-
useLocaleStructure = true,
|
|
85
|
-
removeComments = true,
|
|
86
|
-
} = options;
|
|
87
|
-
|
|
88
|
-
const pluginName = "vite-plugin-msgfmt";
|
|
89
|
-
|
|
90
|
-
async function compilePoFiles() {
|
|
91
|
-
try {
|
|
92
|
-
// Check if PO directory exists
|
|
93
|
-
try {
|
|
94
|
-
await ensureDirectory(poDirectory);
|
|
95
|
-
} catch {
|
|
96
|
-
if (verbose) {
|
|
97
|
-
console.log(
|
|
98
|
-
`[${pluginName}] PO directory ${poDirectory} does not exist yet, skipping compilation`
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Create output directory
|
|
105
|
-
await ensureDirectory(outputDirectory);
|
|
106
|
-
|
|
107
|
-
// For XML format, we can use the bulk mode if a template is provided
|
|
108
|
-
if (format === "xml" && templateFile) {
|
|
109
|
-
// Use bulk mode for XML format
|
|
110
|
-
const outputFile = path.join(
|
|
111
|
-
outputDirectory,
|
|
112
|
-
options.filename || `${domain}${getOutputExtension(format)}`
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
if (verbose) {
|
|
116
|
-
console.log(
|
|
117
|
-
`[${pluginName}] Compiling all languages to ${outputFile} using bulk mode`
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Build arguments for bulk mode
|
|
122
|
-
const baseArgs = [
|
|
123
|
-
"--output-file=" + outputFile,
|
|
124
|
-
"--xml",
|
|
125
|
-
"--template=" + templateFile,
|
|
126
|
-
"-d",
|
|
127
|
-
poDirectory,
|
|
128
|
-
];
|
|
129
|
-
const args = buildMsgfmtArgs(baseArgs, { msgfmtOptions });
|
|
130
|
-
|
|
131
|
-
if (verbose) {
|
|
132
|
-
console.log(`[${pluginName}] Running msgfmt with: ${args.join(" ")}`);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
await execa("msgfmt", args);
|
|
136
|
-
|
|
137
|
-
// Remove comments from XML output if requested
|
|
138
|
-
if (removeComments !== false) {
|
|
139
|
-
try {
|
|
140
|
-
const content = await fs.readFile(outputFile, 'utf-8');
|
|
141
|
-
const cleanedContent = removeXmlComments(content);
|
|
142
|
-
await fs.writeFile(outputFile, cleanedContent, 'utf-8');
|
|
143
|
-
|
|
144
|
-
if (verbose) {
|
|
145
|
-
console.log(`[${pluginName}] Removed comments from ${outputFile}`);
|
|
146
|
-
}
|
|
147
|
-
} catch (error) {
|
|
148
|
-
if (verbose) {
|
|
149
|
-
console.warn(`[${pluginName}] Failed to remove comments: ${error}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
} else {
|
|
154
|
-
// Find available languages for individual processing
|
|
155
|
-
const languages = await findAvailableLanguages(
|
|
156
|
-
poDirectory,
|
|
157
|
-
pluginName,
|
|
158
|
-
verbose
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
if (languages.length === 0) {
|
|
162
|
-
if (verbose) {
|
|
163
|
-
console.log(`[${pluginName}] No translation files found`);
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Process each language individually for other formats
|
|
169
|
-
for (const lang of languages) {
|
|
170
|
-
const poFile = path.join(poDirectory, `${lang}.po`);
|
|
171
|
-
|
|
172
|
-
let outputPath: string;
|
|
173
|
-
let outputFile: string;
|
|
174
|
-
|
|
175
|
-
if (useLocaleStructure && format === "mo") {
|
|
176
|
-
// Use standard gettext locale structure
|
|
177
|
-
outputPath = path.join(
|
|
178
|
-
outputDirectory,
|
|
179
|
-
"locale",
|
|
180
|
-
lang,
|
|
181
|
-
"LC_MESSAGES"
|
|
182
|
-
);
|
|
183
|
-
outputFile = path.join(
|
|
184
|
-
outputPath,
|
|
185
|
-
options.filename || `${domain}${getOutputExtension(format)}`
|
|
186
|
-
);
|
|
187
|
-
} else {
|
|
188
|
-
// Use simple language-based structure
|
|
189
|
-
outputPath = path.join(outputDirectory, lang);
|
|
190
|
-
outputFile = path.join(
|
|
191
|
-
outputPath,
|
|
192
|
-
options.filename || `${domain}${getOutputExtension(format)}`
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Create the directory structure
|
|
197
|
-
await ensureDirectory(outputPath);
|
|
198
|
-
|
|
199
|
-
if (verbose) {
|
|
200
|
-
console.log(`[${pluginName}] Compiling ${poFile} to ${outputFile}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Build arguments for individual processing
|
|
204
|
-
const baseArgs = [
|
|
205
|
-
"--output-file=" + outputFile,
|
|
206
|
-
`--${format}`,
|
|
207
|
-
poFile
|
|
208
|
-
];
|
|
209
|
-
const args = buildMsgfmtArgs(baseArgs, { msgfmtOptions });
|
|
210
|
-
|
|
211
|
-
if (verbose) {
|
|
212
|
-
console.log(
|
|
213
|
-
`[${pluginName}] Running msgfmt with: ${args.join(" ")}`
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
await execa("msgfmt", args);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
} catch (error) {
|
|
221
|
-
throw new Error(`Failed to compile files: ${error}`);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return {
|
|
226
|
-
name: pluginName,
|
|
227
|
-
|
|
228
|
-
async buildStart() {
|
|
229
|
-
await checkDependencies("msgfmt", pluginName, verbose);
|
|
230
|
-
await compilePoFiles();
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
configureServer(server) {
|
|
234
|
-
server.watcher.add(poDirectory);
|
|
235
|
-
|
|
236
|
-
server.watcher.on("change", async (file) => {
|
|
237
|
-
if (file.endsWith(".po")) {
|
|
238
|
-
if (verbose) {
|
|
239
|
-
console.log(
|
|
240
|
-
`[${pluginName}] PO file changed: ${file}, recompiling`
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
await compilePoFiles();
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
}
|