Translation¶
In order to make you bot translatable you have to add a minimal number of hooks to your Python code.
These hooks are called translation strings.
The aiogram translation utils is build on top of GNU gettext Python module and Babel library.
Installation¶
Babel is required to make simple way to extract translation strings from your code
Can be installed from pip directly:
pip install Babel
or as aiogram extra dependency:
pip install aiogram[i18n]
Make messages translatable¶
In order to gettext need to know what the strings should be translated you will need to write translation strings.
For example:
from aiogram import html
from aiogram.utils.i18n import gettext as _
async def my_handler(message: Message) -> None:
await message.answer(
_("Hello, {name}!").format(
name=html.quote(message.from_user.full_name)
)
)
Danger
f-strings can’t be used as translations string because any dynamic variables should be added to message after getting translated message
Also if you want to use translated string in keyword- or magic- filters you will need to use lazy gettext calls:
from aiogram import F
from aiogram.utils.i18n import lazy_gettext as __
@router.message(F.text == __("My menu entry"))
...
Danger
Lazy gettext calls should always be used when the current language is not know at the moment
Danger
Lazy gettext can’t be used as value for API methods or any Telegram Object (like aiogram.types.inline_keyboard_button.InlineKeyboardButton
or etc.)
Working with plural forms
The gettext from aiogram.utils.i18n is the one alias for two functions _gettext_ and _ngettext_ of GNU gettext Python module. Therefore, the wrapper for message strings is the same _(). You need to pass three parameters to the function: a singular string, a plural string, and a value.
Configuring engine¶
After you messages is already done to use gettext your bot should know how to detect user language
On top of your application the instance of aiogram.utils.i18n.I18n
should be created
i18n = I18n(path="locales", default_locale="en", domain="messages")
After that you will need to choose one of builtin I18n middleware or write your own.
Builtin middlewares:
SimpleI18nMiddleware¶
ConstI18nMiddleware¶
FSMI18nMiddleware¶
- class aiogram.utils.i18n.middleware.FSMI18nMiddleware(i18n: I18n, key: str = 'locale', i18n_key: str | None = 'i18n', middleware_key: str = 'i18n_middleware')[source]¶
This middleware stores locale in the FSM storage
I18nMiddleware¶
or define you own based on abstract I18nMiddleware middleware:
- class aiogram.utils.i18n.middleware.I18nMiddleware(i18n: I18n, i18n_key: str | None = 'i18n', middleware_key: str = 'i18n_middleware')[source]¶
Abstract I18n middleware.
- __init__(i18n: I18n, i18n_key: str | None = 'i18n', middleware_key: str = 'i18n_middleware') None [source]¶
Create an instance of middleware
- Parameters:
i18n – instance of I18n
i18n_key – context key for I18n instance
middleware_key – context key for this middleware
- abstract async get_locale(event: TelegramObject, data: Dict[str, Any]) str [source]¶
Detect current user locale based on event and context.
This method must be defined in child classes
- Parameters:
event
data
- Returns:
- setup(router: Router, exclude: Set[str] | None = None) BaseMiddleware [source]¶
Register middleware for all events in the Router
- Parameters:
router
exclude
- Returns:
Deal with Babel¶
Step 1 Extract messages¶
pybabel extract --input-dirs=. -o locales/messages.pot
Here is --input-dirs=.
- path to code and the locales/messages.pot
is template where messages will be extracted and messages is translation domain.
Working with plural forms
Extracting with Pybabel all strings options:
-k _:1,1t -k _:1,2
- for both singular and plural-k __
- for lazy strings
pybabel extract -k _:1,1t -k _:1,2 -k __ --input-dirs=. -o locales/messages.pot
Note
Some useful options:
Add comments for translators, you can use another tag if you want (TR)
--add-comments=NOTE
Contact email for bugreport
--msgid-bugs-address=EMAIL
Disable comments with string location in code
--no-location
Copyrights
--copyright-holder=AUTHOR
Set project name
--project=MySuperBot
Set version
--version=2.2
Step 2: Init language¶
pybabel init -i locales/messages.pot -d locales -D messages -l en
-i locales/messages.pot
- pre-generated template-d locales
- translations directory-D messages
- translations domain-l en
- language. Can be changed to any other valid language code (For example-l uk
for ukrainian language)
Step 3: Translate texts¶
To open .po file you can use basic text editor or any PO editor, e.g. Poedit
Just open the file named locales/{language}/LC_MESSAGES/messages.po
and write translations
Step 4: Compile translations¶
pybabel compile -d locales -D messages
Step 5: Updating messages¶
When you change the code of your bot you need to update po & mo files
Step 5.1: regenerate pot file: command from step 1
- Step 5.2: update po files
pybabel update -d locales -D messages -i locales/messages.pot
Step 5.3: update your translations: location and tools you know from step 3
Step 5.4: compile mo files: command from step 4