@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 @@
|
|
|
1
|
+
{"version":3,"file":"translation-service.mjs","names":["translator: Translator<any>","cache: TranslationCache","config: TranslationServiceConfig","logger: Logger","endTime","filteredMetadata: MetadataSchema","overriddenTranslations: Record<string, string>","hashesNeedingTranslation: string[]","newTranslations: Record<string, string>","errors: TranslationError[]","entries: Record<string, TranslatableEntry>","result: Record<string, string>"],"sources":["../../src/translators/translation-service.ts"],"sourcesContent":["/**\n * TranslationService - Main orchestrator for translation workflow\n *\n * Responsibilities:\n * - Coordinates between metadata, cache, and translator\n * - Determines what needs translation\n * - Handles caching strategy\n * - Manages partial failures\n */\n\nimport type { TranslationCache } from \"./cache\";\nimport type { TranslatableEntry, Translator } from \"./api\";\nimport type { MetadataSchema } from \"../types\";\nimport {\n type PluralizationConfig,\n PluralizationService,\n} from \"./pluralization\";\nimport type { Logger } from \"../utils/logger\";\nimport type { LocaleCode } from \"lingo.dev/spec\";\nimport { PseudoTranslator } from \"./pseudotranslator\";\n\nexport interface TranslationServiceConfig {\n /**\n * Source locale (e.g., \"en\")\n */\n sourceLocale: LocaleCode;\n\n /**\n * Pluralization configuration\n * If provided, enables automatic pluralization of source messages\n */\n pluralization: Omit<PluralizationConfig, \"sourceLocale\">;\n}\n\nexport interface TranslationResult {\n /**\n * Successfully translated entries (hash -> translated text)\n */\n translations: Record<string, string>;\n\n errors: TranslationError[];\n\n stats: {\n total: number;\n cached: number;\n translated: number;\n failed: number;\n };\n}\n\nexport interface TranslationError {\n hash: string;\n sourceText: string;\n error: string;\n}\n\nexport class TranslationService {\n private useCache = true;\n private pluralizationService?: PluralizationService;\n\n constructor(\n private translator: Translator<any>,\n private cache: TranslationCache,\n private config: TranslationServiceConfig,\n private logger: Logger,\n ) {\n const isPseudo = this.translator instanceof PseudoTranslator;\n this.useCache = !isPseudo;\n\n // Initialize pluralization service if enabled\n // Do this once at construction to avoid repeated API key validation and model creation\n if (this.config.pluralization?.enabled !== false && !isPseudo) {\n this.logger.info(\"Initializing pluralization service...\");\n this.pluralizationService = new PluralizationService(\n {\n ...this.config.pluralization,\n sourceLocale: this.config.sourceLocale,\n },\n this.logger,\n );\n }\n }\n\n /**\n * Translate entries to target locale\n *\n * @param locale Target locale (including source locale)\n * @param metadata Metadata schema with all entries\n * @param requestedHashes Optional: only translate specific hashes\n * @returns Translation result with translations and errors\n */\n async translate(\n locale: LocaleCode,\n metadata: MetadataSchema,\n requestedHashes?: string[],\n ): Promise<TranslationResult> {\n const startTime = performance.now();\n\n // Step 1: Determine which hashes we need to work with\n const workingHashes = requestedHashes || Object.keys(metadata.entries);\n\n this.logger.info(\n `Translation requested for ${workingHashes.length} hashes in locale: ${locale}`,\n );\n\n // Step 2: Check cache first (same for all locales, including source)\n this.logger.debug(`[TRACE] Checking cache for locale: ${locale}`);\n const cacheStartTime = performance.now();\n const cachedTranslations = this.useCache\n ? await this.cache.get(locale)\n : {};\n const cacheEndTime = performance.now();\n this.logger.debug(\n `[TRACE] Cache check completed in ${(cacheEndTime - cacheStartTime).toFixed(2)}ms, found ${Object.keys(cachedTranslations).length} entries`,\n );\n\n // Step 3: Determine what needs translation/pluralization\n const uncachedHashes = workingHashes.filter(\n (hash) => !cachedTranslations[hash],\n );\n this.logger.debug(\n `[TRACE] ${uncachedHashes.length} hashes need processing, ${workingHashes.length - uncachedHashes.length} are cached`,\n );\n\n const cachedCount = workingHashes.length - uncachedHashes.length;\n\n if (uncachedHashes.length === 0) {\n // All cached!\n const endTime = performance.now();\n this.logger.info(\n `Cache hit for all ${workingHashes.length} hashes in ${locale} in ${(endTime - startTime).toFixed(2)}ms`,\n );\n\n return {\n translations: this.pickTranslations(cachedTranslations, workingHashes),\n errors: [],\n stats: {\n total: workingHashes.length,\n cached: cachedCount,\n translated: 0,\n failed: 0,\n },\n };\n }\n\n this.logger.info(\n `Generating translations for ${uncachedHashes.length} uncached hashes in ${locale}...`,\n );\n\n // Step 4: Filter metadata to only uncached entries\n const filteredMetadata: MetadataSchema = {\n ...metadata,\n entries: Object.fromEntries(\n uncachedHashes\n .map((hash) => [hash, metadata.entries[hash]])\n .filter(([_, entry]) => entry !== undefined),\n ),\n };\n\n // Step 5: Process pluralization for filtered entries\n if (this.pluralizationService) {\n this.logger.info(\n `Processing pluralization for ${Object.keys(filteredMetadata.entries).length} entries...`,\n );\n const pluralStats =\n await this.pluralizationService.process(filteredMetadata);\n this.logger.info(\n `Pluralization stats: ${pluralStats.pluralized} pluralized, ${pluralStats.rejected} rejected, ${pluralStats.failed} failed`,\n );\n }\n\n // Step 6: Separate overridden entries from entries that need translation\n const overriddenTranslations: Record<string, string> = {};\n const hashesNeedingTranslation: string[] = [];\n\n this.logger.debug(\n `[TRACE] Checking for overrides in ${uncachedHashes.length} entries`,\n );\n\n for (const hash of uncachedHashes) {\n const entry = filteredMetadata.entries[hash];\n if (!entry) continue;\n\n // Check if this entry has an override for the current locale\n if (entry.overrides && entry.overrides[locale]) {\n overriddenTranslations[hash] = entry.overrides[locale];\n this.logger.debug(\n `[TRACE] Using override for ${hash} in locale ${locale}: \"${entry.overrides[locale]}\"`,\n );\n } else {\n hashesNeedingTranslation.push(hash);\n }\n }\n\n const overrideCount = Object.keys(overriddenTranslations).length;\n if (overrideCount > 0) {\n this.logger.info(\n `Found ${overrideCount} override(s) for locale ${locale}, skipping AI translation for these entries`,\n );\n }\n\n // Step 7: Prepare entries for translation (excluding overridden ones)\n this.logger.debug(\n `[TRACE] Preparing ${hashesNeedingTranslation.length} entries for translation (after overrides)`,\n );\n const entriesToTranslate = this.prepareEntries(\n filteredMetadata,\n hashesNeedingTranslation,\n );\n this.logger.debug(\n `[TRACE] Prepared ${Object.keys(entriesToTranslate).length} entries`,\n );\n\n // Step 8: Translate or return source text\n let newTranslations: Record<string, string> = { ...overriddenTranslations };\n const errors: TranslationError[] = [];\n\n if (locale === this.config.sourceLocale) {\n // For source locale, just return the (possibly pluralized) sourceText\n this.logger.debug(\n `[TRACE] Source locale detected, returning sourceText for ${hashesNeedingTranslation.length} entries`,\n );\n for (const [hash, entry] of Object.entries(entriesToTranslate)) {\n newTranslations[hash] = entry.text;\n }\n } else if (Object.keys(entriesToTranslate).length > 0) {\n // For other locales, translate only entries without overrides\n try {\n this.logger.debug(\n `[TRACE] Calling translator.translate() for ${locale} with ${Object.keys(entriesToTranslate).length} entries`,\n );\n this.logger.debug(`[TRACE] About to await translator.translate()...`);\n const translateStartTime = performance.now();\n this.logger.debug(`[TRACE] Executing translator.translate() NOW`);\n const translatedTexts = await this.translator.translate(\n locale,\n entriesToTranslate,\n );\n this.logger.debug(`[TRACE] translator.translate() returned`);\n\n // Merge translated texts with overridden translations\n newTranslations = { ...overriddenTranslations, ...translatedTexts };\n\n const translateEndTime = performance.now();\n this.logger.debug(\n `[TRACE] translator.translate() completed in ${(translateEndTime - translateStartTime).toFixed(2)}ms`,\n );\n this.logger.debug(\n `[TRACE] Received ${Object.keys(translatedTexts).length} translations (+ ${overrideCount} overrides)`,\n );\n } catch (error) {\n // Complete failure - log and return what we have from cache\n this.logger.error(`Translation failed completely:`, error);\n\n return {\n translations: this.pickTranslations(\n cachedTranslations,\n workingHashes,\n ),\n errors: [\n {\n hash: \"all\",\n sourceText: \"all\",\n error:\n error instanceof Error\n ? error.message\n : \"Unknown translation error\",\n },\n ],\n stats: {\n total: workingHashes.length,\n cached: cachedCount,\n translated: 0,\n failed: uncachedHashes.length,\n },\n };\n }\n\n // Check for partial failures (some hashes didn't get translated)\n for (const hash of uncachedHashes) {\n if (!newTranslations[hash]) {\n const entry = filteredMetadata.entries[hash];\n errors.push({\n hash,\n sourceText: entry?.sourceText || \"\",\n error: \"Translation not returned by translator\",\n });\n }\n }\n }\n\n // Step 5: Update cache with successful translations (skip for pseudo)\n if (this.useCache && Object.keys(newTranslations).length > 0) {\n try {\n this.logger.debug(\n `[TRACE] Updating cache with ${Object.keys(newTranslations).length} translations for ${locale}`,\n );\n const updateStartTime = performance.now();\n await this.cache.update(locale, newTranslations);\n const updateEndTime = performance.now();\n this.logger.debug(\n `[TRACE] Cache update completed in ${(updateEndTime - updateStartTime).toFixed(2)}ms`,\n );\n this.logger.info(\n `Updated cache with ${Object.keys(newTranslations).length} translations for ${locale}`,\n );\n } catch (error) {\n this.logger.error(`Failed to update cache:`, error);\n // Don't fail the request if cache update fails\n }\n }\n\n // Step 6: Merge and return\n const allTranslations = { ...cachedTranslations, ...newTranslations };\n const result = this.pickTranslations(allTranslations, workingHashes);\n\n const endTime = performance.now();\n this.logger.info(\n `Translation completed for ${locale}: ${Object.keys(newTranslations).length} new, ${cachedCount} cached, ${errors.length} errors in ${(endTime - startTime).toFixed(2)}ms`,\n );\n\n return {\n translations: result,\n errors,\n stats: {\n total: workingHashes.length,\n cached: cachedCount,\n translated: Object.keys(newTranslations).length,\n failed: errors.length,\n },\n };\n }\n\n /**\n * Prepare metadata entries for translation\n */\n private prepareEntries(\n metadata: MetadataSchema,\n hashes: string[],\n ): Record<string, TranslatableEntry> {\n const entries: Record<string, TranslatableEntry> = {};\n\n for (const hash of hashes) {\n const entry = metadata.entries[hash];\n if (entry) {\n entries[hash] = {\n text: entry.sourceText,\n context: entry.context || {},\n };\n }\n }\n\n return entries;\n }\n\n /**\n * Pick only requested translations from the full set\n */\n // TODO (AleksandrSl 14/12/2025): SHould I use this in the build somehow?\n private pickTranslations(\n allTranslations: Record<string, string>,\n requestedHashes: string[],\n ): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const hash of requestedHashes) {\n if (allTranslations[hash]) {\n result[hash] = allTranslations[hash];\n }\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const require_index = require('./pseudotranslator/index.cjs');
|
|
2
|
+
const require_service = require('./lingo/service.cjs');
|
|
3
|
+
|
|
4
|
+
//#region src/translators/translator-factory.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a translator instance based on configuration
|
|
7
|
+
*
|
|
8
|
+
* Development mode behavior:
|
|
9
|
+
* - If translator is "pseudo" or dev.usePseudotranslator is true, use pseudotranslator
|
|
10
|
+
* - If API keys are missing, auto-fallback to pseudotranslator (with warning)
|
|
11
|
+
* - Otherwise, create real translator
|
|
12
|
+
*
|
|
13
|
+
* Production mode behavior:
|
|
14
|
+
* - Always require real translator with valid API keys
|
|
15
|
+
* - Throw error if API keys are missing
|
|
16
|
+
*
|
|
17
|
+
* Note: Translators are stateless and don't handle caching.
|
|
18
|
+
* Caching is handled by TranslationService layer.
|
|
19
|
+
*
|
|
20
|
+
* API key validation is now done in the LingoTranslator constructor
|
|
21
|
+
* which validates and fetches all keys once at initialization.
|
|
22
|
+
*/
|
|
23
|
+
function createTranslator(config, logger) {
|
|
24
|
+
const isDev = config.environment === "development";
|
|
25
|
+
if (isDev && config.dev?.usePseudotranslator) {
|
|
26
|
+
logger.info("📝 Using pseudotranslator (dev.usePseudotranslator enabled)");
|
|
27
|
+
return new require_index.PseudoTranslator({ delayMedian: 100 }, logger);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const models = config.models;
|
|
31
|
+
logger.info(`Creating Lingo translator with models: ${JSON.stringify(models)}`);
|
|
32
|
+
return new require_service.Service({
|
|
33
|
+
models,
|
|
34
|
+
sourceLocale: config.sourceLocale,
|
|
35
|
+
prompt: config.prompt
|
|
36
|
+
}, logger);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (isDev) {
|
|
39
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
40
|
+
logger.error(`\n❌ [Lingo] Translation setup error: ${errorMsg}\n`);
|
|
41
|
+
logger.warn("⚠️ [Lingo] Auto-fallback to pseudotranslator in development mode.\n Set the required API keys for real translations.\n");
|
|
42
|
+
return new require_index.PseudoTranslator({ delayMedian: 100 }, logger);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
exports.createTranslator = createTranslator;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PseudoTranslator } from "./pseudotranslator/index.mjs";
|
|
2
|
+
import { Service } from "./lingo/service.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/translators/translator-factory.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a translator instance based on configuration
|
|
7
|
+
*
|
|
8
|
+
* Development mode behavior:
|
|
9
|
+
* - If translator is "pseudo" or dev.usePseudotranslator is true, use pseudotranslator
|
|
10
|
+
* - If API keys are missing, auto-fallback to pseudotranslator (with warning)
|
|
11
|
+
* - Otherwise, create real translator
|
|
12
|
+
*
|
|
13
|
+
* Production mode behavior:
|
|
14
|
+
* - Always require real translator with valid API keys
|
|
15
|
+
* - Throw error if API keys are missing
|
|
16
|
+
*
|
|
17
|
+
* Note: Translators are stateless and don't handle caching.
|
|
18
|
+
* Caching is handled by TranslationService layer.
|
|
19
|
+
*
|
|
20
|
+
* API key validation is now done in the LingoTranslator constructor
|
|
21
|
+
* which validates and fetches all keys once at initialization.
|
|
22
|
+
*/
|
|
23
|
+
function createTranslator(config, logger) {
|
|
24
|
+
const isDev = config.environment === "development";
|
|
25
|
+
if (isDev && config.dev?.usePseudotranslator) {
|
|
26
|
+
logger.info("📝 Using pseudotranslator (dev.usePseudotranslator enabled)");
|
|
27
|
+
return new PseudoTranslator({ delayMedian: 100 }, logger);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const models = config.models;
|
|
31
|
+
logger.info(`Creating Lingo translator with models: ${JSON.stringify(models)}`);
|
|
32
|
+
return new Service({
|
|
33
|
+
models,
|
|
34
|
+
sourceLocale: config.sourceLocale,
|
|
35
|
+
prompt: config.prompt
|
|
36
|
+
}, logger);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (isDev) {
|
|
39
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
40
|
+
logger.error(`\n❌ [Lingo] Translation setup error: ${errorMsg}\n`);
|
|
41
|
+
logger.warn("⚠️ [Lingo] Auto-fallback to pseudotranslator in development mode.\n Set the required API keys for real translations.\n");
|
|
42
|
+
return new PseudoTranslator({ delayMedian: 100 }, logger);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//#endregion
|
|
49
|
+
export { createTranslator };
|
|
50
|
+
//# sourceMappingURL=translator-factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translator-factory.mjs","names":[],"sources":["../../src/translators/translator-factory.ts"],"sourcesContent":["/**\n * Factory for creating translators based on configuration\n */\n\nimport type { Translator } from \"./api\";\nimport { PseudoTranslator } from \"./pseudotranslator\";\nimport { Service } from \"./lingo\";\nimport { Logger } from \"../utils/logger\";\nimport type { LocaleCode } from \"lingo.dev/spec\";\nimport type { LingoEnvironment } from \"../types\";\n\ninterface TranslatorFactoryConfig {\n sourceLocale: LocaleCode;\n models: \"lingo.dev\" | Record<string, string>;\n prompt?: string;\n environment: LingoEnvironment;\n dev?: {\n usePseudotranslator?: boolean;\n };\n}\n\n/**\n * Create a translator instance based on configuration\n *\n * Development mode behavior:\n * - If translator is \"pseudo\" or dev.usePseudotranslator is true, use pseudotranslator\n * - If API keys are missing, auto-fallback to pseudotranslator (with warning)\n * - Otherwise, create real translator\n *\n * Production mode behavior:\n * - Always require real translator with valid API keys\n * - Throw error if API keys are missing\n *\n * Note: Translators are stateless and don't handle caching.\n * Caching is handled by TranslationService layer.\n *\n * API key validation is now done in the LingoTranslator constructor\n * which validates and fetches all keys once at initialization.\n */\nexport function createTranslator(\n config: TranslatorFactoryConfig,\n logger: Logger,\n): Translator<unknown> {\n const isDev = config.environment === \"development\";\n\n // 1. Explicit dev override takes precedence\n if (isDev && config.dev?.usePseudotranslator) {\n logger.info(\"📝 Using pseudotranslator (dev.usePseudotranslator enabled)\");\n return new PseudoTranslator({ delayMedian: 100 }, logger);\n }\n\n // 2. Try to create real translator\n // LingoTranslator constructor will validate and fetch API keys\n // If validation fails, it will throw an error with helpful message\n try {\n const models = config.models;\n\n logger.info(\n `Creating Lingo translator with models: ${JSON.stringify(models)}`,\n );\n\n return new Service(\n {\n models,\n sourceLocale: config.sourceLocale,\n prompt: config.prompt,\n },\n logger,\n );\n } catch (error) {\n // 3. Auto-fallback in dev mode if creation fails\n if (isDev) {\n // Use console.error to ensure visibility in all contexts (loader, server, etc.)\n const errorMsg = error instanceof Error ? error.message : String(error);\n logger.error(`\\n❌ [Lingo] Translation setup error: ${errorMsg}\\n`);\n logger.warn(\n `⚠️ [Lingo] Auto-fallback to pseudotranslator in development mode.\\n` +\n ` Set the required API keys for real translations.\\n`,\n );\n\n return new PseudoTranslator({ delayMedian: 100 }, logger);\n }\n\n // 4. Fail in production\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuCA,SAAgB,iBACd,QACA,QACqB;CACrB,MAAM,QAAQ,OAAO,gBAAgB;AAGrC,KAAI,SAAS,OAAO,KAAK,qBAAqB;AAC5C,SAAO,KAAK,8DAA8D;AAC1E,SAAO,IAAI,iBAAiB,EAAE,aAAa,KAAK,EAAE,OAAO;;AAM3D,KAAI;EACF,MAAM,SAAS,OAAO;AAEtB,SAAO,KACL,0CAA0C,KAAK,UAAU,OAAO,GACjE;AAED,SAAO,IAAI,QACT;GACE;GACA,cAAc,OAAO;GACrB,QAAQ,OAAO;GAChB,EACD,OACD;UACM,OAAO;AAEd,MAAI,OAAO;GAET,MAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACvE,UAAO,MAAM,wCAAwC,SAAS,IAAI;AAClE,UAAO,KACL,4HAED;AAED,UAAO,IAAI,iBAAiB,EAAE,aAAa,KAAK,EAAE,OAAO;;AAI3D,QAAM"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { PluralizationConfig } from "./translators/pluralization/types.cjs";
|
|
2
|
+
import { LocaleCode } from "lingo.dev/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cookie configuration for locale persistence
|
|
8
|
+
*/
|
|
9
|
+
interface CookieConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Name of the cookie to store the locale
|
|
12
|
+
* @default 'locale'
|
|
13
|
+
*/
|
|
14
|
+
name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Maximum age of the cookie in seconds
|
|
17
|
+
* @default 31536000 (1 year)
|
|
18
|
+
*/
|
|
19
|
+
maxAge: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Locale persistence configuration
|
|
23
|
+
* Currently only supports cookie-based persistence
|
|
24
|
+
*/
|
|
25
|
+
type LocalePersistenceConfig = {
|
|
26
|
+
type: "cookie";
|
|
27
|
+
config: CookieConfig;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Field that we require users to fill in the config. The rest could be taken from defaults.
|
|
31
|
+
*/
|
|
32
|
+
type LingoConfigRequiredFields = "sourceLocale" | "targetLocales";
|
|
33
|
+
type LingoInternalFields = "environment" | "cacheType";
|
|
34
|
+
/**
|
|
35
|
+
* Configuration for the Lingo compiler
|
|
36
|
+
*/
|
|
37
|
+
type PartialLingoConfig = Pick<LingoConfig, LingoConfigRequiredFields> & Partial<Omit<LingoConfig, LingoConfigRequiredFields | "dev" | LingoInternalFields> & {
|
|
38
|
+
dev: Partial<LingoConfig["dev"]>;
|
|
39
|
+
}>;
|
|
40
|
+
type LingoEnvironment = "development" | "production";
|
|
41
|
+
/**
|
|
42
|
+
* Lingo config with all the defaults applied
|
|
43
|
+
*/
|
|
44
|
+
type LingoConfig = {
|
|
45
|
+
/**
|
|
46
|
+
* Root directory of the source code
|
|
47
|
+
*/
|
|
48
|
+
sourceRoot: string;
|
|
49
|
+
/**
|
|
50
|
+
* Directory for lingo files (.lingo/)
|
|
51
|
+
*/
|
|
52
|
+
lingoDir: string;
|
|
53
|
+
/**
|
|
54
|
+
* Environment mode
|
|
55
|
+
* Determines metadata file naming and translator behavior
|
|
56
|
+
*
|
|
57
|
+
* @default "production"
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
60
|
+
environment: LingoEnvironment;
|
|
61
|
+
/**
|
|
62
|
+
* Cache implementation type
|
|
63
|
+
* - "local": Local file system cache (default)
|
|
64
|
+
* - "remote": Remote cache (future)
|
|
65
|
+
*
|
|
66
|
+
* @default "local"
|
|
67
|
+
* @internal Since we do not support more types, there is no need to make it public, but it allows keeping the config in the single place
|
|
68
|
+
*/
|
|
69
|
+
cacheType: "local";
|
|
70
|
+
/**
|
|
71
|
+
* The locale to translate from.
|
|
72
|
+
*
|
|
73
|
+
* This must match one of the following formats:
|
|
74
|
+
*
|
|
75
|
+
* - [ISO 639-1 language code](https://en.wikipedia.org/wiki/ISO_639-1) (e.g., `"en"`)
|
|
76
|
+
* - [IETF BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag) (e.g., `"en-US"`)
|
|
77
|
+
*
|
|
78
|
+
* @default "en"
|
|
79
|
+
*/
|
|
80
|
+
sourceLocale: LocaleCode;
|
|
81
|
+
/**
|
|
82
|
+
* The locale(s) to translate to.
|
|
83
|
+
*
|
|
84
|
+
* Each locale must match one of the following formats:
|
|
85
|
+
*
|
|
86
|
+
* - [ISO 639-1 language code](https://en.wikipedia.org/wiki/ISO_639-1) (e.g., `"en"`)
|
|
87
|
+
* - [IETF BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag) (e.g., `"en-US"`)
|
|
88
|
+
*
|
|
89
|
+
* @default ["es"]
|
|
90
|
+
*/
|
|
91
|
+
targetLocales: LocaleCode[];
|
|
92
|
+
/**
|
|
93
|
+
* Whether to require 'use i18n' directive
|
|
94
|
+
*/
|
|
95
|
+
useDirective: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Model configuration for lingo translator
|
|
98
|
+
* - Use "lingo.dev" for Lingo.dev Engine (recommended)
|
|
99
|
+
* - Use locale-pair mapping for direct LLM providers
|
|
100
|
+
*
|
|
101
|
+
* Examples:
|
|
102
|
+
* - "lingo.dev"
|
|
103
|
+
* - { "en:es": "google:gemini-2.0-flash", "*:*": "groq:llama3-8b-8192" }
|
|
104
|
+
*
|
|
105
|
+
* @default "lingo.dev"
|
|
106
|
+
*/
|
|
107
|
+
models: "lingo.dev" | Record<string, string>;
|
|
108
|
+
/**
|
|
109
|
+
* Custom translation prompt for lingo translator
|
|
110
|
+
* Use {SOURCE_LOCALE} and {TARGET_LOCALE} placeholders
|
|
111
|
+
*/
|
|
112
|
+
prompt?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Pluralization configuration
|
|
115
|
+
* Automatically detects and converts messages to ICU MessageFormat
|
|
116
|
+
*/
|
|
117
|
+
pluralization: Omit<PluralizationConfig, "sourceLocale">;
|
|
118
|
+
/**
|
|
119
|
+
* Development-specific settings
|
|
120
|
+
*/
|
|
121
|
+
dev: {
|
|
122
|
+
/**
|
|
123
|
+
* Use pseudotranslator in development instead of real translator
|
|
124
|
+
* Useful for:
|
|
125
|
+
* - Testing i18n without API calls
|
|
126
|
+
* - Verifying correct elements are translated
|
|
127
|
+
* - Saving AI tokens during development
|
|
128
|
+
*
|
|
129
|
+
* @default false
|
|
130
|
+
*/
|
|
131
|
+
usePseudotranslator?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Starting port for the translation server in development mode
|
|
134
|
+
* Server will try this port first, then increment if unavailable
|
|
135
|
+
*
|
|
136
|
+
* @default 60000
|
|
137
|
+
*/
|
|
138
|
+
translationServerStartPort: number;
|
|
139
|
+
translationServerUrl?: string;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Locale persistence configuration
|
|
143
|
+
* Defines how locale changes should be persisted
|
|
144
|
+
*
|
|
145
|
+
* @default { type: 'cookie', config: { name: 'locale' } }
|
|
146
|
+
*/
|
|
147
|
+
localePersistence: LocalePersistenceConfig;
|
|
148
|
+
/**
|
|
149
|
+
* Build mode for CI/production
|
|
150
|
+
* - "translate": Generate translations at build time, fail if translation fails (default)
|
|
151
|
+
* - "cache-only": Only use cached translations, fail if cache is incomplete
|
|
152
|
+
*
|
|
153
|
+
* Can be overridden by LINGO_BUILD_MODE environment variable
|
|
154
|
+
*
|
|
155
|
+
* @default "translate"
|
|
156
|
+
*/
|
|
157
|
+
buildMode: "translate" | "cache-only";
|
|
158
|
+
};
|
|
159
|
+
//#endregion
|
|
160
|
+
export { CookieConfig, PartialLingoConfig };
|
|
161
|
+
//# sourceMappingURL=types.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;AAKA;AAEA;AAKY,UA9BK,YAAA,CA8Ba;EAAQ;;;;EAIhC,IAAA,EAAA,MAAA;EAAoC;;;;EAHxC,MAAA,EAAA,MAAA;;AASF;AAKA;;;AAoDiB,KA/EL,uBAAA,GA+EK;EAkBO,IAAA,EAAA,QAAA;EAYF,MAAA,EA7G0C,YA6G1C;CAAL;;;;KAxGL,yBAAA;KAEA,mBAAA;;;;KAKA,kBAAA,GAAqB,KAAK,aAAa,6BACjD,QACE,KACE,aACA,oCAAoC;OAE/B,QAAQ;;KAIP,gBAAA;;;;KAKA,WAAA;;;;;;;;;;;;;;;;eAkBG;;;;;;;;;;;;;;;;;;;;gBAsBC;;;;;;;;;;;iBAYC;;;;;;;;;;;;;;;;wBAkBO;;;;;;;;;;iBAYP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkCD"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { PluralizationConfig } from "./translators/pluralization/types.mjs";
|
|
2
|
+
import { LocaleCode } from "lingo.dev/spec";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cookie configuration for locale persistence
|
|
8
|
+
*/
|
|
9
|
+
interface CookieConfig {
|
|
10
|
+
/**
|
|
11
|
+
* Name of the cookie to store the locale
|
|
12
|
+
* @default 'locale'
|
|
13
|
+
*/
|
|
14
|
+
name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Maximum age of the cookie in seconds
|
|
17
|
+
* @default 31536000 (1 year)
|
|
18
|
+
*/
|
|
19
|
+
maxAge: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Locale persistence configuration
|
|
23
|
+
* Currently only supports cookie-based persistence
|
|
24
|
+
*/
|
|
25
|
+
type LocalePersistenceConfig = {
|
|
26
|
+
type: "cookie";
|
|
27
|
+
config: CookieConfig;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Field that we require users to fill in the config. The rest could be taken from defaults.
|
|
31
|
+
*/
|
|
32
|
+
type LingoConfigRequiredFields = "sourceLocale" | "targetLocales";
|
|
33
|
+
type LingoInternalFields = "environment" | "cacheType";
|
|
34
|
+
/**
|
|
35
|
+
* Configuration for the Lingo compiler
|
|
36
|
+
*/
|
|
37
|
+
type PartialLingoConfig = Pick<LingoConfig, LingoConfigRequiredFields> & Partial<Omit<LingoConfig, LingoConfigRequiredFields | "dev" | LingoInternalFields> & {
|
|
38
|
+
dev: Partial<LingoConfig["dev"]>;
|
|
39
|
+
}>;
|
|
40
|
+
type LingoEnvironment = "development" | "production";
|
|
41
|
+
/**
|
|
42
|
+
* Lingo config with all the defaults applied
|
|
43
|
+
*/
|
|
44
|
+
type LingoConfig = {
|
|
45
|
+
/**
|
|
46
|
+
* Root directory of the source code
|
|
47
|
+
*/
|
|
48
|
+
sourceRoot: string;
|
|
49
|
+
/**
|
|
50
|
+
* Directory for lingo files (.lingo/)
|
|
51
|
+
*/
|
|
52
|
+
lingoDir: string;
|
|
53
|
+
/**
|
|
54
|
+
* Environment mode
|
|
55
|
+
* Determines metadata file naming and translator behavior
|
|
56
|
+
*
|
|
57
|
+
* @default "production"
|
|
58
|
+
* @internal
|
|
59
|
+
*/
|
|
60
|
+
environment: LingoEnvironment;
|
|
61
|
+
/**
|
|
62
|
+
* Cache implementation type
|
|
63
|
+
* - "local": Local file system cache (default)
|
|
64
|
+
* - "remote": Remote cache (future)
|
|
65
|
+
*
|
|
66
|
+
* @default "local"
|
|
67
|
+
* @internal Since we do not support more types, there is no need to make it public, but it allows keeping the config in the single place
|
|
68
|
+
*/
|
|
69
|
+
cacheType: "local";
|
|
70
|
+
/**
|
|
71
|
+
* The locale to translate from.
|
|
72
|
+
*
|
|
73
|
+
* This must match one of the following formats:
|
|
74
|
+
*
|
|
75
|
+
* - [ISO 639-1 language code](https://en.wikipedia.org/wiki/ISO_639-1) (e.g., `"en"`)
|
|
76
|
+
* - [IETF BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag) (e.g., `"en-US"`)
|
|
77
|
+
*
|
|
78
|
+
* @default "en"
|
|
79
|
+
*/
|
|
80
|
+
sourceLocale: LocaleCode;
|
|
81
|
+
/**
|
|
82
|
+
* The locale(s) to translate to.
|
|
83
|
+
*
|
|
84
|
+
* Each locale must match one of the following formats:
|
|
85
|
+
*
|
|
86
|
+
* - [ISO 639-1 language code](https://en.wikipedia.org/wiki/ISO_639-1) (e.g., `"en"`)
|
|
87
|
+
* - [IETF BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag) (e.g., `"en-US"`)
|
|
88
|
+
*
|
|
89
|
+
* @default ["es"]
|
|
90
|
+
*/
|
|
91
|
+
targetLocales: LocaleCode[];
|
|
92
|
+
/**
|
|
93
|
+
* Whether to require 'use i18n' directive
|
|
94
|
+
*/
|
|
95
|
+
useDirective: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Model configuration for lingo translator
|
|
98
|
+
* - Use "lingo.dev" for Lingo.dev Engine (recommended)
|
|
99
|
+
* - Use locale-pair mapping for direct LLM providers
|
|
100
|
+
*
|
|
101
|
+
* Examples:
|
|
102
|
+
* - "lingo.dev"
|
|
103
|
+
* - { "en:es": "google:gemini-2.0-flash", "*:*": "groq:llama3-8b-8192" }
|
|
104
|
+
*
|
|
105
|
+
* @default "lingo.dev"
|
|
106
|
+
*/
|
|
107
|
+
models: "lingo.dev" | Record<string, string>;
|
|
108
|
+
/**
|
|
109
|
+
* Custom translation prompt for lingo translator
|
|
110
|
+
* Use {SOURCE_LOCALE} and {TARGET_LOCALE} placeholders
|
|
111
|
+
*/
|
|
112
|
+
prompt?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Pluralization configuration
|
|
115
|
+
* Automatically detects and converts messages to ICU MessageFormat
|
|
116
|
+
*/
|
|
117
|
+
pluralization: Omit<PluralizationConfig, "sourceLocale">;
|
|
118
|
+
/**
|
|
119
|
+
* Development-specific settings
|
|
120
|
+
*/
|
|
121
|
+
dev: {
|
|
122
|
+
/**
|
|
123
|
+
* Use pseudotranslator in development instead of real translator
|
|
124
|
+
* Useful for:
|
|
125
|
+
* - Testing i18n without API calls
|
|
126
|
+
* - Verifying correct elements are translated
|
|
127
|
+
* - Saving AI tokens during development
|
|
128
|
+
*
|
|
129
|
+
* @default false
|
|
130
|
+
*/
|
|
131
|
+
usePseudotranslator?: boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Starting port for the translation server in development mode
|
|
134
|
+
* Server will try this port first, then increment if unavailable
|
|
135
|
+
*
|
|
136
|
+
* @default 60000
|
|
137
|
+
*/
|
|
138
|
+
translationServerStartPort: number;
|
|
139
|
+
translationServerUrl?: string;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Locale persistence configuration
|
|
143
|
+
* Defines how locale changes should be persisted
|
|
144
|
+
*
|
|
145
|
+
* @default { type: 'cookie', config: { name: 'locale' } }
|
|
146
|
+
*/
|
|
147
|
+
localePersistence: LocalePersistenceConfig;
|
|
148
|
+
/**
|
|
149
|
+
* Build mode for CI/production
|
|
150
|
+
* - "translate": Generate translations at build time, fail if translation fails (default)
|
|
151
|
+
* - "cache-only": Only use cached translations, fail if cache is incomplete
|
|
152
|
+
*
|
|
153
|
+
* Can be overridden by LINGO_BUILD_MODE environment variable
|
|
154
|
+
*
|
|
155
|
+
* @default "translate"
|
|
156
|
+
*/
|
|
157
|
+
buildMode: "translate" | "cache-only";
|
|
158
|
+
};
|
|
159
|
+
//#endregion
|
|
160
|
+
export { CookieConfig, PartialLingoConfig };
|
|
161
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;;AA4BA;AAKA;AAEA;AAKY,UA9BK,YAAA,CA8Ba;EAAQ;;;;EAIhC,IAAA,EAAA,MAAA;EAAoC;;;;EAHxC,MAAA,EAAA,MAAA;;AASF;AAKA;;;AAoDiB,KA/EL,uBAAA,GA+EK;EAkBO,IAAA,EAAA,QAAA;EAYF,MAAA,EA7G0C,YA6G1C;CAAL;;;;KAxGL,yBAAA;KAEA,mBAAA;;;;KAKA,kBAAA,GAAqB,KAAK,aAAa,6BACjD,QACE,KACE,aACA,oCAAoC;OAE/B,QAAQ;;KAIP,gBAAA;;;;KAKA,WAAA;;;;;;;;;;;;;;;;eAkBG;;;;;;;;;;;;;;;;;;;;gBAsBC;;;;;;;;;;;iBAYC;;;;;;;;;;;;;;;;wBAkBO;;;;;;;;;;iBAYP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkCD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils/config-factory.ts
|
|
3
|
+
/**
|
|
4
|
+
* Default configuration values
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_CONFIG = {
|
|
7
|
+
sourceRoot: "src",
|
|
8
|
+
lingoDir: "lingo",
|
|
9
|
+
useDirective: false,
|
|
10
|
+
dev: { translationServerStartPort: 6e4 },
|
|
11
|
+
localePersistence: {
|
|
12
|
+
type: "cookie",
|
|
13
|
+
config: {
|
|
14
|
+
name: "locale",
|
|
15
|
+
maxAge: 31536e3
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
models: "lingo.dev",
|
|
19
|
+
pluralization: {
|
|
20
|
+
enabled: true,
|
|
21
|
+
model: "groq:llama-3.1-8b-instant"
|
|
22
|
+
},
|
|
23
|
+
buildMode: "translate"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Create a LoaderConfig with defaults applied
|
|
27
|
+
*
|
|
28
|
+
* @param options - Partial config to override defaults
|
|
29
|
+
* @returns Complete LoaderConfig with all defaults applied
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
32
|
+
function createLingoConfig(options) {
|
|
33
|
+
return {
|
|
34
|
+
...DEFAULT_CONFIG,
|
|
35
|
+
...options,
|
|
36
|
+
environment: options.environment ?? (process.env.NODE_ENV === "development" ? "development" : "production"),
|
|
37
|
+
cacheType: options.cacheType ?? "local",
|
|
38
|
+
dev: {
|
|
39
|
+
...DEFAULT_CONFIG.dev,
|
|
40
|
+
...options.dev
|
|
41
|
+
},
|
|
42
|
+
pluralization: {
|
|
43
|
+
...DEFAULT_CONFIG.pluralization,
|
|
44
|
+
...options.pluralization
|
|
45
|
+
},
|
|
46
|
+
localePersistence: {
|
|
47
|
+
...DEFAULT_CONFIG.localePersistence,
|
|
48
|
+
...options.localePersistence,
|
|
49
|
+
config: {
|
|
50
|
+
...DEFAULT_CONFIG.localePersistence.config,
|
|
51
|
+
...options.localePersistence?.config
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
exports.createLingoConfig = createLingoConfig;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//#region src/utils/config-factory.ts
|
|
2
|
+
/**
|
|
3
|
+
* Default configuration values
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
sourceRoot: "src",
|
|
7
|
+
lingoDir: "lingo",
|
|
8
|
+
useDirective: false,
|
|
9
|
+
dev: { translationServerStartPort: 6e4 },
|
|
10
|
+
localePersistence: {
|
|
11
|
+
type: "cookie",
|
|
12
|
+
config: {
|
|
13
|
+
name: "locale",
|
|
14
|
+
maxAge: 31536e3
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
models: "lingo.dev",
|
|
18
|
+
pluralization: {
|
|
19
|
+
enabled: true,
|
|
20
|
+
model: "groq:llama-3.1-8b-instant"
|
|
21
|
+
},
|
|
22
|
+
buildMode: "translate"
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Create a LoaderConfig with defaults applied
|
|
26
|
+
*
|
|
27
|
+
* @param options - Partial config to override defaults
|
|
28
|
+
* @returns Complete LoaderConfig with all defaults applied
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
function createLingoConfig(options) {
|
|
32
|
+
return {
|
|
33
|
+
...DEFAULT_CONFIG,
|
|
34
|
+
...options,
|
|
35
|
+
environment: options.environment ?? (process.env.NODE_ENV === "development" ? "development" : "production"),
|
|
36
|
+
cacheType: options.cacheType ?? "local",
|
|
37
|
+
dev: {
|
|
38
|
+
...DEFAULT_CONFIG.dev,
|
|
39
|
+
...options.dev
|
|
40
|
+
},
|
|
41
|
+
pluralization: {
|
|
42
|
+
...DEFAULT_CONFIG.pluralization,
|
|
43
|
+
...options.pluralization
|
|
44
|
+
},
|
|
45
|
+
localePersistence: {
|
|
46
|
+
...DEFAULT_CONFIG.localePersistence,
|
|
47
|
+
...options.localePersistence,
|
|
48
|
+
config: {
|
|
49
|
+
...DEFAULT_CONFIG.localePersistence.config,
|
|
50
|
+
...options.localePersistence?.config
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { createLingoConfig };
|
|
58
|
+
//# sourceMappingURL=config-factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-factory.mjs","names":[],"sources":["../../src/utils/config-factory.ts"],"sourcesContent":["/**\n * Config factory for creating LoaderConfig instances\n */\nimport type {\n LingoConfig,\n LingoConfigRequiredFields,\n LingoInternalFields,\n PartialLingoConfig,\n} from \"../types\";\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG = {\n sourceRoot: \"src\",\n lingoDir: \"lingo\",\n useDirective: false,\n dev: {\n translationServerStartPort: 60000,\n },\n localePersistence: {\n type: \"cookie\" as const,\n config: {\n name: \"locale\",\n maxAge: 31536000,\n },\n },\n models: \"lingo.dev\",\n pluralization: {\n enabled: true,\n model: \"groq:llama-3.1-8b-instant\",\n },\n buildMode: \"translate\",\n} satisfies Omit<\n LingoConfig,\n // Looks like we can use LingoInternalFields, but it's only a coincidence that the types match, we may want to provide default for internal fields\n LingoConfigRequiredFields | \"environment\" | \"cacheType\"\n>;\n\n/**\n * Create a LoaderConfig with defaults applied\n *\n * @param options - Partial config to override defaults\n * @returns Complete LoaderConfig with all defaults applied\n *\n */\nexport function createLingoConfig(\n options: PartialLingoConfig & Partial<Pick<LingoConfig, LingoInternalFields>>,\n): LingoConfig {\n return {\n ...DEFAULT_CONFIG,\n ...options,\n environment:\n options.environment ??\n (process.env.NODE_ENV === \"development\" ? \"development\" : \"production\"),\n cacheType: options.cacheType ?? \"local\",\n dev: {\n ...DEFAULT_CONFIG.dev,\n ...options.dev,\n },\n pluralization: {\n ...DEFAULT_CONFIG.pluralization,\n ...options.pluralization,\n },\n localePersistence: {\n ...DEFAULT_CONFIG.localePersistence,\n ...options.localePersistence,\n config: {\n ...DEFAULT_CONFIG.localePersistence.config,\n ...options.localePersistence?.config,\n },\n },\n };\n}\n"],"mappings":";;;;AAaA,MAAa,iBAAiB;CAC5B,YAAY;CACZ,UAAU;CACV,cAAc;CACd,KAAK,EACH,4BAA4B,KAC7B;CACD,mBAAmB;EACjB,MAAM;EACN,QAAQ;GACN,MAAM;GACN,QAAQ;GACT;EACF;CACD,QAAQ;CACR,eAAe;EACb,SAAS;EACT,OAAO;EACR;CACD,WAAW;CACZ;;;;;;;;AAaD,SAAgB,kBACd,SACa;AACb,QAAO;EACL,GAAG;EACH,GAAG;EACH,aACE,QAAQ,gBACP,QAAQ,IAAI,aAAa,gBAAgB,gBAAgB;EAC5D,WAAW,QAAQ,aAAa;EAChC,KAAK;GACH,GAAG,eAAe;GAClB,GAAG,QAAQ;GACZ;EACD,eAAe;GACb,GAAG,eAAe;GAClB,GAAG,QAAQ;GACZ;EACD,mBAAmB;GACjB,GAAG,eAAe;GAClB,GAAG,QAAQ;GACX,QAAQ;IACN,GAAG,eAAe,kBAAkB;IACpC,GAAG,QAAQ,mBAAmB;IAC/B;GACF;EACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
let crypto = require("crypto");
|
|
3
|
+
crypto = require_rolldown_runtime.__toESM(crypto);
|
|
4
|
+
|
|
5
|
+
//#region src/utils/hash.ts
|
|
6
|
+
/**
|
|
7
|
+
* Generate a hash for a translation entry
|
|
8
|
+
* Hash is based on: sourceText + context
|
|
9
|
+
* This ensures that the same text in different components or files gets different hashes
|
|
10
|
+
*/
|
|
11
|
+
function generateTranslationHash(sourceText, context) {
|
|
12
|
+
const input = `${sourceText}::${Object.entries(context).sort((a, b) => a[0].localeCompare(b[0])).map(([key, value]) => `${key}:${value}`).join("::")}`;
|
|
13
|
+
return crypto.default.createHash("md5").update(input).digest("hex").substring(0, 12);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
exports.generateTranslationHash = generateTranslationHash;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/hash.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generate a hash for a translation entry
|
|
6
|
+
* Hash is based on: sourceText + context
|
|
7
|
+
* This ensures that the same text in different components or files gets different hashes
|
|
8
|
+
*/
|
|
9
|
+
function generateTranslationHash(sourceText, context) {
|
|
10
|
+
const input = `${sourceText}::${Object.entries(context).sort((a, b) => a[0].localeCompare(b[0])).map(([key, value]) => `${key}:${value}`).join("::")}`;
|
|
11
|
+
return crypto.createHash("md5").update(input).digest("hex").substring(0, 12);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { generateTranslationHash };
|
|
16
|
+
//# sourceMappingURL=hash.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.mjs","names":[],"sources":["../../src/utils/hash.ts"],"sourcesContent":["import crypto from \"crypto\";\n\n/*\n * If we find md5 too slow, we can use FNV-1a\n *\n * function generateHash(text: string): string {\n * let hash = 2166136261;\n * for (let i = 0; i < text.length; i++) {\n * hash ^= text.charCodeAt(i);\n * hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 12);\n * }\n * return (hash >>> 0).toString(36).padStart(7, '0').slice(0, 12);\n * }\n *\n */\n\n/**\n * Generate a hash for a translation entry\n * Hash is based on: sourceText + context\n * This ensures that the same text in different components or files gets different hashes\n */\nexport function generateTranslationHash(\n sourceText: string,\n context: Record<string, any>,\n): string {\n const input = `${sourceText}::${Object.entries(context)\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([key, value]) => `${key}:${value}`)\n .join(\"::\")}`;\n return crypto.createHash(\"md5\").update(input).digest(\"hex\").substring(0, 12); // Use first 12 chars for brevity\n}\n\n/**\n * Validate that a hash matches the expected format\n */\nexport function isValidHash(hash: string): boolean {\n return /^[a-f0-9]{12}$/.test(hash);\n}\n"],"mappings":";;;;;;;;AAqBA,SAAgB,wBACd,YACA,SACQ;CACR,MAAM,QAAQ,GAAG,WAAW,IAAI,OAAO,QAAQ,QAAQ,CACpD,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,GAAG,CAAC,CACxC,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,GAAG,QAAQ,CACxC,KAAK,KAAK;AACb,QAAO,OAAO,WAAW,MAAM,CAAC,OAAO,MAAM,CAAC,OAAO,MAAM,CAAC,UAAU,GAAG,GAAG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
let lingo_dev_locale_codes = require("lingo.dev/locale-codes");
|
|
3
|
+
|
|
4
|
+
//#region src/utils/is-valid-locale.ts
|
|
5
|
+
function isValidLocale(locale) {
|
|
6
|
+
return (0, lingo_dev_locale_codes.isValidLocale)(locale);
|
|
7
|
+
}
|
|
8
|
+
function parseLocaleOrThrow(locale) {
|
|
9
|
+
if (locale && isValidLocale(locale)) return locale;
|
|
10
|
+
else throw new Error(`Invalid locale: ${locale}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
14
|
+
exports.parseLocaleOrThrow = parseLocaleOrThrow;
|