From 2f4f8e99ea012eefe10c54f61ba80c415e64d526 Mon Sep 17 00:00:00 2001 From: xixu-me Date: Wed, 19 Aug 2026 17:16:19 +0800 Subject: [PATCH] fix(google): route fallback through XDPL --- src/lib/services/googleTranslate.ts | 27 +++++++++++++--------- tests/lib/services/googleTranslate.test.ts | 21 ++++++++++++++++- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/lib/services/googleTranslate.ts b/src/lib/services/googleTranslate.ts index 41cf08b..8377569 100644 --- a/src/lib/services/googleTranslate.ts +++ b/src/lib/services/googleTranslate.ts @@ -27,10 +27,20 @@ export async function translateWithGoogle( try { const { text, source_lang, target_lang } = params; - // Construct the request to Google Translate's internal API - const googleApiUrl = new URL( - "https://translate.googleapis.com/translate_a/single" - ); + const proxyUrls = String(config?.env?.PROXY_URLS || "") + .split(",") + .filter(Boolean); + const proxyUrl = proxyUrls[Math.floor(Math.random() * proxyUrls.length)]; + const attempts = [ + [ + proxyUrl + ? new URL("/google/translate_a/single", proxyUrl).toString() + : "https://translate.googleapis.com/translate_a/single", + "gtx", + ], + ["https://translate.googleapis.com/translate_a/single", "gtx"], + ["https://translate.google.com/translate_a/single", "dict-chrome-ex"], + ]; const googleParams = new URLSearchParams(); googleParams.append("client", "gtx"); // Google Translate web client googleParams.append( @@ -55,16 +65,11 @@ export async function translateWithGoogle( }; let googleResponse: Response | undefined; - for (const [hostname, client] of [ - ["translate.googleapis.com", "gtx"], - ["translate.google.com", "gtx"], - ["translate.googleapis.com", "dict-chrome-ex"], - ]) { - googleApiUrl.hostname = hostname; + for (const [endpoint, client] of attempts) { googleParams.set("client", client); requestInit.body = googleParams.toString(); try { - googleResponse = await fetch(googleApiUrl.toString(), requestInit); + googleResponse = await fetch(endpoint, requestInit); if (googleResponse.ok) break; } catch { // Try the compatible fallback host. diff --git a/tests/lib/services/googleTranslate.test.ts b/tests/lib/services/googleTranslate.test.ts index 588049e..6e48117 100644 --- a/tests/lib/services/googleTranslate.test.ts +++ b/tests/lib/services/googleTranslate.test.ts @@ -76,6 +76,25 @@ describe("Google Translate Service", () => { expect(result.data).toBeNull(); }); + it("should prefer an XDPL proxy when configured", async () => { + global.fetch = jest.fn().mockResolvedValue({ + ok: true, + json: () => + Promise.resolve([[["Hola", "Hello", null, null, 10]], null, "en"]), + }); + + const result = await translateWithGoogle( + { text: "Hello", source_lang: "en", target_lang: "es" }, + { env: { PROXY_URLS: "https://0.example.com/jsonrpc" } } + ); + + expect(result.code).toBe(200); + expect(fetch).toHaveBeenCalledWith( + "https://0.example.com/google/translate_a/single", + expect.any(Object) + ); + }); + it("should use the compatible host when the primary is unavailable", async () => { global.fetch = jest .fn() @@ -96,7 +115,7 @@ describe("Google Translate Service", () => { expect(result.code).toBe(200); expect(fetch).toHaveBeenCalledTimes(3); expect(fetch).toHaveBeenLastCalledWith( - expect.stringContaining("translate.googleapis.com"), + expect.stringContaining("translate.google.com"), expect.objectContaining({ body: expect.stringContaining("client=dict-chrome-ex"), })