translation of comments and some other german terms

This commit is contained in:
stefan.tollkuehn committed 2026-10-22 16:34:01 +02:00
1 parent 5d54f574e0
commit 3267b6a6a3
3 files changed
+120 -119

No files matched your search

+4 -4
View File
@@ -1,7 +1,7 @@
{
"en": {
"pageTitle": "Jitsi Meeting",
"impressum": "Legal Notice",
"legal_notice": "Legal Notice",
"source": "Source",
"launcher": {
"title": "Jitsi Meeting",
@@ -91,7 +91,7 @@
},
"de": {
"pageTitle": "Jitsi Meeting öffnen",
"impressum": "Impressum",
"legal_notice": "Impressum",
"source": "Quellcode",
"launcher": {
"title": "Jitsi Meeting",
@@ -181,7 +181,7 @@
},
"fr": {
"pageTitle": "Réunion Jitsi",
"impressum": "Mentions légales",
"legal_notice": "Mentions légales",
"source": "Code source",
"launcher": {
"title": "Réunion Jitsi",
@@ -271,7 +271,7 @@
},
"zh": {
"pageTitle": "Jitsi 会议",
"impressum": "法律声明",
"legal_notice": "法律声明",
"source": "源代码",
"launcher": {
"title": "Jitsi 会议",
+114 -113
View File
@@ -1,13 +1,13 @@
"use strict";
/* ============================================================
* KONFIGURATION
* CONFIGURATION
* ============================================================
*/
/*
* Konfiguration liegt in assets/config.json und wird beim
* Start asynchron geladen (siehe START).
* Configuration lives in assets/config.json and is loaded
* asynchronously at startup (see START).
*/
let CONFIG = {};
const CONFIG_URL = "assets/config.json";
@@ -18,8 +18,8 @@ const CONFIG_URL = "assets/config.json";
*/
/*
* Sprachen liegen in assets/i18n.json und werden beim
* Start asynchron geladen (siehe START).
* Translations live in assets/i18n.json and are loaded
* asynchronously at startup (see START).
*/
let TRANSLATIONS = {};
const I18N_URL = "assets/i18n.json";
@@ -31,7 +31,7 @@ const I18N_URL = "assets/i18n.json";
function detectLanguage() {
/*
* Gespeicherte Sprachwahl hat Vorrang.
* Saved language choice takes precedence.
*/
try {
const saved = localStorage.getItem("jitsiLauncherLanguage");
@@ -41,7 +41,7 @@ function detectLanguage() {
}
} catch (error) {
/*
* localStorage kann z.B. im Privat-Modus blockiert sein.
* localStorage can be blocked, e.g. in private mode.
*/
}
@@ -62,7 +62,7 @@ function detectLanguage() {
}
/*
* Englisch ist der Standard/Fallback.
* English is the default/fallback.
*/
return "en";
}
@@ -93,7 +93,7 @@ function applyTranslations() {
});
/*
* Platzhalter von Eingabefeldern übersetzen.
* Translate placeholders of input fields.
*/
document
.querySelectorAll("[data-i18n-placeholder]")
@@ -107,13 +107,13 @@ function applyTranslations() {
}
/*
* Übersetzung anhand eines Pfades lesen.
* Read a translation by path.
*
* Beispiel:
* Example:
*
* "downloads.windows.title"
*
* ergibt:
* resolves to:
*
* translation.downloads.windows.title
*/
@@ -182,7 +182,7 @@ function setLanguage(language) {
localStorage.setItem("jitsiLauncherLanguage", language);
} catch (error) {
/*
* localStorage kann z.B. im Privat-Modus blockiert sein.
* localStorage can be blocked, e.g. in private mode.
*/
}
@@ -236,7 +236,7 @@ function savedTheme() {
}
} catch (error) {
/*
* localStorage kann z.B. im Privat-Modus blockiert sein.
* localStorage can be blocked, e.g. in private mode.
*/
}
@@ -249,7 +249,7 @@ function systemIsDark() {
function detectTheme() {
/*
* Gespeicherte Wahl hat Vorrang, sonst System-Einstellung.
* Saved choice takes precedence, otherwise system setting.
*/
return savedTheme() || (systemIsDark() ? "dark" : "light");
}
@@ -273,7 +273,7 @@ function toggleTheme() {
localStorage.setItem(THEME_KEY, currentTheme);
} catch (error) {
/*
* localStorage kann z.B. im Privat-Modus blockiert sein.
* localStorage can be blocked, e.g. in private mode.
*/
}
@@ -315,8 +315,8 @@ function applyLogo() {
*/
/*
* Nur anzeigen, wenn eine Nextcloud-Instanz konfiguriert
* ist (CONFIG.nextcloudBase in assets/config.json).
* Only show if a Nextcloud instance is configured
* (CONFIG.nextcloudBase in assets/config.json).
*/
function applyNextcloudButton() {
if (!CONFIG.nextcloudBase || !createNextcloudButton) {
@@ -332,7 +332,7 @@ function applyNextcloudButton() {
*/
/*
* Nur anzeigen, wenn explizit aktiviert
* Only show if explicitly enabled
* (CONFIG.allowAdhocMeetings in assets/config.json).
*/
function applyAdhocButton() {
@@ -421,11 +421,11 @@ const themeIconMoon = document.getElementById("themeIconMoon");
* GET ROOM FROM QUERY-PARAMETER
* ============================================================
*
* Beispiel:
* Example:
*
* https://<YOURJITSIINSTANCEADDRESS>/launch.html?room=abc-defg-hij
*
* ergibt:
* results in:
*
* abc-defg-hij
*
@@ -438,16 +438,16 @@ function getRoom() {
);
/*
* Parameter nicht vorhanden.
* Parameter missing.
*/
if (!params.has("room")) {
return null;
}
/*
* Leerzeichen etc. verhindern.
* Prevent whitespace etc.
*
* "?room=" ohne Wert ergibt einen leeren String.
* "?room=" without a value yields an empty string.
*/
return params.get("room").trim();
}
@@ -456,11 +456,11 @@ function getRoom() {
* VALIDATE ROOM
* ============================================================
*
* Jitsi-Roomnamen können je nach Konfiguration relativ
* unterschiedliche Zeichen enthalten.
* Jitsi room names can contain rather different
* characters depending on the configuration.
*
* Wir verhindern hier lediglich Steuerzeichen und
* offensichtliche URL-Manipulation.
* We only prevent control characters and obvious
* URL manipulation here.
*
* ============================================================
*/
@@ -473,7 +473,7 @@ function isValidRoom(room) {
}
/*
* Nur Buchstaben, Zahlen und Bindestriche.
* Only letters, numbers and hyphens.
*/
return ROOM_PATTERN.test(room);
}
@@ -511,10 +511,10 @@ function createAppUrl(room) {
* ============================================================ */
/*
* Die Android-App registriert "org.jitsi.meet", nicht das
* Desktop-Schema. Chrome & Co. verlangen intent://, ohne App
* bietet Chrome den Play-Store-Eintrag aus "package=" an.
* Firefox ignoriert intent://, kennt aber das Custom-Schema.
* The Android app registers "org.jitsi.meet", not the
* desktop scheme. Chrome & co. require intent://; without
* the app Chrome offers the Play Store entry from "package=".
* Firefox ignores intent:// but knows the custom scheme.
*/
function createAndroidIntentUrl(room) {
@@ -528,8 +528,8 @@ function createAndroidIntentUrl(room) {
}
/*
* Die Mobile-Apps (iOS, Firefox auf Android) registrieren
* "org.jitsi.meet", nicht das Desktop-Schema.
* The mobile apps (iOS, Firefox on Android) register
* "org.jitsi.meet", not the desktop scheme.
*/
const APP_SCHEME = "org.jitsi.meet://";
@@ -543,14 +543,14 @@ function createAppSchemeUrl(room) {
}
/* ============================================================
* URL NACH PLATTFORM/BROWSER
* URL BY PLATFORM/BROWSER
* ============================================================ */
function selectProtocolUrl(room) {
const os = detectOperatingSystem();
/*
* iOS-App kennt nur das App-Schema.
* The iOS app only knows the app scheme.
*/
if (os === "ios") {
return createAppSchemeUrl(room);
@@ -571,8 +571,8 @@ function selectProtocolUrl(room) {
*/
/*
* Einmal parsen (assets/lib/ua-parser.min.js).
* Fällt die Bibliothek aus, bleibt die Seite bedienbar.
* Parse once (assets/lib/ua-parser.min.js).
* If the library is missing, the page stays usable.
*/
const uaResult =
typeof UAParser === "function"
@@ -580,8 +580,8 @@ const uaResult =
: { os: {}, browser: {} };
/*
* UAParser-Namen -> interne Kürzel.
* iPadOS meldet sich als macOS – Touchpunkte gelten als iOS.
* UAParser names -> internal shortcuts.
* iPadOS reports as macOS – touch points count as iOS.
*/
const OS_NAMES = {
Android: "android",
@@ -614,9 +614,9 @@ const BROWSER_NAMES = {
function detectOperatingSystem() {
/*
* Chrome im "Desktop-Modus" auf Android sendet einen
* Desktop-UA (z.B. X11; Linux). Client Hints verraten
* das echte System. Firefox/Safari kennen sie nicht.
* Chrome in "desktop mode" on Android sends a desktop
* UA (e.g. X11; Linux). Client hints reveal the real
* system. Firefox/Safari do not support them.
*/
const hints = navigator.userAgentData;
if (hints && hints.platform === "Android") {
@@ -624,8 +624,9 @@ function detectOperatingSystem() {
}
/*
* iPadOS tarnt sich als macOS – Touchpunkte verraten das iPad.
* Der Plattform-Check greift auch ohne geladenen ua-parser.
* iPadOS masquerades as macOS – touch points give the
* iPad away. The platform check also works without the
* ua-parser loaded.
*/
if (
navigator.maxTouchPoints > 1 &&
@@ -638,7 +639,7 @@ function detectOperatingSystem() {
}
/* ============================================================
* BROWSER ERKENNEN
* DETECT BROWSER
* ============================================================
*/
@@ -696,12 +697,12 @@ function configureDownloads() {
return;
}
/* Alles andere */
/* Everything else */
otherDownload.classList.remove("hidden");
}
/* ============================================================
* FALLBACK ANZEIGEN
* SHOW FALLBACK
* ============================================================
*/
@@ -714,7 +715,7 @@ function showFallback() {
}
/* ============================================================
* JITSI DESKTOP STARTEN
* START JITSI DESKTOP
* ============================================================
*/
@@ -729,12 +730,12 @@ function launchJitsi() {
const browserUrl = createBrowserUrl(room);
/*
* Browser-Fallback vorbereiten.
* Prepare the browser fallback.
*/
browserLink.href = browserUrl;
/*
* UI auf "Startvorgang" setzen.
* Set the UI to the "starting" state.
*/
launcher.classList.add("hidden");
fallback.classList.add("hidden");
@@ -744,13 +745,13 @@ function launchJitsi() {
let timeout = null;
/*
* Unsichtbarer iframe für den Protocol Handler.
* Invisible iframe for the protocol handler.
*/
const iframe = document.createElement("iframe");
iframe.style.display = "none";
/*
* Aufräumen.
* Clean up.
*/
function cleanup() {
if (completed) {
@@ -768,25 +769,25 @@ function launchJitsi() {
/*
* --------------------------------------------------------
* WICHTIG:
* IMPORTANT:
*
* Kein "blur" mehr als Erfolgskriterium verwenden.
* Do not use "blur" as a success criterion anymore.
*
* Der Browser kann beim Protocol-Dialog ebenfalls
* blur auslösen.
* The browser can also trigger blur when showing
* the protocol dialog.
*
* Wenn der Benutzer den Dialog abbricht, bleibt die
* Seite sichtbar und unser Timeout läuft weiter.
* If the user cancels the dialog, the page stays
* visible and our timeout keeps running.
* --------------------------------------------------------
*/
document.body.appendChild(iframe);
/*
* Protocol Handler starten.
* Start the protocol handler.
*
* Firefox ignoriert externe Protokolle aus iframes –
* das Custom-Schema direkt in der Hauptnavigation starten.
* Firefox ignores external protocols from iframes –
* start the custom scheme directly in the main navigation.
*/
try {
if (protocolUrl.startsWith(APP_SCHEME)) {
@@ -811,19 +812,19 @@ function launchJitsi() {
* FALLBACK
* --------------------------------------------------------
*
* Wir warten unabhängig davon, ob der Browser kurz
* den Fokus verliert.
* We wait regardless of whether the browser briefly
* loses focus.
*
* Wenn Jitsi erfolgreich startet:
* If Jitsi starts successfully:
*
* -> Jitsi kommt in den Vordergrund
* -> Benutzer sieht diese Seite nicht mehr
* -> Jitsi comes to the foreground
* -> the user no longer sees this page
*
* Wenn der Benutzer den Browser-Dialog abbricht:
* If the user cancels the browser dialog:
*
* -> diese Seite bleibt sichtbar
* -> Timeout läuft ab
* -> Fallback wird angezeigt
* -> this page stays visible
* -> the timeout expires
* -> the fallback is shown
* --------------------------------------------------------
*/
@@ -843,13 +844,13 @@ function launchJitsi() {
*/
/*
* Sonderzeichen in das nächstliegende ASCII-Zeichen
* umwandeln.
* Convert special characters to the closest ASCII
* character.
*
* Beispiel:
* Example:
*
* "Grundstück" ergibt "Grundstueck"
* "François" ergibt "Francois"
* "Grundstück" becomes "Grundstueck"
* "François" becomes "Francois"
*/
function transliterate(text) {
const extras = {
@@ -870,11 +871,11 @@ function transliterate(text) {
}
/*
* Aus dem Meeting-Namen einen gültigen Room-Namen ableiten.
* Derive a valid room name from the meeting name.
*
* Beispiel:
* Example:
*
* "Grund Stück Planung" ergibt "grund-stuck-planung"
* "Grund Stück Planung" becomes "grund-stuck-planung"
*/
function createRoomName(meetingName) {
return transliterate(meetingName)
@@ -954,12 +955,12 @@ const MINUTES_STEP = 15;
const DEFAULT_DURATION_MINUTES = 30;
/*
* Minuten auf das 15-Minuten-Raster aufrunden.
* Round minutes up to the 15-minute grid.
*
* Beispiel:
* Example:
*
* 14:07 ergibt 14:15
* 14:50 ergibt 15:00
* 14:07 becomes 14:15
* 14:50 becomes 15:00
*/
function roundMinutes(date) {
const rounded = new Date(date);
@@ -973,11 +974,11 @@ function roundMinutes(date) {
}
/*
* Lokale Zeit für datetime-local formatieren.
* Format local time for datetime-local.
*
* Beispiel:
* Example:
*
* 1. Januar 2026, 14:15 ergibt "2026-01-01T14:15"
* January 1, 2026, 14:15 becomes "2026-01-01T14:15"
*/
function formatLocal(date) {
const pad = (num) => num.toString().padStart(2, "0");
@@ -1066,8 +1067,8 @@ function openNextcloudCalendarCreator() {
}
/*
* Nextcloud validiert die E-Mail serverseitig und
* bricht sonst mit einer Fehlerseite ab.
* Nextcloud validates the email server-side and
* aborts with an error page otherwise.
*/
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -1177,17 +1178,17 @@ function createMeeting() {
*/
/*
* Zeitspanne, nach der der "Kopiert!"-Text zum
* normalen Button-Label zurückkehrt.
* Time span after which the "Copied!" text returns
* to the normal button label.
*/
const COPY_RESET_MS = 2000;
/*
* Launch-URL, die das Meeting im Jitsi-Client öffnet.
* Launch URL that opens the meeting in the Jitsi client.
*
* Beispiel:
* Example:
*
* "projekt-kickoff" ergibt
* "projekt-kickoff" becomes
* https://meet.bnvb.eu/launch.html?room=projekt-kickoff
*/
function createLaunchUrl(roomName) {
@@ -1221,7 +1222,7 @@ function createAdhocLink() {
async function copyAdhocLink() {
const url = adhocLink.href;
/* Clipboard-API, mit Fallback für ältere Browser */
/* Clipboard API, with a fallback for older browsers */
try {
await navigator.clipboard.writeText(url);
} catch (error) {
@@ -1233,7 +1234,7 @@ async function copyAdhocLink() {
document.body.removeChild(input);
}
/* Kurzes Feedback, dann zurück zum normalen Label */
/* Brief feedback, then back to the normal label */
copyAdhocLinkButton.textContent = getTranslation('creator.copiedLabel') || 'Copied!';
setTimeout(() => {
copyAdhocLinkButton.textContent = getTranslation('creator.copyLinkButton') || 'Copy Link';
@@ -1255,7 +1256,7 @@ function cancelCreateMeeting() {
}
/* ============================================================
* INITIALISIERUNG
* INITIALIZATION
* ============================================================
*/
@@ -1263,8 +1264,8 @@ function initialize() {
const room = getRoom();
/*
* Kein room-Parameter: Meldungen ausblenden,
* nur den Create-Button anzeigen.
* No room parameter: hide the messages,
* only show the Create button.
*/
if (room === null) {
missingRoomTitle.classList.add("hidden");
@@ -1277,8 +1278,8 @@ function initialize() {
}
/*
* Leerer room-Parameter ("?room="):
* "No meeting specified" anzeigen.
* Empty room parameter ("?room="):
* show "No meeting specified".
*/
if (room === "") {
missingRoomTitle.classList.remove("hidden");
@@ -1291,8 +1292,8 @@ function initialize() {
}
/*
* Ungültiger room-Parameter: nur die
* Invalid-Name-Meldung anzeigen.
* Invalid room parameter: only show
* the invalid-name message.
*/
if (!isValidRoom(room)) {
missingRoomTitle.classList.add("hidden");
@@ -1306,17 +1307,17 @@ function initialize() {
}
/*
* Room anzeigen.
* Show the room.
*/
roomName.textContent = room;
/*
* Browser-Fallback vorbereiten.
* Prepare the browser fallback.
*/
browserLink.href = createBrowserUrl(room);
/*
* Launcher anzeigen.
* Show the launcher.
*/
launcher.classList.remove("hidden");
@@ -1326,7 +1327,7 @@ function initialize() {
createNewFromLauncherButton.classList.add("hidden");
/*
* Debug-Informationen.
* Debug information.
*/
console.log(
"Jitsi Launcher",
@@ -1441,7 +1442,7 @@ navToggle.addEventListener(
);
/*
* Ohne gespeicherte Wahl dem System folgen.
* Follow the system if no choice is saved.
*/
window
.matchMedia("(prefers-color-scheme: dark)")
@@ -1463,8 +1464,8 @@ async function loadConfig() {
CONFIG = await response.json();
} catch (error) {
/*
* Ohne Datei bleiben Launcher unbrauchbar – Fehler
* melden und mit leerer Konfiguration fortfahren.
* Without the file the launcher stays unusable –
* report the error and continue with an empty config.
*/
console.error("Error loading config:", error);
}
@@ -1476,7 +1477,7 @@ async function loadTranslations() {
TRANSLATIONS = await response.json();
} catch (error) {
/*
* Ohne Datei bleibt der englische Text aus dem HTML stehen.
* Without the file the English text from the HTML stays.
*/
console.error("Error loading translations:", error);
}
@@ -1486,8 +1487,8 @@ async function loadTranslations() {
}
/*
* Theme/Logo sofort anwenden, damit nichts aufblinkt –
* Text erst nach dem Laden der Übersetzungen.
* Apply theme/logo immediately so nothing flickers –
* text only after the translations have loaded.
*/
async function start() {
applyTheme();