@gjsify/vite-plugin-gettext 0.4.0 → 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 CHANGED
@@ -1,60 +1,63 @@
1
1
  {
2
- "name": "@gjsify/vite-plugin-gettext",
3
- "version": "0.4.0",
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
- "scripts": {
16
- "clear": "rm -rf lib tsconfig.tsbuildinfo || exit 0",
17
- "check": "tsc --noEmit",
18
- "build": "tsc"
19
- },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/gjsify/gjsify.git"
23
- },
24
- "bugs": {
25
- "url": "https://github.com/gjsify/gjsify/issues"
26
- },
27
- "homepage": "https://github.com/gjsify/gjsify/tree/main/packages/infra/vite-plugin-gettext#readme",
28
- "keywords": [
29
- "vite",
30
- "rollup",
31
- "rolldown",
32
- "gettext",
33
- "i18n",
34
- "gnome"
35
- ],
36
- "license": "MIT",
37
- "dependencies": {
38
- "execa": "^9.6.1",
39
- "fast-glob": "^3.3.3",
40
- "gettext-parser": "^9.0.2"
41
- },
42
- "peerDependencies": {
43
- "rolldown": "^1.0.0-rc.18",
44
- "vite": "^8.0.0"
45
- },
46
- "peerDependenciesMeta": {
47
- "rolldown": {
48
- "optional": true
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
- "vite": {
51
- "optional": true
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
- }