@lingo.dev/compiler 0.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/LICENSE.md +201 -0
- package/README.md +192 -0
- package/build/_virtual/rolldown_runtime.cjs +29 -0
- package/build/_virtual/rolldown_runtime.mjs +7 -0
- package/build/index.cjs +0 -0
- package/build/index.d.cts +2 -0
- package/build/index.d.mts +2 -0
- package/build/index.mjs +1 -0
- package/build/metadata/manager.cjs +131 -0
- package/build/metadata/manager.mjs +123 -0
- package/build/metadata/manager.mjs.map +1 -0
- package/build/plugin/build-translator.cjs +198 -0
- package/build/plugin/build-translator.mjs +196 -0
- package/build/plugin/build-translator.mjs.map +1 -0
- package/build/plugin/cleanup.cjs +20 -0
- package/build/plugin/cleanup.mjs +20 -0
- package/build/plugin/cleanup.mjs.map +1 -0
- package/build/plugin/next-compiler-loader.cjs +41 -0
- package/build/plugin/next-compiler-loader.d.cts +12 -0
- package/build/plugin/next-compiler-loader.d.cts.map +1 -0
- package/build/plugin/next-compiler-loader.d.mts +13 -0
- package/build/plugin/next-compiler-loader.d.mts.map +1 -0
- package/build/plugin/next-compiler-loader.mjs +42 -0
- package/build/plugin/next-compiler-loader.mjs.map +1 -0
- package/build/plugin/next-config-loader.cjs +13 -0
- package/build/plugin/next-config-loader.d.cts +8 -0
- package/build/plugin/next-config-loader.d.cts.map +1 -0
- package/build/plugin/next-config-loader.d.mts +9 -0
- package/build/plugin/next-config-loader.d.mts.map +1 -0
- package/build/plugin/next-config-loader.mjs +14 -0
- package/build/plugin/next-config-loader.mjs.map +1 -0
- package/build/plugin/next-locale-client-loader.cjs +9 -0
- package/build/plugin/next-locale-client-loader.d.cts +8 -0
- package/build/plugin/next-locale-client-loader.d.cts.map +1 -0
- package/build/plugin/next-locale-client-loader.d.mts +9 -0
- package/build/plugin/next-locale-client-loader.d.mts.map +1 -0
- package/build/plugin/next-locale-client-loader.mjs +10 -0
- package/build/plugin/next-locale-client-loader.mjs.map +1 -0
- package/build/plugin/next-locale-server-loader.cjs +9 -0
- package/build/plugin/next-locale-server-loader.d.cts +8 -0
- package/build/plugin/next-locale-server-loader.d.cts.map +1 -0
- package/build/plugin/next-locale-server-loader.d.mts +9 -0
- package/build/plugin/next-locale-server-loader.d.mts.map +1 -0
- package/build/plugin/next-locale-server-loader.mjs +10 -0
- package/build/plugin/next-locale-server-loader.mjs.map +1 -0
- package/build/plugin/next.cjs +220 -0
- package/build/plugin/next.d.cts +9 -0
- package/build/plugin/next.d.cts.map +1 -0
- package/build/plugin/next.d.mts +9 -0
- package/build/plugin/next.d.mts.map +1 -0
- package/build/plugin/next.mjs +222 -0
- package/build/plugin/next.mjs.map +1 -0
- package/build/plugin/transform/babel-compat.cjs +13 -0
- package/build/plugin/transform/babel-compat.mjs +10 -0
- package/build/plugin/transform/babel-compat.mjs.map +1 -0
- package/build/plugin/transform/index.cjs +44 -0
- package/build/plugin/transform/index.mjs +42 -0
- package/build/plugin/transform/index.mjs.map +1 -0
- package/build/plugin/transform/metadata.cjs +142 -0
- package/build/plugin/transform/metadata.mjs +141 -0
- package/build/plugin/transform/metadata.mjs.map +1 -0
- package/build/plugin/transform/parse-override.cjs +145 -0
- package/build/plugin/transform/parse-override.mjs +144 -0
- package/build/plugin/transform/parse-override.mjs.map +1 -0
- package/build/plugin/transform/process-file.cjs +391 -0
- package/build/plugin/transform/process-file.mjs +390 -0
- package/build/plugin/transform/process-file.mjs.map +1 -0
- package/build/plugin/transform/use-i18n.cjs +8 -0
- package/build/plugin/transform/use-i18n.mjs +7 -0
- package/build/plugin/transform/use-i18n.mjs.map +1 -0
- package/build/plugin/transform/utils.cjs +205 -0
- package/build/plugin/transform/utils.mjs +192 -0
- package/build/plugin/transform/utils.mjs.map +1 -0
- package/build/plugin/unplugin.cjs +188 -0
- package/build/plugin/unplugin.d.cts +8 -0
- package/build/plugin/unplugin.d.cts.map +1 -0
- package/build/plugin/unplugin.d.mts +8 -0
- package/build/plugin/unplugin.d.mts.map +1 -0
- package/build/plugin/unplugin.mjs +186 -0
- package/build/plugin/unplugin.mjs.map +1 -0
- package/build/plugin/vite.cjs +28 -0
- package/build/plugin/vite.d.cts +9 -0
- package/build/plugin/vite.d.cts.map +1 -0
- package/build/plugin/vite.d.mts +9 -0
- package/build/plugin/vite.d.mts.map +1 -0
- package/build/plugin/vite.mjs +29 -0
- package/build/plugin/vite.mjs.map +1 -0
- package/build/plugin/webpack.cjs +27 -0
- package/build/plugin/webpack.d.cts +8 -0
- package/build/plugin/webpack.d.cts.map +1 -0
- package/build/plugin/webpack.d.mts +8 -0
- package/build/plugin/webpack.d.mts.map +1 -0
- package/build/plugin/webpack.mjs +28 -0
- package/build/plugin/webpack.mjs.map +1 -0
- package/build/react/client/index.cjs +9 -0
- package/build/react/client/index.d.cts +5 -0
- package/build/react/client/index.d.mts +5 -0
- package/build/react/client/index.mjs +6 -0
- package/build/react/client/useTranslation.cjs +71 -0
- package/build/react/client/useTranslation.d.cts +42 -0
- package/build/react/client/useTranslation.d.cts.map +1 -0
- package/build/react/client/useTranslation.d.mts +42 -0
- package/build/react/client/useTranslation.d.mts.map +1 -0
- package/build/react/client/useTranslation.mjs +71 -0
- package/build/react/client/useTranslation.mjs.map +1 -0
- package/build/react/next/client.cjs +25 -0
- package/build/react/next/client.d.cts +9 -0
- package/build/react/next/client.d.cts.map +1 -0
- package/build/react/next/client.d.mts +9 -0
- package/build/react/next/client.d.mts.map +1 -0
- package/build/react/next/client.mjs +24 -0
- package/build/react/next/client.mjs.map +1 -0
- package/build/react/next/cookie-locale-resolver.cjs +29 -0
- package/build/react/next/cookie-locale-resolver.d.cts +33 -0
- package/build/react/next/cookie-locale-resolver.d.cts.map +1 -0
- package/build/react/next/cookie-locale-resolver.d.mts +33 -0
- package/build/react/next/cookie-locale-resolver.d.mts.map +1 -0
- package/build/react/next/cookie-locale-resolver.mjs +29 -0
- package/build/react/next/cookie-locale-resolver.mjs.map +1 -0
- package/build/react/next/server.cjs +21 -0
- package/build/react/next/server.d.cts +13 -0
- package/build/react/next/server.d.cts.map +1 -0
- package/build/react/next/server.d.mts +14 -0
- package/build/react/next/server.d.mts.map +1 -0
- package/build/react/next/server.mjs +20 -0
- package/build/react/next/server.mjs.map +1 -0
- package/build/react/server/ServerLingoProvider.cjs +19 -0
- package/build/react/server/ServerLingoProvider.d.cts +12 -0
- package/build/react/server/ServerLingoProvider.d.cts.map +1 -0
- package/build/react/server/ServerLingoProvider.d.mts +12 -0
- package/build/react/server/ServerLingoProvider.d.mts.map +1 -0
- package/build/react/server/ServerLingoProvider.mjs +19 -0
- package/build/react/server/ServerLingoProvider.mjs.map +1 -0
- package/build/react/server/index.cjs +7 -0
- package/build/react/server/index.d.cts +4 -0
- package/build/react/server/index.d.mts +4 -0
- package/build/react/server/index.mjs +5 -0
- package/build/react/server/useTranslation.cjs +60 -0
- package/build/react/server/useTranslation.d.cts +36 -0
- package/build/react/server/useTranslation.d.cts.map +1 -0
- package/build/react/server/useTranslation.d.mts +36 -0
- package/build/react/server/useTranslation.d.mts.map +1 -0
- package/build/react/server/useTranslation.mjs +60 -0
- package/build/react/server/useTranslation.mjs.map +1 -0
- package/build/react/server-only/index.cjs +42 -0
- package/build/react/server-only/index.d.cts +38 -0
- package/build/react/server-only/index.d.cts.map +1 -0
- package/build/react/server-only/index.d.mts +38 -0
- package/build/react/server-only/index.d.mts.map +1 -0
- package/build/react/server-only/index.mjs +42 -0
- package/build/react/server-only/index.mjs.map +1 -0
- package/build/react/server-only/translations.cjs +85 -0
- package/build/react/server-only/translations.mjs +85 -0
- package/build/react/server-only/translations.mjs.map +1 -0
- package/build/react/shared/LingoContext.cjs +14 -0
- package/build/react/shared/LingoContext.d.cts +41 -0
- package/build/react/shared/LingoContext.d.cts.map +1 -0
- package/build/react/shared/LingoContext.d.mts +41 -0
- package/build/react/shared/LingoContext.d.mts.map +1 -0
- package/build/react/shared/LingoContext.mjs +13 -0
- package/build/react/shared/LingoContext.mjs.map +1 -0
- package/build/react/shared/LingoProvider.cjs +274 -0
- package/build/react/shared/LingoProvider.d.cts +76 -0
- package/build/react/shared/LingoProvider.d.cts.map +1 -0
- package/build/react/shared/LingoProvider.d.mts +76 -0
- package/build/react/shared/LingoProvider.d.mts.map +1 -0
- package/build/react/shared/LingoProvider.mjs +274 -0
- package/build/react/shared/LingoProvider.mjs.map +1 -0
- package/build/react/shared/LocaleSwitcher.cjs +61 -0
- package/build/react/shared/LocaleSwitcher.d.cts +71 -0
- package/build/react/shared/LocaleSwitcher.d.cts.map +1 -0
- package/build/react/shared/LocaleSwitcher.d.mts +71 -0
- package/build/react/shared/LocaleSwitcher.d.mts.map +1 -0
- package/build/react/shared/LocaleSwitcher.mjs +61 -0
- package/build/react/shared/LocaleSwitcher.mjs.map +1 -0
- package/build/react/shared/render-rich-text.cjs +55 -0
- package/build/react/shared/render-rich-text.d.cts +17 -0
- package/build/react/shared/render-rich-text.d.cts.map +1 -0
- package/build/react/shared/render-rich-text.d.mts +17 -0
- package/build/react/shared/render-rich-text.d.mts.map +1 -0
- package/build/react/shared/render-rich-text.mjs +54 -0
- package/build/react/shared/render-rich-text.mjs.map +1 -0
- package/build/react/shared/utils.cjs +34 -0
- package/build/react/shared/utils.mjs +35 -0
- package/build/react/shared/utils.mjs.map +1 -0
- package/build/react/types.d.cts +16 -0
- package/build/react/types.d.cts.map +1 -0
- package/build/react/types.d.mts +16 -0
- package/build/react/types.d.mts.map +1 -0
- package/build/translation-server/logger.cjs +37 -0
- package/build/translation-server/logger.mjs +37 -0
- package/build/translation-server/logger.mjs.map +1 -0
- package/build/translation-server/translation-server.cjs +547 -0
- package/build/translation-server/translation-server.mjs +544 -0
- package/build/translation-server/translation-server.mjs.map +1 -0
- package/build/translation-server/ws-events.cjs +15 -0
- package/build/translation-server/ws-events.mjs +15 -0
- package/build/translation-server/ws-events.mjs.map +1 -0
- package/build/translators/api.cjs +12 -0
- package/build/translators/api.mjs +12 -0
- package/build/translators/api.mjs.map +1 -0
- package/build/translators/cache-factory.cjs +26 -0
- package/build/translators/cache-factory.mjs +27 -0
- package/build/translators/cache-factory.mjs.map +1 -0
- package/build/translators/lingo/model-factory.cjs +179 -0
- package/build/translators/lingo/model-factory.mjs +174 -0
- package/build/translators/lingo/model-factory.mjs.map +1 -0
- package/build/translators/lingo/prompt.cjs +43 -0
- package/build/translators/lingo/prompt.mjs +43 -0
- package/build/translators/lingo/prompt.mjs.map +1 -0
- package/build/translators/lingo/service.cjs +152 -0
- package/build/translators/lingo/service.mjs +152 -0
- package/build/translators/lingo/service.mjs.map +1 -0
- package/build/translators/lingo/shots.cjs +28 -0
- package/build/translators/lingo/shots.mjs +28 -0
- package/build/translators/lingo/shots.mjs.map +1 -0
- package/build/translators/local-cache.cjs +115 -0
- package/build/translators/local-cache.mjs +113 -0
- package/build/translators/local-cache.mjs.map +1 -0
- package/build/translators/parse-xml.cjs +109 -0
- package/build/translators/parse-xml.mjs +108 -0
- package/build/translators/parse-xml.mjs.map +1 -0
- package/build/translators/pluralization/icu-validator.cjs +36 -0
- package/build/translators/pluralization/icu-validator.mjs +36 -0
- package/build/translators/pluralization/icu-validator.mjs.map +1 -0
- package/build/translators/pluralization/pattern-detector.cjs +25 -0
- package/build/translators/pluralization/pattern-detector.mjs +25 -0
- package/build/translators/pluralization/pattern-detector.mjs.map +1 -0
- package/build/translators/pluralization/prompt.cjs +98 -0
- package/build/translators/pluralization/prompt.mjs +98 -0
- package/build/translators/pluralization/prompt.mjs.map +1 -0
- package/build/translators/pluralization/service.cjs +247 -0
- package/build/translators/pluralization/service.mjs +247 -0
- package/build/translators/pluralization/service.mjs.map +1 -0
- package/build/translators/pluralization/shots.cjs +53 -0
- package/build/translators/pluralization/shots.mjs +53 -0
- package/build/translators/pluralization/shots.mjs.map +1 -0
- package/build/translators/pluralization/types.d.cts +17 -0
- package/build/translators/pluralization/types.d.cts.map +1 -0
- package/build/translators/pluralization/types.d.mts +17 -0
- package/build/translators/pluralization/types.d.mts.map +1 -0
- package/build/translators/pseudotranslator/index.cjs +129 -0
- package/build/translators/pseudotranslator/index.mjs +129 -0
- package/build/translators/pseudotranslator/index.mjs.map +1 -0
- package/build/translators/translation-service.cjs +182 -0
- package/build/translators/translation-service.mjs +183 -0
- package/build/translators/translation-service.mjs.map +1 -0
- package/build/translators/translator-factory.cjs +49 -0
- package/build/translators/translator-factory.mjs +50 -0
- package/build/translators/translator-factory.mjs.map +1 -0
- package/build/types.d.cts +161 -0
- package/build/types.d.cts.map +1 -0
- package/build/types.d.mts +161 -0
- package/build/types.d.mts.map +1 -0
- package/build/utils/config-factory.cjs +58 -0
- package/build/utils/config-factory.mjs +58 -0
- package/build/utils/config-factory.mjs.map +1 -0
- package/build/utils/hash.cjs +17 -0
- package/build/utils/hash.mjs +16 -0
- package/build/utils/hash.mjs.map +1 -0
- package/build/utils/is-valid-locale.cjs +14 -0
- package/build/utils/is-valid-locale.mjs +14 -0
- package/build/utils/is-valid-locale.mjs.map +1 -0
- package/build/utils/logger.cjs +51 -0
- package/build/utils/logger.mjs +50 -0
- package/build/utils/logger.mjs.map +1 -0
- package/build/utils/path-helpers.cjs +49 -0
- package/build/utils/path-helpers.mjs +47 -0
- package/build/utils/path-helpers.mjs.map +1 -0
- package/build/utils/timeout.cjs +42 -0
- package/build/utils/timeout.mjs +41 -0
- package/build/utils/timeout.mjs.map +1 -0
- package/build/virtual/code-generator.cjs +54 -0
- package/build/virtual/code-generator.mjs +53 -0
- package/build/virtual/code-generator.mjs.map +1 -0
- package/build/virtual/config.cjs +10 -0
- package/build/virtual/config.d.cts +9 -0
- package/build/virtual/config.d.cts.map +1 -0
- package/build/virtual/config.d.mts +9 -0
- package/build/virtual/config.d.mts.map +1 -0
- package/build/virtual/config.mjs +8 -0
- package/build/virtual/config.mjs.map +1 -0
- package/build/virtual/locale/client.cjs +23 -0
- package/build/virtual/locale/client.d.cts +19 -0
- package/build/virtual/locale/client.d.cts.map +1 -0
- package/build/virtual/locale/client.d.mts +19 -0
- package/build/virtual/locale/client.d.mts.map +1 -0
- package/build/virtual/locale/client.mjs +22 -0
- package/build/virtual/locale/client.mjs.map +1 -0
- package/build/virtual/locale/server.cjs +13 -0
- package/build/virtual/locale/server.d.cts +13 -0
- package/build/virtual/locale/server.d.cts.map +1 -0
- package/build/virtual/locale/server.d.mts +13 -0
- package/build/virtual/locale/server.d.mts.map +1 -0
- package/build/virtual/locale/server.mjs +13 -0
- package/build/virtual/locale/server.mjs.map +1 -0
- package/build/widget/lingo-dev-widget.cjs +228 -0
- package/build/widget/lingo-dev-widget.mjs +229 -0
- package/build/widget/lingo-dev-widget.mjs.map +1 -0
- package/package.json +189 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_api = require('../api.cjs');
|
|
3
|
+
const require_prompt = require('./prompt.cjs');
|
|
4
|
+
const require_parse_xml = require('../parse-xml.cjs');
|
|
5
|
+
const require_shots = require('./shots.cjs');
|
|
6
|
+
const require_model_factory = require('./model-factory.cjs');
|
|
7
|
+
const require_timeout = require('../../utils/timeout.cjs');
|
|
8
|
+
let ai = require("ai");
|
|
9
|
+
let lingo_dev_sdk = require("lingo.dev/sdk");
|
|
10
|
+
|
|
11
|
+
//#region src/translators/lingo/service.ts
|
|
12
|
+
/**
|
|
13
|
+
* Lingo translator using AI models
|
|
14
|
+
*/
|
|
15
|
+
var Service = class {
|
|
16
|
+
validatedKeys;
|
|
17
|
+
constructor(config, logger) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.logger = logger;
|
|
20
|
+
this.logger.info("Validating API keys for translation...");
|
|
21
|
+
this.validatedKeys = require_model_factory.validateAndGetApiKeys(config.models);
|
|
22
|
+
this.logger.info("✅ API keys validated successfully");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Translate multiple entries
|
|
26
|
+
*/
|
|
27
|
+
async translate(locale, entriesMap) {
|
|
28
|
+
this.logger.debug(`[TRACE-LINGO] translate() called for ${locale} with ${Object.keys(entriesMap).length} entries`);
|
|
29
|
+
const sourceDictionary = require_api.dictionaryFrom(this.config.sourceLocale, Object.fromEntries(Object.entries(entriesMap).map(([hash, entry]) => [hash, entry.text])));
|
|
30
|
+
this.logger.debug(`[TRACE-LINGO] Created source dictionary with ${Object.keys(sourceDictionary.entries).length} entries`);
|
|
31
|
+
return (await this.translateDictionary(sourceDictionary, locale)).entries || {};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Translate a complete dictionary
|
|
35
|
+
*/
|
|
36
|
+
async translateDictionary(sourceDictionary, targetLocale) {
|
|
37
|
+
this.logger.debug(`[TRACE-LINGO] Chunking dictionary with ${Object.keys(sourceDictionary.entries).length} entries`);
|
|
38
|
+
const chunks = this.chunkDictionary(sourceDictionary);
|
|
39
|
+
this.logger.debug(`[TRACE-LINGO] Split into ${chunks.length} chunks`);
|
|
40
|
+
const translatedChunks = [];
|
|
41
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
42
|
+
const chunk = chunks[i];
|
|
43
|
+
this.logger.debug(`[TRACE-LINGO] Translating chunk ${i + 1}/${chunks.length} with ${Object.keys(chunk.entries).length} entries`);
|
|
44
|
+
const chunkStartTime = performance.now();
|
|
45
|
+
const translatedChunk = await this.translateChunk(chunk, targetLocale);
|
|
46
|
+
const chunkEndTime = performance.now();
|
|
47
|
+
this.logger.debug(`[TRACE-LINGO] Chunk ${i + 1}/${chunks.length} completed in ${(chunkEndTime - chunkStartTime).toFixed(2)}ms`);
|
|
48
|
+
translatedChunks.push(translatedChunk);
|
|
49
|
+
}
|
|
50
|
+
this.logger.debug(`[TRACE-LINGO] All chunks translated, merging results`);
|
|
51
|
+
const result = this.mergeDictionaries(translatedChunks);
|
|
52
|
+
this.logger.debug(`[TRACE-LINGO] Merge completed, final dictionary has ${Object.keys(result.entries).length} entries`);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Translate a single chunk
|
|
57
|
+
*/
|
|
58
|
+
async translateChunk(sourceDictionary, targetLocale) {
|
|
59
|
+
if (this.config.models === "lingo.dev") return this.translateWithLingoDotDev(sourceDictionary, targetLocale);
|
|
60
|
+
else return this.translateWithLLM(sourceDictionary, targetLocale);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Translate using Lingo.dev Engine
|
|
64
|
+
* Times out after 60 seconds to prevent indefinite hangs
|
|
65
|
+
*/
|
|
66
|
+
async translateWithLingoDotDev(sourceDictionary, targetLocale) {
|
|
67
|
+
const apiKey = this.validatedKeys["lingo.dev"];
|
|
68
|
+
if (!apiKey) throw new Error("Internal error: Lingo.dev API key not found after validation. Please restart the service.");
|
|
69
|
+
this.logger.info(`Using Lingo.dev Engine to localize from "${this.config.sourceLocale}" to "${targetLocale}"`);
|
|
70
|
+
const engine = new lingo_dev_sdk.LingoDotDevEngine({ apiKey });
|
|
71
|
+
try {
|
|
72
|
+
return await require_timeout.withTimeout(engine.localizeObject(sourceDictionary, {
|
|
73
|
+
sourceLocale: this.config.sourceLocale,
|
|
74
|
+
targetLocale
|
|
75
|
+
}), require_timeout.DEFAULT_TIMEOUTS.AI_API, `Lingo.dev API translation to ${targetLocale}`);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
this.logger.error(`translateWithLingoDotDev() failed:`, error);
|
|
78
|
+
throw new Error(`Lingo.dev translation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Translate using generic LLM
|
|
83
|
+
* Times out after 60 seconds to prevent indefinite hangs
|
|
84
|
+
*/
|
|
85
|
+
async translateWithLLM(sourceDictionary, targetLocale) {
|
|
86
|
+
const localeModel = require_model_factory.getLocaleModel(this.config.models, this.config.sourceLocale, targetLocale);
|
|
87
|
+
if (!localeModel) throw new Error(`No model configured for translation from ${this.config.sourceLocale} to ${targetLocale}`);
|
|
88
|
+
this.logger.info(`Using LLM ("${localeModel.provider}":"${localeModel.name}") to translate from "${this.config.sourceLocale}" to "${targetLocale}"`);
|
|
89
|
+
const aiModel = require_model_factory.createAiModel(localeModel, this.validatedKeys);
|
|
90
|
+
try {
|
|
91
|
+
return require_parse_xml.parseXmlFromResponseText((await require_timeout.withTimeout((0, ai.generateText)({
|
|
92
|
+
model: aiModel,
|
|
93
|
+
messages: [
|
|
94
|
+
{
|
|
95
|
+
role: "system",
|
|
96
|
+
content: require_prompt.getSystemPrompt({
|
|
97
|
+
sourceLocale: this.config.sourceLocale,
|
|
98
|
+
targetLocale,
|
|
99
|
+
prompt: this.config.prompt
|
|
100
|
+
})
|
|
101
|
+
},
|
|
102
|
+
...require_shots.shots.flatMap((shotsTuple) => [{
|
|
103
|
+
role: "user",
|
|
104
|
+
content: require_parse_xml.obj2xml(shotsTuple[0])
|
|
105
|
+
}, {
|
|
106
|
+
role: "assistant",
|
|
107
|
+
content: require_parse_xml.obj2xml(shotsTuple[1])
|
|
108
|
+
}]),
|
|
109
|
+
{
|
|
110
|
+
role: "user",
|
|
111
|
+
content: require_parse_xml.obj2xml(sourceDictionary)
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}), require_timeout.DEFAULT_TIMEOUTS.AI_API, `${localeModel.provider} LLM translation to ${targetLocale}`)).text);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new Error(`LLM translation failed with ${localeModel.provider}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Split dictionary into chunks for processing
|
|
121
|
+
*/
|
|
122
|
+
chunkDictionary(dictionary) {
|
|
123
|
+
const MAX_ENTRIES_PER_CHUNK = 100;
|
|
124
|
+
const { entries, ...rest } = dictionary;
|
|
125
|
+
const chunks = [];
|
|
126
|
+
const entryPairs = Object.entries(entries);
|
|
127
|
+
for (let i = 0; i < entryPairs.length; i += MAX_ENTRIES_PER_CHUNK) {
|
|
128
|
+
const chunkEntries = entryPairs.slice(i, i + MAX_ENTRIES_PER_CHUNK);
|
|
129
|
+
chunks.push({
|
|
130
|
+
...rest,
|
|
131
|
+
entries: Object.fromEntries(chunkEntries)
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return chunks;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Merge multiple dictionaries into one
|
|
138
|
+
*/
|
|
139
|
+
mergeDictionaries(dictionaries) {
|
|
140
|
+
if (dictionaries.length === 0) return require_api.dictionaryFrom(this.config.sourceLocale, {});
|
|
141
|
+
const mergedEntries = {};
|
|
142
|
+
for (const dict of dictionaries) Object.assign(mergedEntries, dict.entries);
|
|
143
|
+
return {
|
|
144
|
+
version: dictionaries[0].version,
|
|
145
|
+
locale: dictionaries[0].locale,
|
|
146
|
+
entries: mergedEntries
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
exports.Service = Service;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { dictionaryFrom } from "../api.mjs";
|
|
2
|
+
import { getSystemPrompt } from "./prompt.mjs";
|
|
3
|
+
import { obj2xml, parseXmlFromResponseText } from "../parse-xml.mjs";
|
|
4
|
+
import { shots } from "./shots.mjs";
|
|
5
|
+
import { createAiModel, getLocaleModel, validateAndGetApiKeys } from "./model-factory.mjs";
|
|
6
|
+
import { DEFAULT_TIMEOUTS, withTimeout } from "../../utils/timeout.mjs";
|
|
7
|
+
import { generateText } from "ai";
|
|
8
|
+
import { LingoDotDevEngine } from "lingo.dev/sdk";
|
|
9
|
+
|
|
10
|
+
//#region src/translators/lingo/service.ts
|
|
11
|
+
/**
|
|
12
|
+
* Lingo translator using AI models
|
|
13
|
+
*/
|
|
14
|
+
var Service = class {
|
|
15
|
+
validatedKeys;
|
|
16
|
+
constructor(config, logger) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.logger = logger;
|
|
19
|
+
this.logger.info("Validating API keys for translation...");
|
|
20
|
+
this.validatedKeys = validateAndGetApiKeys(config.models);
|
|
21
|
+
this.logger.info("✅ API keys validated successfully");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Translate multiple entries
|
|
25
|
+
*/
|
|
26
|
+
async translate(locale, entriesMap) {
|
|
27
|
+
this.logger.debug(`[TRACE-LINGO] translate() called for ${locale} with ${Object.keys(entriesMap).length} entries`);
|
|
28
|
+
const sourceDictionary = dictionaryFrom(this.config.sourceLocale, Object.fromEntries(Object.entries(entriesMap).map(([hash, entry]) => [hash, entry.text])));
|
|
29
|
+
this.logger.debug(`[TRACE-LINGO] Created source dictionary with ${Object.keys(sourceDictionary.entries).length} entries`);
|
|
30
|
+
return (await this.translateDictionary(sourceDictionary, locale)).entries || {};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Translate a complete dictionary
|
|
34
|
+
*/
|
|
35
|
+
async translateDictionary(sourceDictionary, targetLocale) {
|
|
36
|
+
this.logger.debug(`[TRACE-LINGO] Chunking dictionary with ${Object.keys(sourceDictionary.entries).length} entries`);
|
|
37
|
+
const chunks = this.chunkDictionary(sourceDictionary);
|
|
38
|
+
this.logger.debug(`[TRACE-LINGO] Split into ${chunks.length} chunks`);
|
|
39
|
+
const translatedChunks = [];
|
|
40
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
41
|
+
const chunk = chunks[i];
|
|
42
|
+
this.logger.debug(`[TRACE-LINGO] Translating chunk ${i + 1}/${chunks.length} with ${Object.keys(chunk.entries).length} entries`);
|
|
43
|
+
const chunkStartTime = performance.now();
|
|
44
|
+
const translatedChunk = await this.translateChunk(chunk, targetLocale);
|
|
45
|
+
const chunkEndTime = performance.now();
|
|
46
|
+
this.logger.debug(`[TRACE-LINGO] Chunk ${i + 1}/${chunks.length} completed in ${(chunkEndTime - chunkStartTime).toFixed(2)}ms`);
|
|
47
|
+
translatedChunks.push(translatedChunk);
|
|
48
|
+
}
|
|
49
|
+
this.logger.debug(`[TRACE-LINGO] All chunks translated, merging results`);
|
|
50
|
+
const result = this.mergeDictionaries(translatedChunks);
|
|
51
|
+
this.logger.debug(`[TRACE-LINGO] Merge completed, final dictionary has ${Object.keys(result.entries).length} entries`);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Translate a single chunk
|
|
56
|
+
*/
|
|
57
|
+
async translateChunk(sourceDictionary, targetLocale) {
|
|
58
|
+
if (this.config.models === "lingo.dev") return this.translateWithLingoDotDev(sourceDictionary, targetLocale);
|
|
59
|
+
else return this.translateWithLLM(sourceDictionary, targetLocale);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Translate using Lingo.dev Engine
|
|
63
|
+
* Times out after 60 seconds to prevent indefinite hangs
|
|
64
|
+
*/
|
|
65
|
+
async translateWithLingoDotDev(sourceDictionary, targetLocale) {
|
|
66
|
+
const apiKey = this.validatedKeys["lingo.dev"];
|
|
67
|
+
if (!apiKey) throw new Error("Internal error: Lingo.dev API key not found after validation. Please restart the service.");
|
|
68
|
+
this.logger.info(`Using Lingo.dev Engine to localize from "${this.config.sourceLocale}" to "${targetLocale}"`);
|
|
69
|
+
const engine = new LingoDotDevEngine({ apiKey });
|
|
70
|
+
try {
|
|
71
|
+
return await withTimeout(engine.localizeObject(sourceDictionary, {
|
|
72
|
+
sourceLocale: this.config.sourceLocale,
|
|
73
|
+
targetLocale
|
|
74
|
+
}), DEFAULT_TIMEOUTS.AI_API, `Lingo.dev API translation to ${targetLocale}`);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.logger.error(`translateWithLingoDotDev() failed:`, error);
|
|
77
|
+
throw new Error(`Lingo.dev translation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Translate using generic LLM
|
|
82
|
+
* Times out after 60 seconds to prevent indefinite hangs
|
|
83
|
+
*/
|
|
84
|
+
async translateWithLLM(sourceDictionary, targetLocale) {
|
|
85
|
+
const localeModel = getLocaleModel(this.config.models, this.config.sourceLocale, targetLocale);
|
|
86
|
+
if (!localeModel) throw new Error(`No model configured for translation from ${this.config.sourceLocale} to ${targetLocale}`);
|
|
87
|
+
this.logger.info(`Using LLM ("${localeModel.provider}":"${localeModel.name}") to translate from "${this.config.sourceLocale}" to "${targetLocale}"`);
|
|
88
|
+
const aiModel = createAiModel(localeModel, this.validatedKeys);
|
|
89
|
+
try {
|
|
90
|
+
return parseXmlFromResponseText((await withTimeout(generateText({
|
|
91
|
+
model: aiModel,
|
|
92
|
+
messages: [
|
|
93
|
+
{
|
|
94
|
+
role: "system",
|
|
95
|
+
content: getSystemPrompt({
|
|
96
|
+
sourceLocale: this.config.sourceLocale,
|
|
97
|
+
targetLocale,
|
|
98
|
+
prompt: this.config.prompt
|
|
99
|
+
})
|
|
100
|
+
},
|
|
101
|
+
...shots.flatMap((shotsTuple) => [{
|
|
102
|
+
role: "user",
|
|
103
|
+
content: obj2xml(shotsTuple[0])
|
|
104
|
+
}, {
|
|
105
|
+
role: "assistant",
|
|
106
|
+
content: obj2xml(shotsTuple[1])
|
|
107
|
+
}]),
|
|
108
|
+
{
|
|
109
|
+
role: "user",
|
|
110
|
+
content: obj2xml(sourceDictionary)
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}), DEFAULT_TIMEOUTS.AI_API, `${localeModel.provider} LLM translation to ${targetLocale}`)).text);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
throw new Error(`LLM translation failed with ${localeModel.provider}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Split dictionary into chunks for processing
|
|
120
|
+
*/
|
|
121
|
+
chunkDictionary(dictionary) {
|
|
122
|
+
const MAX_ENTRIES_PER_CHUNK = 100;
|
|
123
|
+
const { entries, ...rest } = dictionary;
|
|
124
|
+
const chunks = [];
|
|
125
|
+
const entryPairs = Object.entries(entries);
|
|
126
|
+
for (let i = 0; i < entryPairs.length; i += MAX_ENTRIES_PER_CHUNK) {
|
|
127
|
+
const chunkEntries = entryPairs.slice(i, i + MAX_ENTRIES_PER_CHUNK);
|
|
128
|
+
chunks.push({
|
|
129
|
+
...rest,
|
|
130
|
+
entries: Object.fromEntries(chunkEntries)
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return chunks;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Merge multiple dictionaries into one
|
|
137
|
+
*/
|
|
138
|
+
mergeDictionaries(dictionaries) {
|
|
139
|
+
if (dictionaries.length === 0) return dictionaryFrom(this.config.sourceLocale, {});
|
|
140
|
+
const mergedEntries = {};
|
|
141
|
+
for (const dict of dictionaries) Object.assign(mergedEntries, dict.entries);
|
|
142
|
+
return {
|
|
143
|
+
version: dictionaries[0].version,
|
|
144
|
+
locale: dictionaries[0].locale,
|
|
145
|
+
entries: mergedEntries
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
export { Service };
|
|
152
|
+
//# sourceMappingURL=service.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.mjs","names":["config: LingoTranslatorConfig","logger: Logger","sourceDictionary: DictionarySchema","translatedChunks: DictionarySchema[]","chunks: DictionarySchema[]","mergedEntries: Record<string, string>"],"sources":["../../../src/translators/lingo/service.ts"],"sourcesContent":["import { generateText } from \"ai\";\nimport { LingoDotDevEngine } from \"lingo.dev/sdk\";\nimport {\n dictionaryFrom,\n type DictionarySchema,\n type TranslatableEntry,\n type Translator,\n} from \"../api\";\nimport { getSystemPrompt } from \"./prompt\";\nimport { obj2xml, parseXmlFromResponseText } from \"../parse-xml\";\nimport { shots } from \"./shots\";\nimport {\n createAiModel,\n getLocaleModel,\n validateAndGetApiKeys,\n type ValidatedApiKeys,\n} from \"./model-factory\";\nimport { Logger } from \"../../utils/logger\";\nimport { DEFAULT_TIMEOUTS, withTimeout } from \"../../utils/timeout\";\nimport type { LocaleCode } from \"lingo.dev/spec\";\n\n/**\n * Lingo Translator configuration\n */\nexport interface LingoTranslatorConfig {\n models: \"lingo.dev\" | Record<string, string>;\n sourceLocale: LocaleCode;\n prompt?: string;\n}\n\n/**\n * Lingo translator using AI models\n */\nexport class Service implements Translator<LingoTranslatorConfig> {\n private readonly validatedKeys: ValidatedApiKeys;\n\n constructor(\n readonly config: LingoTranslatorConfig,\n private logger: Logger,\n ) {\n this.logger.info(\"Validating API keys for translation...\");\n this.validatedKeys = validateAndGetApiKeys(config.models);\n this.logger.info(\"✅ API keys validated successfully\");\n }\n\n /**\n * Translate multiple entries\n */\n async translate(\n locale: LocaleCode,\n entriesMap: Record<string, TranslatableEntry>,\n ): Promise<Record<string, string>> {\n this.logger.debug(\n `[TRACE-LINGO] translate() called for ${locale} with ${Object.keys(entriesMap).length} entries`,\n );\n\n const sourceDictionary: DictionarySchema = dictionaryFrom(\n this.config.sourceLocale,\n Object.fromEntries(\n Object.entries(entriesMap).map(([hash, entry]) => [hash, entry.text]),\n ),\n );\n\n this.logger.debug(\n `[TRACE-LINGO] Created source dictionary with ${Object.keys(sourceDictionary.entries).length} entries`,\n );\n const translated = await this.translateDictionary(sourceDictionary, locale);\n\n return translated.entries || {};\n }\n\n /**\n * Translate a complete dictionary\n */\n private async translateDictionary(\n sourceDictionary: DictionarySchema,\n targetLocale: string,\n ): Promise<DictionarySchema> {\n this.logger.debug(\n `[TRACE-LINGO] Chunking dictionary with ${Object.keys(sourceDictionary.entries).length} entries`,\n );\n const chunks = this.chunkDictionary(sourceDictionary);\n this.logger.debug(`[TRACE-LINGO] Split into ${chunks.length} chunks`);\n\n const translatedChunks: DictionarySchema[] = [];\n\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i];\n this.logger.debug(\n `[TRACE-LINGO] Translating chunk ${i + 1}/${chunks.length} with ${Object.keys(chunk.entries).length} entries`,\n );\n const chunkStartTime = performance.now();\n\n const translatedChunk = await this.translateChunk(chunk, targetLocale);\n\n const chunkEndTime = performance.now();\n this.logger.debug(\n `[TRACE-LINGO] Chunk ${i + 1}/${chunks.length} completed in ${(chunkEndTime - chunkStartTime).toFixed(2)}ms`,\n );\n\n translatedChunks.push(translatedChunk);\n }\n\n this.logger.debug(`[TRACE-LINGO] All chunks translated, merging results`);\n const result = this.mergeDictionaries(translatedChunks);\n this.logger.debug(\n `[TRACE-LINGO] Merge completed, final dictionary has ${Object.keys(result.entries).length} entries`,\n );\n\n return result;\n }\n\n /**\n * Translate a single chunk\n */\n private async translateChunk(\n sourceDictionary: DictionarySchema,\n targetLocale: string,\n ): Promise<DictionarySchema> {\n if (this.config.models === \"lingo.dev\") {\n return this.translateWithLingoDotDev(sourceDictionary, targetLocale);\n } else {\n return this.translateWithLLM(sourceDictionary, targetLocale);\n }\n }\n\n /**\n * Translate using Lingo.dev Engine\n * Times out after 60 seconds to prevent indefinite hangs\n */\n private async translateWithLingoDotDev(\n sourceDictionary: DictionarySchema,\n targetLocale: string,\n ): Promise<DictionarySchema> {\n const apiKey = this.validatedKeys[\"lingo.dev\"];\n if (!apiKey) {\n throw new Error(\n \"Internal error: Lingo.dev API key not found after validation. Please restart the service.\",\n );\n }\n\n this.logger.info(\n `Using Lingo.dev Engine to localize from \"${this.config.sourceLocale}\" to \"${targetLocale}\"`,\n );\n\n const engine = new LingoDotDevEngine({ apiKey });\n\n try {\n const result = await withTimeout(\n engine.localizeObject(sourceDictionary, {\n sourceLocale: this.config.sourceLocale,\n targetLocale: targetLocale,\n }),\n DEFAULT_TIMEOUTS.AI_API,\n `Lingo.dev API translation to ${targetLocale}`,\n );\n\n return result as DictionarySchema;\n } catch (error) {\n this.logger.error(`translateWithLingoDotDev() failed:`, error);\n throw new Error(\n `Lingo.dev translation failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n /**\n * Translate using generic LLM\n * Times out after 60 seconds to prevent indefinite hangs\n */\n private async translateWithLLM(\n sourceDictionary: DictionarySchema,\n targetLocale: string,\n ): Promise<DictionarySchema> {\n const localeModel = getLocaleModel(\n this.config.models as Record<string, string>,\n this.config.sourceLocale,\n targetLocale,\n );\n\n if (!localeModel) {\n throw new Error(\n `No model configured for translation from ${this.config.sourceLocale} to ${targetLocale}`,\n );\n }\n\n this.logger.info(\n `Using LLM (\"${localeModel.provider}\":\"${localeModel.name}\") to translate from \"${this.config.sourceLocale}\" to \"${targetLocale}\"`,\n );\n\n const aiModel = createAiModel(localeModel, this.validatedKeys);\n\n try {\n const response = await withTimeout(\n generateText({\n model: aiModel,\n messages: [\n {\n role: \"system\",\n content: getSystemPrompt({\n sourceLocale: this.config.sourceLocale,\n targetLocale,\n prompt: this.config.prompt,\n }),\n },\n // Add few-shot examples\n ...shots.flatMap((shotsTuple) => [\n {\n role: \"user\" as const,\n content: obj2xml(shotsTuple[0]),\n },\n {\n role: \"assistant\" as const,\n content: obj2xml(shotsTuple[1]),\n },\n ]),\n {\n role: \"user\",\n content: obj2xml(sourceDictionary),\n },\n ],\n }),\n DEFAULT_TIMEOUTS.AI_API,\n `${localeModel.provider} LLM translation to ${targetLocale}`,\n );\n\n return parseXmlFromResponseText<DictionarySchema>(response.text);\n } catch (error) {\n throw new Error(\n `LLM translation failed with ${localeModel.provider}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n }\n\n /**\n * Split dictionary into chunks for processing\n */\n private chunkDictionary(dictionary: DictionarySchema): DictionarySchema[] {\n const MAX_ENTRIES_PER_CHUNK = 100;\n const { entries, ...rest } = dictionary;\n const chunks: DictionarySchema[] = [];\n\n const entryPairs = Object.entries(entries);\n\n // Split entries into chunks of MAX_ENTRIES_PER_CHUNK\n for (let i = 0; i < entryPairs.length; i += MAX_ENTRIES_PER_CHUNK) {\n const chunkEntries = entryPairs.slice(i, i + MAX_ENTRIES_PER_CHUNK);\n chunks.push({\n ...rest,\n entries: Object.fromEntries(chunkEntries),\n });\n }\n\n return chunks;\n }\n\n /**\n * Merge multiple dictionaries into one\n */\n private mergeDictionaries(\n dictionaries: DictionarySchema[],\n ): DictionarySchema {\n if (dictionaries.length === 0) {\n return dictionaryFrom(this.config.sourceLocale, {});\n }\n\n // Merge all entries from all dictionaries\n const mergedEntries: Record<string, string> = {};\n for (const dict of dictionaries) {\n Object.assign(mergedEntries, dict.entries);\n }\n\n return {\n version: dictionaries[0].version,\n locale: dictionaries[0].locale,\n entries: mergedEntries,\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/translators/lingo/shots.ts
|
|
3
|
+
/**
|
|
4
|
+
* Few-shot examples for LLM translation
|
|
5
|
+
* These help the LLM understand the expected format and behavior
|
|
6
|
+
*/
|
|
7
|
+
const shots = [[{
|
|
8
|
+
version: .1,
|
|
9
|
+
locale: "en",
|
|
10
|
+
entries: {
|
|
11
|
+
"1z2x3c4v": "Dashboard",
|
|
12
|
+
"5t6y7u8i": "Settings",
|
|
13
|
+
"9o0p1q2r": "Logout",
|
|
14
|
+
"9k0l1m2n": "© 2025 Lingo.dev. All rights reserved."
|
|
15
|
+
}
|
|
16
|
+
}, {
|
|
17
|
+
version: .1,
|
|
18
|
+
locale: "es",
|
|
19
|
+
entries: {
|
|
20
|
+
"1z2x3c4v": "Panel de control",
|
|
21
|
+
"5t6y7u8i": "Configuración",
|
|
22
|
+
"9o0p1q2r": "Cerrar sesión",
|
|
23
|
+
"9k0l1m2n": "© 2025 Lingo.dev. Todos los derechos reservados."
|
|
24
|
+
}
|
|
25
|
+
}]];
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
exports.shots = shots;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/translators/lingo/shots.ts
|
|
2
|
+
/**
|
|
3
|
+
* Few-shot examples for LLM translation
|
|
4
|
+
* These help the LLM understand the expected format and behavior
|
|
5
|
+
*/
|
|
6
|
+
const shots = [[{
|
|
7
|
+
version: .1,
|
|
8
|
+
locale: "en",
|
|
9
|
+
entries: {
|
|
10
|
+
"1z2x3c4v": "Dashboard",
|
|
11
|
+
"5t6y7u8i": "Settings",
|
|
12
|
+
"9o0p1q2r": "Logout",
|
|
13
|
+
"9k0l1m2n": "© 2025 Lingo.dev. All rights reserved."
|
|
14
|
+
}
|
|
15
|
+
}, {
|
|
16
|
+
version: .1,
|
|
17
|
+
locale: "es",
|
|
18
|
+
entries: {
|
|
19
|
+
"1z2x3c4v": "Panel de control",
|
|
20
|
+
"5t6y7u8i": "Configuración",
|
|
21
|
+
"9o0p1q2r": "Cerrar sesión",
|
|
22
|
+
"9k0l1m2n": "© 2025 Lingo.dev. Todos los derechos reservados."
|
|
23
|
+
}
|
|
24
|
+
}]];
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { shots };
|
|
28
|
+
//# sourceMappingURL=shots.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shots.mjs","names":["shots: [DictionarySchema, DictionarySchema][]"],"sources":["../../../src/translators/lingo/shots.ts"],"sourcesContent":["import type { DictionarySchema } from \"../api\";\n\n/**\n * Few-shot examples for LLM translation\n * These help the LLM understand the expected format and behavior\n */\nexport const shots: [DictionarySchema, DictionarySchema][] = [\n [\n {\n version: 0.1,\n locale: \"en\",\n entries: {\n \"1z2x3c4v\": \"Dashboard\",\n \"5t6y7u8i\": \"Settings\",\n \"9o0p1q2r\": \"Logout\",\n \"9k0l1m2n\": \"© 2025 Lingo.dev. All rights reserved.\",\n },\n },\n {\n version: 0.1,\n locale: \"es\",\n entries: {\n \"1z2x3c4v\": \"Panel de control\",\n \"5t6y7u8i\": \"Configuración\",\n \"9o0p1q2r\": \"Cerrar sesión\",\n \"9k0l1m2n\": \"© 2025 Lingo.dev. Todos los derechos reservados.\",\n },\n },\n ],\n];\n"],"mappings":";;;;;AAMA,MAAaA,QAAgD,CAC3D,CACE;CACE,SAAS;CACT,QAAQ;CACR,SAAS;EACP,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACb;CACF,EACD;CACE,SAAS;CACT,QAAQ;CACR,SAAS;EACP,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACb;CACF,CACF,CACF"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_api = require('./api.cjs');
|
|
3
|
+
const require_timeout = require('../utils/timeout.cjs');
|
|
4
|
+
let fs_promises = require("fs/promises");
|
|
5
|
+
fs_promises = require_rolldown_runtime.__toESM(fs_promises);
|
|
6
|
+
let path = require("path");
|
|
7
|
+
path = require_rolldown_runtime.__toESM(path);
|
|
8
|
+
|
|
9
|
+
//#region src/translators/local-cache.ts
|
|
10
|
+
/**
|
|
11
|
+
* Local disk-based translation cache implementation
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Local file system cache for translations
|
|
15
|
+
* Stores translations as JSON files in .lingo/cache/
|
|
16
|
+
*/
|
|
17
|
+
var LocalTranslationCache = class {
|
|
18
|
+
config;
|
|
19
|
+
constructor(config, logger) {
|
|
20
|
+
this.logger = logger;
|
|
21
|
+
this.config = config;
|
|
22
|
+
}
|
|
23
|
+
getCachePath(locale) {
|
|
24
|
+
return path.join(this.config.cacheDir, `${locale}.json`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Read dictionary file from disk
|
|
28
|
+
* Times out after 10 seconds to prevent indefinite hangs
|
|
29
|
+
*/
|
|
30
|
+
async getDictionary(locale) {
|
|
31
|
+
try {
|
|
32
|
+
const cachePath = this.getCachePath(locale);
|
|
33
|
+
const content = await require_timeout.withTimeout(fs_promises.readFile(cachePath, "utf-8"), require_timeout.DEFAULT_TIMEOUTS.FILE_IO, `Read cache for ${locale}`);
|
|
34
|
+
return JSON.parse(content);
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write dictionary file to disk
|
|
41
|
+
* Times out after 10 seconds to prevent indefinite hangs
|
|
42
|
+
*/
|
|
43
|
+
async setDictionary(locale, dictionary) {
|
|
44
|
+
try {
|
|
45
|
+
const cachePath = this.getCachePath(locale);
|
|
46
|
+
const cacheDir = path.dirname(cachePath);
|
|
47
|
+
await require_timeout.withTimeout(fs_promises.mkdir(cacheDir, { recursive: true }), require_timeout.DEFAULT_TIMEOUTS.FILE_IO, `Create cache directory for ${locale}`);
|
|
48
|
+
await require_timeout.withTimeout(fs_promises.writeFile(cachePath, JSON.stringify(dictionary, null, 2), "utf-8"), require_timeout.DEFAULT_TIMEOUTS.FILE_IO, `Write cache for ${locale}`);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.logger.error(`Failed to write cache for locale ${locale}:`, error);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get cached translations for a locale
|
|
56
|
+
*/
|
|
57
|
+
async get(locale, hashes) {
|
|
58
|
+
const dictionary = await this.getDictionary(locale);
|
|
59
|
+
if (!dictionary) return {};
|
|
60
|
+
if (hashes) return hashes.reduce((acc, hash) => ({
|
|
61
|
+
...acc,
|
|
62
|
+
[hash]: dictionary.entries[hash]
|
|
63
|
+
}), {});
|
|
64
|
+
return dictionary.entries || {};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Update cache with new translations (merge)
|
|
68
|
+
*/
|
|
69
|
+
async update(locale, translations) {
|
|
70
|
+
const merged = {
|
|
71
|
+
...await this.get(locale),
|
|
72
|
+
...translations
|
|
73
|
+
};
|
|
74
|
+
await this.set(locale, merged);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Replace entire cache for a locale
|
|
78
|
+
*/
|
|
79
|
+
async set(locale, translations) {
|
|
80
|
+
await this.setDictionary(locale, require_api.dictionaryFrom(locale, translations));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if cache exists for a locale
|
|
84
|
+
*/
|
|
85
|
+
async has(locale) {
|
|
86
|
+
try {
|
|
87
|
+
const cachePath = this.getCachePath(locale);
|
|
88
|
+
await fs_promises.access(cachePath);
|
|
89
|
+
return true;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Clear cache for a specific locale
|
|
96
|
+
*/
|
|
97
|
+
async clear(locale) {
|
|
98
|
+
try {
|
|
99
|
+
const cachePath = this.getCachePath(locale);
|
|
100
|
+
await fs_promises.unlink(cachePath);
|
|
101
|
+
} catch {}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Clear all cached translations
|
|
105
|
+
*/
|
|
106
|
+
async clearAll() {
|
|
107
|
+
try {
|
|
108
|
+
const files = await fs_promises.readdir(this.config.cacheDir);
|
|
109
|
+
await Promise.all(files.filter((file) => file.endsWith(".json")).map((file) => fs_promises.unlink(path.join(this.config.cacheDir, file))));
|
|
110
|
+
} catch {}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
//#endregion
|
|
115
|
+
exports.LocalTranslationCache = LocalTranslationCache;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { dictionaryFrom } from "./api.mjs";
|
|
2
|
+
import { DEFAULT_TIMEOUTS, withTimeout } from "../utils/timeout.mjs";
|
|
3
|
+
import * as fs from "fs/promises";
|
|
4
|
+
import * as path$1 from "path";
|
|
5
|
+
|
|
6
|
+
//#region src/translators/local-cache.ts
|
|
7
|
+
/**
|
|
8
|
+
* Local disk-based translation cache implementation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Local file system cache for translations
|
|
12
|
+
* Stores translations as JSON files in .lingo/cache/
|
|
13
|
+
*/
|
|
14
|
+
var LocalTranslationCache = class {
|
|
15
|
+
config;
|
|
16
|
+
constructor(config, logger) {
|
|
17
|
+
this.logger = logger;
|
|
18
|
+
this.config = config;
|
|
19
|
+
}
|
|
20
|
+
getCachePath(locale) {
|
|
21
|
+
return path$1.join(this.config.cacheDir, `${locale}.json`);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read dictionary file from disk
|
|
25
|
+
* Times out after 10 seconds to prevent indefinite hangs
|
|
26
|
+
*/
|
|
27
|
+
async getDictionary(locale) {
|
|
28
|
+
try {
|
|
29
|
+
const cachePath = this.getCachePath(locale);
|
|
30
|
+
const content = await withTimeout(fs.readFile(cachePath, "utf-8"), DEFAULT_TIMEOUTS.FILE_IO, `Read cache for ${locale}`);
|
|
31
|
+
return JSON.parse(content);
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Write dictionary file to disk
|
|
38
|
+
* Times out after 10 seconds to prevent indefinite hangs
|
|
39
|
+
*/
|
|
40
|
+
async setDictionary(locale, dictionary) {
|
|
41
|
+
try {
|
|
42
|
+
const cachePath = this.getCachePath(locale);
|
|
43
|
+
const cacheDir = path$1.dirname(cachePath);
|
|
44
|
+
await withTimeout(fs.mkdir(cacheDir, { recursive: true }), DEFAULT_TIMEOUTS.FILE_IO, `Create cache directory for ${locale}`);
|
|
45
|
+
await withTimeout(fs.writeFile(cachePath, JSON.stringify(dictionary, null, 2), "utf-8"), DEFAULT_TIMEOUTS.FILE_IO, `Write cache for ${locale}`);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
this.logger.error(`Failed to write cache for locale ${locale}:`, error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get cached translations for a locale
|
|
53
|
+
*/
|
|
54
|
+
async get(locale, hashes) {
|
|
55
|
+
const dictionary = await this.getDictionary(locale);
|
|
56
|
+
if (!dictionary) return {};
|
|
57
|
+
if (hashes) return hashes.reduce((acc, hash) => ({
|
|
58
|
+
...acc,
|
|
59
|
+
[hash]: dictionary.entries[hash]
|
|
60
|
+
}), {});
|
|
61
|
+
return dictionary.entries || {};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Update cache with new translations (merge)
|
|
65
|
+
*/
|
|
66
|
+
async update(locale, translations) {
|
|
67
|
+
const merged = {
|
|
68
|
+
...await this.get(locale),
|
|
69
|
+
...translations
|
|
70
|
+
};
|
|
71
|
+
await this.set(locale, merged);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Replace entire cache for a locale
|
|
75
|
+
*/
|
|
76
|
+
async set(locale, translations) {
|
|
77
|
+
await this.setDictionary(locale, dictionaryFrom(locale, translations));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if cache exists for a locale
|
|
81
|
+
*/
|
|
82
|
+
async has(locale) {
|
|
83
|
+
try {
|
|
84
|
+
const cachePath = this.getCachePath(locale);
|
|
85
|
+
await fs.access(cachePath);
|
|
86
|
+
return true;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Clear cache for a specific locale
|
|
93
|
+
*/
|
|
94
|
+
async clear(locale) {
|
|
95
|
+
try {
|
|
96
|
+
const cachePath = this.getCachePath(locale);
|
|
97
|
+
await fs.unlink(cachePath);
|
|
98
|
+
} catch {}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Clear all cached translations
|
|
102
|
+
*/
|
|
103
|
+
async clearAll() {
|
|
104
|
+
try {
|
|
105
|
+
const files = await fs.readdir(this.config.cacheDir);
|
|
106
|
+
await Promise.all(files.filter((file) => file.endsWith(".json")).map((file) => fs.unlink(path$1.join(this.config.cacheDir, file))));
|
|
107
|
+
} catch {}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
export { LocalTranslationCache };
|
|
113
|
+
//# sourceMappingURL=local-cache.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-cache.mjs","names":["logger: Logger","path"],"sources":["../../src/translators/local-cache.ts"],"sourcesContent":["/**\n * Local disk-based translation cache implementation\n */\n\nimport * as fs from \"fs/promises\";\nimport * as path from \"path\";\nimport type { LocalCacheConfig, TranslationCache } from \"./cache\";\nimport { dictionaryFrom, type DictionarySchema } from \"./api\";\nimport { DEFAULT_TIMEOUTS, withTimeout } from \"../utils/timeout\";\nimport type { Logger } from \"../utils/logger\";\nimport type { LocaleCode } from \"lingo.dev/spec\";\n\n/**\n * Local file system cache for translations\n * Stores translations as JSON files in .lingo/cache/\n */\nexport class LocalTranslationCache implements TranslationCache {\n private config: LocalCacheConfig;\n\n constructor(\n config: LocalCacheConfig,\n private logger: Logger,\n ) {\n this.config = config;\n }\n\n private getCachePath(locale: LocaleCode): string {\n return path.join(this.config.cacheDir, `${locale}.json`);\n }\n\n /**\n * Read dictionary file from disk\n * Times out after 10 seconds to prevent indefinite hangs\n */\n async getDictionary(locale: LocaleCode): Promise<DictionarySchema | null> {\n try {\n const cachePath = this.getCachePath(locale);\n const content = await withTimeout(\n fs.readFile(cachePath, \"utf-8\"),\n DEFAULT_TIMEOUTS.FILE_IO,\n `Read cache for ${locale}`,\n );\n return JSON.parse(content);\n } catch {\n return null;\n }\n }\n\n /**\n * Write dictionary file to disk\n * Times out after 10 seconds to prevent indefinite hangs\n */\n private async setDictionary(\n locale: LocaleCode,\n dictionary: DictionarySchema,\n ): Promise<void> {\n try {\n const cachePath = this.getCachePath(locale);\n const cacheDir = path.dirname(cachePath);\n\n // Ensure cache directory exists\n await withTimeout(\n fs.mkdir(cacheDir, { recursive: true }),\n DEFAULT_TIMEOUTS.FILE_IO,\n `Create cache directory for ${locale}`,\n );\n\n // Write cache file\n await withTimeout(\n fs.writeFile(cachePath, JSON.stringify(dictionary, null, 2), \"utf-8\"),\n DEFAULT_TIMEOUTS.FILE_IO,\n `Write cache for ${locale}`,\n );\n } catch (error) {\n this.logger.error(`Failed to write cache for locale ${locale}:`, error);\n throw error;\n }\n }\n\n /**\n * Get cached translations for a locale\n */\n async get(\n locale: LocaleCode,\n hashes?: string[],\n ): Promise<Record<string, string>> {\n const dictionary = await this.getDictionary(locale);\n if (!dictionary) {\n return {};\n }\n if (hashes) {\n return hashes.reduce(\n (acc, hash) => ({ ...acc, [hash]: dictionary.entries[hash] }),\n {},\n );\n }\n return dictionary.entries || {};\n }\n\n /**\n * Update cache with new translations (merge)\n */\n async update(\n locale: LocaleCode,\n translations: Record<string, string>,\n ): Promise<void> {\n const existing = await this.get(locale);\n\n const merged = { ...existing, ...translations };\n\n await this.set(locale, merged);\n }\n\n /**\n * Replace entire cache for a locale\n */\n async set(\n locale: LocaleCode,\n translations: Record<string, string>,\n ): Promise<void> {\n await this.setDictionary(locale, dictionaryFrom(locale, translations));\n }\n\n /**\n * Check if cache exists for a locale\n */\n async has(locale: LocaleCode): Promise<boolean> {\n try {\n const cachePath = this.getCachePath(locale);\n await fs.access(cachePath);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Clear cache for a specific locale\n */\n async clear(locale: LocaleCode): Promise<void> {\n try {\n const cachePath = this.getCachePath(locale);\n await fs.unlink(cachePath);\n } catch {\n // Ignore errors if file doesn't exist\n }\n }\n\n /**\n * Clear all cached translations\n */\n async clearAll(): Promise<void> {\n try {\n const files = await fs.readdir(this.config.cacheDir);\n\n await Promise.all(\n files\n .filter((file) => file.endsWith(\".json\"))\n .map((file) => fs.unlink(path.join(this.config.cacheDir, file))),\n );\n } catch {\n // Ignore errors if directory doesn't exist\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,IAAa,wBAAb,MAA+D;CAC7D,AAAQ;CAER,YACE,QACA,AAAQA,QACR;EADQ;AAER,OAAK,SAAS;;CAGhB,AAAQ,aAAa,QAA4B;AAC/C,SAAOC,OAAK,KAAK,KAAK,OAAO,UAAU,GAAG,OAAO,OAAO;;;;;;CAO1D,MAAM,cAAc,QAAsD;AACxE,MAAI;GACF,MAAM,YAAY,KAAK,aAAa,OAAO;GAC3C,MAAM,UAAU,MAAM,YACpB,GAAG,SAAS,WAAW,QAAQ,EAC/B,iBAAiB,SACjB,kBAAkB,SACnB;AACD,UAAO,KAAK,MAAM,QAAQ;UACpB;AACN,UAAO;;;;;;;CAQX,MAAc,cACZ,QACA,YACe;AACf,MAAI;GACF,MAAM,YAAY,KAAK,aAAa,OAAO;GAC3C,MAAM,WAAWA,OAAK,QAAQ,UAAU;AAGxC,SAAM,YACJ,GAAG,MAAM,UAAU,EAAE,WAAW,MAAM,CAAC,EACvC,iBAAiB,SACjB,8BAA8B,SAC/B;AAGD,SAAM,YACJ,GAAG,UAAU,WAAW,KAAK,UAAU,YAAY,MAAM,EAAE,EAAE,QAAQ,EACrE,iBAAiB,SACjB,mBAAmB,SACpB;WACM,OAAO;AACd,QAAK,OAAO,MAAM,oCAAoC,OAAO,IAAI,MAAM;AACvE,SAAM;;;;;;CAOV,MAAM,IACJ,QACA,QACiC;EACjC,MAAM,aAAa,MAAM,KAAK,cAAc,OAAO;AACnD,MAAI,CAAC,WACH,QAAO,EAAE;AAEX,MAAI,OACF,QAAO,OAAO,QACX,KAAK,UAAU;GAAE,GAAG;IAAM,OAAO,WAAW,QAAQ;GAAO,GAC5D,EAAE,CACH;AAEH,SAAO,WAAW,WAAW,EAAE;;;;;CAMjC,MAAM,OACJ,QACA,cACe;EAGf,MAAM,SAAS;GAAE,GAFA,MAAM,KAAK,IAAI,OAAO;GAET,GAAG;GAAc;AAE/C,QAAM,KAAK,IAAI,QAAQ,OAAO;;;;;CAMhC,MAAM,IACJ,QACA,cACe;AACf,QAAM,KAAK,cAAc,QAAQ,eAAe,QAAQ,aAAa,CAAC;;;;;CAMxE,MAAM,IAAI,QAAsC;AAC9C,MAAI;GACF,MAAM,YAAY,KAAK,aAAa,OAAO;AAC3C,SAAM,GAAG,OAAO,UAAU;AAC1B,UAAO;UACD;AACN,UAAO;;;;;;CAOX,MAAM,MAAM,QAAmC;AAC7C,MAAI;GACF,MAAM,YAAY,KAAK,aAAa,OAAO;AAC3C,SAAM,GAAG,OAAO,UAAU;UACpB;;;;;CAQV,MAAM,WAA0B;AAC9B,MAAI;GACF,MAAM,QAAQ,MAAM,GAAG,QAAQ,KAAK,OAAO,SAAS;AAEpD,SAAM,QAAQ,IACZ,MACG,QAAQ,SAAS,KAAK,SAAS,QAAQ,CAAC,CACxC,KAAK,SAAS,GAAG,OAAOA,OAAK,KAAK,KAAK,OAAO,UAAU,KAAK,CAAC,CAAC,CACnE;UACK"}
|