Gettext в приложениях Windows собранных CMake с использованием MinGW
Материал из Wiki.crossplatform.ru
Kuzulis (Обсуждение | вклад) (→Содержимое файла /SourceTestProject/CMakeLists.txt) |
Kuzulis (Обсуждение | вклад) |
||
(19 промежуточных версий не показаны.) | |||
Строка 2: | Строка 2: | ||
В данном руководстве будет разобран простой пример локализации приложения в [http://ru.wikipedia.org/wiki/Microsoft_Windows ОС Microsoft Windows] с помощью пакета программ [http://ru.wikipedia.org/wiki/Gettext Gettext]. | В данном руководстве будет разобран простой пример локализации приложения в [http://ru.wikipedia.org/wiki/Microsoft_Windows ОС Microsoft Windows] с помощью пакета программ [http://ru.wikipedia.org/wiki/Gettext Gettext]. | ||
+ | |||
При этом подразумеваем, что приложение будем собирать с использованием компилятора [http://ru.wikipedia.org/wiki/MinGW MinGW] при помощи системы кросс-платформенной сборки [http://ru.wikipedia.org/wiki/CMake CMake]. | При этом подразумеваем, что приложение будем собирать с использованием компилятора [http://ru.wikipedia.org/wiki/MinGW MinGW] при помощи системы кросс-платформенной сборки [http://ru.wikipedia.org/wiki/CMake CMake]. | ||
- | После | + | После запуска приложение просто будет выполнять печать в консоль строки ''"Привет, мир!"'' и завершаться. |
Данное руководство не является панацеей или каким-то определенным рецептом при решении данной задачи, | Данное руководство не является панацеей или каким-то определенным рецептом при решении данной задачи, | ||
Строка 17: | Строка 18: | ||
# [http://ru.wikipedia.org/wiki/Microsoft_Windows ОС Microsoft Windows] - операционная система семейств XP/Vista/7 и т.п. | # [http://ru.wikipedia.org/wiki/Microsoft_Windows ОС Microsoft Windows] - операционная система семейств XP/Vista/7 и т.п. | ||
# [http://ru.wikipedia.org/wiki/MinGW MinGW] - порт пакета утилит и компиляторов GCC для Microsoft Windows. | # [http://ru.wikipedia.org/wiki/MinGW MinGW] - порт пакета утилит и компиляторов GCC для Microsoft Windows. | ||
- | # [http://ru.wikipedia.org/wiki/CMake CMake] - | + | # [http://ru.wikipedia.org/wiki/CMake CMake] - кросс-платформенная система автоматизации сборки программного обеспечения из исходного кода. |
# [http://ru.wikipedia.org/wiki/Gettext Gettext] - библиотека проекта GNU для интернационализации. | # [http://ru.wikipedia.org/wiki/Gettext Gettext] - библиотека проекта GNU для интернационализации. | ||
= Получение и установка инструментов = | = Получение и установка инструментов = | ||
- | == Получение и установка | + | == Получение и установка операционной системы MS Windows == |
Описывать этот процесс не имеет смысла, т.к. всем и так все ясно. :) | Описывать этот процесс не имеет смысла, т.к. всем и так все ясно. :) | ||
Строка 28: | Строка 29: | ||
'''Получение:''' | '''Получение:''' | ||
- | Этот пакет программ распространяется бесплатно и скачать инсталляцию можно | + | Этот пакет программ распространяется бесплатно и скачать инсталляцию можно [http://www.mingw.org/ тут]. |
'''Установка:''' | '''Установка:''' | ||
Строка 39: | Строка 40: | ||
'''Получение:''' | '''Получение:''' | ||
- | Этот пакет программ распространяется бесплатно и скачать инсталляцию можно | + | Этот пакет программ распространяется бесплатно и скачать инсталляцию можно [http://www.cmake.org/cmake/resources/software.html тут]. |
+ | |||
Скачивать и использовать можно как версии 2.6.x так и версии 2.8.x, но лучше все-же использовать более свежую версию 2.8.x. | Скачивать и использовать можно как версии 2.6.x так и версии 2.8.x, но лучше все-же использовать более свежую версию 2.8.x. | ||
Строка 54: | Строка 56: | ||
Скачиваемый пакет является полным набором всех необходимых файлов для локализации приложения, | Скачиваемый пакет является полным набором всех необходимых файлов для локализации приложения, | ||
- | т.е. содержит как | + | т.е. содержит как ''runtime'' компоненты, так и компоненты для разработки программ. |
'''Установка:''' | '''Установка:''' | ||
Строка 63: | Строка 65: | ||
При этом, интересующими нас директориями будут являться: | При этом, интересующими нас директориями будут являться: | ||
- | * ''D:\GnuWin32\bin'' - директория runtime компонентов | + | * ''D:\GnuWin32\bin'' - директория ''runtime'' компонентов |
- | * ''D:\GnuWin32\include'' - директория заголовочных файлов [http://ru.wikipedia.org/wiki/Gettext Gettext] для | + | * ''D:\GnuWin32\include'' - директория заголовочных файлов [http://ru.wikipedia.org/wiki/Gettext Gettext] для разработчика |
- | * ''D:\GnuWin32\lib'' - директория линкуемых библиотек [http://ru.wikipedia.org/wiki/Gettext Gettext] для | + | * ''D:\GnuWin32\lib'' - директория линкуемых библиотек [http://ru.wikipedia.org/wiki/Gettext Gettext] для разработчика |
= Подготовка к сборке = | = Подготовка к сборке = | ||
== Создание дерева директории исходных кодов проекта == | == Создание дерева директории исходных кодов проекта == | ||
- | Итак, локализовать мы будем простое консольное приложение (которое сами же и напишем и соберем) на два | + | Итак, локализовать мы будем простое консольное приложение (которое сами же и напишем и соберем) на два языка: ''русский'' и ''немецкий''. |
- | + | ||
- | + | ||
+ | При этом, наш проект будет иметь следующую структуру директорий: | ||
/SourceTestProject | /SourceTestProject | ||
|->main.cpp | |->main.cpp | ||
Строка 82: | Строка 83: | ||
| | | | ||
|->CMakeLists.txt | |->CMakeLists.txt | ||
- | |||
где: | где: | ||
* ''/SourceTestProject'' - директория исходных кодов нашего проекта | * ''/SourceTestProject'' - директория исходных кодов нашего проекта | ||
Строка 91: | Строка 91: | ||
== Создание директории сборки проекта == | == Создание директории сборки проекта == | ||
- | Сборку проекта с использованием [http://ru.wikipedia.org/wiki/CMake CMake] лучше всего производить вне директории нашего проекта | + | Сборку проекта с использованием [http://ru.wikipedia.org/wiki/CMake CMake] лучше всего производить вне директории нашего проекта чтобы не засорять её продуктами компиляции, а также для исключения случайной модификации исходных файлов директории проекта. |
- | чтобы не | + | |
- | + | ||
- | + | {{Замечание | Да и вообще, сборка вне директории с исходным кодом является "правилом хорошего тона".}} | |
+ | Поэтому для сборки, параллельно директории проекта создадим директорию сборки: | ||
/.. | /.. | ||
|->/SourceTestProject | |->/SourceTestProject | ||
|->/build-project | |->/build-project | ||
- | |||
где: | где: | ||
* ''/..'' - какая-то родительская директория | * ''/..'' - какая-то родительская директория | ||
Строка 132: | Строка 130: | ||
Скопируем/переместим этот файл куда нибудь, например, пусть он будет находится в корне диска ''D:'' | Скопируем/переместим этот файл куда нибудь, например, пусть он будет находится в корне диска ''D:'' | ||
- | |||
D:\MyBuildEnv.bat | D:\MyBuildEnv.bat | ||
Строка 165: | Строка 162: | ||
bindtextdomain(domain.c_str(), localedir.c_str()); | bindtextdomain(domain.c_str(), localedir.c_str()); | ||
textdomain(domain.c_str()); | textdomain(domain.c_str()); | ||
+ | bind_textdomain_codeset(domain.c_str(), "CP866"); | ||
std::cout << gettext("Hello, world!") << std::endl; | std::cout << gettext("Hello, world!") << std::endl; | ||
return 0; | return 0; | ||
Строка 173: | Строка 171: | ||
* ''#include <locale.h>'' - подключаемые системные заголовки компилятора | * ''#include <locale.h>'' - подключаемые системные заголовки компилятора | ||
* ''#include <iostream>'' - подключаемые системные заголовки компилятора | * ''#include <iostream>'' - подключаемые системные заголовки компилятора | ||
- | * ''domain("test")'' - домен которому мы присвоили имя | + | * ''domain("test")'' - домен которому мы присвоили имя ''test''(этим именем у нас также будет назван и исполняемый файл ''test.exe'' нашего приложения) |
* ''string localedir("./locale")'' - это имя каталога в котором будут находится бинарные файлы переводов. | * ''string localedir("./locale")'' - это имя каталога в котором будут находится бинарные файлы переводов. | ||
* ''gettext("Hello, world!")'' - собственно строка, которую будем локализовать на разные языки. | * ''gettext("Hello, world!")'' - собственно строка, которую будем локализовать на разные языки. | ||
+ | |||
+ | {{Замечание | Функция ''bind_textdomain_codeset(domain.c_str(), "CP866")'' нам необходима для корректного отображения кириллических символов в консоли и использовать ее нужно только в том случае, если мы имеем консольное приложение. Если же у нас приложение имеет GUI, то использовать данную функцию нельзя (или можно, но нужно вместо кодировки ''CP866'' указать кодировку ''CP1251''). Дело в том, что в Windows в консоль выводятся символы в кодировке ''CP866'', но в GUI приложения в кодировке ''CP1251''!}} | ||
== Определение структуры и содержимого каталогов собранного приложения == | == Определение структуры и содержимого каталогов собранного приложения == | ||
Строка 183: | Строка 183: | ||
{{Замечание | Да и у нас, в исходном коде приложения (см. ''main.cpp'') задано именно такое расположение каталога локализации.}} | {{Замечание | Да и у нас, в исходном коде приложения (см. ''main.cpp'') задано именно такое расположение каталога локализации.}} | ||
- | |||
{{Замечание | В данном случае речь идет о структуре каталогов уже готового (т.е. собранного приложения) | {{Замечание | В данном случае речь идет о структуре каталогов уже готового (т.е. собранного приложения) | ||
- | и никоим образом это не относится к описанному в | + | и никоим образом это не относится к описанному в '''Создание дерева директории исходных кодов проекта'''. }} |
Поддиректории в этой директории должны иметь определенную структуру, например: | Поддиректории в этой директории должны иметь определенную структуру, например: | ||
- | |||
/InstallTestProject | /InstallTestProject | ||
|-> test.exe | |-> test.exe | ||
Строка 215: | Строка 213: | ||
* один находится в корне проекта с исходными кодами | * один находится в корне проекта с исходными кодами | ||
/SourceTestProject/CMakeLists.txt | /SourceTestProject/CMakeLists.txt | ||
- | |||
* другой находится в корне директории /po c переводами | * другой находится в корне директории /po c переводами | ||
/po/CMakeLists.txt | /po/CMakeLists.txt | ||
Строка 222: | Строка 219: | ||
===Содержимое файла /SourceTestProject/CMakeLists.txt=== | ===Содержимое файла /SourceTestProject/CMakeLists.txt=== | ||
- | |||
Ниже приведено содержимое файла с подробными комментариями: | Ниже приведено содержимое файла с подробными комментариями: | ||
<source lang="cmake"> | <source lang="cmake"> | ||
Строка 263: | Строка 259: | ||
===Содержимое файла /po/CMakeLists.txt=== | ===Содержимое файла /po/CMakeLists.txt=== | ||
- | |||
Ниже приведено содержимое файла с подробными комментариями: | Ниже приведено содержимое файла с подробными комментариями: | ||
<source lang="cmake"> | <source lang="cmake"> | ||
+ | # | ||
set( DOMAIN ${APP_TARGET} ) | set( DOMAIN ${APP_TARGET} ) | ||
Строка 272: | Строка 268: | ||
# языком приложения по умолчанию, поэтому переводить его не нужно). | # языком приложения по умолчанию, поэтому переводить его не нужно). | ||
# При этом, кодам имен локализаций у нас соответствуют имена | # При этом, кодам имен локализаций у нас соответствуют имена | ||
- | # поддиректорий | + | # поддиректорий de, ru. Это сделано просто для упрощения и наглядности, |
# а в принципе структуру поддиректорий и их названий можно делать какой угодно, | # а в принципе структуру поддиректорий и их названий можно делать какой угодно, | ||
# главное в дальнейшем правильно написать скрипты для CMake. :) | # главное в дальнейшем правильно написать скрипты для CMake. :) | ||
Строка 279: | Строка 275: | ||
# Устанавливаем имя директории в которую будут устанавливаться уже готовые, | # Устанавливаем имя директории в которую будут устанавливаться уже готовые, | ||
# откомпилированные с помощью gettext файлы переводов *.mo., где: | # откомпилированные с помощью gettext файлы переводов *.mo., где: | ||
- | # | + | # locale - имя этой директории. |
set( LOCALE_INSTALL_DIR locale ) | set( LOCALE_INSTALL_DIR locale ) | ||
Строка 287: | Строка 283: | ||
# Генерируем шаблон перевода, сканируя исходники приложения и | # Генерируем шаблон перевода, сканируя исходники приложения и | ||
# извлекая всё что подлежит переводу. | # извлекая всё что подлежит переводу. | ||
+ | # Еще помимо *.cpp файлов сюда можно подставлять и *.h файлы. | ||
file( GLOB _srcFiles ../*.cpp ) | file( GLOB _srcFiles ../*.cpp ) | ||
- | |||
add_custom_target( translation ALL DEPENDS ) | add_custom_target( translation ALL DEPENDS ) | ||
Строка 299: | Строка 295: | ||
file( GLOB _poFile ${LANG}/*.po ) | file( GLOB _poFile ${LANG}/*.po ) | ||
if( EXISTS ${_poFile} ) | if( EXISTS ${_poFile} ) | ||
- | |||
set( PO_FILE_NEW ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.po ) | set( PO_FILE_NEW ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.po ) | ||
set( GMO_FILE_NEW ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.gmo ) | set( GMO_FILE_NEW ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.gmo ) | ||
Строка 313: | Строка 308: | ||
Генерация бинарных файлов переводов происходит у нас в несколько этапов: | Генерация бинарных файлов переводов происходит у нас в несколько этапов: | ||
- | |||
# Сначала из всех ''*.cpp'' файлов проекта извлекаются всё то, что подлежит переводу, и создается файл-шаблон ''*.pot'' (команда ''$xgettext''). | # Сначала из всех ''*.cpp'' файлов проекта извлекаются всё то, что подлежит переводу, и создается файл-шаблон ''*.pot'' (команда ''$xgettext''). | ||
- | # Далее, по очереди проверяется наличие готовых исходных файлов переводов ''*.po'' разных языков и | + | # Далее, по очереди проверяется наличие готовых исходных файлов переводов ''*.po'' разных языков и на их основе и основе шаблона ''*.pot'' создаются обновленные файлы переводов ''*.po'' (команда ''$msgmerge''). При этом, исходные файлы переводов остаются нетронутыми. {{Замечание | Это сделано для исключения модификации файлов в директории исходных кодов.}} |
# Далее, на основе каждого вновь созданного (обновленного) файла ''*.po'' создается результирующий бинарный файл перевода ''*.gmo'' ( команда ''$msgfmt''). | # Далее, на основе каждого вновь созданного (обновленного) файла ''*.po'' создается результирующий бинарный файл перевода ''*.gmo'' ( команда ''$msgfmt''). | ||
= Сборка приложения = | = Сборка приложения = | ||
- | Итак, после того как все готово, можно приступить к сборке приложения, | + | Итак, после того, как все готово, можно приступить к сборке приложения, |
но перед этим необходимо сгенерировать и перевести файлы исходных переводов. | но перед этим необходимо сгенерировать и перевести файлы исходных переводов. | ||
Строка 337: | Строка 331: | ||
$ msginit -i messages.pot -o po\ru\messages.po -l ru | $ msginit -i messages.pot -o po\ru\messages.po -l ru | ||
</source> | </source> | ||
- | После выполнения данных команд, в директориях ''po\de'' и ''po\ | + | После выполнения данных команд, в директориях ''po\de'' и ''po\ru'' появятся необходимые нам файлы. |
- | Теперь файл шаблона нам не нужен и мы можем его удалить. | + | Теперь файл шаблона ''messages.pot'' нам не нужен и мы можем его удалить. |
- | + | {{Замечание | Для распространения исходных кодов нашего проекта достаточно иметь только файлы переводов ''*.po'', естественно, иметь и ''*.cpp'' и ''CMakeLists.txt'', что само собой разумеется.}} | |
- | + | ||
Далее, произведем "перевод" сообщений в ''*.po'' файлах на требуемые нам языки. | Далее, произведем "перевод" сообщений в ''*.po'' файлах на требуемые нам языки. | ||
Для этого, редактируем их любым доступным образом и добавляем нужные сообщения: | Для этого, редактируем их любым доступным образом и добавляем нужные сообщения: | ||
- | |||
* для ''po\de\messages.po'' | * для ''po\de\messages.po'' | ||
... | ... | ||
Строка 353: | Строка 345: | ||
msgstr "Hallo Welt!" | msgstr "Hallo Welt!" | ||
... | ... | ||
- | |||
* для ''po\ru\messages.po'' | * для ''po\ru\messages.po'' | ||
... | ... | ||
Строка 375: | Строка 366: | ||
При успехе в консоль отобразится примерно следующее: | При успехе в консоль отобразится примерно следующее: | ||
- | |||
D:\SVN\lang_test>cd ..\build | D:\SVN\lang_test>cd ..\build | ||
Строка 426: | Строка 416: | ||
В итоге, в директории ''d:\install'' получим следующую структуру каталогов: | В итоге, в директории ''d:\install'' получим следующую структуру каталогов: | ||
- | |||
/install | /install | ||
|->/Program Files | |->/Program Files | ||
Строка 437: | Строка 426: | ||
| |->test.mo | | |->test.mo | ||
|->/ru | |->/ru | ||
- | + | |->/LC_MESSAGES | |
- | + | |->test.mo | |
{{Замечание | Как видно, файлы переводов теперь вместо расширений ''*.gmo'' имеют расширение ''*.mo'', процесс переименования файлов произошел в процессе установки приложения. }} | {{Замечание | Как видно, файлы переводов теперь вместо расширений ''*.gmo'' имеют расширение ''*.mo'', процесс переименования файлов произошел в процессе установки приложения. }} | ||
Строка 450: | Строка 439: | ||
После выполнения в консоли увидим: | После выполнения в консоли увидим: | ||
- | |||
D:\SVN\inst\Program Files\test>bin\test.exe | D:\SVN\inst\Program Files\test>bin\test.exe | ||
- | + | Привет, мир! | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | |||
{{Замечание | Так как мы линковали наше приложение с библиотеками от [http://ru.wikipedia.org/wiki/Gettext Gettext], то для правильной его работы необходимо, чтобы наше приложение имело к ним доступ, для чего можно поступить двумя путями: | {{Замечание | Так как мы линковали наше приложение с библиотеками от [http://ru.wikipedia.org/wiki/Gettext Gettext], то для правильной его работы необходимо, чтобы наше приложение имело к ним доступ, для чего можно поступить двумя путями: | ||
* Или, в каталог с исполнеяемым файлом ''test.exe'' скопировать как минимум такие библиотеки [http://ru.wikipedia.org/wiki/Gettext Gettext] как: ''libintl3.dll'' и ''libiconv2.dll''. И в этом случае, наше приложение будет работать на любой машине где не установлен [http://ru.wikipedia.org/wiki/Gettext Gettext]. | * Или, в каталог с исполнеяемым файлом ''test.exe'' скопировать как минимум такие библиотеки [http://ru.wikipedia.org/wiki/Gettext Gettext] как: ''libintl3.dll'' и ''libiconv2.dll''. И в этом случае, наше приложение будет работать на любой машине где не установлен [http://ru.wikipedia.org/wiki/Gettext Gettext]. | ||
* Или, если на машине установлен Gettext, необходимо в переменных окружения прописать путь к runtime компонентам Gettext (т.е. путь к директории где находятся разделяемые библиотеки ''*.dll'' [http://ru.wikipedia.org/wiki/Gettext Gettext]-а , например, ''/bin''). }} | * Или, если на машине установлен Gettext, необходимо в переменных окружения прописать путь к runtime компонентам Gettext (т.е. путь к директории где находятся разделяемые библиотеки ''*.dll'' [http://ru.wikipedia.org/wiki/Gettext Gettext]-а , например, ''/bin''). }} |
Текущая версия на 18:19, 8 октября 2010
Содержание
|
[править] Введение
В данном руководстве будет разобран простой пример локализации приложения в ОС Microsoft Windows с помощью пакета программ Gettext.
При этом подразумеваем, что приложение будем собирать с использованием компилятора MinGW при помощи системы кросс-платформенной сборки CMake.
После запуска приложение просто будет выполнять печать в консоль строки "Привет, мир!" и завершаться.
Данное руководство не является панацеей или каким-то определенным рецептом при решении данной задачи, оно представляет собой альтернативный вариант и предназначено для краткого ознакомления читателя со стадиями процесса локализации и сборки программы.
Предполагается, что читатель имеет некоторые знания и навыки программирования.
[править] Инструменты
Для решения нашей задачи нам понадобятся следующее программное обеспечение (ПО):
- ОС Microsoft Windows - операционная система семейств XP/Vista/7 и т.п.
- MinGW - порт пакета утилит и компиляторов GCC для Microsoft Windows.
- CMake - кросс-платформенная система автоматизации сборки программного обеспечения из исходного кода.
- Gettext - библиотека проекта GNU для интернационализации.
[править] Получение и установка инструментов
[править] Получение и установка операционной системы MS Windows
Описывать этот процесс не имеет смысла, т.к. всем и так все ясно. :)
[править] Получение и установка MinGW
Получение: Этот пакет программ распространяется бесплатно и скачать инсталляцию можно тут.
Установка: Для установки пакета программ запускаем исполняемый файл установщика и следуем его советам.
Допустим, он установился в каталог:
D:\MinGW
[править] Получение и установка CMake
Получение: Этот пакет программ распространяется бесплатно и скачать инсталляцию можно тут.
Скачивать и использовать можно как версии 2.6.x так и версии 2.8.x, но лучше все-же использовать более свежую версию 2.8.x.
Установка: Для установки пакета программ запускаем исполняемый файл установщика и следуем его советам.
Допустим, он установился в каталог:
D:\CMake
[править] Получение и установка Gettext
Получение: Этот пакет программ распространяется бесплатно и скачать инсталляцию можно тут, а именно, качать нужно это.
Скачиваемый пакет является полным набором всех необходимых файлов для локализации приложения, т.е. содержит как runtime компоненты, так и компоненты для разработки программ.
Установка: Для установки пакета программ запускаем исполняемый файл установщика и следуем его советам.
Допустим, он установился в каталог:
D:\GnuWin32
При этом, интересующими нас директориями будут являться:
- D:\GnuWin32\bin - директория runtime компонентов
- D:\GnuWin32\include - директория заголовочных файлов Gettext для разработчика
- D:\GnuWin32\lib - директория линкуемых библиотек Gettext для разработчика
[править] Подготовка к сборке
[править] Создание дерева директории исходных кодов проекта
Итак, локализовать мы будем простое консольное приложение (которое сами же и напишем и соберем) на два языка: русский и немецкий.
При этом, наш проект будет иметь следующую структуру директорий:
/SourceTestProject |->main.cpp |->/po | |->/de | |->/ru | |->CMakeLists.txt | |->CMakeLists.txt
где:
- /SourceTestProject - директория исходных кодов нашего проекта
- main.cpp - собственно код нашего приложения
- /po - директория с каталогами, содержащими файлы исходных переводов на различные языки
- /de, /ru - директории, которые содержат файлы переводов на русский и немецкий языки соответственно
- CMakeLists.txt - файлы конфигурации сборки приложения для CMake
[править] Создание директории сборки проекта
Сборку проекта с использованием CMake лучше всего производить вне директории нашего проекта чтобы не засорять её продуктами компиляции, а также для исключения случайной модификации исходных файлов директории проекта.
Замечание: | Да и вообще, сборка вне директории с исходным кодом является "правилом хорошего тона". |
Поэтому для сборки, параллельно директории проекта создадим директорию сборки:
/.. |->/SourceTestProject |->/build-project
где:
- /.. - какая-то родительская директория
- /SourceTestProject - директория исходных кодов нашего проекта
- /build-project - директория для сборки нашего проекта (в которой бумем его собирать)
[править] Создание окружения сборки проекта
Для задания переменных окружения и путей к исполняемым файлам и библиотекам пакетов программ типа CMake, MinGW, Gettext и системным утилитам из System32, а также для исключения влияния этих переменных на другие, создадим для себя консоль сборки с необходимыми нам параметрами.
Для этого создадим файл MyBuildEnv.bat с таким содержимым:
@echo off echo Setting up a MinGW/CMake/Gettext/Libiconv only environment... set PATH=D:\Qt\2009.04\mingw\bin set PATH=%PATH%;D:\CMake 2.6\bin set PATH=%PATH%;D:\GnuWin32\bin set PATH=%PATH%;%SystemRoot%\System32 set GETTEXT_INCLUDE_DIR=d:\GnuWin32\include set GETTEXT_LIB_DIR=d:\GnuWin32\lib
где:
- D:\MinGW\bin - путь к runtime компонентам компилятора MinGW
- D:\CMake\bin - путь runtime компонентам сборщика CMake
- D:\GnuWin32\bin - путь runtime компонентам транслятора Gettext
- %SystemRoot%\System32 - путь системным runtime компонентам Windows
- GETTEXT_INCLUDE_DIR=d:\GnuWin32\include - путь к заголовочным файлам Gettext (понадобится далее для сборки приложения)
- GETTEXT_LIB_DIR=d:\GnuWin32\lib - путь к линкуемым библиотекам Gettext (понадобится далее для сборки приложения)
Скопируем/переместим этот файл куда нибудь, например, пусть он будет находится в корне диска D:
D:\MyBuildEnv.bat
Теперь создадим на рабочем столе ярлык, указывающий на нашу консоль сборки в которой будут использованы переменные окружения из MyBuildEnv.bat
На вкладке "Общие" задаем имя нашей консоли, например:
- My Env Build Command Prompt
На вкладке "Ярлык" пишем к примеру это:
- Объект: C:\WINDOWS\system32\cmd.exe /K d:\MyBuildEnv.bat
- Рабочая папка: D:\
И теперь, при клике по ярлыку "My Env Build Command Prompt" запустится настроеная под наши нужды консоль (командная строка) в которой мы будем производить компиляцию проекта.
[править] Создание кода приложения
Весь код нашего приложения будет находится в одном единственном файле main.cpp.
Код main.cpp:
#include <iostream> #include <libintl.h> #include <locale.h> int main(int argc, char* argv[]) { std::string domain("test"); std::string localedir("./locale"); setlocale(LC_ALL, ""); bindtextdomain(domain.c_str(), localedir.c_str()); textdomain(domain.c_str()); bind_textdomain_codeset(domain.c_str(), "CP866"); std::cout << gettext("Hello, world!") << std::endl; return 0; }
где:
- #include <libintl.h> - подключаемые заголовки Gettext
- #include <locale.h> - подключаемые системные заголовки компилятора
- #include <iostream> - подключаемые системные заголовки компилятора
- domain("test") - домен которому мы присвоили имя test(этим именем у нас также будет назван и исполняемый файл test.exe нашего приложения)
- string localedir("./locale") - это имя каталога в котором будут находится бинарные файлы переводов.
- gettext("Hello, world!") - собственно строка, которую будем локализовать на разные языки.
[править] Определение структуры и содержимого каталогов собранного приложения
Задаем имя и расположение директории локализаций по нашему усмотрению, но обычно (в Windows) лучше и проще чтобы она имела имя locale и находилась в корне каталога с исполняемым файлом приложения.
Замечание: | Да и у нас, в исходном коде приложения (см. main.cpp) задано именно такое расположение каталога локализации. |
Поддиректории в этой директории должны иметь определенную структуру, например:
/InstallTestProject |-> test.exe |-> test1.dll (если необходима) |-> ... |-> testN.dll |->/locale |->/ru | |->/LC_MESSAGES | |->test.mo |->/de | |->/LC_MESSAGES | |->test.mo | и т.п.
где:
- /InstallTestProject - имя директории с готовым проектом (например, установленным в "Program Files" и т.п.)
- test.exe - исполняемый файл нашего приложения
- test1.dll/testN.dll - разделяемые библиотеки нашего приложения (но в текущей задаче их у нас нет)
- /ru, /de - директории в которых находятся откомпилированные Gettext-ом переводы *.mo
- /LC_MESSAGES - обязательная директория, имя которой должно быть таким как есть
[править] Создание конфигурации сборки для CMake
Конфигурация для сборки проекта при помощи CMake будет содержаться всего в двух файлах CMakeLists.txt:
- один находится в корне проекта с исходными кодами
/SourceTestProject/CMakeLists.txt
- другой находится в корне директории /po c переводами
/po/CMakeLists.txt
Итак, рассмотрим содержимое этих файлов по очереди.
[править] Содержимое файла /SourceTestProject/CMakeLists.txt
Ниже приведено содержимое файла с подробными комментариями:
# Задаем имя нашему проекту. # При этом результирующий исполняемый файл приложения пусть тоже имеет такое имя, где: # test - имя проекта set( APP_TARGET test ) project( ${APP_TARGET} ) cmake_minimum_required( VERSION 2.6.0 ) # Здесь подключаем директории с заголовочными файлами, # которые нам потребуются для сборки приложения. # В данном случае нам нужны только заголовки от gettext, где: # GETTEXT_INCLUDE_DIR - переменная окружения пути к заголовкам gettext, # которую мы установили, запустив *.bat файл. include_directories( $ENV{GETTEXT_INCLUDE_DIR} ) # Здесь подключаем директории с дополнительными библиотеками, # которые нам потребуются для линковки приложения. # В данном случае нам нужны только библиотеки от gettext, где: # GETTEXT_LIB_DIR - переменная окружения пути к библиотекам gettext, # которую мы установили, запустив *.bat файл. link_directories( $ENV{GETTEXT_LIB_DIR} ) set( APP_SRCS main.cpp ) add_executable( ${APP_TARGET} ${APP_SRCS} ) # Указываем какие именно нам нужны библиотеки для линковки с приложением. # В нашем случае это библиотека от gettext: intl. target_link_libraries( ${APP_TARGET} intl ) # Указываем имя директории (bin) куда установится исполняемый файл приложения # после выполнения команды: $mingw32-make install. install( TARGETS ${APP_TARGET} RUNTIME DESTINATION bin ) # Подключаем поддиректорию с файлами переводов. add_subdirectory( po )
[править] Содержимое файла /po/CMakeLists.txt
Ниже приведено содержимое файла с подробными комментариями:
# set( DOMAIN ${APP_TARGET} ) # Устанавливаем набор языков, на которые переведено наше приложение. # В нашем случае это русский и немецкий (английский язык является # языком приложения по умолчанию, поэтому переводить его не нужно). # При этом, кодам имен локализаций у нас соответствуют имена # поддиректорий de, ru. Это сделано просто для упрощения и наглядности, # а в принципе структуру поддиректорий и их названий можно делать какой угодно, # главное в дальнейшем правильно написать скрипты для CMake. :) set( LINGUAS de ru ) # Устанавливаем имя директории в которую будут устанавливаться уже готовые, # откомпилированные с помощью gettext файлы переводов *.mo., где: # locale - имя этой директории. set( LOCALE_INSTALL_DIR locale ) # Задаем имя шаблона файла перевода *.pot. set( POT_FILE ${CMAKE_CURRENT_BINARY_DIR}/messages.pot ) # Генерируем шаблон перевода, сканируя исходники приложения и # извлекая всё что подлежит переводу. # Еще помимо *.cpp файлов сюда можно подставлять и *.h файлы. file( GLOB _srcFiles ../*.cpp ) add_custom_target( translation ALL DEPENDS ) add_custom_command( TARGET translation COMMAND xgettext --from-code CP1251 -C -a -o ${POT_FILE} ${_srcFiles} ) # Пробегаем по всем именам директорий (локализациям) и обрабатываем их gettext-ом. foreach( LANG ${LINGUAS}) file( GLOB _poFile ${LANG}/*.po ) if( EXISTS ${_poFile} ) set( PO_FILE_NEW ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.po ) set( GMO_FILE_NEW ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.gmo ) add_custom_command( TARGET translation COMMAND msgmerge ${_poFile} ${POT_FILE} -o ${PO_FILE_NEW} COMMAND msgfmt -c -o ${GMO_FILE_NEW} ${PO_FILE_NEW} ) install(FILES ${GMO_FILE_NEW} DESTINATION ${LOCALE_INSTALL_DIR}/${LANG}/LC_MESSAGES RENAME ${DOMAIN}.mo ) endif( EXISTS ${_poFile} ) endforeach( LANG )
Генерация бинарных файлов переводов происходит у нас в несколько этапов:
- Сначала из всех *.cpp файлов проекта извлекаются всё то, что подлежит переводу, и создается файл-шаблон *.pot (команда $xgettext).
- Далее, по очереди проверяется наличие готовых исходных файлов переводов *.po разных языков и на их основе и основе шаблона *.pot создаются обновленные файлы переводов *.po (команда $msgmerge). При этом, исходные файлы переводов остаются нетронутыми.
Замечание: Это сделано для исключения модификации файлов в директории исходных кодов. - Далее, на основе каждого вновь созданного (обновленного) файла *.po создается результирующий бинарный файл перевода *.gmo ( команда $msgfmt).
[править] Сборка приложения
Итак, после того, как все готово, можно приступить к сборке приложения, но перед этим необходимо сгенерировать и перевести файлы исходных переводов.
Все ниже описанные операции выполняются в "нашей" консоли, которую мы предварительно настроили и запустили (см. Создание окружения сборки проекта).
[править] Первоначальная генерация исходных переводов
Генерируем шаблон исходного файла локализации, предварительно перейдя в корневой каталог исходных кодов проекта:
$ cd <Путь к каталогу исходников проекта>\SourceTestProject $ xgettext -C -a -o messages.pot *.cpp
После выполнения этой команды, в той директории где мы находимся появится файл шаблона messages.pot.
Теперь, нам необходимо из шаблона сгенерировать исходные файлы переводов для разных языков:
$ msginit -i messages.pot -o po\de\messages.po -l de $ msginit -i messages.pot -o po\ru\messages.po -l ru
После выполнения данных команд, в директориях po\de и po\ru появятся необходимые нам файлы.
Теперь файл шаблона messages.pot нам не нужен и мы можем его удалить.
Замечание: | Для распространения исходных кодов нашего проекта достаточно иметь только файлы переводов *.po, естественно, иметь и *.cpp и CMakeLists.txt, что само собой разумеется. |
Далее, произведем "перевод" сообщений в *.po файлах на требуемые нам языки.
Для этого, редактируем их любым доступным образом и добавляем нужные сообщения:
- для po\de\messages.po
... msgid "Hello, world!" msgstr "Hallo Welt!" ...
- для po\ru\messages.po
... msgid "Hello, world!" msgstr "Привет, мир!" ...
Всё, теперь сохраняем все изменения. На этом перевод закончен, и можно приступить к сборке проекта.
[править] Собираем проект
Сначала перейдем в пустую директорию сборки (которую мы заранее создали):
$ cd <Путь к директории сборки>/build-project
Теперь сама сборка:
$ cmake ..\SourceTestProject -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release $ mingw32-make
При успехе в консоль отобразится примерно следующее:
D:\SVN\lang_test>cd ..\build D:\SVN\build>cmake ..\lang_test -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -- The C compiler identification is GNU -- The CXX compiler identification is GNU -- Check for working C compiler: D:/Qt/2009.04/mingw/bin/gcc.exe -- Check for working C compiler: D:/Qt/2009.04/mingw/bin/gcc.exe -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working CXX compiler: D:/Qt/2009.04/mingw/bin/g++.exe -- Check for working CXX compiler: D:/Qt/2009.04/mingw/bin/g++.exe -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- src files: D:/SVN/lang_test/po/../main.cpp -- Configuring done -- Generating done -- Build files have been written to: D:/SVN/build D:\SVN\build>mingw32-make Scanning dependencies of target test [100%] Building CXX object CMakeFiles/test.dir/main.cpp.obj Linking CXX executable test.exe [100%] Built target test Scanning dependencies of target translation D:/SVN/lang_test/po/../main.cpp:32: warning: Empty msgid. It is reserved by GNU gettext: gettext("") returns the header entry with meta information, not the empty string. . done. msgfmt: D:/SVN/build/po/de.po: field `Project-Id-Version' still has initial default value . done. msgfmt: D:/SVN/build/po/ru.po: field `Project-Id-Version' still has initial default value [100%] Built target translation D:\SVN\build>
При этом, автоматически сгенерируются:
- исполняемый файл приложения test.exe
- бинарные файлы переводов *.gmo
[править] Установка проекта
Теперь, после того как мы собрали проект, мы можем установить его в какую нибудь директорию.
Допустим, хотим установить в
D:\install
для этого выполняем в консоли следующую команду:
$ mingw32-make DESTDIR=d:\install install
В итоге, в директории d:\install получим следующую структуру каталогов:
/install |->/Program Files |->/test |->/bin | |->test.exe |->/locale |->/de | |->/LC_MESSAGES | |->test.mo |->/ru |->/LC_MESSAGES |->test.mo
Замечание: | Как видно, файлы переводов теперь вместо расширений *.gmo имеют расширение *.mo, процесс переименования файлов произошел в процессе установки приложения. |
[править] Запуск приложения
Для запуска приложения необходимо, находять в нашей консоли сборки, перейти в директорию с установленным проектом и выполнить файл test.exe
$ cd d:\install\Program Files\test $ bin\test.exe
После выполнения в консоли увидим:
D:\SVN\inst\Program Files\test>bin\test.exe Привет, мир!
Замечание: | Так как мы линковали наше приложение с библиотеками от Gettext, то для правильной его работы необходимо, чтобы наше приложение имело к ним доступ, для чего можно поступить двумя путями:
|