diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 751cb8b..4ce22b5 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -50,6 +50,42 @@ "generalLabel": { "message": "General" }, + "translationApiLabel": { + "message": "Translation engine" + }, + "googleApiLabel": { + "message": "Google translate API" + }, + "googleApiCaptionLabel": { + "message": "Use Google Translate API. No registration is required." + }, + "deeplApiLabel": { + "message": "DeepL API" + }, + "deeplApiCaptionLabel": { + "message": "Use DeepL API. You must register with DeepL API Free or DeepL API Pro to obtain an authorization key." + }, + "howToUseDeeplLabel": { + "message": "How to register DeepL API" + }, + "deeplPlanLabel": { + "message": "DeepL API plan" + }, + "deeplPlanCaptionLabel": { + "message": "Select the DeepL API plan for which you registered." + }, + "deeplFreeLabel": { + "message": "DeepL API Free" + }, + "deeplProLabel": { + "message": "DeepL API Pro" + }, + "deeplAuthKeyLabel": { + "message": "Authorization key" + }, + "deeplAuthKeyCaptionLabel": { + "message": "Enter the authentication key for the DeepL API." + }, "targetLangCaptionLabel": { "message": "Select the default target language." }, @@ -383,6 +419,9 @@ "unavailableError": { "message": "Error: Service usage limit reached. Please wait a while and try again." }, + "deeplAuthError": { + "message": "Error: Authentication of DeepL API failed. Please set the authentication key and plan correctly on the settings page." + }, "unknownError": { "message": "Error: Unknown error" }, @@ -724,5 +763,20 @@ }, "lang_zu": { "message": "Zulu" + }, + "lang_en-US": { + "message": "English (American)" + }, + "lang_en-GB": { + "message": "English (British)" + }, + "lang_pt-PT": { + "message": "Portuguese" + }, + "lang_pt-BR": { + "message": "Portuguese (Brazilian)" + }, + "lang_zh": { + "message": "Chinese" } } \ No newline at end of file diff --git a/src/common/generateLangOptions.js b/src/common/generateLangOptions.js index eb0ef50..ddfdc22 100644 --- a/src/common/generateLangOptions.js +++ b/src/common/generateLangOptions.js @@ -2,9 +2,11 @@ import browser from "webextension-polyfill"; const alphabeticallySort = (a, b) => a.name.localeCompare(b.name); const langListGoogle = ["af", "sq", "am", "ar", "hy", "az", "eu", "be", "bn", "bs", "bg", "ca", "ceb", "zh-CN", "zh-TW", "co", "hr", "cs", "da", "nl", "en", "eo", "et", "fi", "fr", "fy", "gl", "ka", "de", "el", "gu", "ht", "ha", "haw", "he", "hi", "hmn", "hu", "is", "ig", "id", "ga", "it", "ja", "jv", "kn", "kk", "km", "rw", "ko", "ku", "ky", "lo", "lv", "lt", "lb", "mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "my", "ne", "no", "ny", "or", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm", "gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es", "su", "sw", "sv", "tl", "tg", "ta", "tt", "te", "th", "tr", "tk", "uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "yo", "zu"]; +const langListDeepl = ["bg", "cs", "da", "de", "el", "en-GB", "en-US", "es", "et", "fi", "fr", "hu", "it", "ja", "lt", "lv", "nl", "pl", "pt-PT", "pt-BR", "ro", "ru", "sk", "sl", "sv", "zh"]; -export default () => { - const langOptions = langListGoogle.map(lang => ({ +export default (translationApi) => { + const langList = translationApi === "google" ? langListGoogle : langListDeepl; + const langOptions = langList.map(lang => ({ value: lang, name: browser.i18n.getMessage("lang_" + lang) })); diff --git a/src/common/translate.js b/src/common/translate.js index 755d7e9..3a3c5b7 100644 --- a/src/common/translate.js +++ b/src/common/translate.js @@ -1,30 +1,34 @@ import log from "loglevel"; import axios from "axios"; +import { getSettings } from "src/settings/settings"; + let translationHistory = []; const logDir = "common/translate"; -const getHistory = (sourceWord, sourceLang, targetLang) => { +const getHistory = (sourceWord, sourceLang, targetLang, translationApi) => { const history = translationHistory.find( history => history.sourceWord == sourceWord && history.sourceLang == sourceLang && history.targetLang == targetLang && - history.result.statusText == "OK" + history.translationApi == translationApi && + !history.result.isError ); return history; }; -const setHistory = (sourceWord, sourceLang, targetLang, formattedResult) => { +const setHistory = (sourceWord, sourceLang, targetLang, translationApi, result) => { translationHistory.push({ sourceWord: sourceWord, sourceLang: sourceLang, targetLang: targetLang, - result: formattedResult + translationApi: translationApi, + result: result }); }; -const sendRequest = async (word, sourceLang, targetLang) => { +const sendRequestToGoogle = async (word, sourceLang, targetLang) => { const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&dt=bd&dj=1&q=${encodeURIComponent( word )}`; @@ -64,24 +68,47 @@ const sendRequest = async (word, sourceLang, targetLang) => { }; const sendRequestToDeepL = async (word, sourceLang, targetLang) => { - log.log(logDir, "sendRequestToDeepL()"); - let params = new URLSearchParams(); - - const key = "f5a2c02c-7871-af5c-0d6a-244a9e6d4a1f:fx"; - params.append("auth_key", key); + const authKey = getSettings("deeplAuthKey"); + params.append("auth_key", authKey); params.append("text", word); - params.append("target_lang", "ja"); + params.append("target_lang", targetLang); + const url = getSettings("deeplPlan") === "deeplFree" ? + "https://api-free.deepl.com/v2/translate" : + "https://api.deepl.com/v2/translate"; + const result = await axios.post(url, params).catch(e => e.response); - const url = "https://api-free.deepl.com/v2/translate"; + const resultData = { + resultText: "", + candidateText: "", + sourceLanguage: "", + percentage: 0, + isError: false, + errorMessage: "" + }; - const res = await axios.post(url, params).catch(e => e.response); - console.log("!!!!!!!!!!!!!!!", res); + if (!result || result?.status !== 200) { + resultData.isError = true; + + if (!result || result.status === 0) resultData.errorMessage = browser.i18n.getMessage("networkError"); + else if (result.status === 403) resultData.errorMessage = browser.i18n.getMessage("deeplAuthError"); + else resultData.errorMessage = `${browser.i18n.getMessage("unknownError")} [${result?.status} ${result?.statusText}] ${result?.data.message}`; + + log.error(logDir, "sendRequestToDeepL()", result); + return resultData; + } + + resultData.resultText = result.data.translations[0].text; + resultData.sourceLanguage = result.data.translations[0].detected_source_language.toLowerCase(); + resultData.percentage = 1; + + log.log(logDir, "sendRequestToDeepL()", resultData); + return resultData; }; -export default async (sourceWord, sourceLang = "auto", targetLang) => { - log.log(logDir, "tranlate()", sourceWord, targetLang); +export default async (sourceWord, sourceLang = "auto", targetLang, translationApi) => { + log.log(logDir, "tranlate()", sourceWord, targetLang, translationApi); sourceWord = sourceWord.trim(); if (sourceWord === "") return { @@ -95,7 +122,9 @@ export default async (sourceWord, sourceLang = "auto", targetLang) => { const history = getHistory(sourceWord, sourceLang, targetLang); if (history) return history.result; - const result = await sendRequest(sourceWord, sourceLang, targetLang); - setHistory(sourceWord, sourceLang, targetLang, result); + const result = getSettings("translationApi") === "google" ? + await sendRequestToGoogle(sourceWord, sourceLang, targetLang) : + await sendRequestToDeepL(sourceWord, sourceLang, targetLang); + setHistory(sourceWord, sourceLang, targetLang, translationApi, result); return result; }; diff --git a/src/content/components/TranslateContainer.js b/src/content/components/TranslateContainer.js index f680cab..62af2a5 100644 --- a/src/content/components/TranslateContainer.js +++ b/src/content/components/TranslateContainer.js @@ -26,7 +26,7 @@ const matchesTargetLang = async selectedText => { const isNotText = result.percentage === 0; if (isNotText) return true; - const matchsLangs = targetLang === result.sourceLanguage; + const matchsLangs = targetLang.split("-")[0] === result.sourceLanguage.split("-")[0]; // split("-")[0] : deepLでenとen-USを区別しないために必要 return matchsLangs; }; @@ -90,7 +90,7 @@ export default class TranslateContainer extends Component { const secondLang = getSettings("secondTargetLang"); const shouldSwitchSecondLang = getSettings("ifChangeSecondLangOnPage") && - result.sourceLanguage === targetLang && result.percentage > 0 && targetLang !== secondLang; + result.sourceLanguage.split("-")[0] === targetLang.split("-")[0] && result.percentage > 0 && targetLang !== secondLang; if (shouldSwitchSecondLang) result = await translateText(this.selectedText, secondLang); this.setState({ diff --git a/src/options/components/OptionContainer.js b/src/options/components/OptionContainer.js index 0b52abe..d030628 100644 --- a/src/options/components/OptionContainer.js +++ b/src/options/components/OptionContainer.js @@ -18,6 +18,8 @@ export default props => { } setSettings(id, value); + + if (props.handleChange) props.handleChange(); }; const handleCheckedChange = e => { @@ -113,8 +115,8 @@ export default props => { formId = id; optionForm = (