@translatehub/vite-plugin 1.0.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/dist/index.d.mts +55 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +102 -0
- package/dist/index.mjs +77 -0
- package/package.json +48 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* vite-plugin-translatehub
|
|
5
|
+
*
|
|
6
|
+
* Что делает плагин:
|
|
7
|
+
* 1. При сборке генерирует TypeScript-типы (translations.d.ts) из ключей проекта —
|
|
8
|
+
* автодополнение и type-safety в IDE без изменения runtime-поведения.
|
|
9
|
+
* 2. Опционально (downloadTranslations: true): скачивает переводы в public/locales/<lang>.json
|
|
10
|
+
* как статический fallback для оффлайн-поддержки или ускорения первого рендера.
|
|
11
|
+
*
|
|
12
|
+
* ВАЖНО: Переводы в runtime всегда загружает @translatehub/core через Public API.
|
|
13
|
+
* Изменение перевода в TranslateHub появится в production-приложении через TTL кэша Redis
|
|
14
|
+
* (по умолчанию 5 минут) — БЕЗ пересборки и деплоя.
|
|
15
|
+
*
|
|
16
|
+
* Использование в vite.config.ts:
|
|
17
|
+
* import { translateHub } from 'vite-plugin-translatehub';
|
|
18
|
+
*
|
|
19
|
+
* export default defineConfig({
|
|
20
|
+
* plugins: [
|
|
21
|
+
* react(),
|
|
22
|
+
* translateHub({
|
|
23
|
+
* apiKey: process.env.TRANSLATEHUB_API_KEY!,
|
|
24
|
+
* languages: ['ru', 'en', 'de'],
|
|
25
|
+
* // downloadTranslations: true, // опционально — для статической предзагрузки
|
|
26
|
+
* }),
|
|
27
|
+
* ],
|
|
28
|
+
* });
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
interface TranslateHubPluginOptions {
|
|
32
|
+
/** API-ключ проекта из TranslateHub */
|
|
33
|
+
apiKey: string;
|
|
34
|
+
/** Список языков для генерации типов */
|
|
35
|
+
languages: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Генерировать TypeScript-типы ключей (default: true).
|
|
38
|
+
* Типы обновляются при каждом запуске dev-сервера / сборке.
|
|
39
|
+
*/
|
|
40
|
+
generateTypes?: boolean;
|
|
41
|
+
/** Путь для файла с типами (default: 'src/types/translations.d.ts') */
|
|
42
|
+
typesOutputPath?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Скачивать переводы в public/locales/<lang>.json (default: false).
|
|
45
|
+
* Используйте, если хотите статическую предзагрузку переводов.
|
|
46
|
+
* Внимание: при этом обновление переводов без rebuild возможно только
|
|
47
|
+
* для языков, которые SDK получает с API (не из статических файлов).
|
|
48
|
+
*/
|
|
49
|
+
downloadTranslations?: boolean;
|
|
50
|
+
/** Папка для сохранения JSON-файлов (default: 'public/locales') */
|
|
51
|
+
outputDir?: string;
|
|
52
|
+
}
|
|
53
|
+
declare function translateHub(options: TranslateHubPluginOptions): Plugin;
|
|
54
|
+
|
|
55
|
+
export { type TranslateHubPluginOptions, translateHub };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* vite-plugin-translatehub
|
|
5
|
+
*
|
|
6
|
+
* Что делает плагин:
|
|
7
|
+
* 1. При сборке генерирует TypeScript-типы (translations.d.ts) из ключей проекта —
|
|
8
|
+
* автодополнение и type-safety в IDE без изменения runtime-поведения.
|
|
9
|
+
* 2. Опционально (downloadTranslations: true): скачивает переводы в public/locales/<lang>.json
|
|
10
|
+
* как статический fallback для оффлайн-поддержки или ускорения первого рендера.
|
|
11
|
+
*
|
|
12
|
+
* ВАЖНО: Переводы в runtime всегда загружает @translatehub/core через Public API.
|
|
13
|
+
* Изменение перевода в TranslateHub появится в production-приложении через TTL кэша Redis
|
|
14
|
+
* (по умолчанию 5 минут) — БЕЗ пересборки и деплоя.
|
|
15
|
+
*
|
|
16
|
+
* Использование в vite.config.ts:
|
|
17
|
+
* import { translateHub } from 'vite-plugin-translatehub';
|
|
18
|
+
*
|
|
19
|
+
* export default defineConfig({
|
|
20
|
+
* plugins: [
|
|
21
|
+
* react(),
|
|
22
|
+
* translateHub({
|
|
23
|
+
* apiKey: process.env.TRANSLATEHUB_API_KEY!,
|
|
24
|
+
* languages: ['ru', 'en', 'de'],
|
|
25
|
+
* // downloadTranslations: true, // опционально — для статической предзагрузки
|
|
26
|
+
* }),
|
|
27
|
+
* ],
|
|
28
|
+
* });
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
interface TranslateHubPluginOptions {
|
|
32
|
+
/** API-ключ проекта из TranslateHub */
|
|
33
|
+
apiKey: string;
|
|
34
|
+
/** Список языков для генерации типов */
|
|
35
|
+
languages: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Генерировать TypeScript-типы ключей (default: true).
|
|
38
|
+
* Типы обновляются при каждом запуске dev-сервера / сборке.
|
|
39
|
+
*/
|
|
40
|
+
generateTypes?: boolean;
|
|
41
|
+
/** Путь для файла с типами (default: 'src/types/translations.d.ts') */
|
|
42
|
+
typesOutputPath?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Скачивать переводы в public/locales/<lang>.json (default: false).
|
|
45
|
+
* Используйте, если хотите статическую предзагрузку переводов.
|
|
46
|
+
* Внимание: при этом обновление переводов без rebuild возможно только
|
|
47
|
+
* для языков, которые SDK получает с API (не из статических файлов).
|
|
48
|
+
*/
|
|
49
|
+
downloadTranslations?: boolean;
|
|
50
|
+
/** Папка для сохранения JSON-файлов (default: 'public/locales') */
|
|
51
|
+
outputDir?: string;
|
|
52
|
+
}
|
|
53
|
+
declare function translateHub(options: TranslateHubPluginOptions): Plugin;
|
|
54
|
+
|
|
55
|
+
export { type TranslateHubPluginOptions, translateHub };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
translateHub: () => translateHub
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_fs = require("fs");
|
|
27
|
+
var import_path = require("path");
|
|
28
|
+
var BASE_URL = "https://translate-hub.ru";
|
|
29
|
+
function translateHub(options) {
|
|
30
|
+
const {
|
|
31
|
+
apiKey,
|
|
32
|
+
languages,
|
|
33
|
+
generateTypes = true,
|
|
34
|
+
typesOutputPath = "src/types/translations.d.ts",
|
|
35
|
+
downloadTranslations = false,
|
|
36
|
+
outputDir = "public/locales"
|
|
37
|
+
} = options;
|
|
38
|
+
return {
|
|
39
|
+
name: "vite-plugin-translatehub",
|
|
40
|
+
async buildStart() {
|
|
41
|
+
const cwd = process.cwd();
|
|
42
|
+
if (!generateTypes && !downloadTranslations) return;
|
|
43
|
+
console.log(`[translatehub] \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u044E \u043A\u043B\u044E\u0447\u0438 \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0438\u043F\u043E\u0432...`);
|
|
44
|
+
const results = await Promise.allSettled(
|
|
45
|
+
languages.map((lang) => fetchTranslations(BASE_URL, apiKey, lang))
|
|
46
|
+
);
|
|
47
|
+
const allKeys = /* @__PURE__ */ new Set();
|
|
48
|
+
for (let i = 0; i < languages.length; i++) {
|
|
49
|
+
const lang = languages[i];
|
|
50
|
+
const result = results[i];
|
|
51
|
+
if (result.status === "fulfilled") {
|
|
52
|
+
const translations = result.value;
|
|
53
|
+
Object.keys(translations).forEach((k) => allKeys.add(k));
|
|
54
|
+
if (downloadTranslations) {
|
|
55
|
+
const outDir = (0, import_path.resolve)(cwd, outputDir);
|
|
56
|
+
if (!(0, import_fs.existsSync)(outDir)) (0, import_fs.mkdirSync)(outDir, { recursive: true });
|
|
57
|
+
const filePath = (0, import_path.join)(outDir, `${lang}.json`);
|
|
58
|
+
(0, import_fs.writeFileSync)(filePath, JSON.stringify(translations, null, 2), "utf-8");
|
|
59
|
+
console.log(`[translatehub] \u0421\u043A\u0430\u0447\u0430\u043D ${lang}.json (${Object.keys(translations).length} \u043A\u043B\u044E\u0447\u0435\u0439)`);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
console.warn(`[translatehub] \u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u043A\u043B\u044E\u0447\u0435\u0439 \u0434\u043B\u044F "${lang}":`, result.reason?.message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (generateTypes && allKeys.size > 0) {
|
|
66
|
+
const typesPath = (0, import_path.resolve)(cwd, typesOutputPath);
|
|
67
|
+
const typesDir = typesPath.replace(/[/\\][^/\\]+$/, "");
|
|
68
|
+
if (!(0, import_fs.existsSync)(typesDir)) (0, import_fs.mkdirSync)(typesDir, { recursive: true });
|
|
69
|
+
const keyUnion = [...allKeys].sort().map((k) => ` | '${k}'`).join("\n");
|
|
70
|
+
const content = `// \u0410\u0432\u0442\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F vite-plugin-translatehub \u2014 \u043D\u0435 \u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0440\u0443\u0447\u043D\u0443\u044E
|
|
71
|
+
// \u041E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u0440\u0438 \u043A\u0430\u0436\u0434\u043E\u0439 \u0441\u0431\u043E\u0440\u043A\u0435 / \u0437\u0430\u043F\u0443\u0441\u043A\u0435 dev-\u0441\u0435\u0440\u0432\u0435\u0440\u0430
|
|
72
|
+
// \u041F\u0435\u0440\u0435\u0432\u043E\u0434\u044B \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044E\u0442\u0441\u044F \u0432 runtime \u0447\u0435\u0440\u0435\u0437 @translatehub/core (\u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0441\u0431\u043E\u0440\u043A\u0438)
|
|
73
|
+
|
|
74
|
+
export type TranslationKey =
|
|
75
|
+
${keyUnion};
|
|
76
|
+
|
|
77
|
+
declare module '@translatehub/react' {
|
|
78
|
+
interface UseTranslation {
|
|
79
|
+
t(key: TranslationKey, params?: Record<string, string | number>): string;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
(0, import_fs.writeFileSync)(typesPath, content, "utf-8");
|
|
84
|
+
console.log(`[translatehub] TypeScript-\u0442\u0438\u043F\u044B \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u044B: ${typesOutputPath} (${allKeys.size} \u043A\u043B\u044E\u0447\u0435\u0439)`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async function fetchTranslations(baseUrl, apiKey, lang) {
|
|
90
|
+
const url = `${baseUrl}/api/public/translations?lang=${encodeURIComponent(lang)}`;
|
|
91
|
+
const response = await fetch(url, {
|
|
92
|
+
headers: { "X-API-Key": apiKey }
|
|
93
|
+
});
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new Error(`HTTP ${response.status} \u0434\u043B\u044F \u044F\u0437\u044B\u043A\u0430 "${lang}"`);
|
|
96
|
+
}
|
|
97
|
+
return response.json();
|
|
98
|
+
}
|
|
99
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
100
|
+
0 && (module.exports = {
|
|
101
|
+
translateHub
|
|
102
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
3
|
+
import { resolve, join } from "path";
|
|
4
|
+
var BASE_URL = "https://translate-hub.ru";
|
|
5
|
+
function translateHub(options) {
|
|
6
|
+
const {
|
|
7
|
+
apiKey,
|
|
8
|
+
languages,
|
|
9
|
+
generateTypes = true,
|
|
10
|
+
typesOutputPath = "src/types/translations.d.ts",
|
|
11
|
+
downloadTranslations = false,
|
|
12
|
+
outputDir = "public/locales"
|
|
13
|
+
} = options;
|
|
14
|
+
return {
|
|
15
|
+
name: "vite-plugin-translatehub",
|
|
16
|
+
async buildStart() {
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
if (!generateTypes && !downloadTranslations) return;
|
|
19
|
+
console.log(`[translatehub] \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u044E \u043A\u043B\u044E\u0447\u0438 \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0438\u043F\u043E\u0432...`);
|
|
20
|
+
const results = await Promise.allSettled(
|
|
21
|
+
languages.map((lang) => fetchTranslations(BASE_URL, apiKey, lang))
|
|
22
|
+
);
|
|
23
|
+
const allKeys = /* @__PURE__ */ new Set();
|
|
24
|
+
for (let i = 0; i < languages.length; i++) {
|
|
25
|
+
const lang = languages[i];
|
|
26
|
+
const result = results[i];
|
|
27
|
+
if (result.status === "fulfilled") {
|
|
28
|
+
const translations = result.value;
|
|
29
|
+
Object.keys(translations).forEach((k) => allKeys.add(k));
|
|
30
|
+
if (downloadTranslations) {
|
|
31
|
+
const outDir = resolve(cwd, outputDir);
|
|
32
|
+
if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });
|
|
33
|
+
const filePath = join(outDir, `${lang}.json`);
|
|
34
|
+
writeFileSync(filePath, JSON.stringify(translations, null, 2), "utf-8");
|
|
35
|
+
console.log(`[translatehub] \u0421\u043A\u0430\u0447\u0430\u043D ${lang}.json (${Object.keys(translations).length} \u043A\u043B\u044E\u0447\u0435\u0439)`);
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
console.warn(`[translatehub] \u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u043A\u043B\u044E\u0447\u0435\u0439 \u0434\u043B\u044F "${lang}":`, result.reason?.message);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (generateTypes && allKeys.size > 0) {
|
|
42
|
+
const typesPath = resolve(cwd, typesOutputPath);
|
|
43
|
+
const typesDir = typesPath.replace(/[/\\][^/\\]+$/, "");
|
|
44
|
+
if (!existsSync(typesDir)) mkdirSync(typesDir, { recursive: true });
|
|
45
|
+
const keyUnion = [...allKeys].sort().map((k) => ` | '${k}'`).join("\n");
|
|
46
|
+
const content = `// \u0410\u0432\u0442\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F vite-plugin-translatehub \u2014 \u043D\u0435 \u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0440\u0443\u0447\u043D\u0443\u044E
|
|
47
|
+
// \u041E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u0440\u0438 \u043A\u0430\u0436\u0434\u043E\u0439 \u0441\u0431\u043E\u0440\u043A\u0435 / \u0437\u0430\u043F\u0443\u0441\u043A\u0435 dev-\u0441\u0435\u0440\u0432\u0435\u0440\u0430
|
|
48
|
+
// \u041F\u0435\u0440\u0435\u0432\u043E\u0434\u044B \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044E\u0442\u0441\u044F \u0432 runtime \u0447\u0435\u0440\u0435\u0437 @translatehub/core (\u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0441\u0431\u043E\u0440\u043A\u0438)
|
|
49
|
+
|
|
50
|
+
export type TranslationKey =
|
|
51
|
+
${keyUnion};
|
|
52
|
+
|
|
53
|
+
declare module '@translatehub/react' {
|
|
54
|
+
interface UseTranslation {
|
|
55
|
+
t(key: TranslationKey, params?: Record<string, string | number>): string;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
writeFileSync(typesPath, content, "utf-8");
|
|
60
|
+
console.log(`[translatehub] TypeScript-\u0442\u0438\u043F\u044B \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u044B: ${typesOutputPath} (${allKeys.size} \u043A\u043B\u044E\u0447\u0435\u0439)`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async function fetchTranslations(baseUrl, apiKey, lang) {
|
|
66
|
+
const url = `${baseUrl}/api/public/translations?lang=${encodeURIComponent(lang)}`;
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
headers: { "X-API-Key": apiKey }
|
|
69
|
+
});
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
throw new Error(`HTTP ${response.status} \u0434\u043B\u044F \u044F\u0437\u044B\u043A\u0430 "${lang}"`);
|
|
72
|
+
}
|
|
73
|
+
return response.json();
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
translateHub
|
|
77
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@translatehub/vite-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vite plugin — downloads translations from TranslateHub at build time and generates TypeScript types",
|
|
5
|
+
"main": "dist/index.cjs",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.cjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
20
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --watch"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"vite": ">=4.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^25.5.2",
|
|
27
|
+
"tsup": "^8.0.2",
|
|
28
|
+
"typescript": "^5.4.2",
|
|
29
|
+
"vite": "^5.2.0"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"vite",
|
|
33
|
+
"vite-plugin",
|
|
34
|
+
"i18n",
|
|
35
|
+
"translatehub"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public",
|
|
40
|
+
"registry": "https://registry.npmjs.org/"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://gitlab.com/artemryskal/translate-hub.git",
|
|
45
|
+
"directory": "sdk/vite-plugin"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://translate-hub.ru"
|
|
48
|
+
}
|