Przejdź do treści

Moduł internacjonalizacji

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"

Przegląd

Moduł i18n zapewnia obsługę wielu języków poprzez pliki tłumaczeń oparte na JSON. Obsługuje turecki (tr), angielski (en), niemiecki (de) i polski (pl).

Przykłady użycia

Podstawowe tłumaczenie

from weeb_cli.i18n import i18n

# Pobierz przetłumaczony ciąg
message = i18n.t("menu.search", "Wyszukaj anime")
error = i18n.t("errors.network", "Błąd sieci")

Interpolacja ciągów

from weeb_cli.i18n import i18n

# Z nazwanymi parametrami
greeting = i18n.t("welcome.user", name="Jan")
# Wynik: "Witaj, Jan!"

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

Zmiana języka

from weeb_cli.i18n import i18n

# Przełącz na turecki
i18n.set_language("tr")

# Przełącz na niemiecki
i18n.set_language("de")

Zagnieżdżone klucze

Pliki tłumaczeń używają zagnieżdżonej struktury JSON:

{
  "menu": {
    "search": "Wyszukaj anime",
    "downloads": "Pobieranie",
    "settings": "Ustawienia"
  },
  "errors": {
    "network": "Połączenie sieciowe nie powiodło się",
    "not_found": "Nie znaleziono anime"
  }
}

Dostęp z notacją kropkową:

i18n.t("menu.search")      # "Wyszukaj anime"
i18n.t("errors.network")   # "Połączenie sieciowe nie powiodło się"

Obsługiwane języki

Kod Język Status
en Angielski ✅ Kompletny
tr Turecki ✅ Kompletny
de Niemiecki ✅ Kompletny
pl Polski ✅ Kompletny

Pliki tłumaczeń

Pliki tłumaczeń znajdują się w weeb_cli/locales/:

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

Dodawanie tłumaczeń

Aby dodać nowy język:

  1. Utwórz weeb_cli/locales/<kod_języka>.json
  2. Skopiuj strukturę z en.json
  3. Przetłumacz wszystkie ciągi
  4. Testuj za pomocą i18n.set_language("<kod_języka>")

Zachowanie awaryjne

  • Jeśli klucz nie zostanie znaleziony, zwraca wartość domyślną lub ścieżkę klucza
  • Jeśli plik tłumaczenia nie istnieje, powraca do angielskiego
  • Jeśli brakuje pliku angielskiego, zwraca puste tłumaczenia

Dokumentacja API

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 = {}