diff --git a/src/utils/host/__tests__/translate-text.test.tsx b/src/utils/host/__tests__/translate-text.test.tsx index b09c06deb..525c08624 100644 --- a/src/utils/host/__tests__/translate-text.test.tsx +++ b/src/utils/host/__tests__/translate-text.test.tsx @@ -27,11 +27,16 @@ vi.mock("@/utils/host/translate/article-context", () => ({ getOrFetchArticleData: vi.fn(), })) +vi.mock("@/utils/content/language", () => ({ + detectLanguage: vi.fn(), +})) + let mockSendMessage: any let mockMicrosoftTranslate: any let mockGetConfigFromStorage: any let mockGetTranslatePrompt: any let mockGetOrFetchArticleData: any +let mockDetectLanguage: any describe("translate-text", () => { beforeEach(async () => { @@ -43,6 +48,7 @@ describe("translate-text", () => { mockGetConfigFromStorage = vi.mocked((await import("@/utils/config/storage")).getLocalConfig) mockGetTranslatePrompt = vi.mocked((await import("@/utils/prompts/translate")).getTranslatePrompt) mockGetOrFetchArticleData = vi.mocked((await import("@/utils/host/translate/article-context")).getOrFetchArticleData) + mockDetectLanguage = vi.mocked((await import("@/utils/content/language")).detectLanguage) // Mock getOrFetchArticleData to return document.title mockGetOrFetchArticleData.mockImplementation(() => Promise.resolve({ title: document.title })) @@ -132,6 +138,50 @@ describe("translate-text", () => { }) }) + describe("skip language detection with LLM translation provider", () => { + // Text is 14 chars: >= MIN_LENGTH_FOR_SKIP_LLM_DETECTION(10), < MIN_LENGTH_FOR_TARGET_LANG_DETECTION(50) + // so only shouldSkipByLanguage triggers detectLanguage, not isTextAlreadyInTargetLanguage + const japaneseText = "これは日本語のテキスト。" + + it("should not use LLM detection when translation provider is LLM-based", async () => { + const llmConfig = { + ...DEFAULT_CONFIG, + translate: { + ...DEFAULT_CONFIG.translate, + providerId: "openai-default", + page: { ...DEFAULT_CONFIG.translate.page, skipLanguages: ["jpn"] as any }, + }, + languageDetection: { mode: "llm" as const }, + } + mockGetConfigFromStorage.mockResolvedValue(llmConfig) + mockDetectLanguage.mockResolvedValue("jpn") + mockSendMessage.mockResolvedValue("") + + await translateTextForPage(japaneseText) + + expect(mockDetectLanguage).toHaveBeenCalledWith(japaneseText, expect.objectContaining({ enableLLM: false })) + }) + + it("should use LLM detection when translation provider is non-LLM and mode is llm", async () => { + const nonLlmConfig = { + ...DEFAULT_CONFIG, + translate: { + ...DEFAULT_CONFIG.translate, + providerId: "microsoft-translate-default", + page: { ...DEFAULT_CONFIG.translate.page, skipLanguages: ["jpn"] as any }, + }, + languageDetection: { mode: "llm" as const }, + } + mockGetConfigFromStorage.mockResolvedValue(nonLlmConfig) + mockDetectLanguage.mockResolvedValue("jpn") + mockSendMessage.mockResolvedValue("") + + await translateTextForPage(japaneseText) + + expect(mockDetectLanguage).toHaveBeenCalledWith(japaneseText, expect.objectContaining({ enableLLM: true })) + }) + }) + describe("executeTranslate", () => { const langConfig = { sourceCode: "eng" as const, diff --git a/src/utils/host/translate/translate-variants.ts b/src/utils/host/translate/translate-variants.ts index fc2bd6f4c..9ee76b23b 100644 --- a/src/utils/host/translate/translate-variants.ts +++ b/src/utils/host/translate/translate-variants.ts @@ -2,6 +2,7 @@ import type { LangCodeISO6393 } from "@read-frog/definitions" import type { Config, InputTranslationLang } from "@/types/config/config" import { getDetectedCodeFromStorage, getFinalSourceCode } from "@/utils/config/languages" import { resolveProviderConfig } from "@/utils/constants/feature-providers" +import { isLLMProviderConfig } from "@/types/config/provider" import { detectLanguage } from "@/utils/content/language" import { logger } from "@/utils/logger" import { getLocalConfig } from "../../config/storage" @@ -52,7 +53,7 @@ async function translateTextUsingPageConfig( const shouldSkip = await shouldSkipByLanguage( preparedText, skipLanguages, - config.languageDetection.mode === "llm", + config.languageDetection.mode === "llm" && !isLLMProviderConfig(providerConfig), ) if (shouldSkip) { logger.info(`translateTextForPage: skipping translation because text is in skip language list. text: ${preparedText}`)