Translation
Translation package for gllm-intl utilities.
This package provides the translation manager, provider abstractions, backend implementations, and custom exceptions.
BabelBackend(locales_dir=None, translations=None, domain='messages')
Bases: TranslationBackend
Babel gettext backend for standard translation files.
This backend uses Babel's support for gettext .po/.mo files, providing CLDR-compliant plural rules and standard gettext message extraction.
File Structure
locales_dir/ ├── en/ │ └── LC_MESSAGES/ │ ├── messages.po │ └── messages.mo # Compiled, preferred ├── fr/ │ └── LC_MESSAGES/ │ └── messages.mo └── ...
Thread Safety
- Read operations are thread-safe
- Translation cache is protected by a lock during loading
- Once loaded, translations are immutable
Attributes:
| Name | Type | Description |
|---|---|---|
locales_dir |
str | None
|
Path to directory containing locale subdirectories. |
translations |
dict[str, Translations | NullTranslations] | None
|
Pre-loaded Translations objects keyed by locale. |
domain |
str
|
Gettext domain name (default: "messages"). |
Initialize the backend using filesystem or pre-loaded catalogs.
Exactly one of locales_dir or translations must be supplied so the
backend knows where to source translation data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locales_dir |
str | None
|
Absolute or relative path with locale subdirectories (e.g., "./locales/en/LC_MESSAGES"). |
None
|
translations |
dict[str, Translations] | None
|
Mapping of locale identifiers to |
None
|
domain |
str
|
Gettext domain name that determines which |
'messages'
|
Raises:
| Type | Description |
|---|---|
ProviderConfigurationError
|
If both sources are provided, neither is provided, the directory is invalid, or the translations mapping is empty. |
Example
backend = BabelBackend(locales_dir="./locales")
from babel.support import Translations
preloaded = {"en": Translations.load("./locales", ["en"])}
backend = BabelBackend(translations=preloaded)
format_message(message, **variables)
Interpolate variables into message using str.format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message |
str
|
Template containing {placeholder} tokens. |
required |
**variables |
Mapping of placeholder names to values used for interpolation.
These are forwarded as keyword arguments to |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Formatted string when interpolation succeeds, otherwise the original message. |
Example
backend.format_message("{count} files", count=3)
get_context_message(key, locale, context)
Return a translation for key scoped by context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Message identifier. |
required |
locale |
str
|
Locale identifier. |
required |
context |
str
|
Disambiguating context value. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: Context-specific translation or |
Example
backend.get_context_message("name", "en", "person")
backend.get_context_message("name", "en", "file")
get_context_plural_message(key, locale, context, count)
Return a context-aware plural translation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Singular key stored in the catalog. |
required |
locale |
str
|
Locale identifier. |
required |
context |
str
|
Disambiguating context value. |
required |
count |
int
|
Quantity influencing plural selection. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: Formatted template or |
Example
backend.get_context_plural_message("item", "en", "file", 3)
get_message(key, locale)
Return the gettext translation for key in locale.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Message identifier stored in the catalog. |
required |
locale |
str
|
Locale to retrieve the translation from. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: Translated string or |
Example
backend.get_message("greeting", "en")
backend.get_message("greeting", "fr")
get_plural_message(key, locale, count)
Return the plural translation selected by CLDR rules.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Singular form key in the catalog. |
required |
locale |
str
|
Locale identifier. |
required |
count |
int
|
Quantity influencing plural selection. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: Pluralized template or |
Example
backend.get_plural_message("item", "en", 1)
backend.get_plural_message("item", "en", 5)
load_locale(locale)
Ensure the translation catalog for locale is cached.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locale |
str
|
Locale identifier such as "en" or "zh-Hans-CN". |
required |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
Propagated if the locale catalog cannot be found
and Babel raises during |
OSError
|
Propagated on filesystem access issues during loading. |
Notes
Prefers compiled .mo files, uses a lock for thread safety, and
caches NullTranslations when the locale is missing.
LocaleNotFoundError(locale, message=None)
Bases: Exception
Raised when a requested locale is not available in the backend.
This exception is raised in strict mode when a locale is requested but cannot be found in the loaded translations.
Attributes:
| Name | Type | Description |
|---|---|---|
locale |
str
|
The locale identifier that was not found. |
message |
str | None
|
Human-readable error message. Defaults to None. |
Initialize LocaleNotFoundError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locale |
str
|
The locale identifier that was not found. |
required |
message |
str | None
|
Optional custom error message. Defaults to None, in which case a default message is generated. |
None
|
__str__()
Return string representation of the error.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Representation of the error. |
LocaleProvider(default_locale=DEFAULT_LOCALE, strict_mode=False, backend='babel', backend_config=None)
Bases: ABC
Abstract base class for locale providers.
Attributes:
| Name | Type | Description |
|---|---|---|
default_locale |
str
|
Fallback locale identifier. |
strict_mode |
bool
|
Strict error handling mode flag. |
backend |
BaseTranslationBackend
|
Configured translation backend instance. |
Initialize the locale provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default_locale |
str
|
Default locale identifier. Defaults to "en". |
DEFAULT_LOCALE
|
strict_mode |
bool
|
Whether to enable strict error handling. Defaults to False. |
False
|
backend |
str | BaseTranslationBackend
|
Backend identifier to instantiate. Defaults to "babel".
If given as a string, it will be used to create a backend instance using |
'babel'
|
backend_config |
dict[str, Any] | None
|
Configuration for backend factory. Defaults to None.
Will be passed to |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
LocaleNotFoundError
|
If |
get_available_locales()
abstractmethod
Return a sorted list of available locales.
This method is to be implemented by subclasses to enumerate all locales they can serve (normalized as defined by the provider).
Returns:
| Type | Description |
|---|---|
list[str]
|
list[str]: A sorted list of available locales. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the method is not implemented by a subclass. |
get_context_plural_translation(key, locale, context, count, **variables)
Return context-specific plural translation for key and context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
context |
str
|
Context value to use for translation. |
required |
count |
int
|
Count value to use for pluralization. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The context-specific plural translated text. |
get_context_translation(key, locale, context, **variables)
Return context-specific translation for key and context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
context |
str
|
Context value to use for translation. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The context-specific translated text. |
get_context_translation_lazy(key, locale, context, **variables)
Return a lazy translation proxy for context-specific messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
context |
str
|
Context value to use for translation. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
LazyProxy |
LazyProxy
|
A lazy translation proxy for the given key and locale. |
get_plural_translation(key, locale, count, **variables)
Return pluralized translation for key and count.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
count |
int
|
Count value to use for pluralization. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The pluralized translated text. |
get_plural_translation_lazy(key, locale, count, **variables)
Return a lazy translation proxy for plural messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
count |
int
|
Count value to use for pluralization. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
LazyProxy |
LazyProxy
|
A lazy translation proxy for the given key and locale. |
get_translation(key, locale, **variables)
Return translated text for key and locale.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The translated text. |
get_translation_lazy(key, locale, **variables)
Return a lazy translation proxy for key and locale.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
Translation key to retrieve. |
required |
locale |
str
|
Locale identifier to retrieve translation for. |
required |
**variables |
Additional variables to pass to the backend method. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
LazyProxy |
LazyProxy
|
A lazy translation proxy for the given key and locale. |
has_locale(locale)
abstractmethod
Return True if the given locale is available.
This method is to be implemented by subclasses to indicate whether a locale is available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locale |
str
|
Locale identifier to check. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the locale is available, False otherwise. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the method is not implemented by a subclass. |
ProviderConfigurationError(message)
Bases: Exception
Raised when provider configuration is invalid.
This exception is raised during provider initialization when the configuration parameters are invalid or inconsistent.
Common causes: 1. Both locales_dir and translations provided (mutually exclusive) 2. Neither locales_dir nor translations provided (one required) 3. Invalid file paths or malformed translation data
Attributes:
| Name | Type | Description |
|---|---|---|
message |
str
|
Human-readable error message explaining the issue. |
Initialize ProviderConfigurationError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message |
str
|
Error message explaining the configuration issue. |
required |
__str__()
Return string representation of the error.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Representation of the error. |
TranslationBackend
Bases: ABC
Abstract base class defining the translation backend interface.
All translation backends must implement this interface to ensure consistent behavior and allow the LocaleProvider to work with any backend implementation.
Backend responsibilities: 1. Load translation data from files or pre-loaded sources 2. Retrieve raw messages by key (gettext, ngettext, pgettext, npgettext) 3. Format messages with variable interpolation
Backend does NOT: 1. Implement fallback chains (LocaleProvider's responsibility) 2. Handle missing keys gracefully (returns None, provider decides) 3. Normalize locale identifiers (LocaleProvider's responsibility)
Thread Safety: 1. Implementations must be thread-safe for concurrent read operations. 2. Translation data should be loaded once and cached immutably.
format_message(message, **variables)
Format a message by interpolating variables.
This default implementation uses Python's str.format to interpolate variables. Subclasses may override this
method to support alternative formatting syntaxes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message |
str
|
The message string with placeholders. |
required |
**variables |
Mapping of placeholder names to values used for interpolation.
These are forwarded as keyword arguments to |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The formatted message string with variables replaced. |
Example
backend.format_message("Hello, {name}!", name="Alice")
backend.format_message("You have {count} messages", count=5)
get_context_message(key, locale, context)
abstractmethod
Retrieve a context-aware translated message (pgettext).
Context allows disambiguating translations for the same key but with different meanings. For example, "name" could mean "person name" or "file name" depending on context.
This method must be implemented by subclasses to provide a context- specific translation for the supplied key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
locale |
str
|
The locale identifier. |
required |
context |
str
|
The context string to disambiguate the key. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: The translated message for the given context, |
str | None
|
or None if the key+context combination is not found. |
Example
backend.get_context_message("name", "en", "person") # "Full Name"
backend.get_context_message("name", "en", "file") # "Filename"
get_context_plural_message(key, locale, context, count)
abstractmethod
Retrieve a context-aware plural message (npgettext).
Combines context disambiguation with plural handling. Useful when the same key needs different translations based on context AND different plural forms based on count.
This method must be implemented by subclasses to resolve a context-aware plural translation for the given key and count.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
locale |
str
|
The locale identifier. |
required |
context |
str
|
The context string to disambiguate the key. |
required |
count |
int
|
The numeric count used to determine plural form. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: The translated message with appropriate context and plural form, |
str | None
|
or None if the key+context combination is not found. |
Example
backend.get_context_plural_message("item", "en", "file", 1) # "{count} file"
backend.get_context_plural_message("item", "en", "file", 5) # "{count} files"
get_message(key, locale)
abstractmethod
Retrieve a simple translated message (gettext).
This is the basic translation lookup - equivalent to GNU gettext's gettext() function. Returns the translated message for the given key in the specified locale.
This method must be implemented by subclasses to fetch a simple translated string from the underlying message store.
Example
backend.get_message("greeting.hello", "en") # "Hello"
backend.get_message("greeting.hello", "fr") # "Bonjour"
backend.get_message("nonexistent", "en") # None
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
locale |
str
|
The locale identifier. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: The translated message string, or None if the key is not found in the specified locale. Backend should NOT implement fallback logic - return None to let the provider handle fallback. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the method is not implemented by the subclass. |
get_plural_message(key, locale, count)
abstractmethod
Retrieve a plural-aware translated message (ngettext).
This method implements CLDR plural rules to select the grammatically correct plural form based on the count. Different languages have different numbers of plural forms (English: 2, Russian: 3, Arabic: 6).
This method must be implemented by subclasses to return a pluralized translation string appropriate for the given locale and count.
Example
backend.get_plural_message("item", "en", 1) # "{count} item"
backend.get_plural_message("item", "en", 5) # "{count} items"
backend.get_plural_message("item", "ru", 2) # "{count} предмета"
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
locale |
str
|
The locale identifier. |
required |
count |
int
|
The numeric count used to determine plural form. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: The translated message with the appropriate plural form, or None if the key is not found in the specified locale. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the method is not implemented by the subclass. |
load_locale(locale)
abstractmethod
Load translation data for a specific locale.
This method should load and cache the translation data for the specified locale. Subsequent calls with the same locale should be idempotent (no-op if already loaded).
This method must be implemented by subclasses to load locale-specific translation resources into memory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locale |
str
|
The locale identifier (e.g., "en", "fr", "zh-Hans-CN"). |
required |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the method is not implemented by the subclass. |
Note
Implementations should cache loaded translations for performance.
TranslationKeyError(key, locale, message=None)
Bases: Exception
Raised when a translation key is not found in any locale.
This exception is raised in strict mode when a translation key is requested but cannot be found in the target locale or any fallback locales.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
The translation key that was not found. |
locale |
str
|
The locale where the key was requested. |
message |
str | None
|
Human-readable error message. Defaults to None, in which case a default message is generated. |
Initialize TranslationKeyError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The translation key that was not found. |
required |
locale |
str
|
The locale where the key was requested. |
required |
message |
str | None
|
Optional custom error message. Defaults to None, in which case a default message is generated. |
None
|
__str__()
Return string representation of the error.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Representation of the error. |
TranslationManager(provider, default_locale=None)
Convenience API layer for translation operations.
TranslationManager wraps a LocaleProvider and maintains a current locale context, allowing translation methods to be called without explicitly passing the locale parameter each time.
This layer is optional - applications can use LocaleProvider directly if they prefer explicit locale parameters.
Thread Safety
The current_locale attribute is instance-specific. For multi-threaded applications (e.g., web servers), either: 1. Create a manager instance per request/thread, or 2. Use LocaleProvider directly with explicit locale parameters
Attributes:
| Name | Type | Description |
|---|---|---|
provider |
LocaleProvider
|
The LocaleProvider instance. |
current_locale |
str
|
Currently active locale identifier. |
Initialize TranslationManager with a provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider |
LocaleProvider
|
LocaleProvider instance to delegate to. |
required |
default_locale |
str | None
|
Initial locale to set.
Defaults to |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If provider is None. |
LocaleNotFoundError
|
If default_locale is not available (strict mode only). |
Example
from gllm_intl.translation.manager import TranslationManager
from gllm_intl.translation.providers import FileSystemLocaleProvider
provider = FileSystemLocaleProvider(
locales_dir="./locales",
backend="babel",
default_locale="en",
strict_mode=False,
)
manager = TranslationManager(provider)
manager.set_locale("fr")
print(manager.translate("greeting")) # "Bonjour"
get_locale()
Get the current locale.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Current locale identifier. |
Example
manager.get_locale()
set_locale(locale)
Set the current locale for subsequent translation operations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locale |
str
|
Locale identifier to set as current. |
required |
Raises:
| Type | Description |
|---|---|
LocaleNotFoundError
|
If locale not available (strict mode only). |
ValueError
|
If locale is empty. |
Example
manager.set_locale("fr")
manager.set_locale("en-US")
translate(key, **variables)
Translate a message using the current locale (gettext).
Convenience method that uses current_locale automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
**variables |
Variables for message interpolation. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Translated and formatted message string. |
Raises:
| Type | Description |
|---|---|
TranslationKeyError
|
If key not found (strict mode only). |
Example
manager.set_locale("fr")
manager.translate("greeting.hello", name="Alice")
translate_context(key, context, **variables)
Translate a context-aware message using the current locale (pgettext).
Convenience method that uses current_locale automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
context |
str
|
Context string for disambiguation. |
required |
**variables |
Variables for message interpolation. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Translated message for the given context. |
Raises:
| Type | Description |
|---|---|
TranslationKeyError
|
If key+context not found (strict mode only). |
Example
manager.set_locale("en")
manager.translate_context("name", context="person")
translate_context_plural(key, context, count, **variables)
Translate a context+plural message using current locale (npgettext).
Convenience method that uses current_locale automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
context |
str
|
Context string for disambiguation. |
required |
count |
int
|
Numeric count for plural form selection. |
required |
**variables |
Variables for message interpolation. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Translated message with context and correct plural form. |
Raises:
| Type | Description |
|---|---|
TranslationKeyError
|
If key+context not found (strict mode only). |
Example
manager.set_locale("en")
manager.translate_context_plural("item", context="file", count=5)
translate_lazy(key, **variables)
Get a lazy translation using the current locale (lazy gettext).
Returns a LazyProxy that evaluates the translation when converted to string.
Convenience method that uses current_locale automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
**variables |
Variables for message interpolation. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
LazyProxy |
LazyProxy
|
Object that evaluates translation on demand. |
Example
manager.set_locale("en")
label = manager.translate_lazy("form.username")
print(str(label)) # Evaluates now
translate_plural(key, count, **variables)
Translate a plural message using the current locale (ngettext).
Convenience method that uses current_locale automatically.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key |
str
|
The message key/identifier. |
required |
count |
int
|
Numeric count for plural form selection. |
required |
**variables |
Variables for message interpolation. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Translated message with correct plural form. |
Raises:
| Type | Description |
|---|---|
TranslationKeyError
|
If key not found (strict mode only). |
Example
manager.set_locale("en")
manager.translate_plural("item", count=5)