feat(i18n): Deutsch/Englisch, Sprachknopf und GitHub-Link in der Kopfzeile

- i18n-Kern im gettext-Stil (t/msg, Wörterbuch en.ts); Startsprache aus localStorage, sonst Browsersprache;
  <html lang> setzt auch das Inline-Skript in index.html. Ein Test prüft t()/msg() und en.ts in beide Richtungen.
- Kopfzeile: GitHub-Link und Sprachknopf (Zielsprache, Beschriftung und lang in der Zielsprache), Fußzeile aus mountFooter,
  Banner und Seitentitel übersetzt, statisches index.html englisch.
- Sprachwechsel ohne Neuladen (main.ts): Kopfzeile, Banner, Konto-Menü und Fußzeile neu aufgebaut, rerender() des Routers baut
  die Seite neu auf, der Editor-Store bleibt; der Appwrite-Client bekommt die Sprache.
- Kopfzeile bleibt in einer Zeile: einzeilig ab 1000 px (vorher 900), GitHub-Text ab 1230 px, auf schmalen Telefonen steht
  „Anmelden“ neben der Suche.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-04 18:33:15 +00:00
1 parent 9455013833
commit e1fb632cdd
21 files changed
+1321 -66

No files matched your search

+19 -7
View File
@@ -1,17 +1,19 @@
<!doctype html>
<html lang="de">
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AirCard-IOS – Kartendesigns für Apple Wallet</title>
<title>AirCard-IOS – Card designs for Apple Wallet</title>
<meta name="description" content="Discover community card designs for AirCard-iOS, create your own and download it as PNG." />
<meta name="theme-color" content="#0F1828" />
<meta name="apple-mobile-web-app-title" content="AirCard-IOS" />
<link rel="icon" href="/favicon.svg?v=2" type="image/svg+xml" />
<link rel="icon" href="/favicon-32.png?v=2" sizes="32x32" type="image/png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png?v=2" />
<script>
// Hell/Dunkel vor dem ersten Paint setzen (kein Aufblitzen); dieselbe Regel wie initialTheme() in src/shell/theme.ts.
// In einer sofort aufgerufenen Funktion, damit keine globale Variable `theme` entsteht.
// Hell/Dunkel und Sprache (<html lang>) vor dem ersten Paint setzen (kein Aufblitzen); dieselben Regeln wie
// initialTheme() in src/shell/theme.ts und initialLang() in src/i18n/i18n.ts.
// In einer sofort aufgerufenen Funktion, damit keine globalen Variablen `theme` und `lang` entstehen.
(function () {
try {
var theme = null;
@@ -23,6 +25,18 @@
}
document.documentElement.setAttribute('data-theme', theme);
} catch (e) {}
try {
var lang = null;
try {
lang = localStorage.getItem('aircard.lang');
} catch (e) {}
if (lang !== 'de' && lang !== 'en') {
var browser = window.navigator;
var first = (browser.languages && browser.languages[0]) || browser.language || '';
lang = /^de/i.test(first) ? 'de' : 'en';
}
document.documentElement.setAttribute('lang', lang);
} catch (e) {}
})();
</script>
</head>
@@ -33,9 +47,7 @@
<div id="account-slot"></div>
</header>
<main id="app-root"></main>
<footer id="app-footer">
<p>Inoffizielles Hobbyprojekt. Keine Verbindung zu Apple, Visa, Mastercard, UnionPay, American Express, JCB oder Discover. Alle Marken gehören ihren Inhabern.</p>
</footer>
<footer id="app-footer"></footer>
<script type="module" src="/src/main.ts"></script>
</body>
</html>