I18n example

i18n_example.py
  1"""
  2Internationalize your bot
  3
  4Step 1: extract texts
  5    # pybabel extract --input-dirs=. -o locales/mybot.pot
  6
  7    Some useful options:
  8    - Extract texts with pluralization support
  9    # -k __:1,2
 10    - Add comments for translators, you can use another tag if you want (TR)
 11    # --add-comments=NOTE
 12    - Disable comments with string location in code
 13    # --no-location
 14    - Set project name
 15    # --project=MySuperBot
 16    - Set version
 17    # --version=2.2
 18
 19Step 2: create *.po files. E.g. create en, ru, uk locales.
 20    # pybabel init -i locales/mybot.pot -d locales -D mybot -l en
 21    # pybabel init -i locales/mybot.pot -d locales -D mybot -l ru
 22    # pybabel init -i locales/mybot.pot -d locales -D mybot -l uk
 23    
 24Step 3: translate texts located in locales/{language}/LC_MESSAGES/mybot.po
 25    To open .po file you can use basic text editor or any PO editor, e.g. https://poedit.net/
 26
 27Step 4: compile translations
 28    # pybabel compile -d locales -D mybot
 29
 30Step 5: When you change the code of your bot you need to update po & mo files.
 31    Step 5.1: regenerate pot file:
 32        command from step 1
 33    Step 5.2: update po files
 34        # pybabel update -d locales -D mybot -i locales/mybot.pot
 35    Step 5.3: update your translations 
 36        location and tools you know from step 3
 37    Step 5.4: compile mo files
 38        command from step 4
 39"""
 40
 41from pathlib import Path
 42
 43from aiogram import Bot, Dispatcher, executor, types
 44from aiogram.contrib.middlewares.i18n import I18nMiddleware
 45
 46TOKEN = 'BOT_TOKEN_HERE'
 47I18N_DOMAIN = 'mybot'
 48
 49BASE_DIR = Path(__file__).parent
 50LOCALES_DIR = BASE_DIR / 'locales'
 51
 52bot = Bot(TOKEN, parse_mode=types.ParseMode.HTML)
 53dp = Dispatcher(bot)
 54
 55# Setup i18n middleware
 56i18n = I18nMiddleware(I18N_DOMAIN, LOCALES_DIR)
 57dp.middleware.setup(i18n)
 58
 59# Alias for gettext method
 60_ = i18n.gettext
 61
 62
 63@dp.message_handler(commands='start')
 64async def cmd_start(message: types.Message):
 65    # Simply use `_('message')` instead of `'message'` and never use f-strings for translatable texts.
 66    await message.reply(_('Hello, <b>{user}</b>!').format(user=message.from_user.full_name))
 67
 68
 69@dp.message_handler(commands='lang')
 70async def cmd_lang(message: types.Message, locale):
 71    # For setting custom lang you have to modify i18n middleware
 72    await message.reply(_('Your current language: <i>{language}</i>').format(language=locale))
 73
 74# If you care about pluralization, here's small handler
 75# And also, there's and example of comments for translators. Most translation tools support them.
 76
 77# Alias for gettext method, parser will understand double underscore as plural (aka ngettext)
 78__ = i18n.gettext
 79
 80
 81# some likes manager
 82LIKES_STORAGE = {'count': 0}
 83
 84
 85def get_likes() -> int:
 86    return LIKES_STORAGE['count']
 87
 88
 89def increase_likes() -> int:
 90    LIKES_STORAGE['count'] += 1
 91    return get_likes()
 92
 93
 94@dp.message_handler(commands='like')
 95async def cmd_like(message: types.Message, locale):
 96    likes = increase_likes()
 97
 98    # NOTE: This is comment for a translator
 99    await message.reply(__('Aiogram has {number} like!', 'Aiogram has {number} likes!', likes).format(number=likes))
100
101    
102if __name__ == '__main__':
103    executor.start_polling(dp, skip_updates=True)