もう少しいじってください
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja> git-svn-id: file:///srv/svn/repo/mai/trunk@51 e410bdd4-646f-c54f-a7ce-fffcc4f439ae
This commit is contained in:
2
Makefile
2
Makefile
@@ -2,6 +2,8 @@ PREFIX ?= /usr/local
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
go build -v ./cmd/simplytranslate
|
go build -v ./cmd/simplytranslate
|
||||||
|
clean:
|
||||||
|
rm -f simplytranslate
|
||||||
install:
|
install:
|
||||||
install -Dm0755 simplytranslate ${DESTDIR}${PREFIX}/bin/simplytranslate
|
install -Dm0755 simplytranslate ${DESTDIR}${PREFIX}/bin/simplytranslate
|
||||||
mkdir -p ${DESTDIR}${PREFIX}/share/simplytranslate
|
mkdir -p ${DESTDIR}${PREFIX}/share/simplytranslate
|
||||||
|
|||||||
@@ -9,5 +9,3 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 5000:5000
|
- 5000:5000
|
||||||
environment:
|
|
||||||
- ADDRESS=0.0.0.0:5000
|
|
||||||
277
engines/iciba.go
277
engines/iciba.go
@@ -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 }
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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 {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrap {
|
.wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrap.languages {
|
.wrap.languages {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#could_not_switch_languages_text {
|
#could_not_switch_languages_text {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-wrapper {
|
.item-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -30,31 +35,24 @@
|
|||||||
margin: 5px 10px;
|
margin: 5px 10px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.language,
|
.language,
|
||||||
.switch_languages {
|
.switch_languages {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.language {
|
.language {
|
||||||
margin: 0px 10px;
|
margin: 0px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.switch_languages {
|
.switch_languages {
|
||||||
margin: 0px 5px;
|
margin: 0px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#switchbutton {
|
#switchbutton {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
border: 2px solid #888888;
|
border: 2px solid #888888;
|
||||||
}
|
}
|
||||||
|
|
||||||
input,
|
input,
|
||||||
select,
|
select,
|
||||||
textarea {
|
textarea {
|
||||||
@@ -63,7 +61,6 @@ textarea {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
border: 2px solid #888888;
|
border: 2px solid #888888;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
height: 5rem;
|
height: 5rem;
|
||||||
@@ -72,7 +69,6 @@ textarea {
|
|||||||
/* Stretch to form width */
|
/* Stretch to form width */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus,
|
input:focus,
|
||||||
select:focus,
|
select:focus,
|
||||||
textarea:focus,
|
textarea:focus,
|
||||||
@@ -95,7 +91,6 @@ body {
|
|||||||
grid-template-areas: "definitions translations";
|
grid-template-areas: "definitions translations";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.def_type {
|
.def_type {
|
||||||
color: #007979;
|
color: #007979;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
@@ -104,19 +99,15 @@ body {
|
|||||||
.syn {
|
.syn {
|
||||||
color: #804700;
|
color: #804700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.syn_type {
|
.syn_type {
|
||||||
color: #007979;
|
color: #007979;
|
||||||
}
|
}
|
||||||
|
|
||||||
.use_in_sentence {
|
.use_in_sentence {
|
||||||
color: #009902;
|
color: #009902;
|
||||||
}
|
}
|
||||||
|
|
||||||
.definitions li:not(:last-child) {
|
.definitions li:not(:last-child) {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1200px) {
|
@media screen and (max-width: 1200px) {
|
||||||
#definitions_and_translations {
|
#definitions_and_translations {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -126,63 +117,59 @@ body {
|
|||||||
"translations translations";
|
"translations translations";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
div.definitions {
|
div.definitions {
|
||||||
grid-area: definitions;
|
grid-area: definitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.translations {
|
div.translations {
|
||||||
grid-area: translations;
|
grid-area: translations;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (prefers-color-scheme: dark) {
|
@media screen and (prefers-color-scheme: dark) {
|
||||||
|
/* Loosely based on エレガントなお嬢様 - https://github.com/mei23/misskey/blob/mei-m544/src/client/themes/promo.json5 */
|
||||||
body {
|
body {
|
||||||
background-color: #212529;
|
background-color: #700000;
|
||||||
color: #f8f9fa;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#could_not_switch_languages_text {
|
#could_not_switch_languages_text {
|
||||||
color: #F13333;
|
color: yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited {
|
a:visited {
|
||||||
color: #9759f6;
|
color: #18c018;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #599bf6;
|
color: #18c018;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
button {
|
||||||
input,
|
background-color: #18c018;
|
||||||
select,
|
color: #ffffff;
|
||||||
button,
|
}
|
||||||
textarea {
|
input,
|
||||||
background-color: #131618;
|
textarea {
|
||||||
border-color: #495057;
|
background-color: #5b0000;
|
||||||
color: #f8f9fa;
|
border-color: #202020;
|
||||||
|
color: #b3784b;
|
||||||
|
}
|
||||||
|
select,
|
||||||
|
option {
|
||||||
|
background-color: #5b0000;
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.def_type {
|
.def_type {
|
||||||
color: cyan;
|
color: #5d590c;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.syn {
|
.syn {
|
||||||
color: burlywood;
|
color: #bc8080;
|
||||||
}
|
}
|
||||||
|
|
||||||
.syn_type {
|
.syn_type {
|
||||||
color: cyan;
|
color: #358611;
|
||||||
}
|
}
|
||||||
|
|
||||||
.use_in_sentence {
|
.use_in_sentence {
|
||||||
color: yellow;
|
color: #d7b081;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,23 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
<head>
|
<title>単に翻訳する</title>
|
||||||
<title>SimplyTranslate</title>
|
|
||||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||||
<meta name="description" content="Experience simple and private Google translations">
|
<meta name="description" content="Experience simple and private translations">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
|
||||||
<meta name="referrer" content="no-referrer">
|
<meta name="referrer" content="no-referrer">
|
||||||
<link rel="stylesheet" href="/static/style.css">
|
<link rel="stylesheet" href="/static/style.css">
|
||||||
</head>
|
</head>
|
||||||
|
<body>
|
||||||
<body>
|
|
||||||
<header class="center">
|
<header class="center">
|
||||||
<h1>SimplyTranslate</h1>
|
<h1>単に翻訳する</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<form action="/?engine={{.Engine}}" method="POST" id="translation-form">
|
<form action="/?engine={{.Engine}}" method="POST" id="translation-form">
|
||||||
|
|
||||||
<div class="center">
|
<div class="center">
|
||||||
Translation Engine
|
Choose translation engine:
|
||||||
|
<br>
|
||||||
{{$i := 0}}
|
{{$i := 0}}
|
||||||
{{ range $k, $v := .enginesNames }}
|
{{ range $k, $v := .enginesNames }}
|
||||||
<a {{ if eq $k $.Engine }}style="text-decoration:underline" {{end}} href="/?engine={{ $k }}">{{ $v }}</a>
|
<a {{ if eq $k $.Engine }}style="text-decoration:underline" {{end}} href="/?engine={{ $k }}">{{ $v }}</a>
|
||||||
@@ -29,7 +26,6 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div class="wrap languages">
|
<div class="wrap languages">
|
||||||
<div class="language">
|
<div class="language">
|
||||||
<select name="from" aria-label="Source language">
|
<select name="from" aria-label="Source language">
|
||||||
@@ -43,12 +39,10 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="switch_languages">
|
<div class="switch_languages">
|
||||||
<button id="switchbutton" aria-label="Switch languages"
|
<button id="switchbutton" aria-label="Switch languages"
|
||||||
formaction="/switchlanguages/?engine={{ .Engine }}" type="submit"><-></button>
|
formaction="/switchlanguages/?engine={{ .Engine }}" type="submit"><-></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="language">
|
<div class="language">
|
||||||
<select name="to" aria-label="Target language">
|
<select name="to" aria-label="Target language">
|
||||||
{{range $code, $name := .TargetLanguages}}
|
{{range $code, $name := .TargetLanguages}}
|
||||||
@@ -57,7 +51,6 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="item-wrapper">
|
<div class="item-wrapper">
|
||||||
<textarea autofocus class="item" id="input" name="text" dir="auto"
|
<textarea autofocus class="item" id="input" name="text" dir="auto"
|
||||||
@@ -68,7 +61,6 @@
|
|||||||
</audio>
|
</audio>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="item-wrapper">
|
<div class="item-wrapper">
|
||||||
<textarea id="output" class="translation item" dir="auto" placeholder="Translation"
|
<textarea id="output" class="translation item" dir="auto" placeholder="Translation"
|
||||||
readonly>{{.Translation.TranslatedText}}</textarea>
|
readonly>{{.Translation.TranslatedText}}</textarea>
|
||||||
@@ -79,15 +71,11 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<button type="submit">Translate with {{ index .enginesNames .Engine }}!</button>
|
<button type="submit">Translate with {{ index .enginesNames .Engine }}!</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div id="definitions_and_translations">
|
<div id="definitions_and_translations">
|
||||||
{{ if .Translation.Definitions }}
|
{{ if .Translation.Definitions }}
|
||||||
<div class="definitions">
|
<div class="definitions">
|
||||||
@@ -118,7 +106,6 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{ end}}
|
{{ end}}
|
||||||
|
|
||||||
{{ if .Translation.Translations }}
|
{{ if .Translation.Translations }}
|
||||||
<div class="translations">
|
<div class="translations">
|
||||||
{{ range $def_type, $translations := .Translation.Translations }}
|
{{ range $def_type, $translations := .Translation.Translations }}
|
||||||
@@ -138,14 +125,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
<br><br><br><br><br>
|
<br><br><br><br><br>
|
||||||
<footer class="center">
|
<footer class="center">
|
||||||
<a href="https://codeberg.org/ManeraKai/simplytranslate">Source Code</a>
|
<a href="https://codeberg.org/ManeraKai/simplytranslate">Source code</a> / <a href="https://git.chaotic.ninja/yakumo.izuru/simplytranslate">Modified source code</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="/static/script.js"></script>
|
<script src="/static/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user