Simple internationalization (i18n) utilities for Python applications
Project description
kiarina-i18n
English | 日本語
[!NOTE] What is this? A package for using translation catalogs from dictionaries or YAML through functions or typed Pydantic models.
Dependencies
| Package | Version | License |
|---|---|---|
| Pydantic | >=2.0.0 |
MIT |
| pydantic-settings | >=2.0.0 |
MIT |
| pydantic-settings-manager | >=3.2.0 |
MIT |
| PyYAML | >=6.0.0 |
MIT |
Installation
pip install kiarina-i18n
Features
- Translating Text Retrieve catalog text by language, scope, and key, then substitute template variables.
- Loading Catalogs Build catalogs from dictionaries, file-system YAML, and package-resource YAML.
- Defining Typed Translations Define translation keys and default text as fields on a Pydantic model.
- Translating Pydantic Schemas Translate Pydantic model docstrings and field descriptions by language.
Translating Text
Catalog data is structured as language → scope → key → text.
from kiarina.i18n import catalog, get_translator
catalog.add_from_dict(
{
"en": {"app.greeting": {"hello": "Hello, $name!"}},
"ja": {"app.greeting": {"hello": "こんにちは、$name!"}},
}
)
translate = get_translator("ja", "app.greeting")
message = translate("hello", name="World")
Translations are searched from the most specific requested language tag through its parent tags, followed by the default language. For example, ja-JP searches ja-JP, ja, then en.
If no translation exists, the translator returns default, or <scope>#<key> when no default is given. Template variables use string.Template.safe_substitute, so variables without supplied values remain unchanged.
Loading Catalogs
Catalog additions are deeply merged. A later value replaces an earlier value with the same language, scope, and key.
from kiarina.i18n import catalog
catalog.add_from_file("translations.yaml")
catalog.add_from_dir("translations")
catalog.add_from_package_file("my_app.catalogs", "ja.yaml")
catalog.add_from_package_dir("my_app.catalogs")
add_from_dir searches child directories. add_from_package_dir searches only the specified package's immediate directory.
When a YAML file is named after a language tag, such as ja.yaml or en-US.yaml, its contents are treated as the catalog for that language.
app.greeting:
hello: "こんにちは、$name!"
For other file names, declare languages at the top level.
en:
app.greeting:
hello: "Hello, $name!"
ja:
app.greeting:
hello: "こんにちは、$name!"
Defining Typed Translations
In an I18n subclass, field names are keys and default values are translation fallbacks.
from kiarina.i18n import I18n, catalog, get_i18n
class ProfileText(I18n, scope="app.profile"):
title: str = "Profile"
description: str = "Edit your profile."
catalog.add_from_dict(
{
"ja": {
"app.profile": {
"title": "プロフィール",
"description": "プロフィールを編集します。",
}
}
}
)
text = get_i18n(ProfileText, "ja")
If scope is omitted, <module>.<class name> is used. If language is omitted from get_i18n, the system language is used.
Regular Pydantic models can also be passed to get_i18n. Their scope is the public module path before the first private module segment.
Translating Pydantic Schemas
translate_pydantic_model creates a translated model class without changing the original model. It translates the model docstring with the __doc__ key and each field description with the corresponding field-name key.
from pydantic import BaseModel, Field
from kiarina.i18n import catalog
from kiarina.i18n_pydantic import translate_pydantic_model
class UserInput(BaseModel):
name: str = Field(description="Your name")
catalog.add_from_dict(
{
"ja": {
"__main__": {
"__doc__": "ユーザー入力",
"name": "名前",
}
}
}
)
JapaneseUserInput = translate_pydantic_model(UserInput, "ja")
Field annotations of list[I18nSubclass] and dict[str, I18nSubclass] recursively translate their inner models.
API Reference
kiarina.i18n
from kiarina.i18n import (
Catalog,
I18n,
I18nKey,
I18nScope,
I18nSettings,
Language,
Translator,
catalog,
get_i18n,
get_system_language,
get_translator,
settings_manager,
)
Translation functions
def get_i18n(
model_class: type[T],
language: Language | None = None,
) -> T: ...
def get_system_language() -> Language: ...
def get_translator(
language: Language,
scope: I18nScope,
) -> Translator: ...
get_i18n returns an instance with each model field translated. When language is omitted, it uses the result of get_system_language.
get_system_language checks the LANG, LC_ALL, LC_MESSAGES, and LANGUAGE environment variables in that order, followed by locale.getlocale(). It returns en when detection fails or the locale is C / POSIX.
get_translator creates a Translator using the shared catalog and settings_manager.settings.default_language.
Translator
class Translator:
def __init__(
self,
*,
catalog: Catalog,
language: Language,
scope: I18nScope,
default_language: Language = "en",
) -> None: ...
def __call__(
self,
key: I18nKey,
default: str | None = None,
**kwargs: Any,
) -> str: ...
language and default_language are normalized during initialization. An invalid language tag raises ValueError.
Catalog
class Catalog:
def __init__(self) -> None: ...
def add_from_dict(
self,
data: dict[
Language,
dict[I18nScope, dict[I18nKey, str]],
],
) -> None: ...
def add_from_file(self, file_path: str) -> None: ...
def add_from_dir(self, dir_path: str) -> None: ...
def add_from_package_file(
self,
package: str,
file_path: str,
) -> None: ...
def add_from_package_dir(self, package: str) -> None: ...
def clear(self) -> None: ...
def get_text(
self,
language: Language,
scope: I18nScope,
key: I18nKey,
) -> str | None: ...
add_from_file and add_from_dir read file-system YAML. add_from_package_file and add_from_package_dir read resources from an importable package.
A missing directory raises NotADirectoryError. Missing YAML files or packages raise FileNotFoundError. get_text returns None when no text exists, including when the language tag is invalid.
I18n
class I18n(BaseModel):
def __init_subclass__(
cls,
scope: I18nScope = "",
**kwargs: Any,
) -> None: ...
Subclasses are frozen Pydantic models and reject undefined fields. Define the fields to translate on each subclass.
Settings
class I18nSettings(BaseSettings):
default_language: Language = "en"
settings_manager: SettingsManager[I18nSettings]
default_language is used when a translation is unavailable. settings_manager is the shared configuration manager provided by pydantic-settings-manager.
Catalog instance
catalog: Catalog
The package shares this catalog instance. Call catalog.clear() to discard state between tests or other isolated operations.
Types
Language: TypeAlias = str
I18nScope: TypeAlias = str
I18nKey: TypeAlias = str
Language represents a BCP 47 language tag, I18nScope a namespace for keys, and I18nKey a translation key within a scope.
kiarina.i18n_pydantic
from kiarina.i18n_pydantic import translate_pydantic_model
translate_pydantic_model
def translate_pydantic_model(
model: type[T],
language: str,
) -> type[T]: ...
Returns a new model class with translated docstrings and field descriptions while preserving the original Pydantic model's configuration, base class, module, and field attributes.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kiarina_i18n-2.3.1.tar.gz.
File metadata
- Download URL: kiarina_i18n-2.3.1.tar.gz
- Upload date:
- Size: 24.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdf241ee9f5e299cd2aa5eb6106f37e0591a14f38c8a09dd9255e7c7c07d2bdd
|
|
| MD5 |
f3a59fae59837dab35deb06361c25a1c
|
|
| BLAKE2b-256 |
b5e9e3b22ca501c146174b90567cdcc85a784d1d6d705c4def1ae753083169ad
|
Provenance
The following attestation bundles were made for kiarina_i18n-2.3.1.tar.gz:
Publisher:
release-pypi.yml on kiarina/kiarina-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kiarina_i18n-2.3.1.tar.gz -
Subject digest:
bdf241ee9f5e299cd2aa5eb6106f37e0591a14f38c8a09dd9255e7c7c07d2bdd - Sigstore transparency entry: 2044312811
- Sigstore integration time:
-
Permalink:
kiarina/kiarina-python@443dbb48340706ef8cf35551de167d64bc11ee82 -
Branch / Tag:
refs/tags/v2.3.1 - Owner: https://github.com/kiarina
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@443dbb48340706ef8cf35551de167d64bc11ee82 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kiarina_i18n-2.3.1-py3-none-any.whl.
File metadata
- Download URL: kiarina_i18n-2.3.1-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86a944d84197086518c1a70eaf041944425045ff4a8e6f434c1a233fb7ba3d3b
|
|
| MD5 |
80007cb7deb90195b95f28bb4bbb6d9b
|
|
| BLAKE2b-256 |
77bb5cebe82c09852e9cd12aadecbec07b61c08da050b9b96db085adcb6c3baa
|
Provenance
The following attestation bundles were made for kiarina_i18n-2.3.1-py3-none-any.whl:
Publisher:
release-pypi.yml on kiarina/kiarina-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kiarina_i18n-2.3.1-py3-none-any.whl -
Subject digest:
86a944d84197086518c1a70eaf041944425045ff4a8e6f434c1a233fb7ba3d3b - Sigstore transparency entry: 2044313084
- Sigstore integration time:
-
Permalink:
kiarina/kiarina-python@443dbb48340706ef8cf35551de167d64bc11ee82 -
Branch / Tag:
refs/tags/v2.3.1 - Owner: https://github.com/kiarina
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi.yml@443dbb48340706ef8cf35551de167d64bc11ee82 -
Trigger Event:
push
-
Statement type: