@open-xchange/vite-plugin-i18next-gettext 0.0.1

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.
@@ -0,0 +1,3 @@
1
+ {
2
+ "typescript.tsdk": "node_modules/typescript/lib"
3
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## [0.0.1] - 2024-07-26
4
+
5
+ - initial release
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @open-xchange/vite-plugin-i18next-gettext
2
+
3
+ A Vite plugin that allows using [i18next](https://www.i18next.com/) in source code, while using gettext with `.po` and `.pot` files under the hood.
4
+
5
+ This plugin has the following responsibilities:
6
+
7
+ - Vite's development server will convert `.po` files imported in source code to i18next-compatible JSON data on-the-fly.
8
+ - When building the project, `.po` files will be converted to and written as i18next-compatible JSON files into the bundle.
9
+ - When building the project, the source code will be scanned for translation strings (`t` function calls), and a `.pot` file containing all strings will be generated into the output directory.
10
+
11
+ ## Usage
12
+
13
+ ### Vite
14
+
15
+ Add the plugin to your Vite configuration:
16
+
17
+ ```ts
18
+ // vite.config.ts
19
+
20
+ import { defineConfig } from "vite" // or "vitest/config"
21
+ import i18nextPlugin from "@open-xchange/vite-plugin-i18next-gettext"
22
+
23
+ export default defineConfig(() => {
24
+
25
+ // ...
26
+
27
+ plugins: [
28
+ // ...
29
+
30
+ i18nextPlugin({
31
+ poFiles: "i18n/*.po",
32
+ srcFiles: "src/**/*.{js,jsx,ts,tsx}",
33
+ potFile: "main.pot",
34
+ projectName: "My Project",
35
+ }),
36
+ ],
37
+ })
38
+ ```
39
+
40
+ #### Options
41
+
42
+ | Name | Type | Default | Description |
43
+ | - | - | - | - |
44
+ | `poFiles` | `string\|string[]` | _required_ | Glob pattern(s) for all `.po` files containing the translations. |
45
+ | `srcFiles` | `string\|string[]` | _required_ | Glob pattern(s) for all source files to be scanned for UI strings. |
46
+ | `potFile` | `string` | _required_ | Path to the `.pot` file to be generated when building the project, relative to the build output directory. |
47
+ | `projectName` | `string` | _required_ | The project name to be inserted into the `.pot` file under the key "Project-Id-Version". |
48
+
49
+ ### Source Code
50
+
51
+ Import the `.po` files directly when setting up i18next, for example:
52
+
53
+ ```ts
54
+ // src/@types/globals.d.ts
55
+
56
+ declare module "*.po" {
57
+ import { ResourceKey } from "i18next"
58
+ const resource: ResourceKey
59
+ export default resource
60
+ }
61
+ ```
62
+
63
+ ```ts
64
+ // src/hooks/useTranslation.ts
65
+
66
+ import i18next from "i18next"
67
+ import type { BackendModule, ReadCallback } from "i18next"
68
+
69
+ class POFileBackend implements BackendModule {
70
+
71
+ // type needs to be provided statically (expected by i18next runtime), and as instance prop (for typings only)
72
+ static readonly type = "backend"
73
+ readonly type = "backend"
74
+
75
+ init(): void {
76
+ // nothing to do
77
+ }
78
+
79
+ async read(lang: string, _ns: string, cb: ReadCallback): Promise<void> {
80
+ try {
81
+ const module = await import(`./i18n/${lang}.po`) as typeof import("*.po")
82
+ cb(null, module.default)
83
+ } catch (error) {
84
+ cb(error as Error, null)
85
+ }
86
+ }
87
+ }
88
+
89
+ i18next.use(POFileBackend)
90
+
91
+ export default useTranslation
92
+ ```
@@ -0,0 +1,50 @@
1
+ import type { Plugin } from "vite";
2
+ export interface VitePluginI18nextGettextOptions {
3
+ /**
4
+ * Glob pattern(s) for all `.po` files containing the translations.
5
+ *
6
+ * @example
7
+ * {
8
+ * poFiles: "i18n/*.po",
9
+ * // ...
10
+ * }
11
+ */
12
+ poFiles: string | string[];
13
+ /**
14
+ * Glob pattern(s) for all source files to be scanned for UI strings.
15
+ *
16
+ * @example
17
+ * {
18
+ * srcFiles: "src/*.{js,ts}",
19
+ * // ...
20
+ * }
21
+ */
22
+ srcFiles: string | string[];
23
+ /**
24
+ * Path to the `.pot` file to be generated when building the project,
25
+ * relative to the build output directory.
26
+ *
27
+ * @example
28
+ * {
29
+ * potFile: "i18n/main.pot",
30
+ * // ...
31
+ * }
32
+ */
33
+ potFile: string;
34
+ /**
35
+ * The project name to be inserted into the `.pot` file under the key
36
+ * "Project-Id-Version".
37
+ */
38
+ projectName: string;
39
+ }
40
+ export declare const PROJECT_NAME = "@open-xchange/vite-plugin-i18next-gettext";
41
+ /**
42
+ * Vite plugin for using i18next with gettext `.po` files under the hood.
43
+ *
44
+ * @param options
45
+ * Plugin configuration.
46
+ *
47
+ * @returns
48
+ * The Vite plugin object.
49
+ */
50
+ export default function vitePluginI18nextGettext(options: VitePluginI18nextGettextOptions): Plugin;
package/dist/index.js ADDED
@@ -0,0 +1,74 @@
1
+ /*
2
+ * Copyright (C) Open-Xchange GmbH, Germany <info@open-xchange.com>
3
+ *
4
+ * This program is proprietary software and licensed to you under Open-Xchange
5
+ * GmbH's Software License Agreement.
6
+ */
7
+ import { readFile } from "node:fs/promises";
8
+ import pm from "picomatch";
9
+ import converter from "gettext-converter";
10
+ import { transform as Transformer } from "i18next-parser";
11
+ import * as vfs from "vinyl-fs";
12
+ // constants ==================================================================
13
+ export const PROJECT_NAME = "@open-xchange/vite-plugin-i18next-gettext";
14
+ // plugin =====================================================================
15
+ /**
16
+ * Vite plugin for using i18next with gettext `.po` files under the hood.
17
+ *
18
+ * @param options
19
+ * Plugin configuration.
20
+ *
21
+ * @returns
22
+ * The Vite plugin object.
23
+ */
24
+ export default function vitePluginI18nextGettext(options) {
25
+ return {
26
+ name: PROJECT_NAME,
27
+ // register esbuild loader for `.po` files (load as plain text)
28
+ config: () => ({
29
+ optimizeDeps: {
30
+ esbuildOptions: {
31
+ loader: { ".po": "text" },
32
+ },
33
+ },
34
+ }),
35
+ // convert `.po` files to i18next JSON v4
36
+ async load(id) {
37
+ if (!pm.isMatch(id, options.poFiles)) {
38
+ return;
39
+ }
40
+ // read the `.po` file and convert it to i18next JSON
41
+ const data = await readFile(id, { encoding: "utf8" });
42
+ const json = converter.po2i18next(data, { compatibilityJSON: "v4" });
43
+ // generate a module that exports a _stringified_ JSON object
44
+ const code = `export default ${JSON.stringify(json)};`;
45
+ return { code, map: { mappings: "" } };
46
+ },
47
+ // parse source files and create a `.pot` file
48
+ async generateBundle() {
49
+ // parse all source files and collect the translatable strings
50
+ const json = await new Promise((resolve, reject) => {
51
+ // the transformer instance that parses all source files, and assembles the translation catalogue
52
+ const transformer = new Transformer({
53
+ failOnWarnings: true,
54
+ contextSeparator: "",
55
+ keySeparator: false,
56
+ lineEnding: "lf",
57
+ namespaceSeparator: false,
58
+ // locales to generate catalogue for
59
+ locales: ["en"],
60
+ });
61
+ // warnings and errors
62
+ transformer.on("warning", (message) => reject(new Error(message)));
63
+ transformer.on("error", (message) => reject(new Error(message)));
64
+ // fulfil promise with the resulting JSON data
65
+ transformer.on("data", (file) => resolve(file.contents.toString("utf8")));
66
+ // pipe all source files to transformer
67
+ vfs.src(options.srcFiles).pipe(transformer);
68
+ });
69
+ // convert JSON data to `.pot` file
70
+ const source = converter.i18next2po("en", json, { project: options.projectName, compatibilityJSON: "v4" });
71
+ this.emitFile({ type: "asset", fileName: options.potFile, source });
72
+ },
73
+ };
74
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@open-xchange/vite-plugin-i18next-gettext",
3
+ "version": "0.0.1",
4
+ "description": "Vite integration of i18next using gettext",
5
+ "repository": {
6
+ "url": "https://gitlab.open-xchange.com/fspd/npm-packages/vite-plugin-i18next-gettext"
7
+ },
8
+ "license": "MIT",
9
+ "engines": {
10
+ "node": "18.18.0 || ^20.9.0 || >=21.1.0"
11
+ },
12
+ "packageManager": "yarn@4.3.1",
13
+ "type": "module",
14
+ "exports": "./dist/index.js",
15
+ "scripts": {
16
+ "prepare": "husky",
17
+ "prepack": "yarn build && yarn lint",
18
+ "build": "npx --yes rimraf dist && tsc",
19
+ "lint": "eslint ."
20
+ },
21
+ "lint-staged": {
22
+ "*.{js,ts,json}": "yarn lint"
23
+ },
24
+ "devDependencies": {
25
+ "@open-xchange/linter-presets": "0.1.9",
26
+ "@types/node": "20.14.12",
27
+ "@types/vinyl-fs": "3.0.5",
28
+ "eslint": "9.7.0",
29
+ "husky": "9.1.2",
30
+ "typescript": "5.5.4",
31
+ "vinyl": "3.0.0",
32
+ "vite": "5.3.5"
33
+ },
34
+ "peerDependencies": {
35
+ "vite": "^5.3"
36
+ },
37
+ "resolutions": {
38
+ "semver": "^7.6.2"
39
+ },
40
+ "dependencies": {
41
+ "gettext-converter": "1.3.0",
42
+ "i18next-parser": "9.0.0",
43
+ "picomatch": "4.0.2",
44
+ "vinyl-fs": "4.0.0"
45
+ }
46
+ }