Internationalization
This commit is contained in:
+32
-32
@@ -15,7 +15,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function storage() {
|
||||
const target = globalThis.localStorage;
|
||||
if (!target) throw new Error('Lokaler Browser-Speicher ist auf diesem Gerät nicht verfügbar.');
|
||||
if (!target) throw new Error(ns.I18n.t("local-routes.deine.strecke.kann.auf.diesem.gerat.gerade"));
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
if (mediaDatabasePromise) return mediaDatabasePromise;
|
||||
const indexedDb = globalThis.indexedDB;
|
||||
if (!indexedDb || typeof indexedDb.open !== 'function') {
|
||||
return Promise.reject(new Error('Der lokale Medienspeicher (IndexedDB) ist in diesem Browser nicht verfügbar.'));
|
||||
return Promise.reject(new Error(ns.I18n.t("local-routes.bilder.und.ton.konnen.auf.diesem.gerat")));
|
||||
}
|
||||
|
||||
mediaDatabasePromise = new Promise((resolve, reject) => {
|
||||
@@ -41,11 +41,11 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
request.onsuccess = () => resolve(request.result);
|
||||
request.onerror = () => {
|
||||
mediaDatabasePromise = null;
|
||||
reject(request.error || new Error('Der lokale Medienspeicher konnte nicht geöffnet werden.'));
|
||||
reject(request.error || new Error(ns.I18n.t("local-routes.gespeicherte.bilder.und.ton.konnten.nicht.geoffnet")));
|
||||
};
|
||||
request.onblocked = () => {
|
||||
mediaDatabasePromise = null;
|
||||
reject(new Error('Der lokale Medienspeicher ist durch eine andere Browser-Sitzung blockiert.'));
|
||||
reject(new Error(ns.I18n.t("local-routes.schliesse.andere.fenster.mit.wegwichtel.und.versuche")));
|
||||
};
|
||||
});
|
||||
return mediaDatabasePromise;
|
||||
@@ -59,8 +59,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const transaction = database.transaction(MEDIA_STORE_NAME, mode);
|
||||
request = operation(transaction.objectStore(MEDIA_STORE_NAME));
|
||||
request.onsuccess = () => resolve(request.result ?? null);
|
||||
request.onerror = () => reject(request.error || new Error('Der lokale Medienspeicher konnte nicht gelesen oder geschrieben werden.'));
|
||||
transaction.onabort = () => reject(transaction.error || new Error('Die Medien-Speicheroperation wurde abgebrochen.'));
|
||||
request.onerror = () => reject(request.error || new Error(ns.I18n.t("local-routes.bilder.und.ton.konnten.nicht.geoffnet.oder")));
|
||||
transaction.onabort = () => reject(transaction.error || new Error(ns.I18n.t("local-routes.das.speichern.von.bildern.und.ton.wurde")));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
};
|
||||
} catch (error) {
|
||||
if (error?.name === 'QuotaExceededError') {
|
||||
throw new Error('Der lokale Medienspeicher ist voll. Entferne nicht mehr benötigte lokale Medien oder Strecken.', { cause: error });
|
||||
throw new Error(ns.I18n.t("local-routes.der.platz.fur.bilder.und.ton.ist"), { cause: error });
|
||||
}
|
||||
// Manche Browser können FileSystemFileHandle noch nicht in IndexedDB serialisieren.
|
||||
// In diesem Fall wird die Datei als Blob in IndexedDB gespeichert.
|
||||
@@ -111,9 +111,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
await putMediaRecord({ ...metadata, storage: 'indexeddb', blob: file });
|
||||
} catch (error) {
|
||||
const prefix = error?.name === 'QuotaExceededError'
|
||||
? 'Der lokale Medienspeicher ist voll.'
|
||||
: 'Die Mediendatei konnte nicht lokal gespeichert werden.';
|
||||
throw new Error(`${prefix} Entferne nicht mehr benötigte lokale Medien oder Strecken.`, { cause: error });
|
||||
? ns.I18n.t("local-routes.der.platz.fur.bilder.und.ton.ist.2")
|
||||
: ns.I18n.t("local-routes.das.bild.oder.die.tonaufnahme.konnte.nicht");
|
||||
throw new Error(ns.I18n.t("local-routes.entferne.bilder.tonaufnahmen.oder.eigene.strecken.die", { value1: prefix }), { cause: error });
|
||||
}
|
||||
return {
|
||||
id: String(mediaId),
|
||||
@@ -135,12 +135,12 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
permission = await handle.requestPermission({ mode: 'read' });
|
||||
}
|
||||
if (permission !== 'granted') {
|
||||
throw new Error('Der Zugriff auf eine lokale Mediendatei muss erneut erlaubt werden.');
|
||||
throw new Error(ns.I18n.t("local-routes.erlaube.noch.einmal.den.zugriff.auf.das"));
|
||||
}
|
||||
try {
|
||||
return await handle.getFile();
|
||||
} catch (error) {
|
||||
throw new Error('Eine referenzierte Mediendatei ist auf dem Gerät nicht mehr verfügbar.', { cause: error });
|
||||
throw new Error(ns.I18n.t("local-routes.ein.ausgewahltes.bild.oder.eine.tonaufnahme.wurde"), { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
if (typeof cryptoApi?.getRandomValues === 'function') {
|
||||
return `local-${uuidFromRandomValues(cryptoApi)}`;
|
||||
}
|
||||
throw new Error('Keine sichere Zufallsquelle für eine lokale Strecken-ID verfügbar.');
|
||||
throw new Error(ns.I18n.t("local-routes.auf.diesem.gerat.kann.gerade.keine.neue"));
|
||||
}
|
||||
|
||||
function createPoiId() {
|
||||
@@ -255,7 +255,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
.replaceAll("'", ''');
|
||||
}
|
||||
|
||||
function emptyGpx(name = 'Neue Strecke') {
|
||||
function emptyGpx(name = ns.I18n.t("editor-ui.neue.strecke")) {
|
||||
const safeName = escapeXml(name);
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>\n`
|
||||
+ `<gpx version="1.1" creator="Wegwichtel" xmlns="${GPX_NAMESPACE}" xmlns:wegwichtel="${POI_NAMESPACE}">\n`
|
||||
@@ -268,7 +268,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const parser = new DOMParser();
|
||||
const document = parser.parseFromString(String(gpx || ''), 'application/xml');
|
||||
if (document.querySelector('parsererror') || document.documentElement?.localName !== 'gpx') {
|
||||
throw new Error('Die GPX-Datei ist nicht gültig.');
|
||||
throw new Error(ns.I18n.t("local-routes.diese.datei.enthalt.keinen.lesbaren.weg.wahle"));
|
||||
}
|
||||
return document;
|
||||
}
|
||||
@@ -300,7 +300,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const document = parseXml(gpx);
|
||||
return Array.from(document.getElementsByTagNameNS('*', 'wpt')).map((node, index) => ({
|
||||
id: waypointId(node),
|
||||
title: textOfChild(node, 'name') || `Streckenpunkt ${index + 1}`,
|
||||
title: textOfChild(node, 'name') || ns.I18n.t("editor-ui.station", { value1: index + 1 }),
|
||||
description: textOfChild(node, 'desc'),
|
||||
lat: numberAttribute(node, 'lat'),
|
||||
lon: numberAttribute(node, 'lon'),
|
||||
@@ -360,11 +360,11 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function syncGpx(gpx, route, pois) {
|
||||
const routeName = route?.name || 'Neue Strecke';
|
||||
const routeName = route?.name || ns.I18n.t("editor-ui.neue.strecke");
|
||||
const document = parseXml(gpx || emptyGpx(routeName));
|
||||
updateMetadataName(document, routeName);
|
||||
|
||||
// Wegwichtel verwaltet neue Streckenpunkte direkt als Punkte im GPX-Track.
|
||||
// Wegwichtel verwaltet neue Stationen direkt als Punkte im GPX-Track.
|
||||
// Fremde/importierte GPX-Punkte ohne Wegwichtel-ID bleiben erhalten.
|
||||
Array.from(document.getElementsByTagNameNS('*', 'wpt')).forEach(node => node.remove());
|
||||
Array.from(document.getElementsByTagNameNS('*', 'trkpt'))
|
||||
@@ -374,9 +374,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const segment = ensureTrackSegment(document, routeName);
|
||||
const orderedPois = [...(pois || [])].sort((left, right) => Number(left.sequence) - Number(right.sequence));
|
||||
orderedPois.forEach((poi, index) => {
|
||||
const title = poi.title || `Streckenpunkt ${index + 1}`;
|
||||
const title = poi.title || ns.I18n.t("editor-ui.station", { value1: index + 1 });
|
||||
if (!Number.isFinite(Number(poi.lat)) || !Number.isFinite(Number(poi.lon))) {
|
||||
throw new TypeError(`Für ${title} fehlen gültige Koordinaten.`);
|
||||
throw new TypeError(ns.I18n.t("local-routes.der.ort.von.fehlt", { value1: title }));
|
||||
}
|
||||
|
||||
const gpxPoint = createElement(document, 'trkpt');
|
||||
@@ -469,9 +469,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
ns.StorageUsage?.reportError(error);
|
||||
const name = error?.name === 'QuotaExceededError'
|
||||
? 'Der lokale Speicher für Streckendaten ist voll.'
|
||||
: 'Die lokale Strecke konnte nicht gespeichert werden.';
|
||||
throw new Error(`${name} Entferne nicht mehr benötigte lokale Strecken.`, { cause: error });
|
||||
? ns.I18n.t("local-routes.der.platz.fur.deine.strecken.ist.voll")
|
||||
: ns.I18n.t("local-routes.deine.strecke.konnte.nicht.gespeichert.werden");
|
||||
throw new Error(ns.I18n.t("local-routes.entferne.eigene.strecken.die.du.nicht.mehr", { value1: name }), { cause: error });
|
||||
}
|
||||
|
||||
notify(id, 'saved');
|
||||
@@ -514,9 +514,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function gpxForUpload(routePackage) {
|
||||
if (!routePackage?.gpx) throw new Error('Für die lokale Strecke ist keine GPX-Datei vorhanden.');
|
||||
if (!routePackage?.gpx) throw new Error(ns.I18n.t("local-routes.der.weg.deiner.strecke.fehlt"));
|
||||
if (!routePoints(routePackage.gpx).length) {
|
||||
throw new Error('Die lokale Strecke enthält noch keine Streckenpunkte im GPX-Track.');
|
||||
throw new Error(ns.I18n.t("local-routes.deine.strecke.hat.noch.keinen.aufgezeichneten.weg"));
|
||||
}
|
||||
return routePackage.gpx;
|
||||
}
|
||||
@@ -577,7 +577,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
function appPoi(poi) {
|
||||
return {
|
||||
id: Number(poi.id),
|
||||
title: poi.title || 'Unbenannter Streckenpunkt',
|
||||
title: poi.title || ns.I18n.t("editor-ui.station.ohne.namen"),
|
||||
description: poi.description || '',
|
||||
lat: Number(poi.lat),
|
||||
lon: Number(poi.lon),
|
||||
@@ -604,9 +604,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
id: String(routePackage.id),
|
||||
source: 'local',
|
||||
local: true,
|
||||
name: routePackage.route?.name || 'Unbenannte Strecke',
|
||||
name: routePackage.route?.name || ns.I18n.t("editor-ui.unbenannte.strecke"),
|
||||
description: routePackage.route?.description || '',
|
||||
schoolName: 'Lokal gespeichert',
|
||||
schoolName: ns.I18n.t("local.device"),
|
||||
status: 'local',
|
||||
activatedAt: null,
|
||||
points,
|
||||
@@ -625,7 +625,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
async function getAppRoute(id, options = {}) {
|
||||
const routePackage = await withMedia(readPackage(id), options);
|
||||
if (!routePackage) throw new Error('Die lokale Strecke wurde nicht gefunden.');
|
||||
if (!routePackage) throw new Error(ns.I18n.t("local-routes.deine.strecke.wurde.nicht.gefunden"));
|
||||
return toAppRoute(routePackage);
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
function readFileAsText(file) {
|
||||
if (!file) return Promise.resolve('');
|
||||
if (typeof file.text !== 'function') {
|
||||
return Promise.reject(new TypeError('Die ausgewählte Datei unterstützt Blob.text() nicht.'));
|
||||
return Promise.reject(new TypeError(ns.I18n.t("local-routes.diese.datei.kann.auf.deinem.gerat.nicht")));
|
||||
}
|
||||
return file.text();
|
||||
}
|
||||
@@ -647,7 +647,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => {
|
||||
if (typeof reader.result !== 'string') {
|
||||
reject(new TypeError('Die Datei konnte nicht als Data-URL gelesen werden.'));
|
||||
reject(new TypeError(ns.I18n.t("local-routes.diese.datei.konnte.nicht.geoffnet.werden.wahle")));
|
||||
return;
|
||||
}
|
||||
resolve({
|
||||
@@ -657,7 +657,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
type: file.type || 'application/octet-stream'
|
||||
});
|
||||
}, { once: true });
|
||||
reader.addEventListener('error', () => reject(reader.error || new Error('Datei konnte nicht gelesen werden.')), { once: true });
|
||||
reader.addEventListener('error', () => reject(reader.error || new Error(ns.I18n.t("file.read.failed"))), { once: true });
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user