From d165c6f5fca4287d429d1bf002fa57e408c5ed9e Mon Sep 17 00:00:00 2001 From: "yakumo.izuru" Date: Sat, 7 Oct 2023 17:36:50 +0000 Subject: [PATCH] =?UTF-8?q?=E3=82=82=E3=81=86=E5=B0=91=E3=81=97=E3=81=84?= =?UTF-8?q?=E3=81=98=E3=81=A3=E3=81=A6=E3=81=8F=E3=81=A0=E3=81=95=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Izuru Yakumo git-svn-id: file:///srv/svn/repo/mai/trunk@51 e410bdd4-646f-c54f-a7ce-fffcc4f439ae --- Makefile | 2 + docker-compose.yml | 2 - engines/iciba.go | 277 -------------------------------------- engines/libretranslate.go | 170 ----------------------- static/style.css | 93 ++++++------- views/index.html | 252 ++++++++++++++++------------------ 6 files changed, 160 insertions(+), 636 deletions(-) delete mode 100644 engines/iciba.go delete mode 100644 engines/libretranslate.go diff --git a/Makefile b/Makefile index 401c5ac..29c2bc6 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ PREFIX ?= /usr/local build: go build -v ./cmd/simplytranslate +clean: + rm -f simplytranslate install: install -Dm0755 simplytranslate ${DESTDIR}${PREFIX}/bin/simplytranslate mkdir -p ${DESTDIR}${PREFIX}/share/simplytranslate diff --git a/docker-compose.yml b/docker-compose.yml index 68f8b90..b406c70 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,5 +9,3 @@ services: restart: unless-stopped ports: - 5000:5000 - environment: - - ADDRESS=0.0.0.0:5000 \ No newline at end of file diff --git a/engines/iciba.go b/engines/iciba.go deleted file mode 100644 index 91da9c5..0000000 --- a/engines/iciba.go +++ /dev/null @@ -1,277 +0,0 @@ -package engines - -import ( - "crypto/md5" - "encoding/hex" - "encoding/json" - "fmt" - "net/http" - "net/url" -) - -// ICIBA is an engine that fetches data from https://www.iciba.com. -type ICIBA struct{} - -func (_ *ICIBA) DisplayName() string { return "iCIBA" } - -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 - // as researched on Wikipedia are used. They're validated against - // the Chinese names to the best of my ability. - // Missing "cni", "kbh", "tmh" - // due to conflict between ISO-639 table and Chinese label - // one "//" means on iciba but not on google - "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) TargetLanguages() (Language, error) { return icibaLanguages, nil } - -func (_ *ICIBA) Translate(text string, from, to string) (TranslationResult, error) { - requestURL, _ := url.Parse("https://ifanyi.iciba.com/index.php") - - query := url.Values{} - query.Add("c", "trans") - query.Add("m", "fy") - query.Add("client", "6") - query.Add("auth_user", "key_web_fanyi") - - sum := md5.Sum([]byte(("6key_web_fanyiifanyiweb8hc9s98e" + text))) - query.Add("sign", hex.EncodeToString(sum[:])[:16]) - - requestURL.RawQuery = query.Encode() - - formData := url.Values{} - formData.Add("from", from) - formData.Add("to", to) - formData.Add("q", text) - - response, err := http.PostForm(requestURL.String(), formData) - if err != nil { - return TranslationResult{}, err - } - - defer response.Body.Close() - - if response.StatusCode != 200 { - return TranslationResult{}, fmt.Errorf("got status code %d from iCIBA", response.StatusCode) - } - - var responseJSON struct { - Content struct { - From string `json:"from"` - Out string `json:"out"` - } `json:"content"` - } - - if err := json.NewDecoder(response.Body).Decode(&responseJSON); err != nil { - return TranslationResult{}, err - } - - var sourceLanguage string - - for code := range icibaLanguages { - if code == responseJSON.Content.From { - sourceLanguage = code - break - } - } - - if sourceLanguage == "" { - return TranslationResult{TranslatedText: responseJSON.Content.Out}, - fmt.Errorf("language code \"%s\" is not in iCIBA's language list", responseJSON.Content.From) - } - - return TranslationResult{ - SourceLanguage: sourceLanguage, - TranslatedText: responseJSON.Content.Out, - }, nil -} - -func (_ *ICIBA) Tts(text, lang string) (string, error) { return "", nil } diff --git a/engines/libretranslate.go b/engines/libretranslate.go deleted file mode 100644 index a8740f8..0000000 --- a/engines/libretranslate.go +++ /dev/null @@ -1,170 +0,0 @@ -package engines - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" -) - -// LibreTranslate is an engine that interfaces with any -// [LibreTranslate](https://github.com/LibreTranslate/LibreTranslate) instance. -type LibreTranslate struct { - // InstanceURL is the URL to a LibreTranslate instance, for example - // "https://libretranslate.com". - InstanceURL string - // APIKey is the API key for the given instance. If empty, then no API - // key will be sent along with requests to the instance. - // - // Some instances issue API keys to users so that they can have a - // higher rate limit. See - // https://github.com/LibreTranslate/LibreTranslate#manage-api-keys for - // more information. - APIKey string -} - -func (_ *LibreTranslate) DisplayName() string { return "LibreTranslate" } - -func (e *LibreTranslate) getLangs() (Language, error) { - response, err := http.Get(e.InstanceURL + "/languages") - - if err != nil { - return nil, err - } - - defer response.Body.Close() - - if response.StatusCode != 200 { - return nil, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode) - } - - 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 := Language{} - - for _, lang := range langsResponse { - langs[lang.Code] = lang.Name - } - - return langs, nil - -} - -func (e *LibreTranslate) SourceLanguages() (Language, error) { return e.getLangs() } - -func (e *LibreTranslate) TargetLanguages() (Language, error) { return e.getLangs() } - -func (e *LibreTranslate) Tts(text, lang string) (string, error) { return "", nil } - -type libreDetectResponse []struct { - Confidence float64 `json:"confidence"` - LanguageCode string `json:"language"` -} - -func (e *LibreTranslate) detectLanguage(text string) (string, error) { - formData := map[string]string{"q": text} - - if e.APIKey != "" { - formData["api_key"] = e.APIKey - } - - formDataJSON, err := json.Marshal(formData) - - if err != nil { - return "", err - } - - response, err := http.Post(e.InstanceURL+"/detect", "application/json", bytes.NewBuffer(formDataJSON)) - - if err != nil { - return "", err - } - - defer response.Body.Close() - - if response.StatusCode != 200 { - 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 "", err - } - - maxConfidenceLang := langs[0] - - for _, lang := range langs[1:] { - if lang.Confidence > maxConfidenceLang.Confidence { - maxConfidenceLang = lang - } - } - - engineLangs, err := e.getLangs() - - if err != nil { - return "", err - } - - for code := range engineLangs { - if code == maxConfidenceLang.LanguageCode { - return code, nil - } - } - - return "", fmt.Errorf("language code \"%s\" is not in the instance's language list", maxConfidenceLang.LanguageCode) -} - -func (e *LibreTranslate) Translate(text string, from, to string) (TranslationResult, error) { - formData := map[string]string{ - "q": text, - "source": from, - "target": to, - } - - if e.APIKey != "" { - formData["api_key"] = e.APIKey - } - - formDataJSON, err := json.Marshal(formData) - - if err != nil { - return TranslationResult{}, err - } - - response, err := http.Post(e.InstanceURL+"/translate", "application/json", bytes.NewBuffer(formDataJSON)) - - if err != nil { - return TranslationResult{}, err - } - - defer response.Body.Close() - - if response.StatusCode != 200 { - return TranslationResult{}, fmt.Errorf("got status code %d from LibreTranslate API", response.StatusCode) - } - - var responseJSON struct { - TranslatedText string `json:"translatedText"` - } - - if err := json.NewDecoder(response.Body).Decode(&responseJSON); err != nil { - return TranslationResult{}, err - } - - if r, err := e.detectLanguage(text); err == nil { - from = r - } - - return TranslationResult{ - TranslatedText: responseJSON.TranslatedText, - SourceLanguage: from, - }, nil -} diff --git a/static/style.css b/static/style.css index 5021b16..a0e626f 100644 --- a/static/style.css +++ b/static/style.css @@ -1,27 +1,32 @@ +body { + background-color: #ffffff; + color: rgb(206, 147, 191); +} +a { + color: rgb(206, 147, 191); +} +a:visited { + color: rgb(206, 147, 191); +} .center { text-align: center; } - .wrap { display: flex; flex-wrap: wrap; justify-content: center; } - .wrap.languages { flex-wrap: nowrap; margin-bottom: 20px; } - #could_not_switch_languages_text { color: red; } - .item { width: 100%; height: 150px; } - .item-wrapper { display: flex; flex-wrap: wrap; @@ -30,31 +35,24 @@ margin: 5px 10px; gap: 10px; } - - .language, .switch_languages { display: flex; } - .language { margin: 0px 10px; } - .switch_languages { margin: 0px 5px; } - #switchbutton { white-space: nowrap; } - button { font-size: 1rem; padding: 4px 10px; border: 2px solid #888888; } - input, select, textarea { @@ -63,7 +61,6 @@ textarea { padding: 4px; border: 2px solid #888888; } - textarea { resize: vertical; height: 5rem; @@ -72,7 +69,6 @@ textarea { /* Stretch to form width */ width: 100%; } - input:focus, select:focus, textarea:focus, @@ -95,7 +91,6 @@ body { grid-template-areas: "definitions translations"; } - .def_type { color: #007979; text-transform: capitalize; @@ -104,85 +99,77 @@ body { .syn { color: #804700; } - .syn_type { color: #007979; } - .use_in_sentence { color: #009902; } - .definitions li:not(:last-child) { margin-bottom: 1rem; } - @media screen and (max-width: 1200px) { #definitions_and_translations { - display: grid; - width: 90vw; - grid-template-areas: - "definitions definitions" - "translations translations"; + display: grid; + width: 90vw; + grid-template-areas: + "definitions definitions" + "translations translations"; } } - - div.definitions { grid-area: definitions; } - div.translations { grid-area: translations; } - a { text-decoration: none; } - @media screen and (prefers-color-scheme: dark) { + /* Loosely based on エレガントなお嬢様 - https://github.com/mei23/misskey/blob/mei-m544/src/client/themes/promo.json5 */ body { - background-color: #212529; - color: #f8f9fa; + background-color: #700000; + color: #ffffff; } - #could_not_switch_languages_text { - color: #F13333; + color: yellow; } a:visited { - color: #9759f6; + color: #18c018; text-decoration: none; } - a { - color: #599bf6; + color: #18c018; text-decoration: none; } - - input, - select, - button, - textarea { - background-color: #131618; - border-color: #495057; - color: #f8f9fa; + button { + background-color: #18c018; + color: #ffffff; + } + input, + textarea { + background-color: #5b0000; + border-color: #202020; + color: #b3784b; + } + select, + option { + background-color: #5b0000; + color: #ffffff; } - .def_type { - color: cyan; + color: #5d590c; text-transform: capitalize; } - .syn { - color: burlywood; + color: #bc8080; } - .syn_type { - color: cyan; + color: #358611; } - .use_in_sentence { - color: yellow; + color: #d7b081; } -} \ No newline at end of file +} diff --git a/views/index.html b/views/index.html index a836c12..9d80a77 100644 --- a/views/index.html +++ b/views/index.html @@ -1,151 +1,135 @@ - - - SimplyTranslate + + 単に翻訳する - + - - - + +
-

SimplyTranslate

+

単に翻訳する

-
- -
- Translation Engine - {{$i := 0}} - {{ range $k, $v := .enginesNames }} - {{ $v }} - {{$i = (inc $i)}} - {{if eq $i (len $.enginesNames)}}{{else}}|{{end}} +
+ Choose translation engine: +
+ {{$i := 0}} + {{ range $k, $v := .enginesNames }} + {{ $v }} + {{$i = (inc $i)}} + {{if eq $i (len $.enginesNames)}}{{else}}|{{end}} + {{end}} +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ + {{if .TtsFrom}} + + {{end}} +
+
+ + {{if .TtsTo}} + + {{end}} +
+
+
+
+ +
+
+
+ {{ if .Translation.Definitions }} +
+ {{ range $type, $definitions :=.Translation.Definitions }} + {{ $type }} +
    + {{ range $definition_item := $definitions }} +
  1. + {{ $definition_item.definition }} +
    + {{with $definition_item.use_in_sentence}} + "{{$definition_item.use_in_sentence}}" +
    + {{end}} + {{with $definition_item.synonyms}} + {{ range $synonym_type, $_ := $definition_item.synonyms }} + + {{if $synonym_type }} +
    + {{$synonym_type}}: {{end}}{{ range $index, $element := index + $definition_item.synonyms $synonym_type}}{{if $index}}, {{end}}{{$element}}{{end}} +
    + {{end}} + {{end}} +
  2. + {{end}} +
+ {{end}} +
+ {{ end}} + {{ if .Translation.Translations }} +
+ {{ range $def_type, $translations := .Translation.Translations }} + {{ $def_type }} +
    + {{ range $word, $word_translations := $translations }} +
  • + {{$word}}: + {{ range $index, $element := $word_translations.words}}{{if $index}}, + {{end}}{{$element}}{{end}} + {{$word_translations.frequency}} +
  • +
    {{end}} -
-
- -
-
- -
- -
- -
- -
- -
-
- -
-
- - {{if .TtsFrom}} - - {{end}} -
- -
- - {{if .TtsTo}} - - {{end}} -
-
- -
- -
- -
- -
- -
- {{ if .Translation.Definitions }} -
- {{ range $type, $definitions :=.Translation.Definitions }} - {{ $type }} -
    - {{ range $definition_item := $definitions }} -
  1. - {{ $definition_item.definition }} -
    - {{with $definition_item.use_in_sentence}} - "{{$definition_item.use_in_sentence}}" -
    - {{end}} - {{with $definition_item.synonyms}} - {{ range $synonym_type, $_ := $definition_item.synonyms }} - - {{if $synonym_type }} -
    - {{$synonym_type}}: {{end}}{{ range $index, $element := index - $definition_item.synonyms $synonym_type}}{{if $index}}, {{end}}{{$element}}{{end}} -
    - {{end}} - {{end}} -
  2. - {{end}} -
- {{end}} -
- {{ end}} - - {{ if .Translation.Translations }} -
- {{ range $def_type, $translations := .Translation.Translations }} - {{ $def_type }} -
    - {{ range $word, $word_translations := $translations }} -
  • - {{$word}}: - {{ range $index, $element := $word_translations.words}}{{if $index}}, - {{end}}{{$element}}{{end}} - {{$word_translations.frequency}} -
  • -
    - {{end}} -
- {{end}} -
- {{end}} -
- + + {{end}} +
+ {{end}} +





- - - - \ No newline at end of file + +