- Add get_suggested_languages() to i18n.py returning ≤6 ranked
suggestions (current locale → Accept-Language header → popular
language fallbacks); refactor _parse_accept_language to share
a common _parse_accept_language_entries() helper
- Inject suggested_languages into every template context (base.py)
- Redesign nav-bar language dropdown (base.html): button shows
current-language flag emoji; dropdown lists 5-7 suggestions with
flags and native names; Alpine.js search input filters all 77
languages live; footer shows count and Search shortcut
- Add language.search_placeholder and language.no_results keys to
all 77 translation JSON files (en values; external script
propagates translations to other locales)
- Remove test_all_languages_have_same_keys (external sync script
owns key completeness); add TestGetSuggestedLanguages (7 unit
tests); update test_language_selector_in_nav for new HTML
- Update InternationalizationGuide.md: single-step en.json-only
workflow for adding new translation keys
- Update .github/copilot-instructions.md: add i18n/l10n section
documenting the en.json-only rule for future agents
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Register _() translation function in app/auth.py, app/api/local_auth.py, and
app/api/billing.py template env globals to fix jinja2.exceptions.UndefinedError
- Update test_settings_template_has_db_wizard_link to assert i18n key instead of
literal "DB Wizard" (template now uses {{ _("settings.db_wizard_btn") }})
- Add 418 missing en.json keys to all 30 non-English translation files as English
fallbacks to fix test_all_languages_have_same_keys
- Fix orphan </template> tag in pipelines.html by adding missing
<template x-if="pipelineModal.saving"> opening tag (fixes djlint H025)
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Fix detect_language() to safely handle unhashable session values and
requests missing cookies/headers attributes (TypeError + AttributeError)
- Add default English `_()` translation function to Jinja2 template
environment globals so error pages always have it available
- Fix app/main.py exception handlers to use a dedicated error templates
instance with `_` registered, keeping it separate from view templates
to avoid test patches breaking error rendering
- Fix app/views/plans.py to import shared templates from app.views.base
instead of creating its own Jinja2Templates instance
- Make migration 029_add_user_language_preference idempotent: skip
ALTER TABLE if user_profiles table does not exist
- Update test_i18n.py expectations to reflect 31 supported languages
- Create 21 missing translation files (nb, da, sv, fi, is, ga, lb, ca,
cs, sk, hu, sl, hr, ro, bg, el, et, lv, lt, tr, uk) with English
placeholder translations
- Update de.json with 117 missing translation keys including proper
German translations
- Update es, fr, it, nl, pl, pt, ru, zh translation files with missing
keys using English fallbacks
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Create i18n utility module (app/utils/i18n.py) with translation loading,
browser language detection, AI fallback, and l10n helpers
- Add JSON translation files for EN, DE, FR, ES, IT, PT, NL, PL, ZH, RU
- Add preferred_language column to UserProfile model with migration
- Register _() translation function as Jinja2 global
- Update base.html with translated navigation, footer, cookie notice
- Add language selector dropdown in nav bar (desktop + mobile)
- Create API endpoints for language preference (POST/GET /api/i18n/)
- Support language detection: user profile > cookie > Accept-Language > default
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>