Translate the whole site to English: English routes with 301 redirects from the Dutch paths, English UI, docs, seeds and captions, one-time live content migration

This commit is contained in:
2026-10-05 11:25:41 +02:00
parent bbdecdc95b
commit ff547e1677
153 changed files with 1095 additions and 774 deletions
+3 -3
View File
@@ -38,13 +38,13 @@ export class Application {
wireCopy() {
document.querySelectorAll("[data-copy]").forEach((node) => {
node.title = "Klik om te kopi\u00ebren";
node.title = "Click to copy";
node.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(node.textContent.trim());
this.toast("Gekopieerd");
this.toast("Copied");
} catch {
Toast.flash(node, "Kopi\u00ebren mislukt", 1500);
Toast.flash(node, "Copy failed", 1500);
}
});
});
+2 -2
View File
@@ -12,11 +12,11 @@ export class Chat extends Component {
form.className = "chat-form";
this.input = document.createElement("textarea");
this.input.rows = 2;
this.input.setAttribute("aria-label", "Bericht");
this.input.setAttribute("aria-label", "Message");
const send = document.createElement("button");
send.type = "submit";
send.className = "button small";
send.textContent = "Verstuur";
send.textContent = "Send";
form.append(this.input, send);
form.addEventListener("submit", (event) => {
event.preventDefault();
+3 -3
View File
@@ -23,13 +23,13 @@ export class Code extends Component {
const button = document.createElement("button");
button.type = "button";
button.className = "copy-button";
button.textContent = "Kopieer";
button.textContent = "Copy";
button.addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(code.textContent);
Toast.flash(button, "Gekopieerd", 1500, "Kopieer");
Toast.flash(button, "Copied", 1500, "Copy");
} catch {
Toast.flash(button, "Mislukt", 1500, "Kopieer");
Toast.flash(button, "Failed", 1500, "Copy");
}
});
this.prepend(button);
+1 -1
View File
@@ -10,7 +10,7 @@ export class Dialog extends Component {
this.setAttribute("aria-modal", "true");
}
confirm(message, { okLabel = "Ja", cancelLabel = "Annuleren" } = {}) {
confirm(message, { okLabel = "Yes", cancelLabel = "Cancel" } = {}) {
return new Promise((resolve) => {
this.replaceChildren();
const box = document.createElement("div");
+2 -2
View File
@@ -7,7 +7,7 @@ export class Lightbox extends Component {
setup() {
this.setAttribute("role", "dialog");
this.setAttribute("aria-modal", "true");
this.setAttribute("aria-label", "Afbeelding");
this.setAttribute("aria-label", "Image");
this.hidden = true;
this.image = document.createElement("img");
this.image.alt = "";
@@ -16,7 +16,7 @@ export class Lightbox extends Component {
this.closeButton = document.createElement("button");
this.closeButton.type = "button";
this.closeButton.className = "modal-close lightbox-close";
this.closeButton.setAttribute("aria-label", "Sluiten");
this.closeButton.setAttribute("aria-label", "Close");
this.closeButton.textContent = "\u00d7";
this.append(this.closeButton, this.image, this.caption);
this.items = [];
+1 -1
View File
@@ -13,7 +13,7 @@ export class Upload extends Component {
const button = document.createElement("button");
button.type = "button";
button.className = "button ghost small";
button.textContent = this.getAttribute("label") || "Bestand kiezen";
button.textContent = this.getAttribute("label") || "Choose file";
button.addEventListener("click", () => this.input.click());
this.input.addEventListener("change", () => this.emit("dp-files", { files: [...this.input.files] }));
this.addEventListener("dragover", (event) => {
+2 -2
View File
@@ -12,7 +12,7 @@ export class ApiTester {
const section = button.closest("[data-endpoint]");
const output = section.querySelector("[data-response]");
if (section.dataset.destructive === "1") {
const accepted = await window.app.dialog.confirm("Dit verzoek wijzigt echte data. Doorgaan?");
const accepted = await window.app.dialog.confirm("This request changes real data. Continue?");
if (!accepted) {
return;
}
@@ -53,7 +53,7 @@ export class ApiTester {
}
output.textContent = `${response.status} ${response.statusText} (${Math.round(performance.now() - started)} ms)\n\n${pretty}`;
} catch (error) {
output.textContent = `Fout: ${error.message}`;
output.textContent = `Error: ${error.message}`;
} finally {
LoadingButton.setLoading(button, false);
}
+4 -4
View File
@@ -3,10 +3,10 @@ import { Poller } from "./Poller.js";
export class LocalTime {
constructor() {
this.dateFormat = new Intl.DateTimeFormat("nl-NL", { day: "2-digit", month: "2-digit", year: "numeric" });
this.timeFormat = new Intl.DateTimeFormat("nl-NL", { hour: "2-digit", minute: "2-digit" });
this.fullFormat = new Intl.DateTimeFormat("nl-NL", { dateStyle: "full", timeStyle: "long" });
this.relative = new Intl.RelativeTimeFormat("nl-NL", { numeric: "auto" });
this.dateFormat = new Intl.DateTimeFormat("en-GB", { day: "2-digit", month: "2-digit", year: "numeric" });
this.timeFormat = new Intl.DateTimeFormat("en-GB", { hour: "2-digit", minute: "2-digit" });
this.fullFormat = new Intl.DateTimeFormat("en-GB", { dateStyle: "full", timeStyle: "long" });
this.relative = new Intl.RelativeTimeFormat("en-GB", { numeric: "auto" });
this.renderAll(document);
this.observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => mutation.addedNodes.forEach((node) => node.nodeType === 1 && this.renderAll(node)));
+2 -2
View File
@@ -12,12 +12,12 @@ export class TermsGate {
}
if (!this.pending) {
this.pending = this.dialog
.confirm(`De voorwaarden zijn gewijzigd (versie ${payload.error.terms_version}). Accepteren en doorgaan?`)
.confirm(`The terms have changed (version ${payload.error.terms_version}). Accept and continue?`)
.then(async (accepted) => {
if (!accepted) {
return false;
}
const result = await fetch("/voorwaarden/accept", {
const result = await fetch("/terms/accept", {
method: "POST",
credentials: "same-origin",
headers: { Accept: "application/json", "Content-Type": "application/json" },