Если вы хотите, чтобы ваш аддон был доступен для всех пользователей Blender по всему миру, вам обязательно нужно предусмотреть его локализацию – перевод интерфейса на разные языки.
Простейший способ сделать ваш аддон мультиязычным – классический, он используется во многих программах и, к тому же, требует минимального обращения к Blender Python API.
Если кратко – он заключается в создании словаря, в который заносятся все варианты перевода, и функции, которая в зависимости от текущей локали (выбранного пользователем языка) по коду возвращает текст из словаря на требуемом языке.
Рассмотрим локализацию простейшего аддона на практике.
Для начала создадим и зарегистрируем в Blender Python API классы для аддона.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
from bpy.types import Panel, Operator from bpy.utils import register_class, unregister_class bl_info = { 'name': 'Localizatoin Test', 'category': 'All', 'version': (1, 0, 0), 'blender': (2, 91, 0), } class LOCALIZATION_TEST_OT_test(Operator): bl_idname = 'localization_test.test' bl_label = 'Operator name' def execute(self, context): print('Test text for printing in system console') return {'FINISHED'} class LOCALIZATION_TEST_PT_panel(Panel): bl_idname = 'LOCALIZATION_TEST_PT_panel' bl_label = 'Panel Header' bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'Localization test' def draw(self, context): layout = self.layout layout.label(text='Test text in Blender UI') layout.operator('localization_test.test', icon='BLENDER') def register(): register_class(LOCALIZATION_TEST_OT_test) register_class(LOCALIZATION_TEST_PT_panel) def unregister(): unregister_class(LOCALIZATION_TEST_PT_panel) unregister_class(LOCALIZATION_TEST_OT_test) if __name__ == '__main__': register() |
Мы создали два класса:
LOCALIZATION_TEST_OT_test – оператор, который при вызове печатает в консоль строку текста
LOCALIZATION_TEST_PT_panel – для оформления интерфейса аддона, он создает в N-панели окна 3D Viewport вкладку со строкой текста и кнопкой для вызова оператора.
И зарегистрировали их в API Blender в результате чего получили работающий аддон.
Теперь мы можем заняться его локализацией.
Для начала создадим словарь с переводами текстовых строк, которые мы используем в нашем аддоне, на разные языки.
Создадим словарь с именем “langs”, и для текста “Test text in Blender UI” добавим варианты переводов на английский, испанский и японский языки.
1 2 3 4 5 6 7 |
langs = { 'test_text_in_bl_ui': { 'en_US': 'Test text in Blender UI', 'es': 'Prueba de texto en la interfaz de usuario de Blender', 'ja_JP': 'Blender ユーザーインターフェースでテキストをテストする' } } |
Все варианты переводов будем хранить в отдельном словаре, к которому будем обращаться по ключу “test_text_in_bl_ui”. Обычно для удобства работы используют ключи в виде упрощенной и укороченной строки исходного текста. Это добавляет наглядности и читаемости в код вашего аддона.
Внутри словаря с вариантами перевода в качестве ключей указывается текстовое обозначение локали, а значения – перевод на соответствующий этой локали язык.
Теперь мы можем получить перевод строки текста, просто обратившись к словарю с нужным ключами.
1 2 |
langs['test_text_in_bl_ui']['ja_JP'] # Blender ユーザーインターフェースでテキストをテストする |
Имея словарь с переводами, мы можем определить функцию, которая по двум ключам (строки и локали) вернет нам текст на нужном языке.
1 2 3 4 5 6 7 8 9 10 11 |
import bpy def loc_str(str_key, def_locale_key='en_US'): if str_key in langs: locale_key = bpy.app.translations.locale if locale_key in langs[str_key]: return langs[str_key][locale_key] else: return langs[str_key][def_locale_key] else: return 'ERR: no such string in localization' |
Функция “loc_str” принимает в качестве параметров один обязательных аргумент и один необязательный.
Обязательный аргумент “str_key” – это ключ строки для поиска по созданному нами ранее словарю переводов. По нему выбирается нужная строка текста в словаре. Если строка с указанным ключом в словаре “langs” не найдена, функция вернет текст ошибки “ERR: no such string in localization”.
Получив по ключу “str_key” словарь для нужной строки, теперь по ключу локали получим ее перевод на нужный язык.
Текущая используемая локаль в Blender может быть получена через его API:
1 2 |
bpy.app.translations.locale # 'en_US' |
Так как мы используем текстовое значение локали в качестве ключа, мы легко можем по нему получить нужный перевод.
1 |
return langs[str_key][locale_key] |
Если для текущей локали мы перевод еще не сделали (не добавили в наш словарь “langs”), функция вернет перевод “по умолчанию”, указанной во втором, необязательном, параметре “def_locale_key” функции. Значение для этого параметра конечно нужно указывать такое, которое точно есть в вашем словаре. Чтобы не указывать его каждый раз при вызове функции, зададим для этого параметра значение по умолчанию равное “en_US”.
Теперь мы можем вызывать эту функцию для получения перевода текста в зависимости от текущей локали.
Например:
1 2 3 4 5 6 7 8 9 10 11 |
bpy.app.translations.locale # 'es' print(loc_str('test_text_in_bl_ui')) # Prueba de texto en la interfaz de usuario de Blender bpy.app.translations.locale # 'it_IT' print(loc_str('test_text_in_bl_ui')) # Test text in Blender UI |
Во втором случае, при использовании итальянского языка, функция вернула текст на английском, т.к. перевода на итальянский нет, а английский вариант указан по умолчанию.
Теперь нам осталось для каждой строки текста, используемой в аддоне, добавить в словарь”langs” свой уникальный ключ и варианты перевода на нужные языки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
langs = { 'test_text_in_bl_ui': { 'en_US': 'Test text in Blender UI', 'es': 'Prueba de texto en la interfaz de usuario de Blender', 'ja_JP': 'Blender ユーザーインターフェースでテキストをテストする' }, 'op_name': { 'en_US': 'Operator name', 'es': 'Nombre del operador', 'ja_JP': 'オペレーター名' }, 'test_str_cons': { 'en_US': 'Test text for printing in system console', 'es': 'Prueba de texto para imprimir en la consola del sistema', 'ja_JP': 'システムコンソールで印刷するためのテストテキスト' }, 'panel_head': { 'en_US': 'Panel Header', 'es': 'Encabezado del panel', 'ja_JP': 'パネルヘッダー' }, 'loc_test': { 'en_US': 'Localization test', 'es': 'Prueba de localización', 'ja_JP': 'ローカリゼーションテスト' }, } |
А все используемые в аддоне строки текста заменить на вызов функции “loc_str” с нужными ключами.
Например указание строки:
1 |
layout.label(text='Test text in Blender UI') |
нужно заменить на вызов функции:
1 |
layout.label(text=loc_str('test_text_in_bl_ui')) |
Теперь Blender будет отображать интерфейс вашего аддона в соответствии с языком, выбранным пользователем.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import bpy from bpy.types import Panel, Operator from bpy.utils import register_class, unregister_class bl_info = { 'name': 'Localizatoin Test', 'category': 'All', 'version': (1, 0, 0), 'blender': (2, 91, 0), } langs = { 'test_text_in_bl_ui': { 'en_US': 'Test text in Blender UI', 'es': 'Prueba de texto en la interfaz de usuario de Blender', 'ja_JP': 'Blender ユーザーインターフェースでテキストをテストする' }, 'op_name': { 'en_US': 'Operator name', 'es': 'Nombre del operador', 'ja_JP': 'オペレーター名' }, 'test_str_cons': { 'en_US': 'Test text for printing in system console', 'es': 'Prueba de texto para imprimir en la consola del sistema', 'ja_JP': 'システムコンソールで印刷するためのテストテキスト' }, 'panel_head': { 'en_US': 'Panel Header', 'es': 'Encabezado del panel', 'ja_JP': 'パネルヘッダー' }, 'loc_test': { 'en_US': 'Localization test', 'es': 'Prueba de localización', 'ja_JP': 'ローカリゼーションテスト' }, } def loc_str(str_key, def_locale_key='en_US'): if str_key in langs: locale_key = bpy.app.translations.locale if locale_key in langs[str_key]: return langs[str_key][locale_key] else: return langs[str_key][def_locale_key] else: return 'ERR: no such string in localization' # --- OPS --- class LOCALIZATION_TEST_OT_test(Operator): bl_idname = 'localization_test.test' bl_label = loc_str('op_name') def execute(self, context): # execute test operator print(loc_str('test_str_cons')) return {'FINISHED'} # --- UI --- class LOCALIZATION_TEST_PT_panel(Panel): bl_idname = 'LOCALIZATION_TEST_PT_panel' bl_label = loc_str('panel_head') bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = loc_str('loc_test') def draw(self, context): layout = self.layout layout.label(text=loc_str('test_text_in_bl_ui')) layout.operator('localization_test.test', icon='BLENDER') def register(): register_class(LOCALIZATION_TEST_OT_test) register_class(LOCALIZATION_TEST_PT_panel) def unregister(): unregister_class(LOCALIZATION_TEST_PT_panel) unregister_class(LOCALIZATION_TEST_OT_test) if __name__ == '__main__': register() |
Классический подход к локализации аддонов Blender прост и удобен, хотя у него и есть определенные недостатки. Например, обратите внимание на то, что при переключении локали в настройках Blender, в нашем аддоне динамически переключается язык для элементов интерфейса, но не для названий операторов и заголовков панелей. Для них язык изменится только после перезапуска Blender. Впрочем, в большинстве случаев это не критично.
Исходные файлы для этого урока доступны на Patreon.