Zum Inhalt

Internationalisierungsmodul

i18n

Internationalization (i18n) support for Weeb CLI.

This module provides multi-language support through JSON-based translation files. Supports Turkish (tr), English (en), German (de), and Polish (pl).

The translation system uses dot-notation for nested keys and supports string interpolation with keyword arguments.

Example

Basic usage::

from weeb_cli.i18n import i18n

# Get translated string
message = i18n.t("menu.search", "Search Anime")

# With interpolation
greeting = i18n.t("welcome.user", name="John")

# Change language
i18n.set_language("tr")

Attributes:

Name Type Description
LOCALES_DIR Path

Directory containing translation JSON files.

i18n I18n

Global i18n instance for application-wide use.

I18n

Internationalization manager for multi-language support.

Loads and manages translation strings from JSON files, providing a simple interface for retrieving localized text with support for nested keys and string interpolation.

Attributes:

Name Type Description
language str

Current language code (e.g., 'en', 'tr', 'de', 'pl').

translations Dict[str, Any]

Loaded translation dictionary.

Source code in weeb_cli/i18n.py
class I18n:
    """Internationalization manager for multi-language support.

    Loads and manages translation strings from JSON files, providing
    a simple interface for retrieving localized text with support for
    nested keys and string interpolation.

    Attributes:
        language (str): Current language code (e.g., 'en', 'tr', 'de', 'pl').
        translations (Dict[str, Any]): Loaded translation dictionary.
    """

    def __init__(self) -> None:
        """Initialize i18n with language from config or default to English."""
        try:
            self.language: str = config.get("language", "en")
        except Exception as e:
            from weeb_cli.services.logger import debug
            debug(f"[I18n] Config read failed, defaulting to English: {e}")
            self.language = "en"
        self.translations: Dict[str, Any] = {}
        self.load_translations()

    def set_language(self, language_code: str) -> None:
        """Set the active language and reload translations.

        Args:
            language_code: Language code (e.g., 'en', 'tr', 'de', 'pl').
        """
        self.language = language_code
        config.set("language", language_code)
        self.load_translations()

    def load_translations(self) -> None:
        """Load translation file for the current language.

        Falls back to English if the requested language file doesn't exist.
        Silently handles file read errors by using an empty dictionary.
        """
        file_path = LOCALES_DIR / f"{self.language}.json"
        if not file_path.exists():
            file_path = LOCALES_DIR / "en.json"

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                self.translations = json.load(f)
        except (json.JSONDecodeError, OSError) as e:
            from weeb_cli.services.logger import debug
            debug(f"[I18n] Failed to load translations for '{self.language}': {e}")
            self.translations = {}

    def get(self, key_path: str, default: Optional[str] = None, **kwargs: Any) -> str:
        """Get translated string by dot-notation key path.

        Supports nested keys using dot notation (e.g., 'menu.search.title')
        and string interpolation using keyword arguments.

        Args:
            key_path: Dot-separated path to translation key (e.g., 'menu.search').
            default: Default value if key not found. If None, returns key_path.
            **kwargs: Variables for string interpolation using .format().

        Returns:
            Translated and interpolated string, or default/key_path if not found.

        Example:
            >>> i18n.get("welcome.message", name="John")
            "Welcome, John!"
            >>> i18n.get("missing.key", "Default Text")
            "Default Text"
        """
        keys = key_path.split(".")
        value: Any = self.translations

        for key in keys:
            if isinstance(value, dict):
                value = value.get(key)
            else:
                return default if default is not None else key_path

        if value is None:
            return default if default is not None else key_path

        if isinstance(value, str):
            try:
                return value.format(**kwargs)
            except KeyError:
                return value

        return value

    # Alias for convenience
    t = get

__init__

__init__() -> None

Initialize i18n with language from config or default to English.

Source code in weeb_cli/i18n.py
def __init__(self) -> None:
    """Initialize i18n with language from config or default to English."""
    try:
        self.language: str = config.get("language", "en")
    except Exception as e:
        from weeb_cli.services.logger import debug
        debug(f"[I18n] Config read failed, defaulting to English: {e}")
        self.language = "en"
    self.translations: Dict[str, Any] = {}
    self.load_translations()

set_language

set_language(language_code: str) -> None

Set the active language and reload translations.

Parameters:

Name Type Description Default
language_code str

Language code (e.g., 'en', 'tr', 'de', 'pl').

required
Source code in weeb_cli/i18n.py
def set_language(self, language_code: str) -> None:
    """Set the active language and reload translations.

    Args:
        language_code: Language code (e.g., 'en', 'tr', 'de', 'pl').
    """
    self.language = language_code
    config.set("language", language_code)
    self.load_translations()

load_translations

load_translations() -> None

Load translation file for the current language.

Falls back to English if the requested language file doesn't exist. Silently handles file read errors by using an empty dictionary.

Source code in weeb_cli/i18n.py
def load_translations(self) -> None:
    """Load translation file for the current language.

    Falls back to English if the requested language file doesn't exist.
    Silently handles file read errors by using an empty dictionary.
    """
    file_path = LOCALES_DIR / f"{self.language}.json"
    if not file_path.exists():
        file_path = LOCALES_DIR / "en.json"

    try:
        with open(file_path, "r", encoding="utf-8") as f:
            self.translations = json.load(f)
    except (json.JSONDecodeError, OSError) as e:
        from weeb_cli.services.logger import debug
        debug(f"[I18n] Failed to load translations for '{self.language}': {e}")
        self.translations = {}

get

get(key_path: str, default: Optional[str] = None, **kwargs: Any) -> str

Get translated string by dot-notation key path.

Supports nested keys using dot notation (e.g., 'menu.search.title') and string interpolation using keyword arguments.

Parameters:

Name Type Description Default
key_path str

Dot-separated path to translation key (e.g., 'menu.search').

required
default Optional[str]

Default value if key not found. If None, returns key_path.

None
**kwargs Any

Variables for string interpolation using .format().

{}

Returns:

Type Description
str

Translated and interpolated string, or default/key_path if not found.

Example

i18n.get("welcome.message", name="John") "Welcome, John!" i18n.get("missing.key", "Default Text") "Default Text"

Source code in weeb_cli/i18n.py
def get(self, key_path: str, default: Optional[str] = None, **kwargs: Any) -> str:
    """Get translated string by dot-notation key path.

    Supports nested keys using dot notation (e.g., 'menu.search.title')
    and string interpolation using keyword arguments.

    Args:
        key_path: Dot-separated path to translation key (e.g., 'menu.search').
        default: Default value if key not found. If None, returns key_path.
        **kwargs: Variables for string interpolation using .format().

    Returns:
        Translated and interpolated string, or default/key_path if not found.

    Example:
        >>> i18n.get("welcome.message", name="John")
        "Welcome, John!"
        >>> i18n.get("missing.key", "Default Text")
        "Default Text"
    """
    keys = key_path.split(".")
    value: Any = self.translations

    for key in keys:
        if isinstance(value, dict):
            value = value.get(key)
        else:
            return default if default is not None else key_path

    if value is None:
        return default if default is not None else key_path

    if isinstance(value, str):
        try:
            return value.format(**kwargs)
        except KeyError:
            return value

    return value

get_locales_dir

get_locales_dir() -> Path

Get the locales directory path.

Handles both development and frozen (PyInstaller) environments.

Returns:

Type Description
Path

Path to the locales directory containing translation files.

Source code in weeb_cli/i18n.py
def get_locales_dir() -> Path:
    """Get the locales directory path.

    Handles both development and frozen (PyInstaller) environments.

    Returns:
        Path to the locales directory containing translation files.
    """
    if getattr(sys, 'frozen', False):
        base_path = Path(sys._MEIPASS)
        possible_path = base_path / "weeb_cli" / "locales"
        if possible_path.exists():
            return possible_path
        return base_path / "locales"

    return Path(__file__).parent / "locales"

Übersicht

Das i18n-Modul bietet mehrsprachige Unterstützung durch JSON-basierte Übersetzungsdateien. Unterstützt Türkisch (tr), Englisch (en), Deutsch (de) und Polnisch (pl).

Verwendungsbeispiele

Basis-Übersetzung

from weeb_cli.i18n import i18n

# Übersetzten String abrufen
message = i18n.t("menu.search", "Anime suchen")
error = i18n.t("errors.network", "Netzwerkfehler")

String-Interpolation

from weeb_cli.i18n import i18n

# Mit benannten Parametern
greeting = i18n.t("welcome.user", name="Max")
# Ergebnis: "Willkommen, Max!"

progress = i18n.t("download.progress", 
                  current=5, 
                  total=12, 
                  percent=42)
# Ergebnis: "Herunterladen 5/12 (42%)"

Sprache ändern

from weeb_cli.i18n import i18n

# Zu Türkisch wechseln
i18n.set_language("tr")

# Zu Deutsch wechseln
i18n.set_language("de")

Verschachtelte Schlüssel

Übersetzungsdateien verwenden verschachtelte JSON-Struktur:

{
  "menu": {
    "search": "Anime suchen",
    "downloads": "Downloads",
    "settings": "Einstellungen"
  },
  "errors": {
    "network": "Netzwerkverbindung fehlgeschlagen",
    "not_found": "Anime nicht gefunden"
  }
}

Zugriff mit Punkt-Notation:

i18n.t("menu.search")      # "Anime suchen"
i18n.t("errors.network")   # "Netzwerkverbindung fehlgeschlagen"

Unterstützte Sprachen

Code Sprache Status
en Englisch ✅ Vollständig
tr Türkisch ✅ Vollständig
de Deutsch ✅ Vollständig
pl Polnisch ✅ Vollständig

Übersetzungsdateien

Übersetzungsdateien befinden sich in weeb_cli/locales/:

weeb_cli/locales/
├── en.json
├── tr.json
├── de.json
└── pl.json

Übersetzungen hinzufügen

Um eine neue Sprache hinzuzufügen:

  1. weeb_cli/locales/<sprach_code>.json erstellen
  2. Struktur von en.json kopieren
  3. Alle Strings übersetzen
  4. Mit i18n.set_language("<sprach_code>") testen

Fallback-Verhalten

  • Wenn ein Schlüssel nicht gefunden wird, wird der Standardwert oder Schlüsselpfad zurückgegeben
  • Wenn eine Übersetzungsdatei nicht existiert, wird auf Englisch zurückgegriffen
  • Wenn die englische Datei fehlt, werden leere Übersetzungen zurückgegeben

API-Referenz

Internationalization manager for multi-language support.

Loads and manages translation strings from JSON files, providing a simple interface for retrieving localized text with support for nested keys and string interpolation.

Attributes:

Name Type Description
language str

Current language code (e.g., 'en', 'tr', 'de', 'pl').

translations Dict[str, Any]

Loaded translation dictionary.

Source code in weeb_cli/i18n.py
class I18n:
    """Internationalization manager for multi-language support.

    Loads and manages translation strings from JSON files, providing
    a simple interface for retrieving localized text with support for
    nested keys and string interpolation.

    Attributes:
        language (str): Current language code (e.g., 'en', 'tr', 'de', 'pl').
        translations (Dict[str, Any]): Loaded translation dictionary.
    """

    def __init__(self) -> None:
        """Initialize i18n with language from config or default to English."""
        try:
            self.language: str = config.get("language", "en")
        except Exception as e:
            from weeb_cli.services.logger import debug
            debug(f"[I18n] Config read failed, defaulting to English: {e}")
            self.language = "en"
        self.translations: Dict[str, Any] = {}
        self.load_translations()

    def set_language(self, language_code: str) -> None:
        """Set the active language and reload translations.

        Args:
            language_code: Language code (e.g., 'en', 'tr', 'de', 'pl').
        """
        self.language = language_code
        config.set("language", language_code)
        self.load_translations()

    def load_translations(self) -> None:
        """Load translation file for the current language.

        Falls back to English if the requested language file doesn't exist.
        Silently handles file read errors by using an empty dictionary.
        """
        file_path = LOCALES_DIR / f"{self.language}.json"
        if not file_path.exists():
            file_path = LOCALES_DIR / "en.json"

        try:
            with open(file_path, "r", encoding="utf-8") as f:
                self.translations = json.load(f)
        except (json.JSONDecodeError, OSError) as e:
            from weeb_cli.services.logger import debug
            debug(f"[I18n] Failed to load translations for '{self.language}': {e}")
            self.translations = {}

    def get(self, key_path: str, default: Optional[str] = None, **kwargs: Any) -> str:
        """Get translated string by dot-notation key path.

        Supports nested keys using dot notation (e.g., 'menu.search.title')
        and string interpolation using keyword arguments.

        Args:
            key_path: Dot-separated path to translation key (e.g., 'menu.search').
            default: Default value if key not found. If None, returns key_path.
            **kwargs: Variables for string interpolation using .format().

        Returns:
            Translated and interpolated string, or default/key_path if not found.

        Example:
            >>> i18n.get("welcome.message", name="John")
            "Welcome, John!"
            >>> i18n.get("missing.key", "Default Text")
            "Default Text"
        """
        keys = key_path.split(".")
        value: Any = self.translations

        for key in keys:
            if isinstance(value, dict):
                value = value.get(key)
            else:
                return default if default is not None else key_path

        if value is None:
            return default if default is not None else key_path

        if isinstance(value, str):
            try:
                return value.format(**kwargs)
            except KeyError:
                return value

        return value

    # Alias for convenience
    t = get

get

get(key_path: str, default: Optional[str] = None, **kwargs: Any) -> str

Get translated string by dot-notation key path.

Supports nested keys using dot notation (e.g., 'menu.search.title') and string interpolation using keyword arguments.

Parameters:

Name Type Description Default
key_path str

Dot-separated path to translation key (e.g., 'menu.search').

required
default Optional[str]

Default value if key not found. If None, returns key_path.

None
**kwargs Any

Variables for string interpolation using .format().

{}

Returns:

Type Description
str

Translated and interpolated string, or default/key_path if not found.

Example

i18n.get("welcome.message", name="John") "Welcome, John!" i18n.get("missing.key", "Default Text") "Default Text"

Source code in weeb_cli/i18n.py
def get(self, key_path: str, default: Optional[str] = None, **kwargs: Any) -> str:
    """Get translated string by dot-notation key path.

    Supports nested keys using dot notation (e.g., 'menu.search.title')
    and string interpolation using keyword arguments.

    Args:
        key_path: Dot-separated path to translation key (e.g., 'menu.search').
        default: Default value if key not found. If None, returns key_path.
        **kwargs: Variables for string interpolation using .format().

    Returns:
        Translated and interpolated string, or default/key_path if not found.

    Example:
        >>> i18n.get("welcome.message", name="John")
        "Welcome, John!"
        >>> i18n.get("missing.key", "Default Text")
        "Default Text"
    """
    keys = key_path.split(".")
    value: Any = self.translations

    for key in keys:
        if isinstance(value, dict):
            value = value.get(key)
        else:
            return default if default is not None else key_path

    if value is None:
        return default if default is not None else key_path

    if isinstance(value, str):
        try:
            return value.format(**kwargs)
        except KeyError:
            return value

    return value

set_language

set_language(language_code: str) -> None

Set the active language and reload translations.

Parameters:

Name Type Description Default
language_code str

Language code (e.g., 'en', 'tr', 'de', 'pl').

required
Source code in weeb_cli/i18n.py
def set_language(self, language_code: str) -> None:
    """Set the active language and reload translations.

    Args:
        language_code: Language code (e.g., 'en', 'tr', 'de', 'pl').
    """
    self.language = language_code
    config.set("language", language_code)
    self.load_translations()

load_translations

load_translations() -> None

Load translation file for the current language.

Falls back to English if the requested language file doesn't exist. Silently handles file read errors by using an empty dictionary.

Source code in weeb_cli/i18n.py
def load_translations(self) -> None:
    """Load translation file for the current language.

    Falls back to English if the requested language file doesn't exist.
    Silently handles file read errors by using an empty dictionary.
    """
    file_path = LOCALES_DIR / f"{self.language}.json"
    if not file_path.exists():
        file_path = LOCALES_DIR / "en.json"

    try:
        with open(file_path, "r", encoding="utf-8") as f:
            self.translations = json.load(f)
    except (json.JSONDecodeError, OSError) as e:
        from weeb_cli.services.logger import debug
        debug(f"[I18n] Failed to load translations for '{self.language}': {e}")
        self.translations = {}