Как мы решали вопрос многоязычности в боте
Русский или English?
Введение
Ранее в статье Как мы запускали серьезный проект в Telegram я рассказал общую информацию о моем телеграм-бот проекте World for Life Bot
В этой статье я поделюсь опытом реализации многоязычности, расскажу о принципах выбора языков, которыми я руководствовался, технических аспектах реализации и принятых решениях.
Постановка Задачи
С самого начала разработки телеграм-бота я ставил перед собой амбициозную задачу создания сервиса, доступного и понятного для пользователей по всему миру. Вопрос о поддержке нескольких языков был ключевым, учитывая международный характер аудитории.
При определение списка поддерживаемых языков и выбор языка по умолчанию, я исходил из нескольких ключевых соображений:
Аудитория Телеграма: Учитывая популярность Телеграма в русскоязычном сегменте, русский язык был выбран как основной. Это решение было направлено на обеспечение максимального удобства для первоначальной целевой аудитории.
Международный Язык: Английский язык, как самый распространенный и универсальный в международном общении, стал вторым официальным языком бота. Этот выбор позволил обратиться к широкому кругу пользователей по всему миру.
Язык По Умолчанию: В случаях, когда язык пользователя не совпадал ни с русским, ни с английским, мы решили использовать английский язык по умолчанию, учитывая его международный статус и широкое распространение.
Дополнительные Требования
Мы также реализовали функционал, позволяющий пользователям в любой момент переключиться на один из официальных языков бота. Это решение было направлено на повышение удобства использования бота для международной аудитории.
Делается это достаточно просто:
На главной странице выбираем «Личный кабинет»
В Личном кабинете нажимаем на кнопку «Выбрать язык».
Далее выбираете язык интерфейса.
Все, теперь бот будет полностью на, выбранном вами, языке. Настройка сохраняется, и повторные действия не требуются
Минимизация Затрат на Внедрение Языков
В процессе разработки многоязычного телеграм-бота я уделил особое внимание минимизации затрат и упрощению процесса добавления новых языков. Главной задачей было найти оптимальные пути реализации многоязычной поддержки, не увеличивая при этом существенно сложность и стоимость разработки.
Первое ключевое решение, которое я принял, заключалось в том, чтобы избегать внесения текстов непосредственно в код бота. Весь текстовый контент бота организован через переменные, что позволяет легко управлять языковыми версиями. Каждый текст в коде представлен переменной, которая затем конвертируется в соответствующую надпись непосредственно перед добавлением в интерфейс пользователя. Это обеспечивает гибкость и удобство в управлении многоязычным контентом.
def get_text(param: str, lang: str = 'ru') -> str:
""" get text based on language settings """
ret: str = ""
# form text based on language settings
# in case of key is absent in the dictionary - print param`s name
if lang == 'ru':
ret = LEXICON_RU.get(param, param)
elif lang == 'en':
ret = LEXICON_EN.get(param, param)
else: # by default in English
ret = LEXICON_EN.get(param, param)
return ret
Такой подход также помог решить вопрос с языком по умолчанию. В случае отсутствия перевода или пропущенной переменной в словаре, пользователь увидит необработанное название переменной, но функциональность бота при этом останется неприкосновенной. Это обеспечивает стабильность работы бота даже при возникновении ошибок в локализации.
Теперь во всем коде вместо форматирования текста прямо используем:
txt = get_text('city_CoL_info', language)
Как это все хранится. Тоже все достаточно удобно и просто — 1 словарь на каждый язык.
LEXICON_RU: Dict[str, str] = {
# ------------------MAIN------------------#
# buttons
'cost_of_living': "Уровень жизни по странам",
'all_services': "Список сервисов",
'to_bot_guide': "Руководство пользователя",
'propose_new_feature': "Написать админу",
'profile': "Личный кабинет",
'to_main': "На главную страницу",
'cancel': 'Отмена'
}
На примере добавления испанского языка, я покажу что алгоритм действий чрезвычайно эффективный и гибкий. Процесс добавления нового языка в телеграм-бот происходит в несколько четко определенных шагов, минимизируя трудозатраты и время.
Перевод Словаря Лексикона: В качестве первого шага берем существующий русский словарь лексикона бота, где каждая фраза соответствует уникальному ключу. Этот словарь передается фрилансеру или переводческой службе для перевода значений на испанский язык. Важно отметить, что ключи остаются без изменений.
Интеграция Перевода в Систему: После получения переведенного словаря я добавляю всего лишь две строки строки кода в функцию
get_text
, которая отвечает за вывод текста в интерфейсе бота. Эти строки позволяют боту использовать новый испанский словарь в соответствии с выбранным пользователем языком.Добавление Опции Выбора Языка: Последним шагом является добавление кнопки выбора испанского языка в личном кабинете пользователя.
Таким образом, весь бот — от меню и кнопок до сообщений — быстро адаптируется под испаноговорящую аудиторию.
Гибкая Масштабируемость Словаря
По мере развития бота и добавления функционала о мы перешли на модульно-сервисную архитектуру. Каждый встроенный функционал оформляется в виде библиотеки с определенной структурой. Расширение словаря начало доставлять неудобство. Было необходимо оформлять область в общем пространстве под модуль и следить за уникальностью ключей.
В итоге я остановился на следующем решении:
В файл assets, который входит в стандартную структуру, в котором есть еще много чего полезного, описывающего модуль, но об этом мы поговорим в следующих статьях, добавлен свой словарь лексикона, который используется только внутри модуля
Lexicons: Dict[str, dict] = {
# Russion localization
"RU": {
# ::buttons
'ratings_service': "Рейтинги",
'to_ratings_main': "К списку рейтингов",
'country_cost_of_living': 'Стоимость жизни по странам'
},
# English localization
"EN": {
# ::buttons
'ratings_service': "Ratings",
}
}
Описанная ранее функция get_text немного модифицировалась
def get_text(param: str, lang: str = 'ru', lexicons: dict = {}) -> str:
""" get text based on language settings """
ret: str = ""
# form text based on language settings
# in case of key is absent in the dictionary - print param`s name
if lexicons == {}:
if lang == 'ru':
ret = LEXICON_RU.get(param, param)
elif lang == 'en':
ret = LEXICON_EN.get(param, param)
else: # by default in English
ret = LEXICON_EN.get(param, param)
else:
lexicon: Dict[str, str] = lexicons.get(lang.upper(), {})
ret = lexicon.get(param, param)
return ret
Теперь у нас есть возможность либо использовать глобальный лексикон бота, либо локальный модуля, передавая его в качестве параметра функции.
В итоге я получил простоту добавления модулей — по сути это изолированная функция со своим лексиконом. С другой стороны я сохранил гибкость в масштабировании языков, только теперь переводчику надо отдать не 1 файл, а россыпь фалов assets.
Описанное решение является текущей имплементацией и полностью меня устраивает. Поэтому поиски в направлении мультиязычности я прекратил и могу заниматься другим функционалом
Немного интересного
А теперь, на десерт я приведу немного статистики. По результатам прочтения, возможно у появился вопрос: «Если все так просто, то почему вы уже не локализовали на другие языки. Этому есть объяснение.
По статистике, у бота русскоязычных пользователей — 80%, англоязычных — 16%.
Остальные языки в сумме занимают всего 4%. Посмотреть распределение пользоваталей по языкам вы можете видеть на диаграмме
А вот постоянное расширение и синхронизация дело затратное. Поэтому когда случится выход на иностранный рынок, проще локализовать все с нуля, нежели заниматься постоянной поддержкой языков, не пользующихся популярностью.
Заключение: Многоязычность в боте — не просто техническая задача, но и важный шаг к созданию удобного и доступного для широкой аудитории сервиса. В этой статье я поделился своим опытом и принятыми решениями, которые помогут другим разработчикам в их проектах.
Буду рад за конструктив в комментариях, а также ваш опыт в разработке и продвижении телеграм-проектов!