From 297d862c9d1d3bd87f18b75b0510added66af624 Mon Sep 17 00:00:00 2001 From: manerakai Date: Wed, 30 Aug 2023 11:57:46 +0000 Subject: [PATCH] Added gofiber git-svn-id: file:///srv/svn/repo/mai/trunk@15 e410bdd4-646f-c54f-a7ce-fffcc4f439ae --- engines/engine.go | 22 ++- engines/google.go | 36 ++-- engines/iciba.go | 396 +++++++++++++++++++------------------- engines/language.go | 5 - engines/libretranslate.go | 52 +++-- engines/reverso.go | 83 ++++---- web/go.mod | 5 +- web/go.sum | 36 ++++ web/main.go | 39 +++- 9 files changed, 365 insertions(+), 309 deletions(-) delete mode 100644 engines/language.go diff --git a/engines/engine.go b/engines/engine.go index 10463a1..1be4c20 100644 --- a/engines/engine.go +++ b/engines/engine.go @@ -1,16 +1,24 @@ package engines type TranslationResult struct { - SourceLanguage Language - TranslatedText string + SourceLanguage string `json:"source_language"` + TranslatedText string `json:"translated_text"` } type Engine interface { InternalName() string DisplayName() string - SourceLanguages() ([]Language, error) - TargetLanguages() ([]Language, error) - Translate(text string, from, to Language) (TranslationResult, error) - SupportsAutodetect() bool - DetectLanguage(text string) (Language, error) + SourceLanguages() (Language, error) + TargetLanguages() (Language, error) + Translate(text string, from, to string) (TranslationResult, error) + DetectLanguage(text string) (string, error) +} + +type Language map[string]string + +var Engines = map[string]Engine{ + "google": &GoogleTranslate{}, + "icibia": &ICIBA{}, + "libre": &LibreTranslate{}, + "reverseo": &Reverso{}, } diff --git a/engines/google.go b/engines/google.go index d7075d8..d178f54 100644 --- a/engines/google.go +++ b/engines/google.go @@ -14,7 +14,7 @@ func (_ *GoogleTranslate) InternalName() string { return "google" } func (_ *GoogleTranslate) DisplayName() string { return "Google" } -func (_ *GoogleTranslate) getLangs(type_ string) ([]Language, error) { +func (_ *GoogleTranslate) getLangs(type_ string) (Language, error) { var langsType string switch type_ { case "source": @@ -27,12 +27,7 @@ func (_ *GoogleTranslate) getLangs(type_ string) ([]Language, error) { panic(fmt.Errorf("getLangs was passed an invalid language type: %s", langsType)) } - requestURL, err := url.Parse("https://translate.google.com/m") - - if err != nil { - // The URL is constant, so it should never fail. - panic(err) - } + requestURL, _ := url.Parse("https://translate.google.com/m") query := url.Values{} query.Add("mui", langsType) @@ -53,7 +48,7 @@ func (_ *GoogleTranslate) getLangs(type_ string) ([]Language, error) { return nil, err } - var langs []Language + var langs Language doc.Find(".language-item").Each(func(_ int, s *goquery.Selection) { a := s.Find("a").First() @@ -77,36 +72,33 @@ func (_ *GoogleTranslate) getLangs(type_ string) ([]Language, error) { return } - langs = append(langs, Language{Name: a.Text(), Code: langCode}) + langs[langCode] = a.Text() }) return langs, nil } -func (e *GoogleTranslate) SourceLanguages() ([]Language, error) { +func (e *GoogleTranslate) SourceLanguages() (Language, error) { return e.getLangs("source") } -func (e *GoogleTranslate) TargetLanguages() ([]Language, error) { +func (e *GoogleTranslate) TargetLanguages() (Language, error) { return e.getLangs("target") } -func (_ *GoogleTranslate) SupportsAutodetect() bool { return true } +func (_ *GoogleTranslate) DetectLanguage(text string) (string, error) { return "", nil } -func (_ *GoogleTranslate) DetectLanguage(text string) (Language, error) { return Language{}, nil } +func (_ *GoogleTranslate) Translate(text string, from, to string) (TranslationResult, error) { + requestURL, _ := url.Parse("https://translate.google.com/m") -func (_ *GoogleTranslate) Translate(text string, from, to Language) (TranslationResult, error) { - requestURL, err := url.Parse("https://translate.google.com/m") - - if err != nil { - // The URL is constant, so it should never fail. - panic(err) + if from == "" { + from = "auto" } query := url.Values{} - query.Add("sl", from.Code) - query.Add("tl", to.Code) - query.Add("hl", to.Code) + query.Add("sl", from) + query.Add("tl", to) + query.Add("hl", to) query.Add("q", text) requestURL.RawQuery = query.Encode() diff --git a/engines/iciba.go b/engines/iciba.go index b597cc0..4a8f1e7 100644 --- a/engines/iciba.go +++ b/engines/iciba.go @@ -16,7 +16,7 @@ func (_ *ICIBA) InternalName() string { return "iciba" } func (_ *ICIBA) DisplayName() string { return "iCIBA" } -var icibaLanguages = []Language{ +var icibaLanguages = Language{ // ICIBA does have an API, but they return Chinese names. // For languages already present in Google translate, the English // names in that engine file are used; Otherwise official names @@ -25,199 +25,197 @@ var icibaLanguages = []Language{ // Missing "cni", "kbh", "tmh" // due to conflict between ISO-639 table and Chinese label // one "//" means on iciba but not on google - {Name: "Achinese", Code: "ace"}, // - {Name: "Achuar-Shiwiar", Code: "acu"}, // - {Name: "Afrikaans", Code: "af"}, - {Name: "Aguaruna", Code: "agr"}, // - {Name: "Akawaio", Code: "ake"}, // - {Name: "Albanian", Code: "sq"}, - {Name: "Amharic", Code: "am"}, - {Name: "Arabic", Code: "ar"}, - {Name: "Armenian", Code: "hy"}, - {Name: "Azerbaijani", Code: "az"}, - {Name: "Barasana-Eduria", Code: "bsn"}, // - {Name: "Bashkir", Code: "ba"}, // - {Name: "Basque", Code: "eu"}, - {Name: "Belarusian", Code: "be"}, - {Name: "Bemba", Code: "bem"}, // - {Name: "Bengali", Code: "bn"}, - {Name: "Berber", Code: "ber"}, // - {Name: "Bislama", Code: "bi"}, // - {Name: "Bosnian", Code: "bs"}, - {Name: "Breton", Code: "br"}, // - {Name: "Bulgarian", Code: "bg"}, - {Name: "Cabécar", Code: "cjp"}, // - {Name: "Cantonese", Code: "yue"}, - {Name: "Catalan", Code: "ca"}, - {Name: "Cebuano", Code: "ceb"}, - {Name: "Chamorro", Code: "cha"}, // - {Name: "Cherokee", Code: "chr"}, // - {Name: "Chichewa", Code: "ny"}, - {Name: "Chinese (Simplified)", Code: "zh"}, // "zh-cn" on Google - {Name: "Chinese (Traditional)", Code: "cht"}, // "zh-tw" on Google - {Name: "Chuvash", Code: "cv"}, - {Name: "Coptic", Code: "cop"}, // - {Name: "Corsican", Code: "co"}, - {Name: "Croatian", Code: "hr"}, - {Name: "Czech", Code: "cs"}, - {Name: "Danish", Code: "da"}, - {Name: "Dhivehi", Code: "dv"}, // - {Name: "Dinka", Code: "dik"}, // - {Name: "Dutch", Code: "nl"}, - {Name: "Dzongkha", Code: "dz"}, // - {Name: "English", Code: "en"}, - {Name: "Esperanto", Code: "eo"}, - {Name: "Estonian", Code: "et"}, - {Name: "Ewe", Code: "ee"}, // - {Name: "Faroese", Code: "fo"}, // - {Name: "Fijian", Code: "fj"}, // - {Name: "Filipino", Code: "fil"}, // "tl" on Google - {Name: "Finnish", Code: "fi"}, - {Name: "French", Code: "fr"}, - {Name: "Frisian", Code: "fy"}, - {Name: "Galela", Code: "gbi"}, // - {Name: "Galician", Code: "gl"}, - {Name: "Ganda", Code: "lg"}, // - {Name: "Georgian", Code: "jy"}, // "ka" on Google - {Name: "German", Code: "de"}, - {Name: "Greek", Code: "el"}, - {Name: "Guerrero Amuzgo", Code: "amu"}, // - {Name: "Gujarati", Code: "gu"}, - {Name: "Haitian Creole", Code: "ht"}, - {Name: "Hausa", Code: "ha"}, - {Name: "Hawaiian", Code: "haw"}, - {Name: "Hebrew", Code: "he"}, // "iw" on Google - {Name: "Hindi", Code: "hi"}, - {Name: "Hmong Daw", Code: "mww"}, // - {Name: "Hmong", Code: "hmn"}, // not in iciba - {Name: "Hungarian", Code: "hu"}, - {Name: "Icelandic", Code: "is"}, - {Name: "Igbo", Code: "ig"}, - {Name: "Indonesian", Code: "id"}, - {Name: "Irish", Code: "ga"}, - {Name: "Italian", Code: "it"}, - {Name: "Jacalteco", Code: "jac"}, // - {Name: "Japanese", Code: "ja"}, - {Name: "Javanese", Code: "jv"}, // "jw" on Google - {Name: "Kabyle", Code: "kab"}, // - {Name: "Kannada", Code: "kn"}, - {Name: "Kaqchikel", Code: "cak"}, // - {Name: "Kazakh", Code: "ka"}, // Google only has "kk" - {Name: "Kazakh (Cyrillic)", Code: "kk"}, // Google has it as just "Kazakh" - {Name: "Kekchí", Code: "kek"}, // - {Name: "Khmer", Code: "km"}, - {Name: "Kinyarwanda", Code: "rw"}, - {Name: "Kongo", Code: "kg"}, // - {Name: "Korean", Code: "ko"}, - {Name: "Kurdish (Kurmanji)", Code: "ku"}, - {Name: "Kyrgyz", Code: "ky"}, - {Name: "Lao", Code: "lo"}, - {Name: "Latin", Code: "la"}, - {Name: "Latvian", Code: "lv"}, - {Name: "Lingala", Code: "ln"}, // - {Name: "Lithuanian", Code: "lt"}, - {Name: "Lukpa", Code: "dop"}, // - {Name: "Luxembourgish", Code: "lb"}, - {Name: "Macedonian", Code: "mk"}, - {Name: "Malagasy", Code: "mg"}, - {Name: "Malay", Code: "ms"}, - {Name: "Malayalam", Code: "ml"}, - {Name: "Maltese", Code: "mt"}, - {Name: "Mam", Code: "mam"}, // - {Name: "Manx", Code: "gv"}, // - {Name: "Maori", Code: "mi"}, - {Name: "Marathi", Code: "mr"}, - {Name: "Mari (Eastern)", Code: "mhr"}, // - {Name: "Mari (Western)", Code: "mrj"}, // - {Name: "Mongolian", Code: "mn"}, - {Name: "Montenegrin", Code: "me"}, // - {Name: "Myanmar (Burmese)", Code: "my"}, - {Name: "Nahuatl", Code: "nhg"}, // - {Name: "Ndyuka", Code: "djk"}, // - {Name: "Nepali", Code: "ne"}, - {Name: "Norwegian", Code: "no"}, - {Name: "Odia (Oriya)", Code: "or"}, - {Name: "Ojibwa", Code: "ojb"}, - {Name: "Oromo", Code: "om"}, // - {Name: "Ossetian", Code: "os"}, // - {Name: "Paite", Code: "pck"}, // - {Name: "Papiamento", Code: "pap"}, // - {Name: "Pashto", Code: "ps"}, - {Name: "Persian", Code: "fa"}, - {Name: "Polish", Code: "pl"}, - {Name: "Portuguese", Code: "pt"}, - {Name: "Potawatomi", Code: "pot"}, // - {Name: "Punjabi", Code: "pa"}, - {Name: "Querétaro Otomi", Code: "otq"}, // - {Name: "Quiché", Code: "quc"}, // - {Name: "Quichua", Code: "quw"}, // - {Name: "Quiotepec Chinantec", Code: "chq"}, // - {Name: "Romani", Code: "rmn"}, // - {Name: "Romanian", Code: "ro"}, - {Name: "Rundi", Code: "rn"}, // - {Name: "Russian", Code: "ru"}, - {Name: "Samoan", Code: "sm"}, - {Name: "Sango", Code: "sg"}, // - {Name: "Scots Gaelic", Code: "gd"}, - {Name: "Serbian", Code: "sr"}, - {Name: "Seselwa Creole French", Code: "crs"}, // - {Name: "Sesotho", Code: "st"}, - {Name: "Shona", Code: "sn"}, - {Name: "Shuar", Code: "jiv"}, // - {Name: "Sindhi", Code: "sd"}, - {Name: "Sinhala", Code: "si"}, - {Name: "Slovak", Code: "sk"}, - {Name: "Slovenian", Code: "sl"}, - {Name: "Somali", Code: "so"}, - {Name: "Spanish", Code: "es"}, - {Name: "Sundanese", Code: "su"}, - {Name: "Swahili", Code: "sw"}, - {Name: "Swedish", Code: "sv"}, - {Name: "Syriac", Code: "syc"}, // considered "extinct" but is somehow supported - {Name: "Tachelhit", Code: "shi"}, // - {Name: "Tahitian", Code: "ty"}, // - {Name: "Tajik", Code: "tg"}, - {Name: "Tamil", Code: "ta"}, - {Name: "Tatar", Code: "tt"}, - {Name: "Telugu", Code: "te"}, - {Name: "Tetum", Code: "tet"}, // - {Name: "Thai", Code: "th"}, - {Name: "Tigre", Code: "ti"}, // - {Name: "Tiwi", Code: "tw"}, // - {Name: "Tok Pisin", Code: "tpi"}, // - {Name: "Tonga", Code: "to"}, // - {Name: "Tsonga", Code: "ts"}, - {Name: "Tswana", Code: "tn"}, // - {Name: "Turkish", Code: "tr"}, - {Name: "Turkmen", Code: "tk"}, - {Name: "Udmurt", Code: "udm"}, // - {Name: "Ukrainian", Code: "uk"}, - {Name: "Uma", Code: "ppk"}, // - {Name: "Urdu", Code: "ur"}, - {Name: "Uspanteco", Code: "usp"}, // - {Name: "Uyghur", Code: "uy"}, // "ug" on Google - {Name: "Uzbek", Code: "uz"}, - {Name: "Venda", Code: "ve"}, // - {Name: "Vietnamese", Code: "vi"}, - {Name: "Waray", Code: "war"}, // - {Name: "Welsh", Code: "cy"}, - {Name: "Wolaitta", Code: "wal"}, // - {Name: "Wolof", Code: "wol"}, - {Name: "Xhosa", Code: "xh"}, - {Name: "Yiddish", Code: "yi"}, - {Name: "Yoruba", Code: "yo"}, - {Name: "Yucatán Maya", Code: "yua"}, // - {Name: "Zarma", Code: "dje"}, // - {Name: "Zulu", Code: "zu"}, + "ace": "Achinese", // + "acu": "Achuar-Shiwiar", // + "af": "Afrikaans", + "agr": "Aguaruna", // + "ake": "Akawaio", // + "sq": "Albanian", + "am": "Amharic", + "ar": "Arabic", + "hy": "Armenian", + "az": "Azerbaijani", + "bsn": "Barasana-Eduria", // + "ba": "Bashkir", // + "eu": "Basque", + "be": "Belarusian", + "bem": "Bemba", // + "bn": "Bengali", + "ber": "Berber", // + "bi": "Bislama", // + "bs": "Bosnian", + "br": "Breton", // + "bg": "Bulgarian", + "cjp": "Cabécar", // + "yue": "Cantonese", + "ca": "Catalan", + "ceb": "Cebuano", + "cha": "Chamorro", // + "chr": "Cherokee", // + "ny": "Chichewa", + "zh": "Chinese (Simplified)", // "zh-cn" on Google + "cht": "Chinese (Traditional)", // "zh-tw" on Google + "cv": "Chuvash", + "cop": "Coptic", // + "co": "Corsican", + "hr": "Croatian", + "cs": "Czech", + "da": "Danish", + "dv": "Dhivehi", // + "dik": "Dinka", // + "nl": "Dutch", + "dz": "Dzongkha", // + "en": "English", + "eo": "Esperanto", + "et": "Estonian", + "ee": "Ewe", // + "fo": "Faroese", // + "fj": "Fijian", // + "fil": "Filipino", // "tl" on Google + "fi": "Finnish", + "fr": "French", + "fy": "Frisian", + "gbi": "Galela", // + "gl": "Galician", + "lg": "Ganda", // + "jy": "Georgian", // "ka" on Google + "de": "German", + "el": "Greek", + "amu": "Guerrero Amuzgo", // + "gu": "Gujarati", + "ht": "Haitian Creole", + "ha": "Hausa", + "haw": "Hawaiian", + "he": "Hebrew", // "iw" on Google + "hi": "Hindi", + "mww": "Hmong Daw", // + "hmn": "Hmong", // not in iciba + "hu": "Hungarian", + "is": "Icelandic", + "ig": "Igbo", + "id": "Indonesian", + "ga": "Irish", + "it": "Italian", + "jac": "Jacalteco", // + "ja": "Japanese", + "jv": "Javanese", // "jw" on Google + "kab": "Kabyle", // + "kn": "Kannada", + "cak": "Kaqchikel", // + "ka": "Kazakh", // Google only has "kk" + "kk": "Kazakh (Cyrillic)", // Google has it as just "Kazakh" + "kek": "Kekchí", // + "km": "Khmer", + "rw": "Kinyarwanda", + "kg": "Kongo", // + "ko": "Korean", + "ku": "Kurdish (Kurmanji)", + "ky": "Kyrgyz", + "lo": "Lao", + "la": "Latin", + "lv": "Latvian", + "ln": "Lingala", // + "lt": "Lithuanian", + "dop": "Lukpa", // + "lb": "Luxembourgish", + "mk": "Macedonian", + "mg": "Malagasy", + "ms": "Malay", + "ml": "Malayalam", + "mt": "Maltese", + "mam": "Mam", // + "gv": "Manx", // + "mi": "Maori", + "mr": "Marathi", + "mhr": "Mari (Eastern)", // + "mrj": "Mari (Western)", // + "mn": "Mongolian", + "me": "Montenegrin", // + "my": "Myanmar (Burmese)", + "nhg": "Nahuatl", // + "djk": "Ndyuka", // + "ne": "Nepali", + "no": "Norwegian", + "or": "Odia (Oriya)", + "ojb": "Ojibwa", + "om": "Oromo", // + "os": "Ossetian", // + "pck": "Paite", // + "pap": "Papiamento", // + "ps": "Pashto", + "fa": "Persian", + "pl": "Polish", + "pt": "Portuguese", + "pot": "Potawatomi", // + "pa": "Punjabi", + "otq": "Querétaro Otomi", // + "quc": "Quiché", // + "quw": "Quichua", // + "chq": "Quiotepec Chinantec", // + "rmn": "Romani", // + "ro": "Romanian", + "rn": "Rundi", // + "ru": "Russian", + "sm": "Samoan", + "sg": "Sango", // + "gd": "Scots Gaelic", + "sr": "Serbian", + "crs": "Seselwa Creole French", // + "st": "Sesotho", + "sn": "Shona", + "jiv": "Shuar", // + "sd": "Sindhi", + "si": "Sinhala", + "sk": "Slovak", + "sl": "Slovenian", + "so": "Somali", + "es": "Spanish", + "su": "Sundanese", + "sw": "Swahili", + "sv": "Swedish", + "syc": "Syriac", // considered "extinct" but is somehow supported + "shi": "Tachelhit", // + "ty": "Tahitian", // + "tg": "Tajik", + "ta": "Tamil", + "tt": "Tatar", + "te": "Telugu", + "tet": "Tetum", // + "th": "Thai", + "ti": "Tigre", // + "tw": "Tiwi", // + "tpi": "Tok Pisin", // + "to": "Tonga", // + "ts": "Tsonga", + "tn": "Tswana", // + "tr": "Turkish", + "tk": "Turkmen", + "udm": "Udmurt", // + "uk": "Ukrainian", + "ppk": "Uma", // + "ur": "Urdu", + "usp": "Uspanteco", // + "uy": "Uyghur", // "ug" on Google + "uz": "Uzbek", + "ve": "Venda", // + "vi": "Vietnamese", + "war": "Waray", // + "cy": "Welsh", + "wal": "Wolaitta", // + "wol": "Wolof", + "xh": "Xhosa", + "yi": "Yiddish", + "yo": "Yoruba", + "yua": "Yucatán Maya", // + "dje": "Zarma", // + "zu": "Zulu", } -func (_ *ICIBA) SourceLanguages() ([]Language, error) { return icibaLanguages, nil } +func (_ *ICIBA) SourceLanguages() (Language, error) { return icibaLanguages, nil } -func (_ *ICIBA) TargetLanguages() ([]Language, error) { return icibaLanguages, nil } +func (_ *ICIBA) TargetLanguages() (Language, error) { return icibaLanguages, nil } -func (_ *ICIBA) SupportsAutodetect() bool { return true } - -func (_ *ICIBA) DetectLanguage(text string) (Language, error) { return Language{}, nil } +func (_ *ICIBA) DetectLanguage(text string) (string, error) { return "", nil } type icibaTranslateResponse struct { Content struct { @@ -226,7 +224,7 @@ type icibaTranslateResponse struct { } `json:"content"` } -func (_ *ICIBA) Translate(text string, from, to Language) (TranslationResult, error) { +func (_ *ICIBA) Translate(text string, from, to string) (TranslationResult, error) { requestURL, err := url.Parse("https://ifanyi.iciba.com/index.php") if err != nil { @@ -247,8 +245,8 @@ func (_ *ICIBA) Translate(text string, from, to Language) (TranslationResult, er requestURL.RawQuery = query.Encode() formData := url.Values{} - formData.Add("from", from.Code) - formData.Add("to", to.Code) + formData.Add("from", from) + formData.Add("to", to) formData.Add("q", text) response, err := http.PostForm(requestURL.String(), formData) @@ -269,17 +267,17 @@ func (_ *ICIBA) Translate(text string, from, to Language) (TranslationResult, er return TranslationResult{}, err } - var sourceLanguage Language + var sourceLanguage string - for _, lang := range icibaLanguages { - if lang.Code == responseJSON.Content.From { - sourceLanguage = lang + for code := range icibaLanguages { + if code == responseJSON.Content.From { + sourceLanguage = code break } } - if sourceLanguage == (Language{}) { - return TranslationResult{SourceLanguage: from, TranslatedText: responseJSON.Content.Out}, + if sourceLanguage == "" { + return TranslationResult{TranslatedText: responseJSON.Content.Out}, fmt.Errorf("language code \"%s\" is not in iCIBA's language list", responseJSON.Content.From) } diff --git a/engines/language.go b/engines/language.go deleted file mode 100644 index 5dad0f6..0000000 --- a/engines/language.go +++ /dev/null @@ -1,5 +0,0 @@ -package engines - -type Language struct { - Name, Code string -} diff --git a/engines/libretranslate.go b/engines/libretranslate.go index f97e2d8..564f49f 100644 --- a/engines/libretranslate.go +++ b/engines/libretranslate.go @@ -27,12 +27,7 @@ func (_ *LibreTranslate) InternalName() string { return "libre" } func (_ *LibreTranslate) DisplayName() string { return "LibreTranslate" } -type libreLanguagesResponse []struct { - Name string `json:"name"` - Code string `json:"code"` -} - -func (e *LibreTranslate) getLangs() ([]Language, error) { +func (e *LibreTranslate) getLangs() (Language, error) { response, err := http.Get(e.InstanceURL + "/languages") if err != nil { @@ -45,34 +40,35 @@ func (e *LibreTranslate) getLangs() ([]Language, error) { return nil, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode) } - var langsResponse libreLanguagesResponse + var langsResponse []struct { + Name string `json:"name"` + Code string `json:"code"` + } if err := json.NewDecoder(response.Body).Decode(&langsResponse); err != nil { return nil, err } - langs := make([]Language, len(langsResponse)) + langs := Language{} - for i, lang := range langsResponse { - langs[i] = Language{Name: lang.Name, Code: lang.Code} + for _, lang := range langsResponse { + langs[lang.Code] = lang.Name } return langs, nil } -func (e *LibreTranslate) SourceLanguages() ([]Language, error) { return e.getLangs() } +func (e *LibreTranslate) SourceLanguages() (Language, error) { return e.getLangs() } -func (e *LibreTranslate) TargetLanguages() ([]Language, error) { return e.getLangs() } - -func (_ *LibreTranslate) SupportsAutodetect() bool { return true } +func (e *LibreTranslate) TargetLanguages() (Language, error) { return e.getLangs() } type libreDetectResponse []struct { Confidence float64 `json:"confidence"` LanguageCode string `json:"language"` } -func (e *LibreTranslate) DetectLanguage(text string) (Language, error) { +func (e *LibreTranslate) DetectLanguage(text string) (string, error) { formData := map[string]string{"q": text} if e.APIKey != "" { @@ -82,25 +78,25 @@ func (e *LibreTranslate) DetectLanguage(text string) (Language, error) { formDataJSON, err := json.Marshal(formData) if err != nil { - return Language{}, err + return "", err } response, err := http.Post(e.InstanceURL+"/detect", "application/json", bytes.NewBuffer(formDataJSON)) if err != nil { - return Language{}, err + return "", err } defer response.Body.Close() if response.StatusCode != 200 { - return Language{}, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode) + return "", fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode) } var langs libreDetectResponse if err := json.NewDecoder(response.Body).Decode(&langs); err != nil { - return Language{}, err + return "", err } maxConfidenceLang := langs[0] @@ -114,27 +110,27 @@ func (e *LibreTranslate) DetectLanguage(text string) (Language, error) { engineLangs, err := e.getLangs() if err != nil { - return Language{}, err + return "", err } - for _, lang := range engineLangs { - if lang.Code == maxConfidenceLang.LanguageCode { - return lang, nil + for code := range engineLangs { + if code == maxConfidenceLang.LanguageCode { + return code, nil } } - return Language{}, fmt.Errorf("language code \"%s\" is not in the instance's language list", maxConfidenceLang.LanguageCode) + return "", fmt.Errorf("language code \"%s\" is not in the instance's language list", maxConfidenceLang.LanguageCode) } type libreTranslateResponse struct { TranslatedText string `json:"translatedText"` } -func (e *LibreTranslate) Translate(text string, from, to Language) (TranslationResult, error) { +func (e *LibreTranslate) Translate(text string, from, to string) (TranslationResult, error) { formData := map[string]string{ "q": text, - "source": from.Code, - "target": to.Code, + "source": from, + "target": to, } if e.APIKey != "" { @@ -165,5 +161,5 @@ func (e *LibreTranslate) Translate(text string, from, to Language) (TranslationR return TranslationResult{}, err } - return TranslationResult{SourceLanguage: from, TranslatedText: responseJSON.TranslatedText}, nil + return TranslationResult{TranslatedText: responseJSON.TranslatedText}, nil } diff --git a/engines/reverso.go b/engines/reverso.go index db1cebc..e63fb70 100644 --- a/engines/reverso.go +++ b/engines/reverso.go @@ -14,39 +14,37 @@ func (_ *Reverso) InternalName() string { return "reverso" } func (_ *Reverso) DisplayName() string { return "Reverso" } -var reversoLangs = []Language{ - {Name: "Arabic", Code: "ara"}, - {Name: "Chinese (Simplified)", Code: "chi"}, // marketed as just "Chinese" - {Name: "Czech", Code: "cze"}, - {Name: "Danish", Code: "dan"}, - {Name: "Dutch", Code: "dut"}, - {Name: "English", Code: "eng"}, - {Name: "French", Code: "fra"}, - {Name: "German", Code: "ger"}, - {Name: "Hebrew", Code: "heb"}, - {Name: "Hindi", Code: "hin"}, - {Name: "Hungarian", Code: "hun"}, - {Name: "Italian", Code: "ita"}, - {Name: "Japanese", Code: "jpn"}, - {Name: "Korean", Code: "kor"}, - {Name: "Persian", Code: "per"}, - {Name: "Polish", Code: "pol"}, - {Name: "Portuguese", Code: "por"}, - {Name: "Romanian", Code: "rum"}, - {Name: "Russian", Code: "rus"}, - {Name: "Slovak", Code: "slo"}, - {Name: "Spanish", Code: "spa"}, - {Name: "Swedish", Code: "swe"}, - {Name: "Thai", Code: "tha"}, - {Name: "Turkish", Code: "tur"}, - {Name: "Ukrainian", Code: "ukr"}, +var reversoLangs = Language{ + "ara": "Arabic", + "chi": "Chinese (Simplified)", // marketed as just "Chinese" + "cze": "Czech", + "dan": "Danish", + "dut": "Dutch", + "eng": "English", + "fra": "French", + "ger": "German", + "heb": "Hebrew", + "hin": "Hindi", + "hun": "Hungarian", + "ita": "Italian", + "jpn": "Japanese", + "kor": "Korean", + "per": "Persian", + "pol": "Polish", + "por": "Portuguese", + "rum": "Romanian", + "rus": "Russian", + "slo": "Slovak", + "spa": "Spanish", + "swe": "Swedish", + "tha": "Thai", + "tur": "Turkish", + "ukr": "Ukrainian", } -func (_ *Reverso) SourceLanguages() ([]Language, error) { return reversoLangs, nil } +func (_ *Reverso) SourceLanguages() (Language, error) { return reversoLangs, nil } -func (_ *Reverso) TargetLanguages() ([]Language, error) { return reversoLangs, nil } - -func (_ *Reverso) SupportsAutodetect() bool { return true } +func (_ *Reverso) TargetLanguages() (Language, error) { return reversoLangs, nil } type reversoAPIResponse struct { LanguageDetection struct { @@ -55,12 +53,12 @@ type reversoAPIResponse struct { Translation []string `json:"translation"` } -func (e *Reverso) callAPI(text string, from, to Language) (reversoAPIResponse, error) { +func (e *Reverso) callAPI(text string, from, to string) (reversoAPIResponse, error) { // `contextResults` must be false for language detection formData := map[string]interface{}{ "format": "text", - "from": from.Code, - "to": to.Code, + "from": from, + "to": to, "input": text, "options": map[string]interface{}{ "sentenceSplitter": false, @@ -109,27 +107,27 @@ func (e *Reverso) callAPI(text string, from, to Language) (reversoAPIResponse, e return result, nil } -func (e *Reverso) DetectLanguage(text string) (Language, error) { +func (e *Reverso) DetectLanguage(text string) (string, error) { // Any language pair works here, does not affect result - r, err := e.callAPI(text, reversoLangs[0], reversoLangs[1]) + r, err := e.callAPI(text, "ara", "chi") if err != nil { - return Language{}, err + return "", err } langCode := r.LanguageDetection.DetectedLanguage - for _, lang := range reversoLangs { - if lang.Code == langCode { - return lang, nil + for code := range reversoLangs { + if code == langCode { + return code, nil } } - return Language{}, fmt.Errorf("language code \"%s\" is not in Reverso's language list", langCode) + return "", fmt.Errorf("language code \"%s\" is not in Reverso's language list", langCode) } -func (e *Reverso) Translate(text string, from, to Language) (TranslationResult, error) { - if from.Code == "auto" { +func (e *Reverso) Translate(text string, from, to string) (TranslationResult, error) { + if from == "auto" { from_, err := e.DetectLanguage(text) if err != nil { @@ -154,7 +152,6 @@ func (e *Reverso) Translate(text string, from, to Language) (TranslationResult, } return TranslationResult{ - SourceLanguage: from, TranslatedText: translation, }, nil } diff --git a/web/go.mod b/web/go.mod index 3ea3a28..5ef9dc7 100644 --- a/web/go.mod +++ b/web/go.mod @@ -2,6 +2,9 @@ module codeberg.org/SimpleWeb/SimplyTranslate/web go 1.16 -require codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0 +require ( + codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0 + github.com/gofiber/fiber/v2 v2.49.0 // indirect +) replace codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0 => ../engines diff --git a/web/go.sum b/web/go.sum index 0850893..b6a6e0e 100644 --- a/web/go.sum +++ b/web/go.sum @@ -1,16 +1,45 @@ github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/gofiber/fiber/v2 v2.49.0 h1:xBVG2c66GDcWfww56xHvMn52Q0XX7UrSvjj6MD8/5EE= +github.com/gofiber/fiber/v2 v2.49.0/go.mod h1:oxpt7wQaEYgdDmq7nMxCGhilYicBLFnZ+jQSJcQDlSE= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc= +github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= @@ -24,20 +53,27 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/web/main.go b/web/main.go index a069156..427e330 100644 --- a/web/main.go +++ b/web/main.go @@ -2,11 +2,42 @@ package main import ( "codeberg.org/SimpleWeb/SimplyTranslate/engines" + "github.com/gofiber/fiber/v2" ) -// TODO: port web frontend to Go. - func main() { - engine := &engines.GoogleTranslate{} - print(engine.DisplayName()) + app := fiber.New() + + app.All("/api/translate", func(c *fiber.Ctx) error { + from := "" + to := "" + engine := "" + text := "" + if c.Method() == "GET" { + engine = c.Query("engine") + text = c.Query("text") + from = c.Query("from") + to = c.Query("to") + } else if c.Method() == "POST" { + engine = c.FormValue("engine") + text = c.FormValue("text") + from = c.FormValue("from") + to = c.FormValue("to") + } else { + return c.SendStatus(400) + } + if engine == "" { + engine = "google" + } + if to == "" { + return c.SendStatus(400) + } + if result, err := engines.Engines[engine].Translate(text, from, to); err != nil { + return c.SendStatus(500) + } else { + return c.JSON(result) + } + }) + + app.Listen(":3000") }