@gjsify/vite-plugin-gettext 0.2.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/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # vite-plugin-gettext
2
+
3
+ A Vite plugin for managing GNU Gettext translations in your JavaScript/TypeScript applications.
4
+
5
+ ## Features
6
+
7
+ - Extracts translatable strings from source files using xgettext
8
+ - Automatically compiles PO translation files to binary MO format
9
+ - Compiles PO files to various formats (MO, XML, JSON, desktop entries, etc.)
10
+ - Supports metainfo files with ITS rules
11
+ - Watches for changes and recompiles during development
12
+ - Follows GNU Gettext standard directory structure
13
+ - Supports multiple languages
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @gjsify/vite-plugin-gettext --save-dev
19
+ ```
20
+
21
+ or if you use Yarn:
22
+
23
+ ```bash
24
+ yarn add @gjsify/vite-plugin-gettext -D
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ Add both plugins to your Vite configuration:
30
+
31
+ ```javascript
32
+ // vite.config.js / vite.config.ts
33
+ import { defineConfig } from "vite";
34
+ import {
35
+ xgettextPlugin,
36
+ gettextPlugin,
37
+ msgfmtPlugin,
38
+ } from "@gjsify/vite-plugin-gettext";
39
+ export default defineConfig({
40
+ plugins: [
41
+ // Extract strings to POT file
42
+ xgettextPlugin({
43
+ sources: ["src/**/*.{ts,js}"],
44
+ output: "po/messages.pot",
45
+ domain: "myapp",
46
+ keywords: ["_", "gettext", "ngettext"],
47
+ verbose: true,
48
+ }),
49
+ // Compile PO files to MO format (standard approach)
50
+ gettextPlugin({
51
+ poDirectory: "po",
52
+ moDirectory: "public",
53
+ verbose: true,
54
+ }),
55
+ // Optionally use msgfmtPlugin for advanced use cases
56
+ msgfmtPlugin({
57
+ poDirectory: "po",
58
+ outputDirectory: "public",
59
+ domain: "myapp",
60
+ format: "xml", // Output format, e.g. 'xml' for metainfo
61
+ metainfo: true, // Enable metainfo support with ITS rules
62
+ verbose: true,
63
+ }),
64
+ ],
65
+ });
66
+ ```
67
+
68
+ ## Requirements
69
+
70
+ - Vite 2.x or higher
71
+ - Node.js 12.x or higher
72
+ - GNU Gettext tools must be installed:
73
+ - Ubuntu/Debian: `sudo apt-get install gettext`
74
+ - Fedora: `sudo dnf install gettext`
75
+ - Arch: `sudo pacman -S gettext`
76
+ - macOS: `brew install gettext`
77
+
78
+ ## How it Works
79
+
80
+ 1. The `xgettextPlugin` extracts translatable strings from your source files into a POT template file
81
+ 2. Translators create PO files for each language from the POT template
82
+ 3. The `gettextPlugin` automatically compiles PO files to binary MO format
83
+ 4. Alternatively, `msgfmtPlugin` can be used to compile to various formats with additional options
84
+ 5. The MO files are placed in the standard gettext directory structure:
85
+ `{moDirectory}/locale/{lang}/LC_MESSAGES/messages.mo`
86
+
87
+ ## Plugin Options
88
+
89
+ ### xgettextPlugin Options
90
+
91
+ - `sources`: Array of glob patterns for source files to extract strings from
92
+ - `output`: Output path for the POT template file
93
+ - `domain`: The gettext domain name (defaults to 'messages')
94
+ - `keywords`: Keywords to look for when extracting strings (defaults to ['_', 'gettext', 'ngettext'])
95
+ - `xgettextOptions`: Additional options to pass to xgettext command
96
+ - `verbose`: Enable verbose logging
97
+
98
+ ### gettextPlugin Options
99
+
100
+ - `poDirectory`: Directory containing PO translation files
101
+ - `moDirectory`: Output directory for compiled MO files
102
+ - `verbose`: Enable verbose logging
103
+
104
+ ### msgfmtPlugin Options
105
+
106
+ - `poDirectory`: Directory containing PO translation files
107
+ - `outputDirectory`: Output directory for compiled files
108
+ - `domain`: The gettext domain name (defaults to 'messages')
109
+ - `format`: Output format, one of: 'mo', 'java', 'java2', 'csharp', 'csharp-resources', 'tcl', 'qt', 'desktop', 'xml', 'json' (defaults to 'mo')
110
+ - `verbose`: Enable verbose logging
111
+ - `msgfmtOptions`: Additional options to pass to msgfmt command
112
+ - `useLocaleStructure`: Whether to use the standard locale structure (defaults to true for 'mo' format)
113
+
114
+ ## Examples
115
+
116
+ ### Compiling PO files for metainfo XML files
117
+
118
+ ```javascript
119
+ msgfmtPlugin({
120
+ poDirectory: "po",
121
+ outputDirectory: "public/metainfo",
122
+ domain: "myapp",
123
+ format: "xml",
124
+ metainfo: true,
125
+ useLocaleStructure: false, // Output will be public/metainfo/LANG/myapp.xml
126
+ });
127
+ ```
128
+
129
+ ### Generating JSON translations for web applications
130
+
131
+ ```javascript
132
+ msgfmtPlugin({
133
+ poDirectory: "po",
134
+ outputDirectory: "public/i18n",
135
+ domain: "myapp",
136
+ format: "json",
137
+ useLocaleStructure: false, // Output will be public/i18n/LANG/myapp.json
138
+ });
139
+ ```
140
+
141
+ ## Development
142
+
143
+ The plugin is structured as follows:
144
+
145
+ - `src/gettext.ts` - Core plugin for compiling PO to MO files
146
+ - `src/msgfmt.ts` - Extended plugin for compiling PO to various formats
147
+ - `src/xgettext.ts` - Plugin for extracting strings from source code
148
+ - `src/utils.ts` - Shared utility functions
149
+ - `src/types.ts` - TypeScript type definitions
150
+ - `src/index.ts` - Main entry point that exports all plugins
151
+
152
+ ## Contributing
153
+
154
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,10 @@
1
+ import { type Plugin } from "vite";
2
+ import type { GettextPluginOptions } from "./types.js";
3
+ /**
4
+ * Creates a Vite plugin that compiles PO translation files to binary MO format
5
+ * The MO files are placed in the standard gettext directory structure:
6
+ * {moDirectory}/locale/{lang}/LC_MESSAGES/messages.mo
7
+ * @param options Configuration options for the plugin
8
+ * @returns A Vite plugin that handles PO compilation
9
+ */
10
+ export declare function gettextPlugin(options: GettextPluginOptions): Plugin;
@@ -0,0 +1,73 @@
1
+ import {} from "vite";
2
+ import { execa } from "execa";
3
+ import path from "node:path";
4
+ import { checkDependencies, findAvailableLanguages, generateLinguasFile, ensureDirectory, } from "./utils.js";
5
+ /**
6
+ * Creates a Vite plugin that compiles PO translation files to binary MO format
7
+ * The MO files are placed in the standard gettext directory structure:
8
+ * {moDirectory}/locale/{lang}/LC_MESSAGES/messages.mo
9
+ * @param options Configuration options for the plugin
10
+ * @returns A Vite plugin that handles PO compilation
11
+ */
12
+ export function gettextPlugin(options) {
13
+ const { poDirectory, moDirectory, filename = "messages.mo", verbose = false, } = options;
14
+ const pluginName = "vite-plugin-gettext";
15
+ async function compileMoFiles() {
16
+ try {
17
+ // Check if PO directory exists
18
+ try {
19
+ await ensureDirectory(poDirectory);
20
+ }
21
+ catch {
22
+ if (verbose) {
23
+ console.log(`[${pluginName}] PO directory ${poDirectory} does not exist yet, skipping compilation`);
24
+ }
25
+ return;
26
+ }
27
+ // Find available languages
28
+ const languages = await findAvailableLanguages(poDirectory, pluginName, verbose);
29
+ if (languages.length === 0) {
30
+ if (verbose) {
31
+ console.log(`[${pluginName}] No translation files found`);
32
+ }
33
+ return;
34
+ }
35
+ // Generate LINGUAS file
36
+ await generateLinguasFile(languages, poDirectory, verbose);
37
+ // Create MO directory
38
+ await ensureDirectory(path.join(moDirectory, "locale"));
39
+ for (const lang of languages) {
40
+ const poFile = path.join(poDirectory, `${lang}.po`);
41
+ const moPath = path.join(moDirectory, "locale", lang, "LC_MESSAGES");
42
+ const moFile = path.join(moPath, filename);
43
+ await ensureDirectory(moPath);
44
+ if (verbose) {
45
+ console.log(`[${pluginName}] Compiling ${poFile} to ${moFile}`);
46
+ }
47
+ await execa("msgfmt", ["--output-file=" + moFile, poFile]);
48
+ }
49
+ }
50
+ catch (error) {
51
+ throw new Error(`Failed to compile MO files: ${error}`);
52
+ }
53
+ }
54
+ return {
55
+ name: pluginName,
56
+ async buildStart() {
57
+ await checkDependencies("msgfmt", pluginName, verbose);
58
+ await compileMoFiles();
59
+ },
60
+ configureServer(server) {
61
+ server.watcher.add(poDirectory);
62
+ server.watcher.on("change", async (file) => {
63
+ if (file.endsWith(".po")) {
64
+ if (verbose) {
65
+ console.log(`[${pluginName}] PO file changed: ${file}, recompiling`);
66
+ }
67
+ await compileMoFiles();
68
+ }
69
+ });
70
+ },
71
+ };
72
+ }
73
+ //# sourceMappingURL=gettext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gettext.js","sourceRoot":"","sources":["../src/gettext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
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 { GettextPluginOptions, MsgfmtPluginOptions, MsgfmtFormat, XGettextPluginOptions, } from "./types.js";
6
+ export * from "./utils.js";
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
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 * from "./utils.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C,cAAc,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type Plugin } from "vite";
2
+ import type { MsgfmtPluginOptions } from "./types.js";
3
+ /**
4
+ * Creates a Vite plugin that compiles PO translation files to various formats
5
+ * Supports metainfo files with special processing
6
+ * @param options Configuration options for the plugin
7
+ * @returns A Vite plugin that handles PO compilation
8
+ */
9
+ export declare function msgfmtPlugin(options: MsgfmtPluginOptions): Plugin;
package/dist/msgfmt.js ADDED
@@ -0,0 +1,147 @@
1
+ import {} from "vite";
2
+ import { execa } from "execa";
3
+ import path from "node:path";
4
+ import { checkDependencies, findAvailableLanguages, ensureDirectory, } from "./utils.js";
5
+ /**
6
+ * Get output file extension based on the format
7
+ * @param format The output format
8
+ * @returns The file extension for the given format
9
+ */
10
+ function getOutputExtension(format) {
11
+ switch (format) {
12
+ case "mo":
13
+ return ".mo";
14
+ case "java":
15
+ case "java2":
16
+ return ".class";
17
+ case "csharp":
18
+ return ".dll";
19
+ case "csharp-resources":
20
+ return ".resources.dll";
21
+ case "tcl":
22
+ return ".msg";
23
+ case "desktop":
24
+ return ".desktop";
25
+ case "xml":
26
+ return ".xml";
27
+ case "json":
28
+ return ".json";
29
+ case "qt":
30
+ return ".qm";
31
+ default:
32
+ return ".mo";
33
+ }
34
+ }
35
+ /**
36
+ * Creates a Vite plugin that compiles PO translation files to various formats
37
+ * Supports metainfo files with special processing
38
+ * @param options Configuration options for the plugin
39
+ * @returns A Vite plugin that handles PO compilation
40
+ */
41
+ export function msgfmtPlugin(options) {
42
+ const { poDirectory, outputDirectory, domain = "messages", format = "mo", templateFile, verbose = false, msgfmtOptions = [], useLocaleStructure = true, } = options;
43
+ const pluginName = "vite-plugin-msgfmt";
44
+ async function compilePoFiles() {
45
+ try {
46
+ // Check if PO directory exists
47
+ try {
48
+ await ensureDirectory(poDirectory);
49
+ }
50
+ catch {
51
+ if (verbose) {
52
+ console.log(`[${pluginName}] PO directory ${poDirectory} does not exist yet, skipping compilation`);
53
+ }
54
+ return;
55
+ }
56
+ // Create output directory
57
+ await ensureDirectory(outputDirectory);
58
+ // For XML format, we can use the bulk mode if a template is provided
59
+ if (format === "xml" && templateFile) {
60
+ // Use bulk mode for XML format
61
+ const outputFile = path.join(outputDirectory, options.filename || `${domain}${getOutputExtension(format)}`);
62
+ if (verbose) {
63
+ console.log(`[${pluginName}] Compiling all languages to ${outputFile} using bulk mode`);
64
+ }
65
+ // Base arguments for bulk mode
66
+ const args = [
67
+ "--output-file=" + outputFile,
68
+ "--xml",
69
+ "--template=" + templateFile,
70
+ "-d",
71
+ poDirectory,
72
+ ];
73
+ // Add any additional options
74
+ args.push(...msgfmtOptions);
75
+ if (verbose) {
76
+ console.log(`[${pluginName}] Running msgfmt with: ${args.join(" ")}`);
77
+ }
78
+ await execa("msgfmt", args);
79
+ }
80
+ else {
81
+ // Find available languages for individual processing
82
+ const languages = await findAvailableLanguages(poDirectory, pluginName, verbose);
83
+ if (languages.length === 0) {
84
+ if (verbose) {
85
+ console.log(`[${pluginName}] No translation files found`);
86
+ }
87
+ return;
88
+ }
89
+ // Process each language individually for other formats
90
+ for (const lang of languages) {
91
+ const poFile = path.join(poDirectory, `${lang}.po`);
92
+ let outputPath;
93
+ let outputFile;
94
+ if (useLocaleStructure && format === "mo") {
95
+ // Use standard gettext locale structure
96
+ outputPath = path.join(outputDirectory, "locale", lang, "LC_MESSAGES");
97
+ outputFile = path.join(outputPath, options.filename || `${domain}${getOutputExtension(format)}`);
98
+ }
99
+ else {
100
+ // Use simple language-based structure
101
+ outputPath = path.join(outputDirectory, lang);
102
+ outputFile = path.join(outputPath, options.filename || `${domain}${getOutputExtension(format)}`);
103
+ }
104
+ // Create the directory structure
105
+ await ensureDirectory(outputPath);
106
+ if (verbose) {
107
+ console.log(`[${pluginName}] Compiling ${poFile} to ${outputFile}`);
108
+ }
109
+ // Base arguments
110
+ const args = ["--output-file=" + outputFile];
111
+ // Add format-specific arguments
112
+ args.push(`--${format}`);
113
+ // Add any additional options
114
+ args.push(...msgfmtOptions);
115
+ // Add the input PO file
116
+ args.push(poFile);
117
+ if (verbose) {
118
+ console.log(`[${pluginName}] Running msgfmt with: ${args.join(" ")}`);
119
+ }
120
+ await execa("msgfmt", args);
121
+ }
122
+ }
123
+ }
124
+ catch (error) {
125
+ throw new Error(`Failed to compile files: ${error}`);
126
+ }
127
+ }
128
+ return {
129
+ name: pluginName,
130
+ async buildStart() {
131
+ await checkDependencies("msgfmt", pluginName, verbose);
132
+ await compilePoFiles();
133
+ },
134
+ configureServer(server) {
135
+ server.watcher.add(poDirectory);
136
+ server.watcher.on("change", async (file) => {
137
+ if (file.endsWith(".po")) {
138
+ if (verbose) {
139
+ console.log(`[${pluginName}] PO file changed: ${file}, recompiling`);
140
+ }
141
+ await compilePoFiles();
142
+ }
143
+ });
144
+ },
145
+ };
146
+ }
147
+ //# sourceMappingURL=msgfmt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msgfmt.js","sourceRoot":"","sources":["../src/msgfmt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type Plugin } from "vite";
2
+ import type { GettextPo2JsonPluginOptions } from "./types.js";
3
+ /**
4
+ * Creates a Vite plugin that converts PO translation files to JSON format
5
+ * The JSON files are placed in the specified output directory
6
+ * @param options Configuration options for the plugin
7
+ * @returns A Vite plugin that handles PO to JSON conversion
8
+ */
9
+ export declare function po2jsonPlugin(options: GettextPo2JsonPluginOptions): Plugin;
@@ -0,0 +1,190 @@
1
+ import {} from "vite";
2
+ import path from "node:path";
3
+ import fs from "node:fs/promises";
4
+ import * as gettextParser from "gettext-parser";
5
+ import { checkDependencies, findAvailableLanguages, ensureDirectory, } from "./utils.js";
6
+ /**
7
+ * Simplifies the gettext-parser output to a clean key-value object
8
+ * where the key is the original text and the value is the translation
9
+ * @param translations The parsed PO file from gettext-parser
10
+ * @returns A simplified object with just the translations
11
+ */
12
+ function simplifyTranslations(translations) {
13
+ const result = {};
14
+ // Go through all translation contexts
15
+ Object.keys(translations.translations).forEach((context) => {
16
+ const contextTranslations = translations.translations[context];
17
+ // Skip the header (empty msgid)
18
+ Object.keys(contextTranslations).forEach((key) => {
19
+ if (key === "")
20
+ return;
21
+ const translation = contextTranslations[key];
22
+ // Get the original text (msgid)
23
+ const original = translation.msgid;
24
+ // Get the translated text (first item in msgstr array)
25
+ const translated = translation.msgstr[0];
26
+ // Only add the translation if it exists and is not empty
27
+ if (translated && translated.trim() !== "") {
28
+ result[original] = translated;
29
+ }
30
+ });
31
+ });
32
+ return result;
33
+ }
34
+ /**
35
+ * Creates a dictionary of all original strings from all translations
36
+ * For the default language, we need to gather all possible keys
37
+ * @param jsonDirectory Directory with JSON files
38
+ * @param allTranslations Collection of all translations
39
+ * @param defaultLanguage The default language code
40
+ * @param verbose Whether to log verbose messages
41
+ * @param pluginName The name of the plugin
42
+ * @param additionalTranslations Additional translations to include
43
+ * @returns Object with original strings as both keys and values
44
+ */
45
+ async function createDefaultLanguageJson(jsonDirectory, allTranslations, defaultLanguage, verbose, pluginName, additionalTranslations = {}) {
46
+ // Create a set of all original strings from all translations
47
+ const allOriginalStrings = new Set();
48
+ // Collect all original strings from all translations
49
+ Object.values(allTranslations).forEach((translations) => {
50
+ Object.keys(translations).forEach((key) => {
51
+ allOriginalStrings.add(key);
52
+ });
53
+ });
54
+ // Create the default language JSON with keys matching values
55
+ const defaultLanguageJson = {};
56
+ allOriginalStrings.forEach((str) => {
57
+ defaultLanguageJson[str] = str;
58
+ });
59
+ // Process additional translations
60
+ const finalTranslations = { ...defaultLanguageJson };
61
+ // For each additional translation, try to find a translation or use the original
62
+ Object.entries(additionalTranslations).forEach(([key, originalText]) => {
63
+ // If there's a translation for the original text, use it
64
+ if (defaultLanguageJson[originalText]) {
65
+ finalTranslations[key] = defaultLanguageJson[originalText];
66
+ }
67
+ else {
68
+ // Otherwise use the original text
69
+ finalTranslations[key] = originalText;
70
+ }
71
+ });
72
+ // Write the default language file with .default.json extension
73
+ const defaultLangDefaultFile = path.join(jsonDirectory, `${defaultLanguage}.default.json`);
74
+ if (verbose) {
75
+ console.log(`[${pluginName}] Creating default language file: ${defaultLangDefaultFile}`);
76
+ }
77
+ await fs.writeFile(defaultLangDefaultFile, JSON.stringify(finalTranslations, null, 2));
78
+ }
79
+ /**
80
+ * Creates a Vite plugin that converts PO translation files to JSON format
81
+ * The JSON files are placed in the specified output directory
82
+ * @param options Configuration options for the plugin
83
+ * @returns A Vite plugin that handles PO to JSON conversion
84
+ */
85
+ export function po2jsonPlugin(options) {
86
+ const { poDirectory, jsonDirectory, defaultLanguage = "en", verbose = false, additionalTranslations = {}, } = options;
87
+ const pluginName = "vite-plugin-gettext-po2json";
88
+ async function convertPoToJson() {
89
+ try {
90
+ // Check if PO directory exists
91
+ try {
92
+ await ensureDirectory(poDirectory);
93
+ }
94
+ catch {
95
+ if (verbose) {
96
+ console.log(`[${pluginName}] PO directory ${poDirectory} does not exist yet, skipping conversion`);
97
+ }
98
+ return;
99
+ }
100
+ // Find available languages
101
+ const languages = await findAvailableLanguages(poDirectory, pluginName, verbose);
102
+ if (languages.length === 0) {
103
+ if (verbose) {
104
+ console.log(`[${pluginName}] No translation files found`);
105
+ }
106
+ return;
107
+ }
108
+ // Create JSON directory
109
+ await ensureDirectory(jsonDirectory);
110
+ // Collection of all translations to create the default language file
111
+ const allTranslations = {};
112
+ // Skip the default language if it exists in the list
113
+ const nonDefaultLanguages = languages.filter((lang) => lang !== defaultLanguage);
114
+ // Handle default language if it exists in the list
115
+ if (languages.includes(defaultLanguage)) {
116
+ const poFile = path.join(poDirectory, `${defaultLanguage}.po`);
117
+ const jsonFile = path.join(jsonDirectory, `${defaultLanguage}.json`);
118
+ if (verbose) {
119
+ console.log(`[${pluginName}] Converting default language ${poFile} to ${jsonFile}`);
120
+ }
121
+ // Read and parse PO file
122
+ const poContent = await fs.readFile(poFile);
123
+ const translations = gettextParser.po.parse(poContent);
124
+ // Convert the translations to a simple JSON object
125
+ const simplifiedTranslations = simplifyTranslations(translations);
126
+ // Process additional translations for default language
127
+ const finalTranslations = { ...simplifiedTranslations };
128
+ // For each additional translation, add it to the default language file
129
+ Object.entries(additionalTranslations).forEach(([key, originalText]) => {
130
+ finalTranslations[key] = originalText;
131
+ });
132
+ // Write JSON file for default language
133
+ await fs.writeFile(jsonFile, JSON.stringify(finalTranslations, null, 2));
134
+ }
135
+ // Add additional translations for all languages
136
+ for (const lang of nonDefaultLanguages) {
137
+ const poFile = path.join(poDirectory, `${lang}.po`);
138
+ const jsonFile = path.join(jsonDirectory, `${lang}.json`);
139
+ if (verbose) {
140
+ console.log(`[${pluginName}] Converting ${poFile} to ${jsonFile}`);
141
+ }
142
+ // Read and parse PO file
143
+ const poContent = await fs.readFile(poFile);
144
+ const translations = gettextParser.po.parse(poContent);
145
+ // Convert the translations to a simple JSON object
146
+ const simplifiedTranslations = simplifyTranslations(translations);
147
+ // Store translations for creating the default language file
148
+ allTranslations[lang] = simplifiedTranslations;
149
+ // Process additional translations
150
+ const finalTranslations = { ...simplifiedTranslations };
151
+ // For each additional translation, try to find a translation or use the original
152
+ Object.entries(additionalTranslations).forEach(([key, originalText]) => {
153
+ // If there's a translation for the original text, use it
154
+ if (simplifiedTranslations[originalText]) {
155
+ finalTranslations[key] = simplifiedTranslations[originalText];
156
+ }
157
+ else {
158
+ // Otherwise use the original text
159
+ finalTranslations[key] = originalText;
160
+ }
161
+ });
162
+ // Write JSON file
163
+ await fs.writeFile(jsonFile, JSON.stringify(finalTranslations, null, 2));
164
+ }
165
+ // Create the default language file (with all original strings as both keys and values)
166
+ await createDefaultLanguageJson(jsonDirectory, allTranslations, defaultLanguage, verbose, pluginName, additionalTranslations);
167
+ }
168
+ catch (error) {
169
+ throw new Error(`Failed to convert PO files to JSON: ${error}`);
170
+ }
171
+ }
172
+ return {
173
+ name: pluginName,
174
+ async buildStart() {
175
+ await convertPoToJson();
176
+ },
177
+ configureServer(server) {
178
+ server.watcher.add(poDirectory);
179
+ server.watcher.on("change", async (file) => {
180
+ if (file.endsWith(".po")) {
181
+ if (verbose) {
182
+ console.log(`[${pluginName}] PO file changed: ${file}, reconverting`);
183
+ }
184
+ await convertPoToJson();
185
+ }
186
+ });
187
+ },
188
+ };
189
+ }
190
+ //# sourceMappingURL=po2json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"po2json.js","sourceRoot":"","sources":["../src/po2json.ts"],"names":[],"mappings":"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"}