feat: complete German translation of all public-facing content

Translate the entire public-facing surface of the app to German,
using a hybrid approach: {{ t.key }} for short UI strings and
{% if lang == 'de' %} conditionals for prose blocks/FAQs.

Coverage:
- i18n.py: +300 UI keys, +200 planner JS locale strings, +35
  CAPEX/OPEX item name translations; new get_planner_translations()
  and get_calc_item_names() helpers
- base.html / _cookie_banner.html: nav, footer, cookie banner,
  feedback placeholder; JS toggle text injected via tojson
- public/: landing.html (hero, ROI calc, FAQ, SEO, JSON-LD),
  features.html, about.html — all with German meta tags
- planner/: planner.html (wizard, tabs, chart labels, CTAs),
  all export templates, scenario_list.html; window.__PADELNOMICS_LOCALE__
  injected server-side; planner.js all ~200 strings via tr()
- calculator.py: add lang param, translated CAPEX/OPEX item names,
  replace rent name-lookup with local rent_amount variable
- directory/: directory.html, supplier_detail.html, results.html,
  enquiry_result.html
- leads/: quote_step_1–9.html, quote_request.html, quote_submitted.html,
  quote_verify_sent.html; routes.py flash messages + _get_quote_steps(lang)
- suppliers/: signup flow (step 1–4), signup_success.html,
  waitlist.html, waitlist_confirmed.html
- content/: markets.html, article_detail.html, market_results.html,
  all scenario partials (summary, capex, cashflow, operating, returns)
- 629 tests pass, ruff clean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-20 14:42:31 +01:00
parent 32f29c53ec
commit ddbdc00a3d
50 changed files with 2592 additions and 778 deletions

View File

@@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
### Added
- i18n: translate `base.html`, `_cookie_banner.html` — "Manage Cookies", "About" footer links, feedback placeholder via `{{ t.key }}`; cookie banner heading/categories/descriptions/buttons; JS toggle text injected via `tojson` so "Manage"/"Close" states are also translated; `public/routes.py` feedback flash messages use `get_translations(g.lang)` keys
- i18n: expand `i18n.py` with ~300 UI template keys, ~200 planner JS locale strings (`_PLANNER_TRANSLATIONS`), ~35 CAPEX/OPEX item name translations (`_CALC_ITEM_NAMES`), plus `get_planner_translations()` and `get_calc_item_names()` functions
### Fixed
- i18n: `planner.html` used `{% if lang %}...{% block %}` nesting which Jinja2 forbids — restructured to `{% block title %}{% if lang == 'de' %}...{% endif %}{% endblock %}`
- ruff: unsorted import in `planner/routes.py` (new `get_planner_translations` import) — auto-fixed with `ruff --fix`
### Added
- i18n: localize planner — inject `window.__PADELNOMICS_LOCALE__` from server via `get_planner_translations(lang)`, add `const L / tr()` helpers in `planner.js`, replace all hardcoded English strings in TABS, WIZ_STEPS, all `buildInputs()`/`rebuildCapexInputs()`/`rebuildOpexInputs()` slider labels, `renderWith()`, `renderCapex()`, `renderOperating()`, `renderCashflow()`, `renderReturns()`, `renderMetrics()`, `renderSeasonChart()`, `resetToDefaults()`, `saveScenario()`, `renderWizNav()`, and `renderWizPreview()` with `tr('key', 'fallback')` calls
- i18n: localize `planner.html` — add `window.__PADELNOMICS_LOCALE__` script injection, translate wizard step titles/subtitles, toggle labels, chart/section headers, CTA sidebar and inline CTA, signup bar, scenario controls, metrics section headers, and page title/meta via `{% if lang == 'de' %}` and `{{ t.key }}` / `{{ planner_t.key }}`
- i18n: localize all export templates — `export.html`, `export_success.html`, `export_generating.html`, `export_waitlist.html` — all strings via `{{ t.key }}`, feature lists via `{% if lang == 'de' %}` conditionals
- i18n: localize `partials/scenario_list.html` — drawer title, default badge, Load/Delete buttons, updated label, empty state message via `{{ t.scenario_* }}`
- calculator: add `lang: str = "en"` parameter to `calc()`, import `get_calc_item_names`, replace all `ci()`/`oi()` hardcoded English names with `names["key"]` lookups, track `rent_amount` as local variable to replace name-based loop lookup for rentRatio
- routes: pass `lang` and `planner_t` to `planner.html` render context; pass `lang=lang` to `calc()` in both index and `/calculate` endpoints
- i18n: translate directory and leads templates — `directory.html`, `supplier_detail.html`, `partials/results.html`, `partials/enquiry_result.html`, `quote_request.html`, `quote_step_19.html`, `quote_submitted.html`, `quote_verify_sent.html` — short strings via `{{ t.key }}`, long paragraphs and context-sensitive text via `{% if lang == 'de' %}` conditionals, title/meta tags conditional per language
- i18n: translate supplier signup flow (`signup.html`, `signup_step_14.html`, `signup_success.html`), waitlist pages (`waitlist.html`, `waitlist_confirmed.html`), content templates (`markets.html`, `article_detail.html`, `market_results.html`), and all scenario partials (`scenario_summary`, `scenario_capex`, `scenario_cashflow`, `scenario_operating`, `scenario_returns`) — step labels via `{{ t.key }}`, all other strings via `{% if lang == 'de' %}` conditionals
- i18n: translate `landing.html`, `features.html`, and `about.html` to German — all short strings via `{{ t.key }}`, long paragraphs/FAQ answers via `{% if lang == 'de' %}` conditionals, JSON-LD structured data wrapped per language, title/meta blocks conditional
### Changed
- leads/routes.py: replace hardcoded `QUOTE_STEPS` list with `_get_quote_steps(lang)` function — step titles now use i18n keys so the progress bar shows translated step names; all public-facing `flash()` calls now use `get_translations(g.lang)` keys instead of hardcoded English strings
### Fixed
- i18n: improve German nav labels — "Verzeichnis" → "Anbieterverzeichnis", "Planer" → "Kostenrechner"
- CI: add missing env vars to `.env` heredoc — `WAITLIST_MODE`, `LEADS_EMAIL`, `UMAMI_API_URL`; make Paddle vars optional (`:-`) so they don't break deploys when unset