From 26c96e92cda9441ed3fe5e7b1b5849290bfef14c Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sun, 9 Aug 2026 13:59:59 +0200 Subject: Viel mehr Sprachen --- app/README.md | 142 +++++++++-- app/i18n.bar.js | 584 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n.de-x-amt.js | 607 ++++++++++++++++++++++++++++++++++++++++++++++ app/i18n.de-x-sales.js | 599 +++++++++++++++++++++++++++++++++++++++++++++ app/i18n.de.js | 6 +- app/i18n.en.js | 6 +- app/i18n.eo.js | 584 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n.eu.js | 591 +++++++++++++++++++++++++++++++++++++++++++++ app/i18n.fr.js | 585 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n.gmh.js | 623 +++++++++++++++++++++++++++++++++++++++++++++++ app/i18n.goh.js | 624 +++++++++++++++++++++++++++++++++++++++++++++++ app/i18n.got.js | 639 +++++++++++++++++++++++++++++++++++++++++++++++++ app/i18n.grc.js | 612 ++++++++++++++++++++++++++++++++++++++++++++++ app/i18n.ja.js | 6 +- app/i18n.la.js | 6 +- app/i18n.nds.js | 584 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n.nl.js | 582 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n.sa.js | 610 ++++++++++++++++++++++++++++++++++++++++++++++ app/i18n.tr.js | 584 ++++++++++++++++++++++++++++++++++++++++++++ app/i18n.uk.js | 583 ++++++++++++++++++++++++++++++++++++++++++++ app/index.html | 332 +++++++++++++++++++++++-- app/manifest.json | 17 +- app/pruefe.js | 77 +++++- app/service-worker.js | 27 ++- 24 files changed, 9537 insertions(+), 73 deletions(-) create mode 100644 app/i18n.bar.js create mode 100644 app/i18n.de-x-amt.js create mode 100644 app/i18n.de-x-sales.js create mode 100644 app/i18n.eo.js create mode 100644 app/i18n.eu.js create mode 100644 app/i18n.fr.js create mode 100644 app/i18n.gmh.js create mode 100644 app/i18n.goh.js create mode 100644 app/i18n.got.js create mode 100644 app/i18n.grc.js create mode 100644 app/i18n.nds.js create mode 100644 app/i18n.nl.js create mode 100644 app/i18n.sa.js create mode 100644 app/i18n.tr.js create mode 100644 app/i18n.uk.js diff --git a/app/README.md b/app/README.md index 8727649..09cd70e 100644 --- a/app/README.md +++ b/app/README.md @@ -5,11 +5,11 @@ Ergebnisse, aber bedienbar von Menschen, die keine Tabellenkalkulation aufmachen | Datei | Rolle | |---|---| -| `index.html` | **Die ganze App.** Rechenkern, Oberfläche, Diagramme — eine Datei, keine externen Abhängigkeiten außer den vier Wörterbüchern. Läuft per Doppelklick. | -| `i18n.de.js` | Wörterbuch Deutsch. Hauptsprache und Rückfallebene. | -| `i18n.en.js` | Wörterbuch Englisch. | -| `i18n.la.js` | Wörterbuch Latein. | -| `i18n.ja.js` | Wörterbuch Japanisch. | +| `index.html` | **Die ganze App.** Rechenkern, Oberfläche, Diagramme — eine Datei, keine externen Abhängigkeiten außer den Wörterbüchern. Läuft per Doppelklick. | +| `i18n.de.js` | Wörterbuch Deutsch. Hauptsprache und Rückfallebene. **Vollständig.** | +| `i18n.en.js` `i18n.nl.js` `i18n.fr.js` `i18n.la.js` `i18n.ja.js` | Englisch, Niederländisch, Französisch, Latein, Japanisch. **Vollständig** (459 Schlüssel). | +| `i18n.nds.js` `i18n.bar.js` `i18n.eu.js` `i18n.eo.js` `i18n.tr.js` `i18n.uk.js` | Niederdeutsch, Bairisch, Baskisch, Esperanto, Türkisch, Ukrainisch. **Teilweise** (315 Schlüssel, siehe 3b). | +| `i18n.got.js` `i18n.goh.js` `i18n.gmh.js` `i18n.grc.js` `i18n.sa.js` | Gotisch, Althochdeutsch, Mittelhochdeutsch, Altgriechisch, Sanskrit. **Teilweise**. | | `manifest.json` | Macht die App installierbar (Name, Farben, Symbole). | | `service-worker.js` | Offline-Cache, `stale-while-revalidate`. | | `icon-*.png` | App-Symbole, 192 / 512 / 512-maskable. | @@ -18,7 +18,7 @@ Ergebnisse, aber bedienbar von Menschen, die keine Tabellenkalkulation aufmachen ## 1. Weitergeben — drei Wege -**a) Nur die Dateien.** `index.html` samt den vier `i18n.*.js` verschicken — sie gehören +**a) Nur die Dateien.** `index.html` samt allen neunzehn `i18n.*.js` verschicken — sie gehören zusammen und müssen im selben Ordner liegen. Doppelklick genügt, alles rechnet, Eingaben werden im Browser gespeichert. Was fehlt, ist nur die PWA-Hülle — kein Symbol auf dem Startbildschirm, kein Offline-Cache. Beides braucht es hier auch nicht, @@ -106,24 +106,114 @@ Bruttobeitrags. Fällt der Nettoaufwand für das erste Jahr auf null — weil man dann bereits ausgeschieden ist —, existiert die Umkehrung nicht. Die App sagt das statt still nichts zu tun. -## 3b. Vier Sprachen +## 3b. Neunzehn Sprachen -Deutsch ist die Hauptsprache; Englisch, Latein und Japanisch sind Übersetzungen derselben -Rechtslage, kein zweiter Rechtsstand. **Die Normzitate bleiben in allen Sprachen deutsch** +Deutsch ist die Hauptsprache; alle übrigen sind Übersetzungen derselben Rechtslage, kein +zweiter Rechtsstand. **Die Normzitate bleiben in allen Sprachen deutsch** (`§ 1a BetrAVG`, `§ 226 Abs. 2 S. 2 SGB V`, …) — sie sind die Primärquellen und haben keine amtliche Übersetzung; eine eigene wäre hier keine Hilfe, sondern eine Fehlerquelle. Ebenso bleiben zwei Produktnamen stehen, weil sie Eigennamen sind: `Altersvorsorgedepot` und `Versorgungsbezüge`; im Japanischen mit Glosse (`Versorgungsbezüge(企業年金等の給付)`). +| | Sprachen | Schlüssel | +|---|---|---| +| **vollständig** | `de` `de-x-amt` `de-x-sales` `en` `nl` `fr` `la` `ja` `nds` `bar` `eu` `eo` `tr` `uk` `got` `goh` `gmh` `grc` `sa` | 459 | +| **teilweise** | — | — | + +Alle neunzehn Sprachen sind inzwischen vollständige Wörterbücher (459 von 459 Schlüsseln); die +Tabellenzeile „teilweise“ bleibt stehen, weil `TEILWEISE` in `index.html` als Mechanismus +weiterlebt — sie ist nur derzeit leer. Ursprünglich war die Auswahl strukturell, nicht nach +Zeichenzahl: zuerst übersetzt wurde, was man anfasst oder als Überschrift liest — +Feldbeschriftungen, Einheiten, Auswahlwerte, Fenstertitel, Kennzahlen, Tabellenköpfe, +Diagrammlegenden, Meldungen; die langen juristischen Erläuterungen (die `?`-Texte an den +Feldern, das Fazit, die Notizen unter den Feldern, der ganze Rechenweg) kamen erst in einer +zweiten Fassung dazu. Für die drei historischen Sprachstufen und für Sanskrit und Altgriechisch +ist der Vertrauensgrad in diesen Fließtext-Passagen entsprechend niedriger als in den +Feldbeschriftungen selbst — siehe die Kopfkommentare der jeweiligen `i18n.*.js`-Datei für die +genauen Prozentsätze und die dort neu geprägten Fachbegriffe. + +**Die drei alten germanischen Fassungen** (`got` Gotisch, `goh` Althochdeutsch, +`gmh` Mittelhochdeutsch) sind kein Scherz, sondern eine Probe darauf, wie viel Fachsprache eine +Sprachstufe trägt. Nur `goh` und `gmh` sind Vorstufen des Deutschen; **Gotisch ist ostgermanisch +und damit eine Schwester, keine Ahnin** — es steht hier, weil es das älteste umfangreich +überlieferte Germanisch überhaupt ist. Das Ergebnis ist ein klares Gefälle, und es folgt genau +der Verstädterung: + +- **Gotisch** hat mit Wulfilas Bibel ein Korpus von rund 3.000 Lexemen, praktisch keines + davon wirtschaftlich. Belegt sind immerhin `faihu` (Vermögen), `gild` (Abgabe), `wokrs` (Zins, + Lk 19,23 *miþ wokra*), `mizdo` (Lohn), `asneis` (Lohnarbeiter). Alles Übrige — `haubidafaihu` + für Kapital, `gagaleikeins` für Vergleich — ist geprägt. Vertrauensgrad ≈ 30 %. +- **Althochdeutsch** gewinnt durch Tatian und Notker: `gelt`, `zins`, `lon`, `wuohhar` sind + belegt, und **`widarmezzon` steht im Tatian genau für lateinisch *comparare*** — der + Fenstertitel ist also kein Kunstwort. Vertrauensgrad ≈ 50 %. +- **Mittelhochdeutsch** ist die tragfähigste Stufe, weil es bereits eine städtische Geld- und + Rechtssprache gibt. Drei Treffer sind keine Prägung, sondern der jeweilige Terminus: + **`houbetguot`** ist das Kapital, **`lîpgedinge`** die lebenslange Leibrente, **`tiurunge`** + der Preisanstieg — also die Inflation. Dazu `gülte`, `stiure`, `wuocher`, `gewin`, `koste`. + Vertrauensgrad ≈ 65 %. + +**Gotisch steht in lateinischer Umschrift** (Streitberg), nicht im Wulfila-Alphabet +(U+10330–1034F). Der Grund ist der Grundsatz aus § 2: die App lädt keine Schriften von fremden +Domains. Für gotische Schrift gibt es auf keinem verbreiteten System eine vorinstallierte Datei +— 𐌰𐌻𐌻𐌰𐌹𐌼 wären leere Kästchen. Die Umschrift ist ohnehin die Form, in der das Gotische gelesen +wird. Wer die Schrift will, braucht eine eingebettete Schriftart und damit eine andere +Grundsatzentscheidung. + +### Registervarianten des Deutschen: gebaut + +**„Beamtendeutsch“ und „Vertrieb“** sind keine Sprachen, sondern Stilebenen derselben Sprache — +sie stehen daher nach BCP 47 § 2.2.7 unter `de` mit privatem Untertag: `de-x-amt` und +`de-x-sales`, in `i18n.de-x-amt.js` und `i18n.de-x-sales.js`. Anders als bei den übrigen +Sprachen genügt hier keine Teilfassung: der Witz liegt gerade im Fließtext, den eine +Teilübersetzung weglassen würde. Derselbe § 1a BetrAVG heißt im Amtsdeutsch „Ein Rechtsanspruch +besteht ausschließlich bis zur Höhe von 4 vom Hundert der Beitragsbemessungsgrenze der +Rentenversicherung“ und im Vertriebsdeutsch „Bis zu 4 % on top — geschenkt vom Gesetzgeber!“ — +beide beschreiben exakt dieselbe Rechtslage, und der Vergleich ist der Punkt. Die Zahlen ändern +sich auch dort nicht; `pruefe.js` prüft das wie bei jeder anderen Sprache ohne Sonderfall. + +Technisch brauchte das drei Änderungen: `pickLang()` matcht seither zusätzlich zur +Grundsprache beliebig viele `-x-[a-z0-9]{1,8}`-Untertags; `LANGS` und `DICT` bekamen +Einträge mit Bindestrich; `LOCALES`/`GRUPPEN` brauchten dagegen **keine** neuen Einträge, weil +ihre bestehenden `||`-Rückfälle (`'de-DE'` bzw. `'.'`) für beide Varianten schon das Richtige +liefern. Der Sprachknopf zeigt nicht den vollen Code (`DE-X-AMT` wäre zu lang für die +zweizeilige Schaltfläche), sondern nur den Teil nach dem letzten Bindestrich (`AMT`, `SALES`); +`lang="…"` und das Autonym im `title` tragen weiterhin den vollen Code bzw. den vollen Namen. + +### Vorgemerkt, noch nicht gebaut + +**Rechtsläufige Sprachen (`he`, `fa`, `ar`).** Die Übersetzung ist der billige Teil. Teuer ist +dreierlei: `applyStatic()` muss neben `lang` auch `dir` setzen; im Stilblatt müssen +`margin-left`/`-right` durch die logischen Eigenschaften ersetzt werden, sonst kippt die +Kachelung; und Teil 8 zeichnet auf Canvas, wo es **keinen Bidi-Algorithmus gibt** — Achsen, +Legenden und der Wasserfall müssten von Hand gespiegelt werden. Dazu `fa-u-nu-latn` und +`ar-u-nu-latn` in `LOCALES`, sonst liefert ICU ostarabische Ziffern (۱۲۳۴) neben einem `€`. +Die Einzelheiten stehen als Kommentarblock in `index.html` direkt bei `TEILWEISE`. + +**Codes.** ISO 639-1, wo es einen gibt, sonst 639-3. Dreibuchstabig sind `grc` +(**nicht** `el` — das wäre Neugriechisch), `nds` und `bar`; keine der drei hat einen +zweibuchstabigen Code. Deshalb matcht `pickLang()` `[a-z]{2,3}` als Grundcode, optional gefolgt +von den erwähnten `-x-…`-Untertags. + **Wahl der Sprache**, in dieser Reihenfolge: -1. `?lang=de|en|la|ja` in der Adresse — teilbar, überschreibt alles, +1. `?lang=…` in der Adresse — teilbar, überschreibt alles, 2. die gemerkte Wahl in `localStorage` unter `altersvorsorge.lang`, -3. `navigator.language`: `ja…` → Japanisch, `en…` → Englisch, sonst Deutsch. - **Latein wird nie automatisch gewählt** — ein Browser, der `la` meldet, meint es fast sicher - nicht als Anzeigesprache. - -**Zu den beiden neuen Fassungen.** Das Latein ist pragmatisches Neulatein: klassische Syntax, +3. `navigator.language`, nach BCP-47-Teilkette (`xx` oder `xx-…`). + **Latein, Altgriechisch, Sanskrit und Esperanto werden nie automatisch gewählt** — ein + Browser, der `la` meldet, meint es fast sicher nicht als Anzeigesprache. + +Die Knöpfe tragen das Kürzel, der `title` das **Autonym** (`Українська`, `Plattdüütsch`, +`संस्कृतम्`) — nicht den übersetzten Namen. Wer Ukrainisch sucht, erkennt `Українська` auch dann, +wenn die Oberfläche gerade auf Baskisch steht; nebenbei spart das 14 × 14 Wörterbucheinträge. + +**Zahlenformat.** `LOCALES` bildet jeden Code auf ein ICU-Tag ab, `GRUPPEN` auf das +Tausenderzeichen, das `parseNum()` beim mehrdeutigen `1,234` heranzieht. Sprachen ohne eigene +ICU-Daten (`nds`, `bar`, `eo`, `la`, `grc`, `sa`) bekommen `de-DE`: Devanāgarī-Ziffern neben +einem `€` wären eine Schikane, keine Genauigkeit, und griechische Buchstabenzahlen erst recht. +`fr` gruppiert mit U+202F, `uk` mit U+00A0 — beides so, wie ICU es tatsächlich setzt, nachgeprüft +gegen `formatToParts`. + +**Zu Latein und Japanisch.** Das Latein ist pragmatisches Neulatein: klassische Syntax, aber gebildete Neuprägungen für Moderne (`pensio operativa`, `impensa pura`, `valor praesens`, `usura interna`). Römische Ziffern wären ein Witz auf Kosten der Lesbarkeit — und die Trennzeichenkonvention ist ohnehin jünger als jede lateinische Quelle. Das Japanische folgt @@ -179,11 +269,27 @@ nicht den fertigen Satz — sonst stünde nach dem Wechsel „vor der Änderung alten Sprache da. **Prüfung.** `pruefe.js` (Entwicklungswerkzeug, wird vom Service Worker nicht ausgeliefert) lädt die Seite kopflos in -jsdom, schaltet alle vier Sprachen durch, klappt jeden Abschnitt auf, erzwingt über fünf Szenarien -die bedingten Texte und prüft: kein unaufgelöster Schlüssel, keine deutschen Reste im +jsdom, schaltet alle neunzehn Sprachen durch, klappt jeden Abschnitt auf, erzwingt über fünf +Szenarien die bedingten Texte und prüft: kein unaufgelöster Schlüssel, keine deutschen Reste im englischen Modus außer den erlaubten Fachbegriffen, kein sichtbar gebliebener Schlüssel, und — die eigentliche Invariante — -**identische Rechenergebnisse in allen vier Sprachen**. +**identische Rechenergebnisse in allen neunzehn Sprachen**. + +Die Liste der Wörterbücher liest das Skript aus `index.html` statt sie zu pflegen: eine neue +Sprache soll den Test nicht stillschweigend an einem leeren Objekt vorbeilaufen lassen. Das +Regex für die ` + + + + + + + + + + + + + + + ', ''); } @@ -63,6 +67,21 @@ setTimeout(() => { const bad = []; const check = (name, cond, info) => (cond ? ok : bad).push(name + (info ? ' — ' + info : '')); + /* Zuerst: hat das Hauptskript ueberhaupt geparst? Ein Syntaxfehler darin — + etwa ein Blockkommentar, den ein '*' vor einem Schraegstrich vorzeitig + schliesst — laesst jede spaetere Zeile an einem undefined scheitern und + verschuettet die eigentliche Meldung. Deshalb hier abbrechen, nicht + weiterlaufen. */ + if (typeof w.LANGS === 'undefined' || typeof w.t !== 'function' || !w.S) { + console.log('ABBRUCH: das Hauptskript in index.html hat nicht geparst.'); + fehler.forEach(f => console.log(' ' + f)); + process.exit(2); + } + check('Hauptskript geparst', true, w.LANGS.length + ' Sprachen'); + const WBSOLL = w.LANGS.length; + check('ein Wörterbuch je Sprache in LANGS', + w.LANGS.every(l => w.DICT[l] && Object.keys(w.DICT[l]).length > 0), + w.LANGS.filter(l => !w.DICT[l] || !Object.keys(w.DICT[l]).length).join(' ')); check('Wörterbücher geladen', !!w.I18N_DE && !!w.I18N_EN && !!w.I18N_LA && !!w.I18N_JA); check('Startsprache aus ?lang=de', w.LANG === 'de', 'LANG=' + w.LANG); check('keine Skriptfehler beim Start', fehler.length === 0, fehler.join(' | ')); @@ -194,6 +213,58 @@ setTimeout(() => { !/(Rentenbeginn|Nettoaufwand|Bruttorendite|Monatsleistung|Beispielwerte)/.test(laTxt), (laTxt.match(/Rentenbeginn|Nettoaufwand|Bruttorendite|Monatsleistung|Beispielwerte/g)||[]).join(' ')); + // --- Teilsprachen: Rückfall auf Deutsch muss greifen, nicht klaffen --- + // Der Rückfall ist kein Schönheitsfehler, sondern die Zusicherung: fehlt ein + // Schlüssel, erscheint der deutsche Eintrag — nie ein Leerstring und nie der + // Schlüssel selbst. Genau das wird hier für jede Teilsprache nachgewiesen. + Object.keys(w.TEILWEISE).forEach(function(l){ + w.setLang(l); + const eigen = Object.keys(w.DICT[l]); + const fehlend = Object.keys(w.I18N_DE).filter(k => !(k in w.DICT[l])); + check('Teilsprache ' + l + ': Schlüssel eigen/geerbt', + eigen.length > 0 && fehlend.length > 0, eigen.length + '/' + fehlend.length); + // Kein eigener Eintrag darf leer sein oder den Typ wechseln. + const kaputt = eigen.filter(k => typeof w.DICT[l][k] !== typeof w.I18N_DE[k] + || w.DICT[l][k] === ''); + check('Teilsprache ' + l + ': Typen und Leerstrings', kaputt.length === 0, kaputt.join(' ')); + // Jeder geerbte Schlüssel liefert den deutschen Text — nicht den Schlüssel. + const durchgefallen = fehlend.filter(k => typeof w.I18N_DE[k] === 'string' + && w.t(k) !== w.I18N_DE[k]); + check('Teilsprache ' + l + ': Rückfall liefert Deutsch', + durchgefallen.length === 0, durchgefallen.slice(0,3).join(' ')); + // Und die Sprachleiste sagt es dem Nutzer. + const zeile = w.$('#langrow'); + const hinweis = [].slice.call(zeile.children) + .filter(n => n.className === 'sub' && n.style.flexBasis === '100%'); + check('Teilsprache ' + l + ': Hinweis in der Sprachleiste', + hinweis.length === 1 && //.test(hinweis[0].innerHTML)); + }); + // Umgekehrt: Vollsprachen dürfen den Hinweis NICHT zeigen. + w.LANGS.filter(l => !w.TEILWEISE[l]).forEach(function(l){ + w.setLang(l); + const zeile = w.$('#langrow'); + const hinweis = [].slice.call(zeile.children) + .filter(n => n.className === 'sub' && n.style.flexBasis === '100%'); + check('Vollsprache ' + l + ': kein Teilhinweis', hinweis.length === 0); + check('Vollsprache ' + l + ': Wörterbuch vollständig', + Object.keys(w.DICT[l]).length === Object.keys(w.I18N_DE).length, + Object.keys(w.DICT[l]).length + ' von ' + Object.keys(w.I18N_DE).length); + }); + // Dreibuchstabige Codes müssen den Adressparameter überstehen. + ['grc','nds','bar','got','goh','gmh'].forEach(function(l){ + w.setLang('de'); w.setLang(l); + check('Adresse trägt ' + l, new RegExp('lang=' + l + '(?:&|$)').test(w.location.search), + w.location.search); + }); + // Bindestrich-Untertags (Registervarianten) müssen denselben Weg überstehen + // — sowohl das Setzen der Adresse als auch das Zurücklesen via pickLang(). + ['de-x-amt','de-x-sales'].forEach(function(l){ + w.setLang('de'); w.setLang(l); + check('Adresse trägt ' + l, new RegExp('lang=' + l + '(?:&|$)').test(w.location.search), + w.location.search); + check('pickLang liest ' + l + ' zurück', w.pickLang() === l, w.pickLang()); + }); + // --- zurück auf Deutsch --- w.setLang('de'); check('Rückschaltung', w.LANG === 'de' && /Ergebnis/.test(sichtbar())); diff --git a/app/service-worker.js b/app/service-worker.js index 562291e..d47fd2a 100644 --- a/app/service-worker.js +++ b/app/service-worker.js @@ -1,7 +1,7 @@ /* Altersvorsorge-Vergleich — Service Worker * * Strategie: stale-while-revalidate für alles im Scope. - * Die App besteht aus einer Seite und vier Woerterbuechern, ohne Backend; Korrektheit hängt + * Die App besteht aus einer Seite und neunzehn Woerterbuechern, ohne Backend; Korrektheit hängt * also nicht an Frische, wohl aber Verfügbarkeit. Deshalb wird sofort aus * dem Cache geliefert und im Hintergrund aktualisiert. Beim Aktivieren * werden alte Cache-Versionen gelöscht. @@ -9,13 +9,28 @@ * Beim Ändern der App die Version hochzählen — sonst sieht ein bereits * installierter Client die Änderung erst nach zwei Aufrufen. */ -const VERSION = 'av-v16'; +const VERSION = 'av-v21'; const ASSETS = [ './', './index.html', './i18n.de.js', + './i18n.de-x-amt.js', + './i18n.de-x-sales.js', './i18n.en.js', + './i18n.nl.js', + './i18n.nds.js', + './i18n.bar.js', + './i18n.fr.js', + './i18n.eu.js', + './i18n.eo.js', + './i18n.tr.js', + './i18n.uk.js', './i18n.la.js', + './i18n.got.js', + './i18n.goh.js', + './i18n.gmh.js', + './i18n.grc.js', + './i18n.sa.js', './i18n.ja.js', './manifest.json', './icon-192.png', @@ -27,11 +42,11 @@ self.addEventListener('install', (e) => { e.waitUntil( caches.open(VERSION) /* addAll ist atomar: fehlt eine Datei, faellt alles durch. Der - Rueckfall auf die blosse Seite waere dann aber eine App ohne - Woerterbuch — deshalb die drei Pflichtdateien zusammen. */ + Rueckfall traegt nur index.html und das deutsche Woerterbuch: das + ist zugleich die Rueckfallebene von tRaw(), also die kleinste Menge, + mit der die App vollstaendig beschriftet laeuft. */ .then((c) => c.addAll(ASSETS) - .catch(() => c.addAll(['./index.html', './i18n.de.js', './i18n.en.js', - './i18n.la.js', './i18n.ja.js']))) + .catch(() => c.addAll(['./index.html', './i18n.de.js']))) .then(() => self.skipWaiting()) ); }); -- cgit v1.2.1