@open-xchange/vite-plugin-i18next-gettext 1.0.2 → 1.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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## `1.1.0` – 2025-May-05
4
+
5
+ - added: generate separate POT files per i18next namespace
6
+
7
+ ## `1.0.3` – 2025-May-05
8
+
9
+ - chore: use "@open-xchange/i18next-po-parser" to generate POT file
10
+
3
11
  ## `1.0.2` – 2025-Feb-24
4
12
 
5
13
  - chore: remove better-typescript-lib
@@ -26,11 +34,11 @@
26
34
 
27
35
  ## `0.0.3` – 2024-Aug-12
28
36
 
29
- - fix: bump `i18next-parser` (<https://github.com/i18next/i18next-parser/issues/1045>)
37
+ - fixed: bump `i18next-parser` (<https://github.com/i18next/i18next-parser/issues/1045>)
30
38
 
31
39
  ## `0.0.2` – 2024-Jul-26
32
40
 
33
- - fix: match po files against relative module path
41
+ - fixed: match po files against relative module path
34
42
  - docs: mention `i18next-plugin-pofile-backend` package
35
43
  - chore: remove old license headers
36
44
  - chore: bump deps
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @open-xchange/vite-plugin-i18next-gettext
2
2
 
3
- A Vite plugin that allows using [i18next](https://www.i18next.com/) in source code with gettext's' `.po` and `.pot` files under the hood.
3
+ A Vite plugin that allows using [i18next](https://www.i18next.com/) in source code with gettext's `.po` and `.pot` files under the hood.
4
4
 
5
5
  This plugin has the following responsibilities:
6
6
 
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import type { Plugin } from "vite";
4
4
  */
5
5
  export interface VitePluginI18nextGettextOptions {
6
6
  /**
7
- * Glob pattern(s) for all `.po` files containing the translations.
7
+ * Glob pattern(s) for all PO files containing the translations.
8
8
  *
9
9
  * @example
10
10
  * {
@@ -24,19 +24,21 @@ export interface VitePluginI18nextGettextOptions {
24
24
  */
25
25
  srcFiles: string | string[];
26
26
  /**
27
- * Path to the `.pot` file to be generated when building the project,
28
- * relative to the build output directory.
27
+ * Path to the POT files generated when building the project, relative to
28
+ * the build output directory. Should contain the placeholder `$NAMESPACE`
29
+ * if the project contains translation strings in different i18next
30
+ * namespaces.
29
31
  *
30
32
  * @example
31
33
  * {
32
- * potFile: "i18n/main.pot",
34
+ * potFile: "i18n/$NAMESPACE.pot",
33
35
  * // ...
34
36
  * }
35
37
  */
36
38
  potFile: string;
37
39
  /**
38
- * The project name to be inserted into the `.pot` file under the key
39
- * "Project-Id-Version".
40
+ * The project name to be inserted into the POT files under the key
41
+ * "Project-Id-Version". May contain the placeholder `$NAMESPACE`.
40
42
  */
41
43
  projectName: string;
42
44
  }
package/dist/index.js CHANGED
@@ -2,8 +2,7 @@ import { sep, relative, posix } from "node:path";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import pm from "picomatch";
4
4
  import converter from "gettext-converter";
5
- import { transform as Transformer } from "i18next-parser";
6
- import * as vfs from "vinyl-fs";
5
+ import parse from "@open-xchange/i18next-po-parser";
7
6
  // constants ==================================================================
8
7
  export const PROJECT_NAME = "@open-xchange/vite-plugin-i18next-gettext";
9
8
  // plugin =====================================================================
@@ -19,7 +18,7 @@ export const PROJECT_NAME = "@open-xchange/vite-plugin-i18next-gettext";
19
18
  export default function vitePluginI18nextGettext(options) {
20
19
  return {
21
20
  name: PROJECT_NAME,
22
- // register esbuild loader for `.po` files (load as plain text)
21
+ // register esbuild loader for PO files (load as plain text)
23
22
  config: () => ({
24
23
  optimizeDeps: {
25
24
  esbuildOptions: {
@@ -27,44 +26,32 @@ export default function vitePluginI18nextGettext(options) {
27
26
  },
28
27
  },
29
28
  }),
30
- // convert `.po` files to i18next JSON v4
29
+ // convert PO files to i18next JSON v4
31
30
  async load(id) {
32
31
  const relPath = relative(process.cwd(), id).replaceAll(sep, posix.sep);
33
32
  if (!pm.isMatch(relPath, options.poFiles)) {
34
33
  return;
35
34
  }
36
- // read the `.po` file and convert it to i18next JSON
35
+ // read the PO file and convert it to i18next JSON
37
36
  const data = await readFile(id, { encoding: "utf8" });
38
37
  const json = converter.po2i18next(data, { compatibilityJSON: "v4" });
39
38
  // generate a module that exports a _stringified_ JSON object
40
39
  const code = `export default ${JSON.stringify(json)};`;
41
40
  return { code, map: { mappings: "" } };
42
41
  },
43
- // parse source files and create a `.pot` file
42
+ // parse source files and create POT files per namespace
44
43
  async generateBundle() {
45
- // parse all source files and collect the translatable strings
46
- const json = await new Promise((resolve, reject) => {
47
- // the transformer instance that parses all source files, and assembles the translation catalogue
48
- const transformer = new Transformer({
49
- failOnWarnings: true,
50
- contextSeparator: "",
51
- keySeparator: false,
52
- lineEnding: "lf",
53
- namespaceSeparator: false,
54
- // locales to generate catalogue for
55
- locales: ["en"],
56
- });
57
- // warnings and errors
58
- transformer.on("warning", (message) => reject(new Error(message)));
59
- transformer.on("error", (message) => reject(new Error(message)));
60
- // fulfil promise with the resulting JSON data
61
- transformer.on("data", (file) => resolve(file.contents.toString("utf8")));
62
- // pipe all source files to transformer
63
- vfs.src(options.srcFiles).pipe(transformer);
64
- });
65
- // convert JSON data to `.pot` file
66
- const source = converter.i18next2po("en", json, { project: options.projectName, compatibilityJSON: "v4" });
67
- this.emitFile({ type: "asset", fileName: options.potFile, source });
44
+ // parse all source files, extract translations, collect into POT catalogs
45
+ const catalogs = await parse({ project: options.projectName, files: options.srcFiles });
46
+ // warn when writing multiple POT files to same file location
47
+ if ((catalogs.size > 1) && !options.potFile.includes("$NAMESPACE")) {
48
+ this.warn("multiple POT files written to same file location (missing placeholder '$NAMESPACE' in option 'potFile')");
49
+ }
50
+ // add all POT files as assets to the bundle
51
+ for (const [namespace, source] of catalogs) {
52
+ const fileName = options.potFile.replaceAll("$NAMESPACE", namespace);
53
+ this.emitFile({ type: "asset", fileName, source });
54
+ }
68
55
  },
69
56
  };
70
57
  }
package/package.json CHANGED
@@ -1,41 +1,42 @@
1
1
  {
2
2
  "name": "@open-xchange/vite-plugin-i18next-gettext",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Vite integration of i18next using gettext",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "https://gitlab.open-xchange.com/fspd/commons/plugins/-/tree/main/packages/vite-plugin-i18next-gettext"
7
+ "url": "https://gitlab.open-xchange.com/fspd/commons/plugins",
8
+ "directory": "packages/vite-plugin-i18next-gettext"
8
9
  },
9
10
  "license": "MIT",
10
11
  "engines": {
11
12
  "node": ">=20.18"
12
13
  },
13
- "packageManager": "yarn@4.6.0",
14
+ "packageManager": "yarn@4.9.1",
14
15
  "type": "module",
15
16
  "exports": "./dist/index.js",
17
+ "files": [
18
+ "dist",
19
+ "CHANGELOG.*"
20
+ ],
16
21
  "scripts": {
17
- "prepare": "yarn build",
18
22
  "prepack": "yarn build && yarn lint",
19
23
  "clean": "premove dist",
20
24
  "build": "yarn clean && tsc --project src/tsconfig.json",
21
25
  "lint": "tsc && tsc --project src/tsconfig.json --noEmit && eslint ."
22
26
  },
23
27
  "dependencies": {
28
+ "@open-xchange/i18next-po-parser": "^0.0.2",
24
29
  "gettext-converter": "^1.3.0",
25
- "i18next-parser": "^9.3.0",
26
- "picomatch": "^4.0.2",
27
- "vinyl-fs": "^4.0.0"
30
+ "picomatch": "^4.0.2"
28
31
  },
29
32
  "devDependencies": {
30
- "@open-xchange/linter-presets": "^1.2.14",
31
- "@types/node": "^22.13.4",
32
- "@types/vinyl-fs": "^3.0.5",
33
- "eslint": "^9.20.1",
33
+ "@open-xchange/linter-presets": "^1.2.30",
34
+ "@types/node": "^22.15.3",
35
+ "eslint": "^9.25.1",
34
36
  "jiti": "^2.4.2",
35
37
  "premove": "^4.0.0",
36
- "typescript": "^5.7.3",
37
- "vinyl": "^3.0.0",
38
- "vite": "^6.1.1"
38
+ "typescript": "^5.8.3",
39
+ "vite": "^6.3.4"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "vite": "^5.3.0 || ^6.0.0"