From 954d5989bb04f32aeb2627b70647d773011e4092 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sat, 22 Aug 2026 21:03:13 +0200 Subject: =?UTF-8?q?Neufassung=20der=20Dokumentation,=20Entfernung=20der=20?= =?UTF-8?q?urspr=C3=BCnglichen=20Tabellenfassung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Das Wurzel-README beschrieb bislang vorrangig die Excel-Arbeitsmappe nebst ihrem Formelgenerator; die Web-App erschien lediglich in einer Tabellenzeile. Das Verhältnis hat sich umgekehrt, das README nunmehr auch. - README.md vollständig neu als Einstiegspunkt für Unkundige, in Paragraphen gegliedert und durchgängig in amtlicher Diktion. Die excelspezifischen Kapitel (Blattstruktur, feste Adressen, Neubau, LibreOffice-Fallstricke) entfallen ersatzlos. - app/README.md in dieselbe Diktion überführt; Gliederung und sämtliche Zahlen unverändert. Berichtigt: Überschrift „Neunzehn Sprachen" bei dreiundzwanzig Wörterbüchern, sowie die unvollständige Aufzählung der Vollsprachen (ine-x-proto, jbo, tok, akk-x-ob ergänzt). - Die Arbeitsmappe, der Formelgenerator und die leere recalc.log werden entfernt; sie sind über die Versionsgeschichte zugänglich. - Der Anbietername entfällt samt dem Dateinamen, den er trug: Fußzeile footer.2 in index.html und in sämtlichen dreiundzwanzig Sprachfassungen, jeweils mit dem der Sprache angemessenen Bindewort statt einer mechanischen Streichung. Die Keilschriftfassung ist über akk-keilschrift.js neu erzeugt worden, nicht von Hand geändert. In pruefe.js aus der Ausnahmeliste gestrichen. Der Schlüsselbestand bleibt bei 459; es werden ausschließlich Werte gekürzt. Co-Authored-By: Claude Opus 5 --- app/README.md | 1012 ++++++++++++++++++++++------------------- app/i18n.akk-x-ob.js | 2 +- app/i18n.akk-x-ob.translit.js | 2 +- app/i18n.bar.js | 2 +- app/i18n.de-x-amt.js | 2 +- app/i18n.de-x-sales.js | 2 +- app/i18n.de.js | 2 +- app/i18n.en.js | 2 +- app/i18n.eo.js | 2 +- app/i18n.eu.js | 2 +- app/i18n.fr.js | 2 +- app/i18n.gmh.js | 2 +- app/i18n.goh.js | 2 +- app/i18n.got.js | 2 +- app/i18n.grc.js | 2 +- app/i18n.ine-x-proto.js | 2 +- app/i18n.ja.js | 2 +- app/i18n.jbo.js | 2 +- app/i18n.la.js | 2 +- app/i18n.nds.js | 2 +- app/i18n.nl.js | 2 +- app/i18n.sa.js | 2 +- app/i18n.tok.js | 2 +- app/i18n.tr.js | 2 +- app/i18n.uk.js | 2 +- app/index.html | 6 +- app/pruefe.js | 2 +- 27 files changed, 560 insertions(+), 508 deletions(-) (limited to 'app') diff --git a/app/README.md b/app/README.md index 522018c..fab1593 100644 --- a/app/README.md +++ b/app/README.md @@ -1,244 +1,265 @@ -# Altersvorsorge-Vergleich — Web-App +# Altersvorsorge-Vergleich — Webanwendung -Progressive Web-App zum Excel-Modell im übergeordneten Ordner. Derselbe Rechenkern, dieselben -Ergebnisse, aber bedienbar von Menschen, die keine Tabellenkalkulation aufmachen wollen. +Progressive Webanwendung (PWA) zum Vergleich dreier Gestaltungsvarianten der Altersvorsorge. +Es handelt sich um das eigentliche Erzeugnis dieses Bestandes; hinsichtlich einer allgemeinen +Einführung wird auf das [Wurzel-README](../README.md) verwiesen. Der Rechenkern ist aus einer +zwischenzeitlich entfallenen Excel-Arbeitsmappe übernommen worden, welche ausschließlich über +die Versionsgeschichte zugänglich ist; die Ergebnisse sind dieselben, die Bedienung ist jedoch +auch denjenigen Personen eröffnet, welche eine Tabellenkalkulation nicht zu öffnen beabsichtigen. -| Datei | Rolle | +| Datei | Zweckbestimmung | |---|---| -| `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. | +| `index.html` | **Die vollständige Anwendung.** Rechenkern, Bedienoberfläche und Diagramme in einer einzigen Datei, ohne externe Abhängigkeiten mit Ausnahme der Wörterbücher. Der Aufruf erfolgt mittels Doppelklicks. | | `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**. | -| `i18n.ine-x-proto.js` | Urindogermanisch, LIV²/Rix-Notation mit Laryngalen und Asterisk. Kein ISO-639-3-Code möglich (639-3 vergibt keine Codes an Rekonstruate), daher BCP-47-Privatuntertag `ine-x-proto`. **Vollständig**. | -| `i18n.jbo.js` `i18n.tok.js` | Lojban, Toki Pona. Toki Pona speichert sitelen Lasina (ASCII); das Stilblatt setzt für `lang="tok"` ligaturfähige sitelen-pona-Zeichensätze, die die ASCII-Wörter zu Logographen binden — ohne installierten Zeichensatz bleibt lesbares Latein statt PUA-Kästchen. **Vollständig**. | -| `i18n.akk-x-ob.js` | Altbabylonisch in Keilschrift (U+12000…). Erzeugt aus `i18n.akk-x-ob.translit.js` durch `node akk-keilschrift.js`; die Umschrift ist die Quelle, die Keilschrift das Erzeugnis. Codepunkte werden zur Bauzeit über die Unicode-Namenstabelle aufgelöst statt von Hand gesetzt. **Vollständig**. | -| `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. | +| `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. **Vollständig** (siehe § 3b). | +| `i18n.got.js` `i18n.goh.js` `i18n.gmh.js` `i18n.grc.js` `i18n.sa.js` | Gotisch, Althochdeutsch, Mittelhochdeutsch, Altgriechisch, Sanskrit. **Vollständig.** | +| `i18n.ine-x-proto.js` | Urindogermanisch in LIV²/Rix-Notation nebst Laryngalen und Asterisk. Ein Code nach ISO 639-3 ist nicht zu erlangen, da für Rekonstruate keine Codes vergeben werden; es wird daher der Privatuntertag `ine-x-proto` nach BCP 47 geführt. **Vollständig.** | +| `i18n.jbo.js` `i18n.tok.js` | Lojban, Toki Pona. Toki Pona wird in sitelen Lasina (ASCII) vorgehalten; das Stilblatt setzt für `lang="tok"` ligaturfähige sitelen-pona-Zeichensätze, welche die ASCII-Wörter zu Logographen binden. Ist ein solcher Zeichensatz nicht installiert, verbleibt lesbares Latein anstelle leerer Kästchen. **Vollständig.** | +| `i18n.akk-x-ob.js` | Altbabylonisch in Keilschrift (U+12000 ff.). Erzeugt aus `i18n.akk-x-ob.translit.js` mittels `node akk-keilschrift.js`; die Umschrift ist die Quelle, die Keilschrift das Erzeugnis. Die Codepunkte werden zur Bauzeit über die Unicode-Namenstabelle aufgelöst und nicht von Hand gesetzt. **Vollständig.** | +| `manifest.json` | Bewirkt die Installierbarkeit (Bezeichnung, Farben, Symbole). | +| `service-worker.js` | Offline-Zwischenspeicher, Verfahren `stale-while-revalidate`. | +| `icon-*.png` | Symbole der Anwendung, 192 / 512 / 512-maskable. | --- -## 1. Weitergeben — drei Wege +## § 1 Weitergabe — drei Wege -**a) Nur die Dateien.** `index.html` samt allen dreiundzwanzig `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, -die Datei liegt ja schon auf dem Gerät. Die App sagt das dem Nutzer auch selbst. +**a) Ausschließlich die Dateien.** Es sind `index.html` nebst sämtlichen dreiundzwanzig +`i18n.*.js` zu übersenden; sie gehören zusammen und haben in demselben Ordner zu liegen. Ein +Doppelklick genügt, sämtliche Berechnungen werden durchgeführt, und die Eingaben werden im +Browser vorgehalten. Es fehlt lediglich die PWA-Hülle — mithin das Symbol auf dem +Startbildschirm sowie der Offline-Zwischenspeicher. Beides ist hier entbehrlich, da die Datei +bereits auf dem Gerät vorliegt. Die Anwendung weist hierauf von sich aus hin. -**b) Der ganze Ordner auf einem Webspace.** Irgendein HTTPS-Hosting genügt (GitHub Pages, -Netlify, ein Unterverzeichnis auf der eigenen Domain). Dann ist sie installierbar und -offlinefähig. Es gibt kein Backend, keine Datenbank, keine Build-Kette. +**b) Der vollständige Ordner auf einem Webspeicherplatz.** Ein beliebiges HTTPS-Hosting genügt +(GitHub Pages, Netlify, ein Unterverzeichnis der eigenen Domäne). Sodann ist die Anwendung +installierbar und offlinefähig. Ein Hintergrundsystem, eine Datenbank sowie eine Baukette +bestehen nicht. ```bash -# lokal ausprobieren, mit Service Worker: +# örtliche Erprobung einschließlich Dienstarbeiter: cd app && python3 -m http.server 8000 # -> http://localhost:8000 ``` -Service Worker laufen auch auf `http://localhost` — als „secure context“ ist localhost -ausdrücklich ausgenommen. +Dienstarbeiter (*service worker*) sind auch über `http://localhost` betriebsfähig; localhost ist +als sicherer Kontext ausdrücklich ausgenommen. -**c) Als Link.** Der Knopf *„Link mit meinen Zahlen kopieren“* kodiert den kompletten -Eingabestand base64url in den Fragment-Bezeichner. Fragmente werden vom Browser **nicht** an -den Server geschickt (RFC 3986 § 3.5) — der Link enthält also persönliche Zahlen, überträgt -sie aber an niemanden außer den Empfänger. +**c) Als Verweis.** Die Schaltfläche *„Link mit meinen Zahlen kopieren"* kodiert den +vollständigen Eingabestand base64url in den Fragmentbezeichner. Fragmente werden vom Browser +**nicht** an den Server übermittelt (RFC 3986 § 3.5); der Verweis enthält mithin persönliche +Zahlen, überträgt diese jedoch an niemanden außer den Empfänger. -## 2. Wo die Daten liegen +## § 2 Verbleib der Daten -Ausschließlich in `localStorage` unter dem Schlüssel `altersvorsorge.v1`, also im Browser des -Nutzers. Kein Server, keine Analytik, keine Schriftarten von fremden Domains, keine externen -Skripte. Die einzigen Netzwerkzugriffe der App sind die, die der Service Worker macht, um sich -selbst zu aktualisieren. +Ausschließlich in `localStorage` unter dem Schlüssel `altersvorsorge.v1`, mithin im Browser der +nutzenden Person. Ein Server, eine Auswertung, Schriftarten von fremden Domänen sowie externe +Skripte bestehen nicht. Die einzigen Netzwerkzugriffe der Anwendung sind diejenigen, welche der +Dienstarbeiter zum Zwecke seiner eigenen Aktualisierung vornimmt. -## 3. Aufbau der Datei +## § 3 Aufbau der Datei `index.html` ist in nummerierte Teile gegliedert: | Teil | Inhalt | |---|---| | 0 | **Sprachen** — `t()`, Sprachwahl, Rückfall auf Deutsch | -| 1 | **Rechenkern** — Portierung von `build_bav.py`. Reine Funktionen, kein DOM | -| 2 | Felddefinitionen: 80 Eingaben mit Bereich, Einheit, Wörterbuchschlüssel | -| 3 | Zustand, `localStorage`, Kodierung für den Teilen-Link | +| 1 | **Rechenkern** — Portierung des ursprünglichen Formelgenerators. Reine Funktionen, kein DOM | +| 2 | Felddefinitionen: 80 Eingaben nebst Bereich, Einheit und Wörterbuchschlüssel | +| 3 | Zustand, `localStorage`, Kodierung für den Weitergabeverweis | | 4 | Formatierung und Zahleneingabe, sprachabhängig | | 5 | Kennzahlen | -| 6 | Aufbau der Oberfläche | -| 7 | Ergebniskarten mit Δ-Anzeige | -| 7b | Klartext-Fazit, Beispielwert-Hinweis, mitlaufende Ergebnisleiste | -| 8 | Diagramme, reines Canvas | +| 6 | Aufbau der Bedienoberfläche | +| 7 | Ergebniskarten nebst Δ-Anzeige | +| 7b | Klartextfazit, Hinweis auf Beispielwerte, mitlaufende Ergebnisleiste | +| 8 | Diagramme, ausschließlich Canvas | | 9 | Rechenweg | | 10 | Render-Schleife | | 11 | Installation und Offline-Betrieb | | 12 | Fensterrahmen: Titelleisten und Minimieren | -| 13 | Kachelung: ein, zwei oder drei Fensterspalten | -| 14 | Sprachumschaltung in der Oberfläche | +| 13 | Kachelung: eine, zwei oder drei Fensterspalten | +| 14 | Sprachumschaltung in der Bedienoberfläche | Der Rechenkern in Teil 1 ist **die einzige Stelle, an der gerechnet wird.** Er ist zeichengenau -aus `build_bav.py` übertragen; Änderungen an der Rechtslage gehören in beide Dateien. +aus dem ursprünglichen Formelgenerator übertragen worden; Änderungen der Rechtslage sind mithin +ausschließlich dort vorzunehmen. -### Brutto und Netto sind gekoppelt +### Brutto- und Nettobetrag sind gekoppelt -Es gibt keinen Umschalter „ich gebe vor: Brutto / Netto“ mehr. Beide Felder zeigen dieselbe -Größe, nur in verschiedener Währung: +Ein Umschalter „Vorgabe: Brutto / Netto" besteht nicht mehr. Beide Felder weisen dieselbe Größe +aus, lediglich in verschiedener Währung: ``` N(B) = B − SV-Ersparnis_AN(B) − Steuerersparnis(B) ``` `N` ist auf `[0, Bruttogehalt]` stetig und wegen `dN/dB = 1 − Grenz-SV-Satz − Grenzsteuersatz > 0` -streng monoton wachsend, also eine Bijektion auf `[0, N(Bruttogehalt)]`. Ein Umschalter wäre -eine Auswahl zwischen einer Funktion und ihrer Umkehrfunktion — also keine. +streng monoton wachsend, mithin eine Bijektion auf `[0, N(Bruttogehalt)]`. Ein Umschalter wäre +eine Auswahl zwischen einer Funktion und ihrer Umkehrfunktion, mithin keine Auswahl. -`beitrag` bleibt die einzige Quelle der Wahrheit; `netto_ziel` ist ein **abgeleitetes Feld** mit -`get` (Vorwärtsrechnung, Jahr 0 der Ansparphase) und `set` (Bisektion, `bruttoVonNetto`). -Beide werten dasselbe erste Jahr aus — Lohn- und Tarifindex sind dort 1 —, weshalb die -Richtungen exakt invers sind. Gemessen über 12 Parameterkombinationen × 5 Stützstellen: +`beitrag` verbleibt die einzige maßgebliche Größe; `netto_ziel` ist ein **abgeleitetes Feld** mit +`get` (Vorwärtsrechnung, Jahr 0 der Ansparphase) und `set` (Intervallhalbierung, +`bruttoVonNetto`). Beide werten dasselbe erste Jahr aus — Lohn- und Tarifindex betragen dort 1 —, +weshalb die Richtungen exakt invers sind. Gemessen über 12 Parameterkombinationen × 5 +Stützstellen: | Richtung | größter relativer Fehler | |---|---| | B → N → B | 2,3 · 10⁻⁸ | | N → B → N | 2,1 · 10⁻⁸ | -Das ist genau die Auflösung der Bisektion: 34 Halbierungen auf `[0, 250.000 €]` sind -1,5 · 10⁻⁵ €/Jahr, also gut ein Millionstel Cent im Monat. Die Monotonie ist zusätzlich auf -`1 … 1.500 €/Monat` in Ein-Euro-Schritten geprüft; die kleinste beobachtete Steigung ist -`dN/dB = 0,545`, d. h. Steuer und Sozialabgaben tragen zusammen nie mehr als 45,5 % des -Bruttobeitrags. +Dies entspricht genau der Auflösung des Halbierungsverfahrens: 34 Halbierungen auf +`[0, 250.000 €]` ergeben 1,5 · 10⁻⁵ €/Jahr, mithin gut ein Millionstel Cent im Monat. Die +Monotonie ist ergänzend auf `1 … 1.500 €/Monat` in Ein-Euro-Schritten geprüft worden; die +geringste beobachtete Steigung beträgt `dN/dB = 0,545`, mithin tragen Steuer und Sozialabgaben +zusammen niemals mehr als 45,5 vom Hundert des 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. +Fällt der Nettoaufwand für das erste Jahr auf null — weil zu diesem Zeitpunkt bereits ein +Ausscheiden vorliegt —, so existiert die Umkehrung nicht. Die Anwendung weist hierauf hin, +anstatt untätig zu verbleiben. -## 3b. Neunzehn Sprachen +## § 3b Dreiundzwanzig Sprachfassungen -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(企業年金等の給付)`). +Deutsch ist die Hauptsprache; sämtliche übrigen Fassungen sind Übersetzungen derselben +Rechtslage und nicht etwa ein zweiter Rechtsstand. **Die Normzitate verbleiben in sämtlichen +Sprachfassungen in deutscher Sprache** (`§ 1a BetrAVG`, `§ 226 Abs. 2 S. 2 SGB V`, …) — es +handelt sich um die Primärquellen, für welche eine amtliche Übersetzung nicht vorliegt; eine +eigene wäre insoweit keine Hilfe, sondern eine Fehlerquelle. Gleichermaßen verbleiben zwei +Produktbezeichnungen unübersetzt, da es sich um Eigennamen handelt: `Altersvorsorgedepot` und +`Versorgungsbezüge`; im Japanischen nebst 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 | +| **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` `ine-x-proto` `jbo` `tok` `akk-x-ob` | 459 | | **teilweise** | — | — | -Alle dreiundzwanzig 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. +Sämtliche dreiundzwanzig Sprachfassungen sind zwischenzeitlich vollständige Wörterbücher (459 von +459 Schlüsseln); die Tabellenzeile „teilweise" verbleibt, weil `TEILWEISE` in `index.html` als +Mechanismus fortbesteht — sie ist lediglich derzeit unbesetzt. Ursprünglich erfolgte die Auswahl +strukturell und nicht nach Zeichenzahl: zuerst übersetzt wurde dasjenige, was betätigt oder als +Überschrift gelesen wird — Feldbeschriftungen, Einheiten, Auswahlwerte, Fenstertitel, +Kennzahlen, Tabellenköpfe, Diagrammlegenden, Meldungen; die ausführlichen juristischen +Erläuterungen (die `?`-Texte an den Feldern, das Fazit, die Notizen unter den Feldern, der +gesamte Rechenweg) sind erst in einer zweiten Fassung hinzugetreten. Für die drei historischen +Sprachstufen sowie für Sanskrit und Altgriechisch ist der Vertrauensgrad in diesen +Fließtextpassagen entsprechend geringer als in den Feldbeschriftungen selbst; die genauen +Prozentsätze sowie die dort neu geprägten Fachbegriffe sind den Kopfkommentaren der jeweiligen +`i18n.*.js`-Datei zu entnehmen. **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 %. +`gmh` Mittelhochdeutsch) sind nicht als Scherz zu verstehen, sondern als Probe darauf, wie viel +Fachsprache eine Sprachstufe zu tragen vermag. Lediglich `goh` und `gmh` sind Vorstufen des +Deutschen; **das Gotische ist ostgermanisch und mithin eine Schwester, keine Ahnin** — es steht +hier, weil es das älteste umfangreich überlieferte Germanisch überhaupt darstellt. Das Ergebnis +ist ein deutliches Gefälle, welches genau der Verstädterung folgt: + +- **Gotisch** verfügt mit der Wulfila-Bibel über ein Korpus von rund 3.000 Lexemen, von welchen + praktisch keines wirtschaftlicher Natur ist. 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 vom Hundert. - **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: + Fenstertitel ist mithin kein Kunstwort. Vertrauensgrad ≈ 50 vom Hundert. +- **Mittelhochdeutsch** ist die tragfähigste Stufe, da bereits eine städtische Geld- und + Rechtssprache besteht. 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 + der Preisanstieg, mithin die Inflation. Hinzu treten `gülte`, `stiure`, `wuocher`, `gewin`, + `koste`. Vertrauensgrad ≈ 65 vom Hundert. + +**Das Gotische steht in lateinischer Umschrift** (Streitberg) und nicht im Wulfila-Alphabet +(U+10330–1034F). Maßgeblich hierfür ist der Grundsatz gemäß § 2: die Anwendung lädt keine +Schriften von fremden Domänen. Für die gotische Schrift liegt auf keinem verbreiteten System +eine vorinstallierte Datei vor — 𐌰𐌻𐌻𐌰𐌹𐌼 erschiene als leere Kästchen. Die Umschrift ist +ohnehin diejenige Form, in welcher das Gotische gelesen wird. Wer die Schrift wünscht, bedarf +einer eingebetteten Schriftart und mithin einer abweichenden Grundsatzentscheidung. + +### Registervarianten des Deutschen: eingerichtet + +**„Beamtendeutsch" und „Vertrieb"** sind keine Sprachen, sondern Stilebenen derselben Sprache; +sie werden daher nach BCP 47 § 2.2.7 unter `de` mit privatem Untertag geführt: `de-x-amt` und +`de-x-sales`, in `i18n.de-x-amt.js` und `i18n.de-x-sales.js`. Abweichend von den übrigen +Sprachfassungen genügt hier keine Teilfassung: der Witz liegt gerade im Fließtext, welchen eine +Teilübersetzung fortließe. Derselbe § 1a BetrAVG lautet 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=…` in der Adresse — teilbar, überschreibt alles, -2. die gemerkte Wahl in `localStorage` unter `altersvorsorge.lang`, +Rentenversicherung" und im Vertriebsdeutsch „Bis zu 4 % on top — geschenkt vom Gesetzgeber!" — +beide Fassungen beschreiben exakt dieselbe Rechtslage, und der Vergleich ist der Punkt. Die +Zahlen ändern sich auch dort nicht; `pruefe.js` prüft dies wie bei jeder anderen Sprache ohne +Sonderfall. + +Technisch waren hierfür drei Änderungen erforderlich: `pickLang()` erkennt seither zusätzlich +zur Grundsprache beliebig viele `-x-[a-z0-9]{1,8}`-Untertags; `LANGS` und `DICT` haben Einträge +mit Bindestrich erhalten; `LOCALES` und `GRUPPEN` bedurften hingegen **keiner** neuen Einträge, +da deren bestehende `||`-Rückfälle (`'de-DE'` bzw. `'.'`) für beide Varianten bereits das +Zutreffende liefern. Die Sprachschaltfläche weist nicht den vollständigen Code aus (`DE-X-AMT` +wäre für die zweizeilige Schaltfläche zu lang), sondern lediglich den Teil nach dem letzten +Bindestrich (`AMT`, `SALES`); `lang="…"` sowie das Autonym im `title` tragen weiterhin den +vollständigen Code bzw. die vollständige Bezeichnung. + +### Vorgemerkt, noch nicht eingerichtet + +**Rechtsläufige Sprachen (`he`, `fa`, `ar`).** Die Übersetzung stellt den geringeren Aufwand +dar. Aufwendig ist Dreierlei: `applyStatic()` hat neben `lang` auch `dir` zu setzen; im Stilblatt +sind `margin-left`/`-right` durch die logischen Eigenschaften zu ersetzen, da andernfalls die +Kachelung kippt; und Teil 8 zeichnet auf Canvas, wo **ein Bidi-Algorithmus nicht besteht** — +Achsen, Legenden und der Wasserfall wären mithin von Hand zu spiegeln. Hinzu treten +`fa-u-nu-latn` und `ar-u-nu-latn` in `LOCALES`, da ICU andernfalls ostarabische Ziffern (۱۲۳۴) +neben einem `€` liefert. Die Einzelheiten sind als Kommentarblock in `index.html` unmittelbar +bei `TEILWEISE` niedergelegt. + +**Codes.** ISO 639-1, soweit ein solcher besteht, im Übrigen 639-3. Dreibuchstabig sind `grc` +(**nicht** `el` — dies wäre Neugriechisch), `nds` und `bar`; für keine der drei Sprachen besteht +ein zweibuchstabiger Code. `pickLang()` erkennt daher `[a-z]{2,3}` als Grundcode, fakultativ +gefolgt von den vorgenannten `-x-…`-Untertags. + +**Wahl der Sprache**, in nachstehender Reihenfolge: + +1. `?lang=…` in der Adresse — weitergabefähig, überschreibt alles Übrige, +2. die vorgehaltene Wahl in `localStorage` unter `altersvorsorge.lang`, 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. + **Latein, Altgriechisch, Sanskrit und Esperanto werden niemals selbsttätig gewählt** — ein + Browser, welcher `la` meldet, meint dies mit an Sicherheit grenzender Wahrscheinlichkeit + 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. +Die Schaltflächen tragen das Kürzel, der `title` hingegen das **Autonym** (`Українська`, +`Plattdüütsch`, `संस्कृतम्`) und nicht die übersetzte Bezeichnung. Wer Ukrainisch sucht, erkennt +`Українська` auch dann, wenn die Oberfläche gegenwärtig auf Baskisch eingestellt ist; nebenbei +werden hierdurch 14 × 14 Wörterbucheinträge eingespart. **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 +Tausenderzeichen, welches `parseNum()` beim mehrdeutigen `1,234` heranzieht. Sprachen ohne +eigene ICU-Daten (`nds`, `bar`, `eo`, `la`, `grc`, `sa`) erhalten `de-DE`: Devanāgarī-Ziffern +neben einem `€` wären eine Schikane und keine Genauigkeit, 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, jedoch +gebildete Neuprägungen für die Moderne (`pensio operativa`, `impensa pura`, `valor praesens`, +`usura interna`). Römische Ziffern wären ein Witz zu Lasten der Lesbarkeit — und die Trennzeichenkonvention ist ohnehin jünger als jede lateinische Quelle. Das Japanische folgt -dem, was für Software dieser Art dort üblich ist: Erklärtexte in です・ます, Feldbeschriftungen -als Nominalphrasen im 体言止め. Für die Schrift ist der `--ui`-Stapel um MS PGothic, Hiragino, -Yu Gothic und Meiryo erweitert — eine Rasterschrift mit harten Kanten passt zum Thema. +demjenigen, was für Software dieser Art dort üblich ist: Erläuterungstexte in です・ます, +Feldbeschriftungen als Nominalphrasen im 体言止め. Für die Schrift ist der `--ui`-Stapel um +MS PGothic, Hiragino, Yu Gothic und Meiryo erweitert worden — eine Rasterschrift mit harten +Kanten ist dem Gegenstand angemessen. -Der japanische Satzbau erzwingt, wofür die Funktionsform der Einträge da ist. Das Fazit lautet -im Deutschen „X liegt vorn mit W — D mehr als Y“, im Japanischen dagegen -`Xが首位です(W)。YをD上回ります。` — Verb am Ende, Vergleichsgröße mit を statt „als“. Als -Verkettung fester Bausteine ließe sich das nicht bauen. +Der japanische Satzbau erzwingt dasjenige, wozu die Funktionsform der Einträge bestimmt ist. Das +Fazit lautet im Deutschen „X liegt vorn mit W — D mehr als Y", im Japanischen hingegen +`Xが首位です(W)。YをD上回ります。` — das Verb am Ende, die Vergleichsgröße mit を anstelle von +„als". Als Verkettung fester Bausteine ließe sich dies nicht herstellen. -Der Umschalter oben im Kopffenster schreibt beides fort, Speicher und Adresse. Der Teilen-Link -nimmt die Suchzeichenfolge mit, der Zustand steckt weiter im Fragment — beides stört sich nicht. +Der Umschalter oben im Kopffenster schreibt beides fort, mithin Speicher und Adresse. Der +Weitergabeverweis führt die Suchzeichenfolge mit, der Zustand verbleibt im Fragment; beides +stört sich nicht. **Aufbau der Wörterbücher.** Ein Eintrag ist entweder eine Zeichenkette oder eine Funktion -`(p, f) → string`. Die Funktionsform ist keine Bequemlichkeit, sondern notwendig: ein Satz ist -nicht die Verkettung seiner Teile. Stellung, Numerus und Rektion hängen an der Sprache, und -`'mehr als ' + nom` funktioniert nur, solange beide Sprachen denselben Satzbau haben. Deshalb -bekommen die Funktionen **Rohwerte** — Zahlen, keine fertigen Textstücke — und formatieren -selbst über `f` (`f.eur`, `f.pct`, `f.nf2`, …). Sichtbar wird der Unterschied etwa im Fazit: -das Deutsche braucht dort einen Genitiv (`der bAV`), das Englische eine Präposition. +`(p, f) → string`. Die Funktionsform ist keine Bequemlichkeit, sondern zwingend erforderlich: ein +Satz ist nicht die Verkettung seiner Teile. Stellung, Numerus und Rektion hängen an der Sprache, +und `'mehr als ' + nom` ist lediglich so lange tragfähig, wie beide Sprachen denselben Satzbau +aufweisen. Den Funktionen werden daher **Rohwerte** übergeben — Zahlen und keine fertigen +Textstücke —, und die Formatierung erfolgt selbsttätig über `f` (`f.eur`, `f.pct`, `f.nf2`, …). +Sichtbar wird der Unterschied etwa im Fazit: das Deutsche bedarf dort eines Genitivs (`der bAV`), +das Englische einer Präposition. ``` t('n.beitrag.ueber8', { v8: v8 }) @@ -246,213 +267,228 @@ t('n.beitrag.ueber8', { v8: v8 }) en: 'Above 8 % of the pension-insurance contribution ceiling (' + f.eur(p.v8) + ' per year). …' ``` -**Schlüsselschema.** Eingabefelder liegen unter `f.:.label|hint|unit|o`, -die Optionen also unter ihrem *Wert*, nicht unter ihrem Index — dann bleibt die Zuordnung -richtig, wenn eine Option dazukommt. `FIELDS`, `OPTS` und `METRICS` tragen ihre Texte nicht +**Schlüsselschema.** Eingabefelder liegen unter `f.:.label|hint|unit|o`, die +Optionen mithin unter ihrem *Wert* und nicht unter ihrem Index; sodann verbleibt die Zuordnung +zutreffend, wenn eine Option hinzutritt. `FIELDS`, `OPTS` und `METRICS` führen ihre Texte nicht mehr als Feld, sondern als `Object.defineProperty`-Zugriffsfunktion: `f.label` steht unverändert an jeder Aufrufstelle und liefert nach einem Sprachwechsel von selbst den neuen Wert. -**Fehlt ein Eintrag**, greift Deutsch; fehlt auch der, erscheint der Schlüssel selbst im -Klartext. Ein stiller Leerstring wäre die schlechtere Wahl — er verschwindet unbemerkt. +**Fehlt ein Eintrag**, so greift Deutsch; fehlt auch dieser, so erscheint der Schlüssel selbst im +Klartext. Ein stiller Leerstring wäre die schlechtere Wahl, da er unbemerkt verschwände. -**Zahlen.** Umgeschaltet wird nur die Zifferngruppierung — `de` und `la` → `de-DE`, -`en` → `en-GB`, `ja` → `ja-JP`; die Währung bleibt überall der nachgestellte Euro: -`75.000,00 €` bzw. `75,000.00 €`. Die Eingabe nimmt **beide** -Schreibweisen an, damit ein Sprachwechsel keine getippte Zahl entwertet. Die Regel in -`parseNum`: stehen beide Zeichen im Text, ist das rechte das Dezimalzeichen; steht nur eines -und folgen ihm genau drei Ziffern, ist es die Tausendergruppe der aktuellen Sprache -(`GRUPPEN`: `.` für de und la, `,` für en und ja). Damit -bleibt allein `1,234` mehrdeutig — und genau dort entscheidet die Sprache. +**Zahlen.** Umgeschaltet wird ausschließlich die Zifferngruppierung — `de` und `la` → `de-DE`, +`en` → `en-GB`, `ja` → `ja-JP`; die Währung verbleibt durchgängig der nachgestellte Euro: +`75.000,00 €` bzw. `75,000.00 €`. Die Eingabe nimmt **beide** Schreibweisen an, damit ein +Sprachwechsel eine eingegebene Zahl nicht entwertet. Die Regel in `parseNum` lautet: stehen beide +Zeichen im Text, so ist das rechte das Dezimalzeichen; steht lediglich eines und folgen ihm genau +drei Ziffern, so handelt es sich um die Tausendergruppe der gegenwärtigen Sprache (`GRUPPEN`: +`.` für de und la, `,` für en und ja). Damit verbleibt allein `1,234` mehrdeutig — und genau dort +entscheidet die Sprache. **Was ein Sprachwechsel nicht anfasst:** die Eingaben, den Referenzstand und die Ergebnisse. -`setLang` baut nur die Teile neu, deren Beschriftungen beim Aufbau festgeschrieben werden -(Kennzahlenleiste, Registerkarten, Felder, Fenstertitel); alles Übrige zeichnet `refresh()` -ohnehin bei jedem Durchgang. Der Referenzstand merkt sich deshalb den *Feldschlüssel* und -nicht den fertigen Satz — sonst stünde nach dem Wechsel „vor der Änderung von …“ noch in der -alten Sprache da. - -**Prüfung.** `pruefe.js` (Entwicklungswerkzeug, wird vom Service Worker nicht ausgeliefert) lädt die Seite kopflos in -jsdom, schaltet alle dreiundzwanzig 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 dreiundzwanzig 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 +`setLang` baut lediglich diejenigen Teile neu auf, deren Beschriftungen beim Aufbau +festgeschrieben werden (Kennzahlenleiste, Registerkarten, Felder, Fenstertitel); alles Übrige +zeichnet `refresh()` ohnehin bei jedem Durchgang. Der Referenzstand hält daher den +*Feldschlüssel* vor und nicht den fertigen Satz; andernfalls stünde nach dem Wechsel „vor der +Änderung von …" noch in der vormaligen Sprache da. + +**Prüfung.** `pruefe.js` (Entwicklungswerkzeug, wird vom Dienstarbeiter nicht ausgeliefert) lädt +die Seite kopflos in jsdom, schaltet sämtliche dreiundzwanzig Sprachfassungen 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 zugelassenen Fachbegriffen, kein +sichtbar verbliebener Schlüssel, und — die eigentliche Invariante — **identische +Rechenergebnisse in sämtlichen dreiundzwanzig Sprachfassungen**. + +Die Liste der Wörterbücher liest das Skript aus `index.html` aus, anstatt sie zu pflegen: eine +neue Sprache soll den Test nicht stillschweigend an einem leeren Objekt vorbeilaufen lassen. Das Regex für die `