[Программирование, *nix, Локализация продуктов, Kotlin, Изучение языков] Интернационализация и локализация приложения на Kotlin/Native
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
こんにちは, или добрый день по-японски.Как бы не был популярен английский язык, всё же пользователям комфортнее и привычнее в родной языковой среде.Поэтому далее мы пошагово рассмотрим процесс адаптации консольного приложения для Linux на Kotlin/Native к русской и английской локали.Поможет нам в этом старый-добрый GNU gettext.В итоге убедимся, что это совсем не страшно.Заодно посмотрим интеграцию с библиотеками на C, которая значительно расширяет возможности Kotlin/Native.Что напишем: переводчик количественных числительных на японский язык.Что ожидается от читателя: знание языков программирования Kotlin, C, базовый уровень знакомства с ОС Linux (в частности Bash).Что понадобится в процессе: любой дистрибутив Linux, любая версия IntelliJ IDEA, установленный пакет gettext-devel или аналогичный.
МотивацияСобственно почему Kotlin/Native и причём тут японскийГде-то полгода медленно и печально изучаю японский язык по учебнику “Minna no Nihongo”: частью ради перевода текста песен, частью просто из интереса к культуре.Позже решил перейти с системной разработки на прикладную, с десктопа на мобильные платформы, соответственно с C++/Qt/STL на Kotlin/JVM/Android SDK.Теперь хочу два этих занятия совместить, написав для себя программы для помощи в изучении японского. Конечно, уже много готовых, но NIH-синдром ведь не что-то плохое, правда?Раньше я не задумываюсь использовал бы связку Qt/QML/C++: она позволяет быстро и эффективно решать в общем-то любые задачи и на любой платформе.Однако Qt всё больше поворачивается спиной к Open Source, вот и решил пора валить попробовать что-то другое.И тут в процессе изучения Kotlin узнал про Kotlin/Native.Соответственно, первая программа-помощник будет именно на нём.Что такое Kotlin/NativeИзначально Kotlin выступал в качестве "более лучшей" (С) Java, и целиком опирался на платформу JVM.Однако затем компания JetBrains, разработчик Kotlin, решила адаптировать набирающий популярность язык и под другие платформы.В частности, под веб (Kotlin/JS) и под "натив" (Kotlin/Native).Kotlin/Native появился в марте 2017 года, кстати ровно четыре года назад.Он позволяет компилировать код на Kotlin в нативный код с помощью LLVM, без зависимости от виртуальной машины JVM и других библиотек.Далее мои субъективные впечатления по опыту разработки демонстрационного приложения, так что буду рад исправлениям и дополнениям.Из плюсов:
- исходный код под пермиссивной открытой лицензией (Apache-2.0 license)
- работа на всех поддерживаемых LLVM платформах, в частности iOS и десктопы
- генерирует единственный исполняемый файл без сторонних зависимостей
- низкое потребление системных ресурсов
- доступны все базовые "вкусности" Kotlin вроде коллекций и функционального программирования
- есть прозрачный interop с языком C
- как следствие: доступны low-level функции платформы, в частности POSIX
Из минусов:
- стандартная библиотека весьма бедная по сравнению с огромной JVM, многое придётся писать с нуля (пример: оставьте только пункт Native тут)
- нет стабильной библиотеки для GUI, хотя есть некоторые привязки через C interop (GTK, libui)
- слабый инструментарий по сравнению с той же Android Studio, например нет той же локализации
- относительно долгое время сборки
Больше о Kotlin/Native можно почитать тут, а примеры доступны на Github.ТерминологияИнтернационализация (i18n): подготовка приложения к локализации, обычно выполняется разработчиками.Локализация (l18n): Процесс перевода и адаптации контента приложения для конкретных языков, обычно выполняется переводчиками.Важно: "контент" тут это не только строки, но и направление текста, формат даты, чисел и так далее. В данной статье ограничусь только строками.Что такое GNU gettextЭтот пакет из нескольких утилит, библиотек и регламентов.Является частью GNU Translation Project.Состоит из:
- правила оформления исходного кода для последующей интернационализации
- утилиты для генерации текстовых файлов с локализуемыми строками
- кроссплатформенная нативная библиотека для извлечения переводов в runtime
- правила дистрибуции бинарных файлов с переводами
Почему GNU gettextИнтернационализация в Kotlin/JVM для Android использует средства Android SDK, в частности строковые ресурсы, и завязана на JVM. Поэтому для Kotlin/Native эти средства недоступны.В Qt есть собственный инструментарий, но его не получится использовать вне Qt, тем более с отличным от C++ языком.Поэтому остаётся GNU gettext:
- универсальный (поддерживается множество языков программирования)
- кроссплатформенный (Win/Mac/Linux, есть Android/iOS версия)
- стабильный в силу почтенного возраста
- с подробной документацией
- со вспомогательными приложениями
Демонстрационный проектСуть: консольная программа пока только под Linux, чтобы не переусложнять код.Функционал: читает натуральное число из аргумента командной строки или stdin, и переводит его в количественное числительное на японском.Число может содержать специфичные для локали разделители тысяч, которая программа выводит при запуске.Скачать проект можно на Github и затем открыть в IntelliJ IDEA.Характеристики исполняемых файловДля начала время полной сборки: ~18 сек на конфигурации Ryzen 3900X + 32GB DDR4-3600 + NVM-E SSD. На мой взгляд многовато для такого маленького проекта и такой конфигурации.Тут можно вспомнить о преимуществах скриптовых языков, которые компилировать не надо.Теперь посмотрим свойства исполняемого файла для отладочной и релизной конфигураций:Размеры скомпилированных исполняемых файлов
$ file build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe
build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.16, BuildID[xxHash]=a0971dbf76e9db60, with debug_info, not stripped
$ ldd build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe
linux-vdso.so.1 (0x00007fff890d7000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f348e47a000)
libm.so.6 => /lib64/libm.so.6 (0x00007f348e334000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f348e312000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f348e2f7000)
libc.so.6 => /lib64/libc.so.6 (0x00007f348e12c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f348e4a0000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f348e112000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f348e10b000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f348e0d1000)
librt.so.1 => /lib64/librt.so.1 (0x00007f348e0c6000)
$ file build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe
build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.16, BuildID[xxHash]=c76aff5e0db3fdae, not stripped
$ ldd build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe
linux-vdso.so.1 (0x00007ffff69c2000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f41ad9dd000)
libm.so.6 => /lib64/libm.so.6 (0x00007f41ad897000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f41ad875000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f41ad85a000)
libc.so.6 => /lib64/libc.so.6 (0x00007f41ad68f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f41ada03000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f41ad675000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f41ad66e000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f41ad634000)
librt.so.1 => /lib64/librt.so.1 (0x00007f41ad629000)
$ ls -lh build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe
-rwxr-xr-x. 1 eraxillan eraxillan 1.8M Mar 7 13:24 build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe
$ ls -lh build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe
-rwxr-xr-x. 1 eraxillan eraxillan 529K Mar 7 13:24 build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe
Тут всё в порядке, бинарники скромные по размеру и без каких-либо сторонних зависимостей.Отладка проектаОна не работает, по крайней мере в Community Edition.Просто игнорируются точки останова, хотя судя по выводу команды file отладочные символы в исполняемом файле есть. Насколько я понял, соответствующий плагин доступен только в платной редакции IDE, которая пока для меня избыточна.Прошу поправить, если ошибаюсь.Так что для написания демо пришлось обходиться printf-driven отладкой, ну мне не привыкать после Android AOSP.ИнтернационализацияВ случае нашего проекта нужно лишь все локализуемые строки "обернуть" в вызов функции gettext().Для краткости можно сделать синоним этой функции, например tr(), это общепринятая практика.
import kotlinx.cinterop.*
import platform.linux.*
import platform.posix.*
fun tr(key: String): String = gettext(key)?.toKString() ?: ""
Понадобится ещё служебный код для работы с POSIX-локалями, он находится в файле Locale.kt.Также мы должны заранее определиться с количеством поддерживаемых языков: для демо это будут только английский и русский, плюс числительные на японском для любого языка.Кстати, посмотреть названия локалей можно с помощью команды locale -a.Перевод локализуемых строкЯ написал Bash-скрипты для генерации с нуля и обновления файлов gettext:
Далее вкратце опишу основные шаги, которые они выполняют.Генерируем pot-файл ("шаблон"), который содержит базовую информацию о программе и собственно строки нуждающиеся в переводе.
# Extract all tr() wrapped strings to po/jnt.pot file
xgettext --keyword=tr --language=java \
--add-comments --sort-output \
--copyright-holder='Alexander Kamyshnikov <axill777@gmail.com>' \
--package-name='Japanese numeral translator' \
--package-version='1.0' \
--msgid-bugs-address='axill777@gmail.com' \
-o po/jnt.pot --files-from=KT_FILES
Генерируем po-файл (текстовый перевод):
# Generate locale sources
# NOTE: --no-translator option is a workaround to supress email input request
msginit --no-translator --input=po/jnt.pot --locale=en_US.UTF-8 --output po/en_US/jnt.po
msginit --no-translator --input=po/jnt.pot --locale=ru_RU.UTF-8 --output po/ru_RU/jnt.po
Генерируем mo-файл (бинарный перевод):
# Generate locale binary files
msgfmt --output-file=po/en_US/jnt.mo po/en_US/jnt.po
msgfmt --output-file=po/ru_RU/jnt.mo po/ru_RU/jnt.po
Развертывание бинарных файлов с переводамиК сожалению, Kotlin/Native не поддерживает ресурсы, так что "упаковать" mo-файлы в исполняемый файл пока не выйдет.На это есть соответствующий баг.Думаю, функционал ресурсов можно реализовать и вручную дополнительной задачей в Gradle, это пожалуй тема для отдельной статьи.Для тестового проекта положим mo-файлы рядом с приложением, где не нужны права суперпользователя и где gettext сможет их найти.Для релиза приложение следует упаковать в RPM/DEB-пакет, а mo-файлы установить в директорию /usr/share/locale.ИтогКак видите, процесс несложен, по крайней мере при наличии готового кода и скриптов.В процессе разработки нужно лишь периодически вызывать update_localization.sh, переводить новые строки, и снова вызывать этот скрипт для генерации mo-файлов.ありがとう ございます, или спасибо за внимание!ИсточникиОпределения взяты из документации Django Почему интернационализация и локализация имеют значениеKotlin Native: следите за файламиDxGetText — GNU Gettext for Delphi and C++ BuilderP.S.: дальше планирую использовать Kotlin/Native уже в рамках кроссплатформенных библиотек. Если будет интерес, могу доработать демо, например портировать на Windows.
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Разработка под Android, Kotlin] Как можно использовать шейдеры в Android View и как Android View может использовать шейдеры (перевод)
- [Программирование] Как справиться с более чем двумя миллиардами записей в SQL-базе данных (перевод)
- [Программирование, C++] Новый поток в C++20: std::jthread (перевод)
- [Разработка веб-сайтов, JavaScript, Программирование, HTML] Красивое радио для браузера
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] React Social App
- [Kotlin] Погружение в JetBrains Space Applicaitons
- [Open source, Программирование, Геоинформационные сервисы, Визуализация данных, Научно-популярное] Google Earth Engine (GEE) как общедоступный суперкомпьютер
- [Разработка веб-сайтов, Программирование, Компиляторы, IT-стандарты] Wasp — DSL для разработки веб-приложений
- [Программирование микроконтроллеров, Электроника для начинающих] На распутье — Ардуино, Cи или Ассемблер?
- [Программирование, Dart] Ускоряем Dart. Нативно, недорого
Теги для поиска: #_programmirovanie (Программирование), #_*nix, #_lokalizatsija_produktov (Локализация продуктов), #_kotlin, #_izuchenie_jazykov (Изучение языков), #_kotlin, #_gettext, #_localization, #_internationalization, #_linux, #_japanese, #_programmirovanie (
Программирование
), #_*nix, #_lokalizatsija_produktov (
Локализация продуктов
), #_kotlin, #_izuchenie_jazykov (
Изучение языков
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 16:16
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
こんにちは, или добрый день по-японски.Как бы не был популярен английский язык, всё же пользователям комфортнее и привычнее в родной языковой среде.Поэтому далее мы пошагово рассмотрим процесс адаптации консольного приложения для Linux на Kotlin/Native к русской и английской локали.Поможет нам в этом старый-добрый GNU gettext.В итоге убедимся, что это совсем не страшно.Заодно посмотрим интеграцию с библиотеками на C, которая значительно расширяет возможности Kotlin/Native.Что напишем: переводчик количественных числительных на японский язык.Что ожидается от читателя: знание языков программирования Kotlin, C, базовый уровень знакомства с ОС Linux (в частности Bash).Что понадобится в процессе: любой дистрибутив Linux, любая версия IntelliJ IDEA, установленный пакет gettext-devel или аналогичный. МотивацияСобственно почему Kotlin/Native и причём тут японскийГде-то полгода медленно и печально изучаю японский язык по учебнику “Minna no Nihongo”: частью ради перевода текста песен, частью просто из интереса к культуре.Позже решил перейти с системной разработки на прикладную, с десктопа на мобильные платформы, соответственно с C++/Qt/STL на Kotlin/JVM/Android SDK.Теперь хочу два этих занятия совместить, написав для себя программы для помощи в изучении японского. Конечно, уже много готовых, но NIH-синдром ведь не что-то плохое, правда?Раньше я не задумываюсь использовал бы связку Qt/QML/C++: она позволяет быстро и эффективно решать в общем-то любые задачи и на любой платформе.Однако Qt всё больше поворачивается спиной к Open Source, вот и решил пора валить попробовать что-то другое.И тут в процессе изучения Kotlin узнал про Kotlin/Native.Соответственно, первая программа-помощник будет именно на нём.Что такое Kotlin/NativeИзначально Kotlin выступал в качестве "более лучшей" (С) Java, и целиком опирался на платформу JVM.Однако затем компания JetBrains, разработчик Kotlin, решила адаптировать набирающий популярность язык и под другие платформы.В частности, под веб (Kotlin/JS) и под "натив" (Kotlin/Native).Kotlin/Native появился в марте 2017 года, кстати ровно четыре года назад.Он позволяет компилировать код на Kotlin в нативный код с помощью LLVM, без зависимости от виртуальной машины JVM и других библиотек.Далее мои субъективные впечатления по опыту разработки демонстрационного приложения, так что буду рад исправлениям и дополнениям.Из плюсов:
$ file build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe
build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.16, BuildID[xxHash]=a0971dbf76e9db60, with debug_info, not stripped $ ldd build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe linux-vdso.so.1 (0x00007fff890d7000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f348e47a000) libm.so.6 => /lib64/libm.so.6 (0x00007f348e334000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f348e312000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f348e2f7000) libc.so.6 => /lib64/libc.so.6 (0x00007f348e12c000) /lib64/ld-linux-x86-64.so.2 (0x00007f348e4a0000) libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f348e112000) libutil.so.1 => /lib64/libutil.so.1 (0x00007f348e10b000) libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f348e0d1000) librt.so.1 => /lib64/librt.so.1 (0x00007f348e0c6000) $ file build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.16, BuildID[xxHash]=c76aff5e0db3fdae, not stripped $ ldd build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe linux-vdso.so.1 (0x00007ffff69c2000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f41ad9dd000) libm.so.6 => /lib64/libm.so.6 (0x00007f41ad897000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f41ad875000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f41ad85a000) libc.so.6 => /lib64/libc.so.6 (0x00007f41ad68f000) /lib64/ld-linux-x86-64.so.2 (0x00007f41ada03000) libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f41ad675000) libutil.so.1 => /lib64/libutil.so.1 (0x00007f41ad66e000) libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f41ad634000) librt.so.1 => /lib64/librt.so.1 (0x00007f41ad629000) $ ls -lh build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe -rwxr-xr-x. 1 eraxillan eraxillan 1.8M Mar 7 13:24 build/bin/native/debugExecutable/JapaneseNumeralTranslator.kexe $ ls -lh build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe -rwxr-xr-x. 1 eraxillan eraxillan 529K Mar 7 13:24 build/bin/native/releaseExecutable/JapaneseNumeralTranslator.kexe import kotlinx.cinterop.*
import platform.linux.* import platform.posix.* fun tr(key: String): String = gettext(key)?.toKString() ?: "" # Extract all tr() wrapped strings to po/jnt.pot file
xgettext --keyword=tr --language=java \ --add-comments --sort-output \ --copyright-holder='Alexander Kamyshnikov <axill777@gmail.com>' \ --package-name='Japanese numeral translator' \ --package-version='1.0' \ --msgid-bugs-address='axill777@gmail.com' \ -o po/jnt.pot --files-from=KT_FILES # Generate locale sources
# NOTE: --no-translator option is a workaround to supress email input request msginit --no-translator --input=po/jnt.pot --locale=en_US.UTF-8 --output po/en_US/jnt.po msginit --no-translator --input=po/jnt.pot --locale=ru_RU.UTF-8 --output po/ru_RU/jnt.po # Generate locale binary files
msgfmt --output-file=po/en_US/jnt.mo po/en_US/jnt.po msgfmt --output-file=po/ru_RU/jnt.mo po/ru_RU/jnt.po =========== Источник: habr.com =========== Похожие новости:
Программирование ), #_*nix, #_lokalizatsija_produktov ( Локализация продуктов ), #_kotlin, #_izuchenie_jazykov ( Изучение языков ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 16:16
Часовой пояс: UTC + 5