diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a067404f..65f5319e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -39,7 +39,7 @@ if you wanna have a go at coding it up yourself then maybe mention the idea on d
aside from documentation and ideas, some other things that would be cool to have some help with is:
-* **translations** -- the copyparty web-UI has translations for english and norwegian at the top of [browser.js](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/web/browser.js); if you'd like to add a translation for another language then that'd be welcome! and if that language has a grammar that doesn't fit into the way the strings are assembled, then we'll fix that as we go :>
+* **translations** -- the copyparty web-UI has translations in [copyparty/web/tl](https://github.com/9001/copyparty/tree/hovudstraum/copyparty/web/tl); if you'd like to [add a translation](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#translations) for another language then that'd be welcome! and if that language has a grammar that doesn't fit into the way the strings are assembled, then we'll fix that as we go :>
* but please note that support for [RTL (Right-to-Left) languages](https://en.wikipedia.org/wiki/Right-to-left_script) is currently not planned, since the javascript is a bit too jank for that
diff --git a/copyparty/__init__.py b/copyparty/__init__.py
index eba3651e..44ddd3c9 100644
--- a/copyparty/__init__.py
+++ b/copyparty/__init__.py
@@ -100,6 +100,25 @@ web/splash.html
web/splash.js
web/svcs.html
web/svcs.js
+web/tl/chi.js
+web/tl/cze.js
+web/tl/deu.js
+web/tl/epo.js
+web/tl/fin.js
+web/tl/fra.js
+web/tl/grc.js
+web/tl/ita.js
+web/tl/kor.js
+web/tl/nld.js
+web/tl/nno.js
+web/tl/nor.js
+web/tl/pol.js
+web/tl/por.js
+web/tl/rus.js
+web/tl/spa.js
+web/tl/swe.js
+web/tl/tur.js
+web/tl/ukr.js
web/ui.css
web/up2k.js
web/util.js
diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py
index ed5ac993..9020db3a 100644
--- a/copyparty/httpcli.py
+++ b/copyparty/httpcli.py
@@ -275,7 +275,7 @@ class HttpCli(object):
tpl = self.conn.hsrv.j2[name]
ka["r"] = self.args.SR if self.is_vproxied else ""
ka["ts"] = self.conn.hsrv.cachebuster()
- ka["lang"] = self.args.lang
+ ka["lang"] = self.cookies.get("cplng") or self.args.lang
ka["favico"] = self.args.favico
ka["s_doctitle"] = self.args.doctitle
ka["tcolor"] = self.vn.flags["tcolor"]
@@ -5077,7 +5077,7 @@ class HttpCli(object):
"edit": "edit" in self.uparam,
"title": html_escape(self.vpath, crlf=True),
"lastmod": int(ts_md * 1000),
- "lang": self.args.lang,
+ "lang": self.cookies.get("cplng") or self.args.lang,
"favico": self.args.favico,
"have_emp": int(self.args.emp),
"md_no_br": int(vn.flags.get("md_no_br") or 0),
diff --git a/copyparty/web/Makefile b/copyparty/web/Makefile
index 3989e931..99fd53f2 100644
--- a/copyparty/web/Makefile
+++ b/copyparty/web/Makefile
@@ -2,8 +2,8 @@
# which should help on really slow connections
# but then why are you using copyparty in the first place
-pk: $(addsuffix .gz, $(wildcard *.js *.css))
-un: $(addsuffix .un, $(wildcard *.gz))
+pk: $(addsuffix .gz, $(wildcard tl/*.js *.js *.css))
+un: $(addsuffix .un, $(wildcard tl/*.gz *.gz))
%.gz: %
pigz -11 -J 34 -I 573 $<
diff --git a/copyparty/web/browser.html b/copyparty/web/browser.html
index 2201ab58..9470465b 100644
--- a/copyparty/web/browser.html
+++ b/copyparty/web/browser.html
@@ -145,6 +145,9 @@
document.documentElement.className = (STG && STG.cpp_thm) || dtheme;
+ {%- if lang != "eng" %}
+
+ {%- endif %}
diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js
index 4ad645c4..74fcdac5 100644
--- a/copyparty/web/browser.js
+++ b/copyparty/web/browser.js
@@ -3,10 +3,8 @@
var XHR = XMLHttpRequest,
img_re = /\.(a?png|avif|bmp|gif|heif|jpe?g|jfif|svg|webp|webm|mkv|mp4|m4v|mov)(\?|$)/i;
-// please add translations in alphabetic order, but keep "eng" and "nor" first
-// (lines ending with //m are machine translations)
-var Ls = {
- "eng": {
+if (1)
+ Ls.eng = {
"tt": "English",
"cols": {
@@ -26,7 +24,7 @@ var Ls = {
"resw": "horizontal resolution",
"resh": "vertical resolution",
"chs": "audio channels",
- "hz": "sample rate"
+ "hz": "sample rate",
},
"hks": [
@@ -639,18 +637,43 @@ var Ls = {
"lang_set": "refresh to make the change take effect?",
};
-var LANGS = ["eng", "nor", "chi", "cze", "deu", "epo", "fin", "fra", "grc", "ita", "kor", "nld", "nno", "pol", "por", "rus", "spa", "swe", "tur", "ukr"];
+var LANGN = [
+ ["eng", "English"],
+ ["nor", "Norsk"],
+ ["chi", "中文"],
+ ["cze", "Čeština"],
+ ["deu", "Deutsch"],
+ ["epo", "Esperanto"],
+ ["fin", "Suomi"],
+ ["fra", "français"],
+ ["grc", "Ελληνικά"],
+ ["ita", "Italiano"],
+ ["kor", "한국어"],
+ ["nld", "Nederlands"],
+ ["nno", "Nynorsk"],
+ ["pol", "Polski"],
+ ["por", "Português"],
+ ["rus", "Русский"],
+ ["spa", "Español"],
+ ["swe", "Svenska"],
+ ["tur", "Türkçe"],
+ ["ukr", "Українська"],
+];
if (window.langmod)
langmod();
-for (var a = LANGS.length; a > 0;)
- if (!Ls[LANGS[--a]])
- LANGS.splice(a, 1);
+var L = Ls[lang] || Ls.eng, LANGS = [];
+for (var a = 0; a < LANGN.length; a++)
+ LANGS.push(LANGN[a][0]);
-var L = Ls[sread("cpp_lang", LANGS) || lang] ||
- Ls.eng || Ls.nor || Ls.chi;
+function langtest() {
+ var n = LANGS.length - 1;
+ for (var a = 1; a < LANGS.length; a++)
+ import_js(SR + '/.cpr/tl/' + LANGS[a] + '.js', function () { if (!--n) langtest2(); });
+}
+function langtest2() {
for (var a = 0; a < LANGS.length; a++) {
for (var b = a + 1; b < LANGS.length; b++) {
var i1 = Object.keys(Ls[LANGS[a]]).length > Object.keys(Ls[LANGS[b]]).length ? a : b,
@@ -665,8 +688,11 @@ for (var a = 0; a < LANGS.length; a++) {
}
}
}
+}
-if (!has(LANGS, lang))
+
+
+if (!Ls[lang])
alert('unsupported --lang "' + lang + '" specified in server args;\nplease use one of these: ' + LANGS);
modal.load();
@@ -6581,9 +6607,7 @@ var treectl = (function () {
bcfg_bind(r, 'csel', 'csel', dgsel);
bcfg_bind(r, 'dots', 'dotfiles', see_dots, function (v) {
r.goto();
- var xhr = new XHR();
- xhr.open('GET', SR + '/?setck=dots=' + (v ? 'y' : ''), true);
- xhr.send();
+ setck('dots=' + (v ? 'y' : ''));
});
bcfg_bind(r, 'utctid', 'utctid', dutc, function (v) {
window.unix2ui = v ? unix2iso : unix2iso_localtime;
@@ -6620,9 +6644,7 @@ var treectl = (function () {
if (!v == !/\bidxh=y\b/.exec('' + document.cookie))
return;
- var xhr = new XHR();
- xhr.open('GET', SR + '/?setck=idxh=' + (v ? 'y' : 'n'), true);
- xhr.send();
+ setck('idxh=' + (v ? 'y' : 'n'));
}
setidxh(r.idxh);
@@ -7368,10 +7390,7 @@ var treectl = (function () {
qsr('#bbsw');
srvinf = ebi('srv_info').innerHTML.slice(6, -7);
if (ls0 === null) {
- var xhr = new XHR();
- xhr.open('GET', SR + '/?setck=js=y', true);
- xhr.send();
-
+ setck('js=y');
r.ls_cb = showfile.addlinks;
return r.reqls(get_evpath(), false, undefined, true);
}
@@ -8164,11 +8183,9 @@ var setfszf = (function () {
(function () {
function freshen() {
- lang = sread("cpp_lang", LANGS) || lang;
- var k, cb = ebi('langs'), html = [];
- for (var a = 0; a < LANGS.length; a++) {
- k = LANGS[a];
- html.push(''.format(k, Ls[k].tt));
+ var cb = ebi('langs'), html = [];
+ for (var a = 0; a < LANGN.length; a++) {
+ html.push(''.format(LANGN[a][0], LANGN[a][1]));
}
cb.innerHTML = html.join('');
cb.onchange = setlang;
@@ -8177,11 +8194,10 @@ var setfszf = (function () {
function setlang(e) {
ev(e);
- var t = L.lang_set;
lang = ebi('langs').value;
- L = Ls[lang];
- swrite("cpp_lang", lang);
+ setck('cplng=' + lang);
freshen();
+ var t = L.tt == 'English' ? '' : Ls.eng.lang_set;
modal.confirm(L.lang_set + "\n\n" + t, location.reload.bind(location), null);
}
diff --git a/copyparty/web/splash.html b/copyparty/web/splash.html
index e98d5f63..1dd635d6 100644
--- a/copyparty/web/splash.html
+++ b/copyparty/web/splash.html
@@ -211,6 +211,9 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
+{%- if lang != "eng" %}
+
+{%- endif %}
{%- if js %}
diff --git a/copyparty/web/splash.js b/copyparty/web/splash.js
index 11bb714b..6185f341 100644
--- a/copyparty/web/splash.js
+++ b/copyparty/web/splash.js
@@ -1,7 +1,5 @@
-// please add translations in alphabetic order, but keep "nor" and "eng" first
-// (lines ending with //m are machine translations)
-var Ls = {
- "eng": {
+Ls.eng = {
+ "splash": {
"d2": "shows the state of all active threads",
"e2": "reload config files (accounts/volumes/volflags),$Nand rescan all e2ds volumes$N$Nnote: any changes to global settings$Nrequire a full restart to take effect",
"lo2": "ends the session on all browsers",
@@ -10,14 +8,13 @@ var Ls = {
"ta1": "fill in your new password first",
"ta2": "repeat to confirm new password:",
"ta3": "found a typo; please try again",
- },
+ }
};
if (window.langmod)
langmod();
-var d = Ls[sread("cpp_lang", Object.keys(Ls)) || lang] ||
- Ls.eng || Ls.nor || Ls.chi;
+var d = (Ls[lang] || Ls.eng).splash;
d.wb = d.w;
diff --git a/copyparty/web/util.js b/copyparty/web/util.js
index ee8e5b98..9a97b32a 100644
--- a/copyparty/web/util.js
+++ b/copyparty/web/util.js
@@ -296,6 +296,10 @@ function ignex(all) {
window.onerror = vis_exh;
+if (!window.Ls || !window.langmod)
+ var Ls = {};
+
+
function noop() { }
@@ -1307,6 +1311,11 @@ function scfg_bind(obj, oname, cname, defval, cb) {
return v;
}
+function setck(v) {
+ var xhr = new XHR();
+ xhr.open('GET', SR + '/?setck=' + v, true);
+ xhr.send();
+}
window.unix2ui = (function () {
var v = sread('utctid');
diff --git a/docs/devnotes.md b/docs/devnotes.md
index 50bafc89..140f6bbf 100644
--- a/docs/devnotes.md
+++ b/docs/devnotes.md
@@ -415,6 +415,7 @@ if you are unable to use `build`, you can use the old setuptools approach instea
```bash
python3 setup.py install --user setuptools wheel jinja2
python3 setup.py build
+python3 setup.py bdist_wheel
# you now have a wheel which you can install. or extract and repackage:
python3 setup.py install --skip-build --prefix=/usr --root=$HOME/pe/copyparty
```
diff --git a/docs/rice/README.md b/docs/rice/README.md
index 3d3b7cfe..4573a085 100644
--- a/docs/rice/README.md
+++ b/docs/rice/README.md
@@ -69,23 +69,13 @@ there is also `--html-head-s` and volflag `html_head_s` to add a plain static bi
# translations
-add your own translations by using the english or norwegian one from `browser.js` as a template
+add your own translations by using [tl.js](https://github.com/9001/copyparty/blob/hovudstraum/scripts/tl.js) as a base, and add a new file in [copyparty/web/tl](https://github.com/9001/copyparty/tree/hovudstraum/copyparty/web/tl) when you're happy with it
> ⚠ Please do not contribute translations to [RTL (Right-to-Left) languages](https://en.wikipedia.org/wiki/Right-to-left_script) for now; the javascript is [not ready](https://github.com/9001/copyparty/blob/hovudstraum/docs/rice/rtl.patch) to deal with it
-the easy way is to open up and modify `browser.js` in your own installation; depending on how you installed copyparty it might be named `browser.js.gz` instead, in which case just decompress it, restart copyparty, and start editing it anyways
-
you will be delighted to see inline html in the translation strings; to help prevent syntax errors, there is [a very jank linux script](https://github.com/9001/copyparty/blob/hovudstraum/scripts/tlcheck.sh) which is slightly better than nothing -- just beware the false-positives, so even if it complains it's not necessarily wrong/bad
-if you're running `copyparty-sfx.py` then you'll find it at `/tmp/pe-copyparty.1000/copyparty/web` (on linux) or `%TEMP%\pe-copyparty\copyparty\web` (on windows)
-* make sure to keep backups of your work religiously! since that location is volatile af
-
-
-## translations (docker-friendly)
-
-if editing `browser.js` is inconvenient in your setup, for example if you're running in docker, then you can instead do this:
-* if you have python, go to the `scripts` folder and run `./tl.py fra Français` to generate a `tl.js` which is perfect for translating to French, using the three-letter language code `fra`
- * if you do not have python, you can also just grab `tl.js` from the scripts folder, but I'll probably forget to keep that up to date... and then you'll have to find/replace all `"eng"` and `Ls.eng` to your three-letter language code
+to see your translation taking shape in the copyparty ui as you work on it:
* put your `tl.js` inside a folder that is being shared by your copyparty, preferably the webroot
* run copyparty with the argument `--html-head=''`
* if you placed `tl.js` in the webroot then you're all good, but if you put it somewhere else then change `/tl.js` accordingly
@@ -97,6 +87,4 @@ if editing `browser.js` is inconvenient in your setup, for example if you're run
you can now edit `tl.js` and press CTRL-SHIFT-R in the browser to see your changes take effect as you go
-if you want to contribute your translation back to the project (please do!) then you'll want to...
-* grab all of the text inside your `var tl_cpanel = {` and add it to the translations inside `copyparty/web/splash.js` in the repo
-* and the text inside your `var tl_browser = {` and add that to the translations inside `copyparty/web/browser.js` in the repo
+if you want to contribute your translation back to the project (please do!) then grab most of the text inside your `tl.js` , starting from the line that starts with `Ls.` and put it into a new file inside [the translations folder](https://github.com/9001/copyparty/tree/hovudstraum/copyparty/web/tl)
diff --git a/pyproject.toml b/pyproject.toml
index 54668406..6041a3ce 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -94,6 +94,8 @@ copyparty = [
"web/*.css",
"web/*.html",
"web/*.xml",
+ "web/tl/*.js",
+ "web/tl/*.gz",
"web/a/*.bat",
"web/deps/*.gz",
"web/deps/*.woff*",
diff --git a/scripts/make-sfx.sh b/scripts/make-sfx.sh
index 592b9096..e9aa80fb 100755
--- a/scripts/make-sfx.sh
+++ b/scripts/make-sfx.sh
@@ -481,10 +481,12 @@ rm -f ftp/pyftpdlib/{__main__,prefork}.py
langs="eng|$langs"
aerr "ERROR: removing english is not supported; will do this instead: $langs"
}
- for f in copyparty/web/{browser.js,splash.js}; do
- gzip -d "$f.gz" || true
- iawk '/^\}/{l=0} !l; /^var Ls =/{l=1;next} !l{next} o; /^\t["}]/{o=0} /^\t"'"$langs"'"/{o=1;print}' $f
- done
+ f=copyparty/web/browser.js
+ gzip -d "$f.gz" || true
+ iawk '/^\]/{s=0} !s; /^var LANGN /{s=1;next} !s{next} /"'"$langs"'"/' $f
+ ls -1 copyparty/web/tl/* >t
+ grep -vE "/($langs)\." (you're not logged in)",
"c1": "logout",
@@ -115,21 +110,9 @@ var tl_cpanel = {{
"ac1": "enable no304",
"ad1": "enabling no304 will disable all caching; try this if k304 wasn't enough. This will waste a huge amount of network traffic!",
"ae1": "active downloads:",
- "af1": "show recent uploads",
- }},
+ "af1": "show recent uploads",
+ }}
}};
-
-
-////////////////////////////////////////////////////////////////////////
-// translation of browser.js (the filebrowser):
-
-var tl_browser = {{
- "{lang3}": {{
- "tt": "{native_name}",
-
- {tl_browser}
-}};
-
"""
@@ -158,7 +141,8 @@ def main():
browserjs = f.read().decode("utf-8")
_, browserjs = browserjs.split('\n\t\t"tt": "English",\n', 1)
- browserjs, _ = browserjs.split('\n\t"nor": {', 1)
+ browserjs, _ = browserjs.split('\n}', 1)
+ browserjs = browserjs.replace("\n\t", "\n")
try:
lang3 = sys.argv[1]
diff --git a/scripts/tlcheck.sh b/scripts/tlcheck.sh
index 736c4bd5..6bd81c09 100755
--- a/scripts/tlcheck.sh
+++ b/scripts/tlcheck.sh
@@ -1,13 +1,15 @@
#!/bin/bash
set -e
-# usage: ./scripts/tlcheck.sh eng chi copyparty/web/browser.js
+[ -f "$1" ] && [ -f "$2" ] && [ $# = 2 ] || {
+ echo usage: ./scripts/tlcheck.sh scripts/tl.js copyparty/web/tl/nor.js
+ exit 1
+}
-awk <"$3" -v lang1=\"$1\": -v lang2=\"$2\": '
- /^\t\}/{fa=0;fb=0}
+cat "$1" "$2" | awk '
+ /^\}/{fa=0;fb=0}
+ /^Ls\./{if(nln++){fb=1}else{fa=1}}
!/":/{next}
- $0~lang1{fa=1}
- $0~lang2{fb=1}
fa{a[ia++]=$0}
fb{b[ib++]=$0}
END{for (i=0;i