summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstuebinm2021-04-08 17:44:53 +0200
committerstuebinm2021-04-08 17:53:10 +0200
commit3890d8ac88b2fdfa7b54d433e8e2edf2164be6f0 (patch)
tree375aafba67ee4c7a314bd55d17f89275bd691698
parent7e38d7f84463342dd428e7400777fdc675a8fbce (diff)
add translation logic, locales for en and de
This adds a basic "replace fixed keys"-approach to translating the UI of surveys. So far this works great, but for complex things it may fail for some languages — for now I'll just try to take care not to add any output that puts things in the middle of sentences, which I think should work for a simple survey thing. The default language is still english, which is important as the language is declared withing a survey config — i.e. if loading it fails, it cannot be applied, and the "enter passphrase" dialog can also not change based on locales. This could possibly be fixed by adding an unencrypted "header" to the encrypted configs, but for now I'm not sure if that makes a lot of sense — it may be easier to just guess based on the browser's settings, and otherwise fall back to some specified default language. The "thanks for your answers"-page also has no translation so far.
Diffstat (limited to '')
-rw-r--r--example-config.dhall3
-rw-r--r--site/examples/encrypted.jsonbin641 -> 652 bytes
-rw-r--r--site/examples/example.json2
-rw-r--r--site/i18n.js67
-rw-r--r--site/index.html31
-rw-r--r--site/thanks.html2
-rw-r--r--utils/src/main.rs13
7 files changed, 99 insertions, 19 deletions
diff --git a/example-config.dhall b/example-config.dhall
index 0b5d5ae..ae12897 100644
--- a/example-config.dhall
+++ b/example-config.dhall
@@ -1,6 +1,7 @@
{ title = "Test Survey"
, description = "This is a test survey."
-, pubkey = Some "age1te673wg4decpplhwrtw2x8atglrn59t87q0tllx7n7uhnr7qrg0ss6f36g"
+, lang = Lang.en
+, pubkey = Some "age1f380w6eaeuydey65mmu88h4kqv50dda96pxlgkal78sufpnngypqnetmuu"
, questions =
[ { question = "first question", name = "question1", space = Answers.YesOrNo }
, { question = "second question"
diff --git a/site/examples/encrypted.json b/site/examples/encrypted.json
index 3eac1c5..2e24d13 100644
--- a/site/examples/encrypted.json
+++ b/site/examples/encrypted.json
Binary files differ
diff --git a/site/examples/example.json b/site/examples/example.json
index 2a6c2f9..fcd09d8 100644
--- a/site/examples/example.json
+++ b/site/examples/example.json
@@ -1 +1 @@
-{"title":"Test Survey","description":"This is a test survey.","questions":[{"question":"first question","name":"question1","space":"YesOrNo"},{"question":"second question","name":"question2","space":{"Freeform":"test"}},{"question":"third question","name":"question3","space":{"Multiple":["first possible answer","second possible answer","third possible answer"]}}],"pubkey":"age1f380w6eaeuydey65mmu88h4kqv50dda96pxlgkal78sufpnngypqnetmuu"}
+{"title":"Test Survey","description":"This is a test survey.","questions":[{"question":"first question","name":"question1","space":"YesOrNo"},{"question":"second question","name":"question2","space":{"Freeform":"test"}},{"question":"third question","name":"question3","space":{"Multiple":["first possible answer","second possible answer","third possible answer"]}}],"pubkey":"age1f380w6eaeuydey65mmu88h4kqv50dda96pxlgkal78sufpnngypqnetmuu","lang":"en"} \ No newline at end of file
diff --git a/site/i18n.js b/site/i18n.js
new file mode 100644
index 0000000..38ffe7b
--- /dev/null
+++ b/site/i18n.js
@@ -0,0 +1,67 @@
+
+
+
+let langs = {
+ en : {
+ // error message in case the survey url was obviously invalid (currently only the case if none was given)
+ "Error: nothing here": "There's nothing here. Maybe try appending something after the url?\n\nAlternatively, check to see if you copied the whole url.",
+ // error message in case the http request on the survey url returned a status code that wasn't 200
+ "Error: survey doesn't exist": "Could not load this survey; are you sure that it exists?",
+ // error message in case the survey url was loaded, but had some obviously invalid format (i.e. neither json nor age encryption)
+ "Error: unknown format": "Could not load this survey; it appears to be in a wrong or unknown format.",
+ // text fragment in error messages, after which the survey url will be printed
+ "attempted path:": "Attempted path:",
+ // prompt for a passphrase
+ "please enter passphrase": "please enter a passphrase to access the survey:",
+ // error message in case decryption failed
+ "passphrase incorrect": "passphrase was incorrect!",
+ // document title for the decryption dialog
+ "Enter Passphrase": "Enter Passphrase",
+ // header of the decryption dialog
+ "Passphrase": "Passphrase",
+ // the text on the "decrypt" button
+ "decrypt": "decrypt",
+ // the text on the "submit" button
+ "submit": "submit",
+ // error message in case the given answers were invalid
+ "Error: answers invalid":"Cannot submit: not all required questions were filled in!",
+ // error message in case the post request failed entirely (i.e. printed if the .catch-clause of the fetch() function is reached)
+ "Error: could not post":"Error: The http POST request did not succeed.",
+ // error message in case the post request returned some other status code than 200; its status code and message will be appended in the next line after the text given here
+ "Error: post returned error":"Error: The http POST request returned an error code:"
+ },
+ de : {
+ "Error: nothing here": "Hier ist nichts. Evtl. hilft es, etwas hinten an die url dranzuhängen?\n\nAnsonsten: bist du dir sicher, dass du den ganzen Link hierher kopiert hast?",
+ "Error: survey doesn't exist": "Diese Umfrage konnte nicht geladen werden. Bist du sicher, dass sie existiert?",
+ "Error: unknown format": "Diese Umfrage scheint ein unbekanntes Format zu haben und konnte nicht angezeigt werden",
+ "attempted path:": "Abgerufener Pfad:",
+ "please enter passphrase": "Bitte gebe eine Passphrase ein, um die Umfrage zu entschlüsseln",
+ "passphrase incorrect": "Passphrase war nicht korrekt!",
+ "Passphrase": "Passphrase",
+ "decrypt":"entschlüsseln",
+ "submit":"absenden",
+ "Enter Passphrase": "Passphrase eingeben",
+ "Error: answers invalid":"Einige verpflichtenden Antworten fehlen!",
+ "Error: could not post":"Fehler: Die http POST Anfrage schlug fehl.",
+ "Error: post returned error":"Fehler: Die http POST Anfragen schlug fehl und gab einen Fehlercode zurück:"
+ }
+}
+
+// we use english by default until something else is set
+let locale = "en";
+
+// the main translation function. if no fitting translation
+// is found, it returns the key as a fallback value
+// (therefore, keys should themselves be understandable texts)
+export function _(key) {
+ console.log("getting translation for ", locale, key);
+ return !(locale in langs) ? key
+ : !(key in langs[locale]) ? key
+ : langs[locale][key]
+}
+
+export function setLang (loc) {
+ locale = loc;
+}
+
+export default _;
diff --git a/site/index.html b/site/index.html
index 5771e94..bceb936 100644
--- a/site/index.html
+++ b/site/index.html
@@ -1,4 +1,4 @@
-<html>
+<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
@@ -10,6 +10,7 @@
<script type="module">
import init, { age_encrypt, age_decrypt } from "./rage_wasm.js";
+ import _, { setLang } from "./i18n.js";
/// the basic idea here is to have functions which construct parts
/// of the DOM that renders the survey to a user. These functions
@@ -122,6 +123,8 @@
// makes a survey from a given json config object
function mkSurvey (survey) {
document.title = survey.title;
+ setLang(survey.lang);
+ document.getElementsByTagName("html")[0].lang = survey.lang;
// make the header with general information
let header = document.createElement("div");
appendChildren(header, [
@@ -146,7 +149,7 @@
});
let footer = mkElement("section");
- let submit = mkElement("button", "Submit");
+ let submit = mkElement("button", _("submit"));
let errormsg = mkElement("p", "", "error");
appendChildren(footer, [
mkElement("hr"),
@@ -182,17 +185,17 @@
console.log(response.text())
window.location.href = "thanks.html";
}
- errormsg.innerText = "POST request returned error code:\n"
+ errormsg.innerText = _("Error: post returned error") + "\n"
+ response.status + ": " + response.statusText;
errormsg.hidden = false;
}).catch(error => {
console.log(error);
- errormsg.innerText = "Error: The http POST request did not succeed.";
+ errormsg.innerText = _("Error: could not post");
errormsg.hidden = false;
});
} else {
- errormsg.innerText = "Cannot submit: not all required questions were filled in!";
+ errormsg.innerText = _("Error: answers invalid");
errormsg.hidden = false;
}
}
@@ -207,21 +210,21 @@
/// displays a passphrase prompt until the use enters a passphrase
/// which age can use for successful decryption
function askPassphrase (ciphertext, secondTry=false) {
- document.title = "Enter Passphrase";
+ document.title = _("Enter Passphrase");
let div = mkElement("div");
- let button = mkElement("button", "decrypt");
+ let button = mkElement("button", _("decrypt"));
let [passphrase,label] = mkOption(
"password",
- "please enter a passphrase to access the survey:"
+ _("please enter passphrase")
);
passphrase.value = "";
appendChildren(div, [
- mkElement("h1", "Passphrase"),
+ mkElement("h1", _("Passphrase")),
appendChildren(mkElement("p"),[label]),
passphrase,
button
].concat(
- secondTry ? [mkElement("p","passphrase was incorrect!","error")] : []
+ secondTry ? [mkElement("p",_("passphrase incorrect"),"error")] : []
));
root.appendChild(div);
button.onclick = () => {
@@ -247,7 +250,7 @@
mkElement("h1", "Error"),
mkElement("p", msg, "error"),
appendChildren(
- mkElement("p","attempted path: ","error"),
+ mkElement("p",_("attempted path:"),"error"),
[mkElement("tt", surveyUrl,"error")]
)
]);
@@ -275,7 +278,7 @@
console.log ("survey appears to be encrypted");
askPassphrase(bytearray);
} else {
- mkReadError ("Could not load this survey; it appears to be in a wrong or unknown format.");
+ mkReadError (_("Error: unknown format"));
}
}
/// if the survey was unencrypted, start it here. If it
@@ -287,14 +290,14 @@
}
// couldn't load survey json, show error message
} else {
- mkReadError ("Could not load this survey; are you sure that it exists?");
+ mkReadError (_("Error: survey doesn't exist"));
}
}
}
}
if (surveyUrl === "") {
- mkReadError ("There's nothing here. Maybe try appending something after the url?\n\nAlternatively, check to see if you copied the whole url.");
+ mkReadError (_("Error: nothing here"));
} else {
main ()
}
diff --git a/site/thanks.html b/site/thanks.html
index 1f0a18b..e7b5ad4 100644
--- a/site/thanks.html
+++ b/site/thanks.html
@@ -1,4 +1,4 @@
-<html>
+<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thanks for answering the survey!</title>
diff --git a/utils/src/main.rs b/utils/src/main.rs
index 3d6f885..4428ac3 100644
--- a/utils/src/main.rs
+++ b/utils/src/main.rs
@@ -12,11 +12,19 @@ use secrecy::ExposeSecret;
use age::x25519::Recipient;
#[derive(Deserialize, Serialize, StaticType, Debug)]
+#[serde(rename_all="lowercase")]
+enum Lang {
+ de,
+ en
+}
+
+#[derive(Deserialize, Serialize, StaticType, Debug)]
struct Survey {
title: String,
description: String,
questions: Vec<Question>,
- pubkey: Option<String>
+ pubkey: Option<String>,
+ lang: Lang
}
#[derive(Deserialize, Serialize, StaticType, Debug)]
@@ -56,9 +64,10 @@ fn main () {
// imported: just wrap our input code into a dhall "let"-statement.
// Probably doesn't scale very vell, though ...
let code = format!(
- "let Question = {} \nlet Answers = {} \nin {}",
+ "let Question = {} \nlet Answers = {} \nlet Lang = {}\nin {}",
Question::static_type(),
AnswerSpace::static_type(),
+ Lang::static_type(),
config_file
);
match serde_dhall::from_str(&code)