[9] | 1 | package engines
|
---|
| 2 |
|
---|
| 3 | import (
|
---|
| 4 | "crypto/md5"
|
---|
| 5 | "encoding/hex"
|
---|
| 6 | "encoding/json"
|
---|
| 7 | "fmt"
|
---|
| 8 | "net/http"
|
---|
| 9 | "net/url"
|
---|
| 10 | )
|
---|
| 11 |
|
---|
[10] | 12 | // ICIBA is an engine that fetches data from https://www.iciba.com.
|
---|
| 13 | type ICIBA struct{}
|
---|
[9] | 14 |
|
---|
[10] | 15 | func (_ *ICIBA) InternalName() string { return "iciba" }
|
---|
[9] | 16 |
|
---|
[10] | 17 | func (_ *ICIBA) DisplayName() string { return "iCIBA" }
|
---|
[9] | 18 |
|
---|
[15] | 19 | var icibaLanguages = Language{
|
---|
[9] | 20 | // ICIBA does have an API, but they return Chinese names.
|
---|
| 21 | // For languages already present in Google translate, the English
|
---|
| 22 | // names in that engine file are used; Otherwise official names
|
---|
| 23 | // as researched on Wikipedia are used. They're validated against
|
---|
| 24 | // the Chinese names to the best of my ability.
|
---|
| 25 | // Missing "cni", "kbh", "tmh"
|
---|
| 26 | // due to conflict between ISO-639 table and Chinese label
|
---|
| 27 | // one "//" means on iciba but not on google
|
---|
[15] | 28 | "ace": "Achinese", //
|
---|
| 29 | "acu": "Achuar-Shiwiar", //
|
---|
| 30 | "af": "Afrikaans",
|
---|
| 31 | "agr": "Aguaruna", //
|
---|
| 32 | "ake": "Akawaio", //
|
---|
| 33 | "sq": "Albanian",
|
---|
| 34 | "am": "Amharic",
|
---|
| 35 | "ar": "Arabic",
|
---|
| 36 | "hy": "Armenian",
|
---|
| 37 | "az": "Azerbaijani",
|
---|
| 38 | "bsn": "Barasana-Eduria", //
|
---|
| 39 | "ba": "Bashkir", //
|
---|
| 40 | "eu": "Basque",
|
---|
| 41 | "be": "Belarusian",
|
---|
| 42 | "bem": "Bemba", //
|
---|
| 43 | "bn": "Bengali",
|
---|
| 44 | "ber": "Berber", //
|
---|
| 45 | "bi": "Bislama", //
|
---|
| 46 | "bs": "Bosnian",
|
---|
| 47 | "br": "Breton", //
|
---|
| 48 | "bg": "Bulgarian",
|
---|
| 49 | "cjp": "Cabécar", //
|
---|
| 50 | "yue": "Cantonese",
|
---|
| 51 | "ca": "Catalan",
|
---|
| 52 | "ceb": "Cebuano",
|
---|
| 53 | "cha": "Chamorro", //
|
---|
| 54 | "chr": "Cherokee", //
|
---|
| 55 | "ny": "Chichewa",
|
---|
| 56 | "zh": "Chinese (Simplified)", // "zh-cn" on Google
|
---|
| 57 | "cht": "Chinese (Traditional)", // "zh-tw" on Google
|
---|
| 58 | "cv": "Chuvash",
|
---|
| 59 | "cop": "Coptic", //
|
---|
| 60 | "co": "Corsican",
|
---|
| 61 | "hr": "Croatian",
|
---|
| 62 | "cs": "Czech",
|
---|
| 63 | "da": "Danish",
|
---|
| 64 | "dv": "Dhivehi", //
|
---|
| 65 | "dik": "Dinka", //
|
---|
| 66 | "nl": "Dutch",
|
---|
| 67 | "dz": "Dzongkha", //
|
---|
| 68 | "en": "English",
|
---|
| 69 | "eo": "Esperanto",
|
---|
| 70 | "et": "Estonian",
|
---|
| 71 | "ee": "Ewe", //
|
---|
| 72 | "fo": "Faroese", //
|
---|
| 73 | "fj": "Fijian", //
|
---|
| 74 | "fil": "Filipino", // "tl" on Google
|
---|
| 75 | "fi": "Finnish",
|
---|
| 76 | "fr": "French",
|
---|
| 77 | "fy": "Frisian",
|
---|
| 78 | "gbi": "Galela", //
|
---|
| 79 | "gl": "Galician",
|
---|
| 80 | "lg": "Ganda", //
|
---|
| 81 | "jy": "Georgian", // "ka" on Google
|
---|
| 82 | "de": "German",
|
---|
| 83 | "el": "Greek",
|
---|
| 84 | "amu": "Guerrero Amuzgo", //
|
---|
| 85 | "gu": "Gujarati",
|
---|
| 86 | "ht": "Haitian Creole",
|
---|
| 87 | "ha": "Hausa",
|
---|
| 88 | "haw": "Hawaiian",
|
---|
| 89 | "he": "Hebrew", // "iw" on Google
|
---|
| 90 | "hi": "Hindi",
|
---|
| 91 | "mww": "Hmong Daw", //
|
---|
| 92 | "hmn": "Hmong", // not in iciba
|
---|
| 93 | "hu": "Hungarian",
|
---|
| 94 | "is": "Icelandic",
|
---|
| 95 | "ig": "Igbo",
|
---|
| 96 | "id": "Indonesian",
|
---|
| 97 | "ga": "Irish",
|
---|
| 98 | "it": "Italian",
|
---|
| 99 | "jac": "Jacalteco", //
|
---|
| 100 | "ja": "Japanese",
|
---|
| 101 | "jv": "Javanese", // "jw" on Google
|
---|
| 102 | "kab": "Kabyle", //
|
---|
| 103 | "kn": "Kannada",
|
---|
| 104 | "cak": "Kaqchikel", //
|
---|
| 105 | "ka": "Kazakh", // Google only has "kk"
|
---|
| 106 | "kk": "Kazakh (Cyrillic)", // Google has it as just "Kazakh"
|
---|
| 107 | "kek": "Kekchí", //
|
---|
| 108 | "km": "Khmer",
|
---|
| 109 | "rw": "Kinyarwanda",
|
---|
| 110 | "kg": "Kongo", //
|
---|
| 111 | "ko": "Korean",
|
---|
| 112 | "ku": "Kurdish (Kurmanji)",
|
---|
| 113 | "ky": "Kyrgyz",
|
---|
| 114 | "lo": "Lao",
|
---|
| 115 | "la": "Latin",
|
---|
| 116 | "lv": "Latvian",
|
---|
| 117 | "ln": "Lingala", //
|
---|
| 118 | "lt": "Lithuanian",
|
---|
| 119 | "dop": "Lukpa", //
|
---|
| 120 | "lb": "Luxembourgish",
|
---|
| 121 | "mk": "Macedonian",
|
---|
| 122 | "mg": "Malagasy",
|
---|
| 123 | "ms": "Malay",
|
---|
| 124 | "ml": "Malayalam",
|
---|
| 125 | "mt": "Maltese",
|
---|
| 126 | "mam": "Mam", //
|
---|
| 127 | "gv": "Manx", //
|
---|
| 128 | "mi": "Maori",
|
---|
| 129 | "mr": "Marathi",
|
---|
| 130 | "mhr": "Mari (Eastern)", //
|
---|
| 131 | "mrj": "Mari (Western)", //
|
---|
| 132 | "mn": "Mongolian",
|
---|
| 133 | "me": "Montenegrin", //
|
---|
| 134 | "my": "Myanmar (Burmese)",
|
---|
| 135 | "nhg": "Nahuatl", //
|
---|
| 136 | "djk": "Ndyuka", //
|
---|
| 137 | "ne": "Nepali",
|
---|
| 138 | "no": "Norwegian",
|
---|
| 139 | "or": "Odia (Oriya)",
|
---|
| 140 | "ojb": "Ojibwa",
|
---|
| 141 | "om": "Oromo", //
|
---|
| 142 | "os": "Ossetian", //
|
---|
| 143 | "pck": "Paite", //
|
---|
| 144 | "pap": "Papiamento", //
|
---|
| 145 | "ps": "Pashto",
|
---|
| 146 | "fa": "Persian",
|
---|
| 147 | "pl": "Polish",
|
---|
| 148 | "pt": "Portuguese",
|
---|
| 149 | "pot": "Potawatomi", //
|
---|
| 150 | "pa": "Punjabi",
|
---|
| 151 | "otq": "Querétaro Otomi", //
|
---|
| 152 | "quc": "Quiché", //
|
---|
| 153 | "quw": "Quichua", //
|
---|
| 154 | "chq": "Quiotepec Chinantec", //
|
---|
| 155 | "rmn": "Romani", //
|
---|
| 156 | "ro": "Romanian",
|
---|
| 157 | "rn": "Rundi", //
|
---|
| 158 | "ru": "Russian",
|
---|
| 159 | "sm": "Samoan",
|
---|
| 160 | "sg": "Sango", //
|
---|
| 161 | "gd": "Scots Gaelic",
|
---|
| 162 | "sr": "Serbian",
|
---|
| 163 | "crs": "Seselwa Creole French", //
|
---|
| 164 | "st": "Sesotho",
|
---|
| 165 | "sn": "Shona",
|
---|
| 166 | "jiv": "Shuar", //
|
---|
| 167 | "sd": "Sindhi",
|
---|
| 168 | "si": "Sinhala",
|
---|
| 169 | "sk": "Slovak",
|
---|
| 170 | "sl": "Slovenian",
|
---|
| 171 | "so": "Somali",
|
---|
| 172 | "es": "Spanish",
|
---|
| 173 | "su": "Sundanese",
|
---|
| 174 | "sw": "Swahili",
|
---|
| 175 | "sv": "Swedish",
|
---|
| 176 | "syc": "Syriac", // considered "extinct" but is somehow supported
|
---|
| 177 | "shi": "Tachelhit", //
|
---|
| 178 | "ty": "Tahitian", //
|
---|
| 179 | "tg": "Tajik",
|
---|
| 180 | "ta": "Tamil",
|
---|
| 181 | "tt": "Tatar",
|
---|
| 182 | "te": "Telugu",
|
---|
| 183 | "tet": "Tetum", //
|
---|
| 184 | "th": "Thai",
|
---|
| 185 | "ti": "Tigre", //
|
---|
| 186 | "tw": "Tiwi", //
|
---|
| 187 | "tpi": "Tok Pisin", //
|
---|
| 188 | "to": "Tonga", //
|
---|
| 189 | "ts": "Tsonga",
|
---|
| 190 | "tn": "Tswana", //
|
---|
| 191 | "tr": "Turkish",
|
---|
| 192 | "tk": "Turkmen",
|
---|
| 193 | "udm": "Udmurt", //
|
---|
| 194 | "uk": "Ukrainian",
|
---|
| 195 | "ppk": "Uma", //
|
---|
| 196 | "ur": "Urdu",
|
---|
| 197 | "usp": "Uspanteco", //
|
---|
| 198 | "uy": "Uyghur", // "ug" on Google
|
---|
| 199 | "uz": "Uzbek",
|
---|
| 200 | "ve": "Venda", //
|
---|
| 201 | "vi": "Vietnamese",
|
---|
| 202 | "war": "Waray", //
|
---|
| 203 | "cy": "Welsh",
|
---|
| 204 | "wal": "Wolaitta", //
|
---|
| 205 | "wol": "Wolof",
|
---|
| 206 | "xh": "Xhosa",
|
---|
| 207 | "yi": "Yiddish",
|
---|
| 208 | "yo": "Yoruba",
|
---|
| 209 | "yua": "Yucatán Maya", //
|
---|
| 210 | "dje": "Zarma", //
|
---|
| 211 | "zu": "Zulu",
|
---|
[9] | 212 | }
|
---|
| 213 |
|
---|
[15] | 214 | func (_ *ICIBA) SourceLanguages() (Language, error) { return icibaLanguages, nil }
|
---|
[9] | 215 |
|
---|
[15] | 216 | func (_ *ICIBA) TargetLanguages() (Language, error) { return icibaLanguages, nil }
|
---|
[9] | 217 |
|
---|
[15] | 218 | func (_ *ICIBA) DetectLanguage(text string) (string, error) { return "", nil }
|
---|
[9] | 219 |
|
---|
| 220 | type icibaTranslateResponse struct {
|
---|
| 221 | Content struct {
|
---|
| 222 | From string `json:"from"`
|
---|
| 223 | Out string `json:"out"`
|
---|
| 224 | } `json:"content"`
|
---|
| 225 | }
|
---|
| 226 |
|
---|
[15] | 227 | func (_ *ICIBA) Translate(text string, from, to string) (TranslationResult, error) {
|
---|
[9] | 228 | requestURL, err := url.Parse("https://ifanyi.iciba.com/index.php")
|
---|
| 229 |
|
---|
| 230 | if err != nil {
|
---|
| 231 | // The URL is constant, so it should never fail.
|
---|
| 232 | panic(err)
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | query := url.Values{}
|
---|
| 236 | query.Add("c", "trans")
|
---|
| 237 | query.Add("m", "fy")
|
---|
| 238 | query.Add("client", "6")
|
---|
| 239 | query.Add("auth_user", "key_web_fanyi")
|
---|
| 240 |
|
---|
| 241 | sum := md5.Sum([]byte(("6key_web_fanyiifanyiweb8hc9s98e" + text)))
|
---|
| 242 |
|
---|
| 243 | query.Add("sign", hex.EncodeToString(sum[:])[:16])
|
---|
| 244 |
|
---|
| 245 | requestURL.RawQuery = query.Encode()
|
---|
| 246 |
|
---|
| 247 | formData := url.Values{}
|
---|
[15] | 248 | formData.Add("from", from)
|
---|
| 249 | formData.Add("to", to)
|
---|
[9] | 250 | formData.Add("q", text)
|
---|
| 251 |
|
---|
| 252 | response, err := http.PostForm(requestURL.String(), formData)
|
---|
| 253 |
|
---|
| 254 | if err != nil {
|
---|
| 255 | return TranslationResult{}, err
|
---|
| 256 | }
|
---|
| 257 |
|
---|
| 258 | defer response.Body.Close()
|
---|
| 259 |
|
---|
| 260 | if response.StatusCode != 200 {
|
---|
| 261 | return TranslationResult{}, fmt.Errorf("got status code %d from iCIBA", response.StatusCode)
|
---|
| 262 | }
|
---|
| 263 |
|
---|
| 264 | var responseJSON icibaTranslateResponse
|
---|
| 265 |
|
---|
| 266 | if err := json.NewDecoder(response.Body).Decode(&responseJSON); err != nil {
|
---|
| 267 | return TranslationResult{}, err
|
---|
| 268 | }
|
---|
| 269 |
|
---|
[15] | 270 | var sourceLanguage string
|
---|
[9] | 271 |
|
---|
[15] | 272 | for code := range icibaLanguages {
|
---|
| 273 | if code == responseJSON.Content.From {
|
---|
| 274 | sourceLanguage = code
|
---|
[9] | 275 | break
|
---|
| 276 | }
|
---|
| 277 | }
|
---|
| 278 |
|
---|
[15] | 279 | if sourceLanguage == "" {
|
---|
| 280 | return TranslationResult{TranslatedText: responseJSON.Content.Out},
|
---|
[9] | 281 | fmt.Errorf("language code \"%s\" is not in iCIBA's language list", responseJSON.Content.From)
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | return TranslationResult{
|
---|
| 285 | SourceLanguage: sourceLanguage,
|
---|
| 286 | TranslatedText: responseJSON.Content.Out,
|
---|
| 287 | }, nil
|
---|
| 288 | }
|
---|