From 8f6ad2e4315a073dc24c4eb93ac58d9923ebdfcb Mon Sep 17 00:00:00 2001 From: David Turnbull <4712958+davidturnbull@users.noreply.github.com> Date: Mon, 27 Oct 2025 12:32:36 -0700 Subject: [PATCH 1/2] feat: expose response_mime_type for Google Gemini provider --- .changeset/bright-ties-itch.md | 5 +++ i18n.json | 8 +++++ packages/cli/src/cli/loaders/index.ts | 31 +++++++++++++++++-- .../{mdx2 => }/locked-patterns.spec.ts | 14 ++++----- .../cli/loaders/{mdx2 => }/locked-patterns.ts | 27 ++++++++++++---- tsconfig.json | 20 ++++++++++++ 6 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 .changeset/bright-ties-itch.md rename packages/cli/src/cli/loaders/{mdx2 => }/locked-patterns.spec.ts (94%) rename packages/cli/src/cli/loaders/{mdx2 => }/locked-patterns.ts (66%) create mode 100644 tsconfig.json diff --git a/.changeset/bright-ties-itch.md b/.changeset/bright-ties-itch.md new file mode 100644 index 000000000..9ae4c5883 --- /dev/null +++ b/.changeset/bright-ties-itch.md @@ -0,0 +1,5 @@ +--- +"lingo.dev": minor +--- + +Enable locked patterns for all buckets diff --git a/i18n.json b/i18n.json index f838bcb43..d4ffbd3a7 100644 --- a/i18n.json +++ b/i18n.json @@ -27,5 +27,13 @@ "include": ["readme/[locale].md"] } }, + "provider": { + "id": "google", + "model": "gemini-2.5-pro", + "prompt": "Translate from {source} to {target}. Output raw JSON only.", + "settings": { + "temperature": 0 + } + }, "$schema": "https://lingo.dev/schema/i18n.json" } diff --git a/packages/cli/src/cli/loaders/index.ts b/packages/cli/src/cli/loaders/index.ts index a9352d7cc..cce4c39be 100644 --- a/packages/cli/src/cli/loaders/index.ts +++ b/packages/cli/src/cli/loaders/index.ts @@ -42,7 +42,7 @@ import createMdxFrontmatterSplitLoader from "./mdx2/frontmatter-split"; import createMdxCodePlaceholderLoader from "./mdx2/code-placeholder"; import createLocalizableMdxDocumentLoader from "./mdx2/localizable-document"; import createMdxSectionsSplit2Loader from "./mdx2/sections-split-2"; -import createMdxLockedPatternsLoader from "./mdx2/locked-patterns"; +import createLockedPatternsLoader from "./locked-patterns"; import createIgnoredKeysLoader from "./ignored-keys"; import createEjsLoader from "./ejs"; import createEnsureKeyOrderLoader from "./ensure-key-order"; @@ -71,6 +71,7 @@ export default function createBucketLoader( case "android": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createAndroidLoader(), createEnsureKeyOrderLoader(), createFlatLoader(), @@ -82,6 +83,7 @@ export default function createBucketLoader( case "csv": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createCsvLoader(), createEnsureKeyOrderLoader(), createFlatLoader(), @@ -94,6 +96,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "html", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createHtmlLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -103,6 +106,7 @@ export default function createBucketLoader( case "ejs": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createEjsLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -113,6 +117,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "json", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createJsonLoader(), createEnsureKeyOrderLoader(), createFlatLoader(), @@ -125,6 +130,7 @@ export default function createBucketLoader( case "json5": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createJson5Loader(), createEnsureKeyOrderLoader(), createFlatLoader(), @@ -137,6 +143,7 @@ export default function createBucketLoader( case "jsonc": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createJsoncLoader(), createEnsureKeyOrderLoader(), createFlatLoader(), @@ -150,6 +157,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "markdown", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createMarkdownLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -159,6 +167,7 @@ export default function createBucketLoader( case "markdoc": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createMarkdocLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -172,7 +181,7 @@ export default function createBucketLoader( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "mdx", bucketPathPattern), createMdxCodePlaceholderLoader(), - createMdxLockedPatternsLoader(lockedPatterns), + createLockedPatternsLoader(lockedPatterns), createMdxFrontmatterSplitLoader(), createMdxSectionsSplit2Loader(), createLocalizableMdxDocumentLoader(), @@ -186,6 +195,7 @@ export default function createBucketLoader( case "po": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createPoLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -198,6 +208,7 @@ export default function createBucketLoader( case "properties": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createPropertiesLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -207,6 +218,7 @@ export default function createBucketLoader( case "xcode-strings": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createXcodeStringsLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -216,6 +228,7 @@ export default function createBucketLoader( case "xcode-stringsdict": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createXcodeStringsdictLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -228,6 +241,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createPlutilJsonTextLoader(), + createLockedPatternsLoader(lockedPatterns), createJsonLoader(), createXcodeXcstringsLoader(options.defaultLocale), createFlatLoader(), @@ -242,6 +256,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createPlutilJsonTextLoader(), + createLockedPatternsLoader(lockedPatterns), createJsonLoader(), createXcodeXcstringsLoader(options.defaultLocale), createXcodeXcstringsV2Loader(options.defaultLocale), @@ -257,6 +272,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "yaml", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createYamlLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -269,6 +285,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "yaml", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createYamlLoader(), createRootKeyLoader(true), createFlatLoader(), @@ -282,6 +299,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "json", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createJsonLoader(), createEnsureKeyOrderLoader(), createFlutterLoader(), @@ -294,6 +312,7 @@ export default function createBucketLoader( case "xliff": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createXliffLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -305,6 +324,7 @@ export default function createBucketLoader( case "xml": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createXmlLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -316,6 +336,7 @@ export default function createBucketLoader( case "srt": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createSrtLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -335,6 +356,7 @@ export default function createBucketLoader( case "vtt": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createVttLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -344,6 +366,7 @@ export default function createBucketLoader( case "php": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createPhpLoader(), createSyncLoader(), createFlatLoader(), @@ -355,6 +378,7 @@ export default function createBucketLoader( case "vue-json": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createVueJsonLoader(), createSyncLoader(), createFlatLoader(), @@ -371,6 +395,7 @@ export default function createBucketLoader( "typescript", bucketPathPattern, ), + createLockedPatternsLoader(lockedPatterns), createTypescriptLoader(), createFlatLoader(), createEnsureKeyOrderLoader(), @@ -382,6 +407,7 @@ export default function createBucketLoader( case "txt": return composeLoaders( createTextFileLoader(bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createTxtLoader(), createLockedKeysLoader(lockedKeys || []), createIgnoredKeysLoader(ignoredKeys || []), @@ -392,6 +418,7 @@ export default function createBucketLoader( return composeLoaders( createTextFileLoader(bucketPathPattern), createFormatterLoader(options.formatter, "json", bucketPathPattern), + createLockedPatternsLoader(lockedPatterns), createJsonLoader(), createJsonKeysLoader(), createEnsureKeyOrderLoader(), diff --git a/packages/cli/src/cli/loaders/mdx2/locked-patterns.spec.ts b/packages/cli/src/cli/loaders/locked-patterns.spec.ts similarity index 94% rename from packages/cli/src/cli/loaders/mdx2/locked-patterns.spec.ts rename to packages/cli/src/cli/loaders/locked-patterns.spec.ts index 788bb74db..98683958a 100644 --- a/packages/cli/src/cli/loaders/mdx2/locked-patterns.spec.ts +++ b/packages/cli/src/cli/loaders/locked-patterns.spec.ts @@ -1,11 +1,11 @@ import { describe, it, expect } from "vitest"; -import createMdxLockedPatternsLoader from "./locked-patterns"; +import createLockedPatternsLoader from "./locked-patterns"; import dedent from "dedent"; -describe("MDX Locked Patterns Loader", () => { +describe("Locked Patterns Loader", () => { describe("Basic functionality", () => { it("should do nothing when no patterns are provided", async () => { - const loader = createMdxLockedPatternsLoader(); + const loader = createLockedPatternsLoader(); loader.setDefaultLocale("en"); const md = dedent` @@ -33,7 +33,7 @@ describe("MDX Locked Patterns Loader", () => { }); it("should preserve content matching patterns", async () => { - const loader = createMdxLockedPatternsLoader([ + const loader = createLockedPatternsLoader([ "!params", "!! [\\w_]+", "!type [\\w<>\\[\\]\"',]+", @@ -101,7 +101,7 @@ describe("MDX Locked Patterns Loader", () => { describe("Real-world patterns", () => { it("should handle !hover syntax in code blocks", async () => { - const loader = createMdxLockedPatternsLoader([ + const loader = createLockedPatternsLoader([ "// !hover[\\s\\S]*?(?=\\n|$)", "// !hover\\([\\d:]+\\)[\\s\\S]*?(?=\\n|$)", ]); @@ -126,7 +126,7 @@ describe("MDX Locked Patterns Loader", () => { }); it("should handle !! parameter headings", async () => { - const loader = createMdxLockedPatternsLoader(["!! [\\w_]+"]); + const loader = createLockedPatternsLoader(["!! [\\w_]+"]); loader.setDefaultLocale("en"); const md = dedent` @@ -195,7 +195,7 @@ describe("MDX Locked Patterns Loader", () => { }); it("should handle !type, !required, and !values declarations", async () => { - const loader = createMdxLockedPatternsLoader([ + const loader = createLockedPatternsLoader([ "!! [\\w_]+", "!type [\\w<>\\[\\]\"',]+", "!required", diff --git a/packages/cli/src/cli/loaders/mdx2/locked-patterns.ts b/packages/cli/src/cli/loaders/locked-patterns.ts similarity index 66% rename from packages/cli/src/cli/loaders/mdx2/locked-patterns.ts rename to packages/cli/src/cli/loaders/locked-patterns.ts index a239f5b1c..a708c9b13 100644 --- a/packages/cli/src/cli/loaders/mdx2/locked-patterns.ts +++ b/packages/cli/src/cli/loaders/locked-patterns.ts @@ -1,8 +1,6 @@ -import { ILoader } from "../_types"; -import { createLoader } from "../_utils"; -import { md5 } from "../../utils/md5"; -import _ from "lodash"; -import { I18nConfig } from "@lingo.dev/_spec"; +import { ILoader } from "./_types"; +import { createLoader } from "./_utils"; +import { md5 } from "../utils/md5"; /** * Extracts content matching regex patterns and replaces it with placeholders. @@ -46,7 +44,24 @@ function extractLockedPatterns( }; } -export default function createMdxLockedPatternsLoader( +/** + * Creates a loader that preserves content matching regex patterns during translation. + * + * This loader extracts content matching the provided regex patterns and replaces it + * with placeholders before translation. After translation, the placeholders are + * restored with the original content. + * + * This is useful for preserving technical terms, code snippets, URLs, template + * variables, and other non-translatable content within translatable files. + * + * Works with any string-based format (JSON, YAML, XML, Markdown, HTML, etc.). + * Note: For structured formats (JSON, XML, YAML), ensure patterns only match + * content within values, not structural syntax, to avoid breaking parsing. + * + * @param defaultPatterns - Array of regex pattern strings to match and preserve + * @returns A loader that handles pattern locking/unlocking + */ +export default function createLockedPatternsLoader( defaultPatterns?: string[], ): ILoader { return createLoader({ diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..6f7642ea4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@lingo.dev/_sdk": ["packages/sdk/src"], + "@lingo.dev/_sdk/*": ["packages/sdk/src/*"], + "@lingo.dev/_react": ["packages/react/src"], + "@lingo.dev/_react/*": ["packages/react/src/*"], + "@lingo.dev/_react/client": ["packages/react/src/client"], + "@lingo.dev/_react/rsc": ["packages/react/src/rsc"], + "@lingo.dev/_react/react-router": ["packages/react/src/react-router"], + "@lingo.dev/_compiler": ["packages/compiler/src"], + "@lingo.dev/_compiler/*": ["packages/compiler/src/*"], + "@lingo.dev/_locales": ["packages/locales/src"], + "@lingo.dev/_locales/*": ["packages/locales/src/*"], + "@lingo.dev/_spec": ["packages/spec/src"], + "@lingo.dev/_spec/*": ["packages/spec/src/*"] + } + } +} From fe38481084f495a4c77d5919f3f823e9cac2c26b Mon Sep 17 00:00:00 2001 From: Harsh Kumar Gupta <188483296+Harsh9934-debug@users.noreply.github.com> Date: Mon, 1 Dec 2025 19:26:23 +0530 Subject: [PATCH 2/2] Update i18n.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- i18n.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i18n.json b/i18n.json index 437076ae0..1864460c6 100644 --- a/i18n.json +++ b/i18n.json @@ -33,7 +33,8 @@ "model": "gemini-2.5-pro", "prompt": "Translate from {source} to {target}. Output raw JSON only.", "settings": { - "temperature": 0 + "temperature": 0, + "response_mime_type": "application/json" } }, "$schema": "https://lingo.dev/schema/i18n.json"