Fix bugs, many other changes
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja> git-svn-id: file:///srv/svn/repo/mai/trunk@67 e410bdd4-646f-c54f-a7ce-fffcc4f439ae
This commit is contained in:
parent
2435673dff
commit
b860f0610b
13
HISTORY.md
Normal file
13
HISTORY.md
Normal file
@ -0,0 +1,13 @@
|
||||
## 2021
|
||||
[SimplyTranslate](https://codeberg.org/SimpleWeb/SimplyTranslate-Web) was founded by metalune and fattalion.
|
||||
It was written in Python and used the Quart framework.
|
||||
|
||||
## 2022
|
||||
fattalion created a Go implementation.
|
||||
|
||||
## 2023
|
||||
* Both metalune and fattalion retired, and they handed SimplyTranslate over to [ManeraKai](https://manerakai.com).
|
||||
* Arya K. from [~vern](https://vern.cc) made a hard-fork named [Mozhi](https://codeberg.org/aryak/mozhi) and has vastly refactored it.
|
||||
|
||||
## 2024
|
||||
Izuru Yakumo took interest in SimplyTranslate and decided to fork it in October 2023, and in January he turned it into a hard-fork, eventually renaming it to "Mai", after a character from the fifth [Touhou Project](https://en.touhouwiki.net/wiki/Touhou_Project) game, [Mai](https://en.touhouwiki.net/wiki/Mai).
|
11
INSTALL.md
Normal file
11
INSTALL.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Installation
|
||||
|
||||
```shell
|
||||
$ git clone https://git.chaotic.ninja/yakumo.izuru/mai
|
||||
$ cd mai
|
||||
$ make
|
||||
# make PREFIX=/usr/local install
|
||||
```
|
||||
* Read the [mai.ini(5)](mai.ini.5) manual page
|
||||
* Use any web server than is able to reverse proxy, like Apache, h2o, or NGINX.
|
||||
|
6
INSTANCES.md
Normal file
6
INSTANCES.md
Normal file
@ -0,0 +1,6 @@
|
||||
# List of known instances
|
||||
|
||||
* [tr.chaotic.ninja](https://tr.chaotic.ninja)
|
||||
* Location: Germany
|
||||
* Cloudflare: No
|
||||
|
9
LEGAL.md
Normal file
9
LEGAL.md
Normal file
@ -0,0 +1,9 @@
|
||||
Mai does not host any content. All content shown on any Mai instances is from [Google Translate](https://translate.google.com), [Reverso](https://www.reverso.net/), and [LibreTranslate](https://libretranslate.com)
|
||||
|
||||
Mai is not affiliated with none of the above, which this program relays.
|
||||
|
||||
Trademarks belong to their respective owners.
|
||||
Google Translate is a trademark of [Google LLC](https://www.google.com). Reverso is a trademark of Reverso, et cetera.
|
||||
|
||||
The creators and maintainers of this repository assume no liability for the accuracy and timeliness of any information provided above. Trademark owner information was researched to the best of the author's knowledge at the time of curation and may be outdated or incorrect.
|
||||
|
42
README.md
42
README.md
@ -1,45 +1,9 @@
|
||||
## Mai
|
||||
A privacy friendly frontend to multiple translation engines.
|
||||
|
||||
### History
|
||||
1. SimplyTranslate was founded by [metalune and fattalion](https://codeberg.org/SimpleWeb/SimplyTranslate-Web). It was written in Python.
|
||||
2. Fattalion created a Go implementation.
|
||||
3. Both metalune and fattalion retired, and they handed SimplyTranslate over to ManeraKai.
|
||||
4. [Izuru Yakumo The Violet Hermit](https://geidontei.chaotic.ninja/usr/yakumo_izuru) stole it, and renamed it after [Mai](https://en.touhouwiki.net/wiki/Mai) from [Mystic Square](https://en.touhouwiki.net/wiki/Mystic_Square)
|
||||
|
||||
### Instances
|
||||
| URL | Location | Cloudflare? |
|
||||
|-----|----------|-------------|
|
||||
| [tr.chaotic.ninja](https://tr.chaotic.ninja) | DE | No |
|
||||
|
||||
### Installation
|
||||
|
||||
```shell
|
||||
% git clone https://git.chaotic.ninja/yakumo.izuru/mai
|
||||
% cd mai
|
||||
% make
|
||||
# make install
|
||||
```
|
||||
|
||||
### Setup
|
||||
For [nginx](https://www.nginx.com) you can use this snippet, this also serves the static resources.
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_set_header Host $host;
|
||||
proxy_pass http://localhost:5000;
|
||||
}
|
||||
```
|
||||
|
||||
### Legal notice
|
||||
Mai does not host any content. All content shown on any Mai instances is from [Google Translate](https://translate.google.com), [Reverso](https://www.reverso.net/), [iCIBA](https://www.iciba.net) and [LibreTranslate](https://libretranslate.com)
|
||||
|
||||
Mai is not affiliated with none of the above, which this program relays.
|
||||
|
||||
Trademarks belong to their respective owners.
|
||||
Google Translate is a trademark of [Google LLC](https://www.google.com). Reverso is a trademark of Reverso, et cetera.
|
||||
|
||||
The creators and maintainers of this repository assume no liability for the accuracy and timeliness of any information provided above. Trademark owner information was researched to the best of the author's knowledge at the time of curation and may be outdated or incorrect.
|
||||
* [How to install](INSTALL.md)
|
||||
* [List of instances](INSTANCES.md)
|
||||
* [Legal notice](LEGAL.md)
|
||||
|
||||
### Other projects
|
||||
* [Mozhi](https://codeberg.org/aryak/mozhi), also a fork of SimplyTranslate
|
||||
|
@ -21,13 +21,13 @@ import (
|
||||
)
|
||||
var (
|
||||
configfile string
|
||||
groupname string
|
||||
username string
|
||||
)
|
||||
var conf struct {
|
||||
group string
|
||||
listen string
|
||||
staticpath string
|
||||
tmplpath string
|
||||
user string
|
||||
}
|
||||
func main() {
|
||||
parseFlags()
|
||||
@ -41,8 +41,8 @@ func main() {
|
||||
conf.staticpath = "./static"
|
||||
conf.tmplpath = "./views"
|
||||
|
||||
if conf.user != "" {
|
||||
uid, gid, err := usergroupids(conf.user, conf.group)
|
||||
if username != "" {
|
||||
uid, gid, err := usergroupids(username, groupname)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
@ -258,6 +258,9 @@ func main() {
|
||||
}
|
||||
}
|
||||
})
|
||||
app.Get("/robots.txt", func(c *fiber.Ctx) error {
|
||||
return c.SendString("User-Agent: *\nDisallow: /\n")
|
||||
})
|
||||
app.Get("/version", func(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{
|
||||
"fiberversion": fiber.Version,
|
||||
|
@ -7,5 +7,7 @@ import (
|
||||
|
||||
func parseFlags() {
|
||||
flag.StringVar(&configfile, "f", "", "Configuration file")
|
||||
flag.StringVar(&username, "u", "", "Sets the user to which privilege dropping is done")
|
||||
flag.StringVar(&groupname, "g", "", "Sets the group to which privilege dropping is done")
|
||||
flag.Parse()
|
||||
}
|
||||
|
@ -10,11 +10,9 @@ func readConf(file string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf.group = cfg.Section("mai").Key("group").String()
|
||||
conf.listen = cfg.Section("mai").Key("listen").String()
|
||||
conf.staticpath = cfg.Section("mai").Key("static").String()
|
||||
conf.tmplpath = cfg.Section("mai").Key("templates").String()
|
||||
conf.user = cfg.Section("mai").Key("user").String()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ func usergroupids(username string, groupname string) (int, int, error) {
|
||||
uid, _ := strconv.Atoi(u.Uid)
|
||||
gid, _ := strconv.Atoi(u.Gid)
|
||||
|
||||
if conf.group != "" {
|
||||
if groupname != "" {
|
||||
g, err := user.LookupGroup(groupname)
|
||||
if err != nil {
|
||||
return uid, -1, err
|
||||
|
@ -7,49 +7,68 @@
|
||||
<title>API Documentation | Mai</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<h1 id="header">API Documentation</h1>
|
||||
<br><hr>
|
||||
<h2 class="get">[GET] /api/translate</h2>
|
||||
<h2 class="post">[POST] /api/translate</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Translation endpoint, input must be URL-encoded (e.g. multi-byte characters, words separated by space)</p>
|
||||
<h3>Arguments</h3>
|
||||
<ul>
|
||||
<li>engine</li>
|
||||
<li>from</li>
|
||||
<li>text</li>
|
||||
<li>to</li>
|
||||
</ul>
|
||||
<h3>Examples</h3>
|
||||
<p><pre><code>GET /api/translate?engine=google&from=auto&to=en&text="sonrisa"</code></pre></p>
|
||||
<hr>
|
||||
<h2 class="get">[GET] /api/source_languages</h2>
|
||||
<h2 class="get">[GET] /api/target_languages</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Get a JSON array of supported source and target languages for a particular engine</p>
|
||||
<h3>Arguments</h3>
|
||||
<ul>
|
||||
<li>engine</li>
|
||||
</ul>
|
||||
<h3>Examples</h3>
|
||||
<p><pre><code>GET /api/source_languages?engine=google</code></pre></p>
|
||||
<p><pre><code>GET /api/target_languages?engine=google</code></pre></p>
|
||||
<hr>
|
||||
<h2 class="get">[GET] /api/tts</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Obtain text-to-speech audio files from an engine, provided said engine supports them</p>
|
||||
<h3>Arguments</h3>
|
||||
<ul>
|
||||
<li>engine</li>
|
||||
<li>lang</li>
|
||||
<li>text</li>
|
||||
</ul>
|
||||
<h3>Examples</h3>
|
||||
<p><pre><code>GET /api/tts?engine=google&lang=en&text="hi"</code></pre></p>
|
||||
<hr>
|
||||
<h2 class="post">[POST] /switchlanguages</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Switch between source and target languages, as long as the source language isn't "auto"</p>
|
||||
<hr>
|
||||
<h1>API documentation</h1>
|
||||
<table border="1" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<h2 class="get">[GET] /api/translate</h2>
|
||||
<h2 class="post">[POST] /api/translate</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Translation endpoint, input must be URL-encoded (e.g. multi-byte characters, words separated by space)</p>
|
||||
<h3>Arguments</h3>
|
||||
<ul>
|
||||
<li>engine</li>
|
||||
<li>from</li>
|
||||
<li>text</li>
|
||||
<li>to</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h2 class="get">[GET] /api/source_languages</h2>
|
||||
<h2 class="get">[GET] /api/target_languages</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Get a JSON array of supported source and target languages for a particular engine</p>
|
||||
<h3>Arguments</h3>
|
||||
<ul>
|
||||
<li>engine</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h2 class="get">[GET] /api/tts</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Obtain text-to-speech audio files from an engine, provided said engine supports them</p>
|
||||
<h3>Arguments</h3>
|
||||
<ul>
|
||||
<li>engine</li>
|
||||
<li>lang</li>
|
||||
<li>text</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h2 class="get">[GET] /robots.txt</h2>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h2 class="post">[POST] /switchlanguages</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Switch between source and target languages, as long as the source language isn't "auto"</p>
|
||||
<p>Must only be called inside the form interface</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h2 class="get">[GET] /version</h2>
|
||||
<h3>Description</h3>
|
||||
<p>Return the software version as a JSON array</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -6,12 +6,27 @@
|
||||
<meta name="author" content="Izuru Yakumo">
|
||||
<title>Mai | Documentation</title>
|
||||
</head>
|
||||
<body id="body">
|
||||
<img src="/static/favicon128x128.png" style="text-align: center;">
|
||||
<h1 id="header">Documentation</h1>
|
||||
<ul id="nav">
|
||||
<li><a href="/docs/api">API</a></li>
|
||||
</ul>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>
|
||||
<table border="1" align="left">
|
||||
<tr>
|
||||
<td><a href="/docs/api">API</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</tr></td>
|
||||
<tr><td>
|
||||
<table border="1" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<p>Welcome to Mai's documentation!<p>
|
||||
<p>See the menu for the available entries</p>
|
||||
<p>Anything else is covered by the man pages</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
122
docs/style.css
122
docs/style.css
@ -1,114 +1,22 @@
|
||||
/*
|
||||
* Taken from vnpower
|
||||
*/
|
||||
|
||||
* {
|
||||
box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
top: 0;
|
||||
margin: 0;
|
||||
background-color: #1d1f21;
|
||||
color: white;
|
||||
font-family: "Open Sans", "Roboto", "Noto Sans", "Noto Sans CJK JP", sans-serif;
|
||||
line-height: 1.618;
|
||||
background-color: #f8cfd2;
|
||||
color: rgb(206, 147, 191);
|
||||
}
|
||||
|
||||
h2.get {
|
||||
color: orange;
|
||||
a, a:visited {
|
||||
color: rgb(206, 147, 191);
|
||||
}
|
||||
|
||||
h2.post {
|
||||
color: green;
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background-color: #700000;
|
||||
color: #ffffff;
|
||||
}
|
||||
a, a:visited {
|
||||
color: #18c018;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 684px) {
|
||||
body {
|
||||
font-size: 1rem; } }
|
||||
|
||||
@media (max-width: 382px) {
|
||||
body {
|
||||
font-size: 1rem; } }
|
||||
|
||||
a {
|
||||
color: #81a2be;
|
||||
text-decoration-color: #81a2be; }
|
||||
|
||||
#header {
|
||||
width: 100%;
|
||||
min-width: 320px;
|
||||
background-color: #282a2e; }
|
||||
|
||||
#header img {
|
||||
width: 280px; }
|
||||
|
||||
#header-content {
|
||||
margin: 0 auto;
|
||||
width: min-content; }
|
||||
|
||||
#nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: #373b41; }
|
||||
|
||||
#footer {
|
||||
margin-top: 0.5rem;
|
||||
text-align: center; }
|
||||
|
||||
#body {
|
||||
min-height: 75vh;
|
||||
max-width: 800px;
|
||||
margin: 1rem auto;
|
||||
padding: 0 0.6rem; }
|
||||
#body h1,
|
||||
#body h2,
|
||||
#body h3,
|
||||
#body h4,
|
||||
#body h5,
|
||||
#body h6 {
|
||||
line-height: 1.1;
|
||||
font-family: sans-serif;
|
||||
font-weight: 700;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
-ms-word-break: break-all;
|
||||
word-break: break-word; }
|
||||
#body h1 {
|
||||
border-bottom: 1px solid #b5bd68;
|
||||
display: block; }
|
||||
#body p {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0.5rem; }
|
||||
#body li > p {
|
||||
padding: 0;
|
||||
margin: 0; }
|
||||
#body small,
|
||||
#body sub,
|
||||
#body sup {
|
||||
font-size: 75%; }
|
||||
#body img,
|
||||
#body video {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.12), 0px 2px 2px 0px rgba(0, 0, 0, 0.12), 0px 4px 4px 0px rgba(0, 0, 0, 0.12), 0px 8px 8px 0px rgba(0, 0, 0, 0.12), 0px 16px 16px 0px rgba(0, 0, 0, 0.12); }
|
||||
#body pre {
|
||||
background-color: #373b41;
|
||||
display: block;
|
||||
padding: 1em;
|
||||
overflow-x: auto;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0.5rem; }
|
||||
#body code, #body kbd, #body samp {
|
||||
padding: 0 0.5em;
|
||||
background-color: #373b41;
|
||||
white-space: pre-wrap; }
|
||||
#body pre > code {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
white-space: pre;
|
||||
font-size: 1em; }
|
||||
|
||||
table {
|
||||
border-color: white;
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ type Language map[string]string
|
||||
var Engines = map[string]Engine{
|
||||
"google": &GoogleTranslate{},
|
||||
"reverso": &Reverso{},
|
||||
"iciba": &ICIBA{},
|
||||
"libretranslate": &LibreTranslate{
|
||||
InstanceURL: os.Getenv("MAI_LIBRETRANSLATE_INSTANCE"),
|
||||
APIKey: os.Getenv("MAI_LIBRETRANSLATE_API"),
|
||||
|
283
engines/iciba.go
283
engines/iciba.go
@ -1,283 +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) {
|
||||
icibaLanguagesCopy := make(Language)
|
||||
for k, v := range icibaLanguages {
|
||||
icibaLanguagesCopy[k] = v
|
||||
}
|
||||
|
||||
icibaLanguagesCopy["auto"] = "Detect Language"
|
||||
return icibaLanguagesCopy, 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
|
||||
}
|
||||
|
||||
for code := range icibaLanguages {
|
||||
if code == responseJSON.Content.From {
|
||||
from = code
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if from == "" {
|
||||
return TranslationResult{TranslatedText: responseJSON.Content.Out},
|
||||
fmt.Errorf("language code \"%s\" is not in iCIBA's language list", responseJSON.Content.From)
|
||||
}
|
||||
|
||||
return TranslationResult{
|
||||
SourceLanguage: from,
|
||||
TranslatedText: responseJSON.Content.Out,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (_ *ICIBA) Tts(text, lang string) (string, error) { return "", nil }
|
@ -2,4 +2,3 @@
|
||||
listen = "127.0.0.1:5000"
|
||||
rootdir = "./static"
|
||||
tmplpath = "./views"
|
||||
user = "www"
|
||||
|
14
mai.1
14
mai.1
@ -7,6 +7,8 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl f Ar config-file
|
||||
.Op Fl u Ar user
|
||||
.Op Fl g Ar group
|
||||
.Sh DESCRIPTION
|
||||
This project has been forked from the remains of the
|
||||
rewrite of the SimplyTranslate project, which is currently
|
||||
@ -14,11 +16,19 @@ maintained by ManeraKai, but as time passed, this fork
|
||||
diverged wildly, and was renamed.
|
||||
Much to anyone's dismay, this was named after
|
||||
.Lk https://en.touhouwiki.net/wiki/Mai Mai from Mystic Square
|
||||
.Sh FEATURES
|
||||
.Bl -tag -width 11n -compact
|
||||
.It Command-line tool
|
||||
See
|
||||
.Xr suwako 1
|
||||
.It Privilege dropping
|
||||
Stolen from
|
||||
.Xr partage 1
|
||||
just so you do not run this as root
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.An fattalion
|
||||
.An metalune
|
||||
.An ManeraKai Lk https://manerakai.com
|
||||
.Sh MAINTAINERS
|
||||
.An Izuru Yakumo Aq Mt yakumo.izuru@chaotic.ninja
|
||||
.Sh BUGS
|
||||
iCIBA engine doesn't work, throws HTTP 500
|
||||
|
@ -7,9 +7,6 @@
|
||||
.Sh OPTIONS
|
||||
.Ss [mai] section
|
||||
.Bl -tag -width 11n
|
||||
.It group
|
||||
Group ID for dropping privileges to.
|
||||
If unset, assume the GID of user
|
||||
.It listen
|
||||
HTTP port for the server to listen.
|
||||
Default is "localhost:5000"
|
||||
@ -19,8 +16,6 @@ Default is "./static"
|
||||
.It templates
|
||||
Directory where the templates are located.
|
||||
Default is "./views"
|
||||
.It user
|
||||
User ID for dropping privileges to.
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width 11n
|
||||
|
@ -20,7 +20,7 @@ load_rc_config $name
|
||||
pidfile="/var/run/${name}.pid"
|
||||
command="/usr/sbin/daemon"
|
||||
procname="/usr/local/bin/${name}"
|
||||
mai_args="-f ${mai_config}"
|
||||
mai_args="-f ${mai_config} -u www -g www"
|
||||
command_args="-S -m 3 -s info -l daemon -p ${pidfile} /usr/bin/env ${procname} ${mai_args}"
|
||||
|
||||
required_files="${mai_config}"
|
||||
|
@ -11,7 +11,7 @@ $_rc_subr_loaded . /etc/rc.subr
|
||||
name="mai"
|
||||
rcvar=$name
|
||||
command="/usr/pkg/bin/mai"
|
||||
command_args="-f /usr/pkg/etc/mai/mai.ini"
|
||||
command_args="-f /usr/pkg/etc/mai/mai.ini -u www -g www"
|
||||
pidfile="/var/run/${name}.pid"
|
||||
start_cmd="mai_start"
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# $TheSupernovaDuo$
|
||||
|
||||
daemon="/usr/local/bin/mai"
|
||||
daemon_flags="-f /usr/local/etc/mai/mai.ini"
|
||||
daemon_flags="-f /usr/local/etc/mai/mai.ini -u www -g www"
|
||||
|
||||
. /etc/rc.d/rc.subr
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
cmd: /usr/local/bin/mai -f /usr/local/etc/mai/mai.ini
|
||||
cmd: /usr/local/bin/mai -f /usr/local/etc/mai/mai.ini -g www -u www
|
||||
cwd: /usr/local/share/mai
|
||||
|
@ -127,8 +127,10 @@
|
||||
<br><br><br><br><br>
|
||||
<footer class="center">
|
||||
<p>
|
||||
<a href="https://git.chaotic.ninja/yakumo.izuru/mai">Source code</a><br>
|
||||
a <em>Mirage AIB</em> project | Favicon source is <a href="https://pixiv.net/en/artworks/97787072">ユキマイ</a>
|
||||
<a href="https://git.chaotic.ninja/yakumo.izuru/mai">Source code</a>
|
||||
</p>
|
||||
<p>
|
||||
A <a href="https://mirage.h0stname.net">Mirage AIB</a> project
|
||||
</p>
|
||||
</footer>
|
||||
<script src="/static/script.js"></script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user