Add internationalization support with English and French translations

- Introduced a new i18n module for managing translations using JSON files.
- Added English (en.json) and French (fr.json) translation files for UI elements.
- Implemented lazy initialization of the translator to load translations on demand.
- Added unit tests for translation lookup, fallback behavior, and available languages detection.
This commit is contained in:
claudi 2026-03-10 14:32:38 +01:00
parent fd0482ed2d
commit 7daec731ca
11 changed files with 1184 additions and 280 deletions

60
tests/unit/test_i18n.py Normal file
View file

@ -0,0 +1,60 @@
"""Unit tests for i18n translation helper."""
import json
from pathlib import Path
from webdrop_bridge.utils import i18n
class TestI18n:
"""Tests for translation lookup and fallback behavior."""
def test_tr_lazy_initialization_uses_english_defaults(self):
"""Translator should lazily initialize and resolve known keys."""
# Force a fresh singleton state for this test.
i18n._translator = i18n.Translator() # type: ignore[attr-defined]
assert i18n.tr("settings.title") == "Settings"
def test_initialize_with_language_falls_back_to_english(self, tmp_path: Path):
"""Missing keys in selected language should fall back to English."""
translations = tmp_path / "translations"
translations.mkdir(parents=True, exist_ok=True)
(translations / "en.json").write_text(
json.dumps(
{
"greeting": "Hello {name}",
"settings.title": "Settings",
}
),
encoding="utf-8",
)
(translations / "de.json").write_text(
json.dumps(
{
"settings.title": "Einstellungen",
}
),
encoding="utf-8",
)
i18n._translator = i18n.Translator() # type: ignore[attr-defined]
i18n.initialize("de", translations)
assert i18n.tr("settings.title") == "Einstellungen"
assert i18n.tr("greeting", name="Alex") == "Hello Alex"
def test_get_available_languages_reads_translation_files(self, tmp_path: Path):
"""Available languages should be discovered from JSON files."""
translations = tmp_path / "translations"
translations.mkdir(parents=True, exist_ok=True)
(translations / "en.json").write_text("{}", encoding="utf-8")
(translations / "fr.json").write_text("{}", encoding="utf-8")
i18n._translator = i18n.Translator() # type: ignore[attr-defined]
i18n.initialize("en", translations)
available = i18n.get_available_languages()
assert "en" in available
assert "fr" in available