Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Boost.Locale: Messages Formatting (Translation)

Boost , ,

Messages Formatting (Translation)

Introduction

Форматирование сообщений, вероятно, является наиболее важной частью локализации - заставить ваше приложение говорить на языке пользователя.

Повышаю. Locale используетGNU GettextМодель локализации. Рекомендуем ознакомиться с общейдокументациейGNU Gettext, поскольку она выходит за рамки данного документа.

Модель выглядит следующим образом:

  • Во-первых, наше приложениеfooподготовлено к локализации, вызываяфункцию переводадля каждого сообщения, используемого в пользовательском интерфейсе.
    Например:
    cout<<"Hello World"<< endl;
    Изменен на
    cout<<переводится"Hello World"]<< endl;
    Is changed to
    cout << translate("Hello World") << endl;
    [ORIG_END] -->
  • Затем все сообщения извлекаются из исходного кода и генерируется специальныйfoo.poфайл, который содержит все исходные английские строки.
       ...
        msgid "Hello World"
        msgstr ""
        ...
  • Файлfoo.poпереводится для поддерживаемых локаций. Например,de.po,ar.po,en_CA.poиhe.po.
       ...
        msgid "Hello World"
        msgstr "שלום עולם"
    А затем компилируется в двоичныйmoформат и хранится в следующей файловой структуре:
       de
        de/LC_MESSAGES
        de/LC_MESSAGES/foo.mo
        en_CA/
        en_CA/LC_MESSAGES
        en_CA/LC_MESSAGES/foo.mo
        ...

    Когда приложение запускается, оно загружает необходимые словари. Затем, когда вызывается функцияtranslateи сообщение записывается в выходной поток, выполняется поиск в словаре и вместо этого записывается локализованное сообщение.

Loading dictionaries

Все словари загружены классомгенератор. Использование локализованных строк в приложении требует уточнения следующих параметров:

  1. Путь поиска словарей
  2. Домен приложения (или имя)

Это делается путем вызова следующих функций членагенераторакласса:

  • add_messages_path— добавить корневой путь к словарям.
    Например: если словарь расположен в/usr/share/locale/ar/LC_MESSAGES/foo.mo, то путь должен быть/usr/share/locale.
  • add_messages_domain— добавить домен (имя) приложения. В вышеприведенном случае это будет «фоо».
Note
At least one domain and one path should be specified in order to load dictionaries.

Вот пример первой полностью локализованной программы:

#include <boost/locale.hpp>
#include <iostream>
using namespace std;
using namespace boost::locale;
int main()
{
generator gen;
// Specify location of dictionaries
gen.add_messages_domain("hello");
// Generate locales and imbue them to iostream
locale::global(gen(""));
cout.imbue(locale());
// Display a message using current system locale
cout << translate("Hello World") << endl;
}

Message Translation

Существует два способа перевода сообщений:

  • Использованиеboost::locale::translate()семейство функций:
    Эти функции создают специальный прокси-объектbasic_message, который может быть преобразован в строку в соответствии с заданной локализацией или записан вstd::ostreamформатирование сообщения вstd::ostream'sлокализации.
    Очень удобно работать сstd::ostreamобъектом и откладывать перевод сообщения
  • Использованиеboost::locale::gettext()семейство функций:
    Это функции, которые используются для прямого перевода сообщения: они получают в качестве параметра оригинальное сообщение или ключ и преобразуют его вstd::basic_stringв заданном месте.
    Эти функции имеют названия, аналогичные тем, которые используются в библиотеке GNU Gettext.

Indirect Message Translation

Основной функцией, которая позволяет нам переводить сообщение, являетсяboost::locale::translate().Семейство функций.

Эти функции используют тип символа<CharType>в качестве параметра шаблона и получают либо<CharType const *>, либо<std::basic_string<CharType>>в качестве ввода.

Эти функции получают исходное сообщение и возвращают специальный прокси-объект —basic_message. Этот объект содержит всю необходимую информацию для форматирования сообщения.

Когда этот объект записывается на выход<ostream>, он выполняет словарный поиск сообщения в соответствии с локализацией, пропитанной<iostream>.

Если сообщение находится в словаре, оно записывается в выходной поток, в противном случае исходная строка записывается в поток.

Например:

// Translate a simple message "Hello World!"
std::cout << boost::locale::translate("Hello World!") << std::endl;

Это позволяет программе отложить перевод сообщения до тех пор, пока перевод действительно не понадобится, даже для разных локальных целей.

// Several output stream that we write a message to
// English, Japanese, Hebrew etc.
// Each one them has installed std::locale object that represents
// their specific locale
std::ofstream en,ja,he,de,ar;
// Send single message to multiple streams
void send_to_all(message const &msg)
{
// in each of the cases below
// the message is translated to different
// language
en << msg;
ja << msg;
he << msg;
de << msg;
ar << msg;
}
int main()
{
...
send_to_all(translate("Hello World"));
}
Note
  • basic_messageможно имплицитно преобразовать в apopriate std::basic_string с использованием глобальной локализации:
    std::wstring msg =translate[L"Хотите открыть файл?";
    [ORIG_END] -->
  • basic_messageможет быть явно преобразован в строку с использованиемstr()Функция члена для конкретной местности.
    std::locale ru_RU = ... ;
    std::string msg =translate["Хотите открыть файл?".str [ru_RU]
    [ORIG_END] -->

Plural Forms

GNU Каталоги Gettext имеют простую, надежную и мощную поддержку множественных форм. Мы рекомендуем прочитать оригинальную документацию GNUздесь.

Попробуем решить простую задачу, отобразив сообщение пользователю:

if(files == 1)
cout << translate("You have 1 file in the directory") << endl;
else
cout << format(translate("You have {1} files in the directory")) % files << endl;

Эта очень простая задача становится довольно сложной, когда мы имеем дело с языками, отличными от английского. Многие языки имеют более двух множественных форм. Например, на иврите существуют специальные формы для одиночного, двойного, множественного и множественного числа выше 10. Их нельзя отличить простым правилом «есть n 1 или нет»

Правильным решением является предоставление переводчику возможности самостоятельно выбрать форму множественного числа. Таким образом, функция перевода может принимать два дополнительных параметра:<translate(single,plural,count)>

Например:

cout << format(translate( "You have {1} file in the directory",
"You have {1} files in the directory",
files)) % files << endl;

Специальная запись в словаре определяет правило выбора правильной формы множественного числа на целевом языке. Например, славянская языковая семья имеет 3 формы множественного числа, которые можно выбрать, используя следующее уравнение:

plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;

Такое уравнение хранится в самом каталоге сообщений и оценивается при переводе для подачи правильной формы.

Таким образом, приведенный выше код будет отображать 3 различные формы в русском языке для значений 1, 3 и 5:

У вас есть 1 файл в каталоге
У вас есть 3 файла в каталоге
У вас есть 5 файлов в каталоге

А для японцев, у которых вообще нет множественных форм, он будет отображать одно и то же сообщение для любого числового значения.

Для получения более подробной информации обратитесь к GNU Gettext:11.2.6 Дополнительные функции для форм множественного числа

Adding Context Information

Во многих случаях недостаточно предоставить только оригинальную английскую строку, чтобы получить правильный перевод. Иногда необходимо предоставить контекстную информацию. Например, на немецком языке кнопка с надписью «открыть» переводится как «öffnen» в контексте «открыть файл» или «aufbauen» в контексте открытия интернет-соединения.

В этих случаях вы должны добавить некоторую контекстную информацию в исходную строку, добавив комментарий.

button->setLabel(translate("File","open"));

Контекстная информация предоставляется в качестве первого параметра функциипереводакак в единственном, так и во множественном числе. Переводчик увидит эту контекстную информацию и сможет правильно перевести «открытую» строку.

Вот как будет выглядеть файл<po>:

msgctxt "File"
msgid "open"
msgstr "öffnen"
msgctxt "Internet Connection"
msgid "open"
msgstr "aufbauen"
Note
Context information requires more recent versions of the gettext tools (>=0.15) for extracting strings and formatting message catalogs.

Working with multiple messages domains

В некоторых случаях полезно работать с несколькими доменами сообщений.

Например, если приложение состоит из нескольких независимых модулей, оно может иметь несколько доменов — отдельный домен для каждого модуля.

Например, разрабатывая офисный пакет FooBar, мы можем:

  • Процессор FooBar Word, использующий домен «foobarwriter»
  • a FooBar Spreadsheet, используя домен «foobarspreadsheet»
  • FooBar Spell Checker, используя домен «foobarspell»
  • Обработчик файлов FooBar, использующий домен «foobarodt»

Существует три способа использования доменов без по умолчанию:

  • При работе сiostreamвы можете использовать параметризованный манипуляторкак::домен (std::string const &), который позволяет переключать домены в потоке:
    cout<<как::домен"foo"]<<перевести"Hello"//
    Первый перевод взят из словаря foo, а другой из словарной строки
    [ORIG_END] -->
  • Вы можете явно указать домен при преобразовании объектаmessageв строку:
    std::wstring foo_msg =translate(L"Hello World".str"foo");
    std::wstring bar_msg =translate(L"Hello World".str"bar");
    [ORIG_END] -->
  • Вы можете указать домен напрямую, используяудобныйинтерфейс:
    MessageBoxdgettext"gui","Error Occurred"];
    [ORIG_END] -->

Direct translation (Convenience Interface)

Многие приложения не пишут сообщения непосредственно в выходной поток или используют только одну локализацию в процессе, поэтому вызов<translate("Hello World").str()>для одного сообщения будет раздражать. Таким образом, рост. Locale предоставляет GNU Gettext-подобные функции локализации для прямого перевода сообщений. Однако, в отличие от функций GNU Gettext, Boost. Функции локального перевода обеспечивают дополнительный дополнительный параметр (локальный) и поддерживают широкие, u16 и u32 строки.

Прототипы функций GNU Gettext можно найтив этом разделе.

Все эти функции могут иметь разные префиксы для разных форм:

  • d- перевод в конкретной области
  • n- множественный перевод
  • pПеревод в конкретном контексте
MessageBoxW(0,pgettext(L"File Dialog",L"Open?").c_str(),gettext(L"Question").c_str(),MB_YESNO);

Extracting messages from the source code

Существует множество инструментов для извлечения сообщений из исходного кода в формате<>.po. Наиболее популярным и «родным» инструментом является<xgettext>, который устанавливается по умолчанию на большинстве систем Unix и свободно загружается для Windows (см.Использование Gettext Tools на Windows).

Например, у нас есть исходный файл<dir.cpp>, который печатает:

cout << format(translate("Listing of catalog {1}:")) % file_name << endl;
cout << format(translate("Catalog {1} contains 1 file","Catalog {1} contains {2,num} files",files_no))
% file_name % files_no << endl;

Теперь бегаем:

xgettext --keyword=translate:1,1t --keyword=translate:1,2,3t dir.cpp

И файл под названием<messages.po>, который выглядит так (приблизительно):

#: dir.cpp:1
msgid "Listing of catalog {1}:"
msgstr ""
#: dir.cpp:2
msgid "Catalog {1} contains 1 file"
msgid_plural "Catalog {1} contains {2,num} files"
msgstr[0] ""
msgstr[1] ""

Этот файл может быть предоставлен переводчикам для адаптации к конкретным языкам.

Мы использовали<–keyword>параметр<xgettext>, чтобы сделать его пригодным для извлечения сообщений из исходного кода, локализованного с Boost. Локальные, поиск<translate()>вызовов функций вместо вызовов по умолчанию<gettext()>и<ngettext()>. Первый параметр<–keyword=translate:1,1t>обеспечивает шаблон для основных сообщений: функция<translate>, которая вызывается 1 аргументом (1t), и первое сообщение принимается за ключ. Второй<–keyword=translate:1,2,3t>используется для множественных форм. Он говорит<xgettext>использовать вызов функции<translate()>с 3 параметрами (3t) и принимать 1-й и 2-й параметр в качестве ключей. Для обозначения контекстной информации может использоваться дополнительный маркер<Nc>.

Полный набор параметров xgettext подходит для Boost. Локальность:

xgettext --keyword=translate:1,1t --keyword=translate:1c,2,2t \
--keyword=translate:1,2,3t --keyword=translate:1c,2,3,4t \
--keyword=gettext:1 --keyword=pgettext:1c,2 \
--keyword=ngettext:1,2 --keyword=npgettext:1c,2,3 \
source_file_1.cpp ... source_file_N.cpp

Конечно, если вы не используете «gettext», как перевод, вы можете игнорировать некоторые из этих параметров.

Custom Filesystem Support

Когда доступ к фактической файловой системе ограничен, как в элементах управления ActiveX, или когда разработчик хочет отправить исполняемый файл «все в одном», полезно иметь возможность загружать каталоги<gettext>из пользовательского местоположения - пользовательской файловой системы.

Повышаю. Locale предоставляет возможность установкиboost::locale::message_formatfacet с настраиваемыми опциями, предоставляемыми вboost::locale:::gnu_gettext:::messages_infoСтруктура.

Эта структура содержит<boost::function>на основеобратного вызова, что позволяет пользователю предоставлять пользовательские функции для загрузки файлов каталога сообщений.

Например:

// Configure all options for message catalog
namespace blg = boost::locale::gnu_gettext;
blg::messages_info info;
info.language = "he";
info.country = "IL";
info.encoding="UTF-8";
info.paths.push_back(""); // You need some even empty path
info.domains.push_back(blg::messages_info::domain("my_app"));
info.callback = some_file_loader; // Provide a callback
// Create a basic locale without messages support
std::locale base_locale = gen("he_IL.UTF-8");
// Install messages catalogs for "char" support to the final locale
// we are going to use
std::locale real_locale(base_locale,blg::create_messages_facet<char>(info));

Повышаю. Locale предполагает, что вы используете английский для оригинальных текстовых сообщений. И лучшая практика — использовать символы US-ASCII для оригинальных ключей.

Однако в некоторых случаях это полезно для вставки некоторых символов Unicode в текст, например, символ Copyright «©».

До тех пор, пока кодирование узкой строки символа является UTF-8, ничего не следует делать.

Повышаю. Locale предполагает, что ваши источники кодируются в UTF-8, а входная узкая строка использует UTF-8, что является по умолчанию для большинства компиляторов (за исключением Microsoft Visual C++).

Однако, если ваши узкие строки, кодирующие исходный файл, не UTF-8, а некоторые другие, такие как Windows-1252, строка будет неправильно истолкована.

Вы можете указать набор символов исходных строк, когда вы указываете доменное имя для приложения.

#include <boost/locale.hpp>
#include <iostream>
using namespace std;
using namespace boost::locale;
int main()
{
generator gen;
// Specify location of dictionaries
// Specify the encoding of the source string
gen.add_messages_domain("copyrighted/windows-1255");
// Generate locales and imbue them to iostream
locale::global(gen(""));
cout.imbue(locale());
// In Windows 1255 (C) symbol is encoded as 0xA9
cout << translate("© 2001 All Rights Reserved") << endl;
}

Таким образом, если программы работают в UTF-8, символ авторского права будет автоматически преобразован в соответствующую последовательность UTF-8, если ключ отсутствует в словаре.

Questions and Answers

  • Нужен ли GNU Gettext для использования Boost.Locale?
    Усиление. Locale предоставляет среду времени выполнения для загрузки и использования каталогов сообщений GNU Gettext, но не предоставляет инструментов для генерации, перевода, компиляции и управления этими каталогами. Повышаю. Локальный реализовывает GNU Gettext libintl.
    Возможно, вам понадобится:
    1. Повышение. Локально себя – для Runtime.
    2. Инструмент для извлечения строк из исходного кода и управления ими: GNU Gettext предоставляет хорошие инструменты, но доступны и другие реализации.
    3. Хорошая программа перевода, такая какLokalize,PeditилиGTranslator.
  • Почему не повышается? Locale предоставляет инструменты для извлечения и управления каталогами сообщений. Почему я должен использовать программное обеспечение GPL? На мои программы или каталоги сообщений влияет его лицензия?
    1. Повышение. Locale не ссылается на какой-либо из текстов GNU Gettext, поэтому вам не нужно беспокоиться о вашем коде, поскольку библиотека времени выполнения полностью реализовывается.
    2. Вы можете свободно использовать программное обеспечение GPL для извлечения и управления каталогами, так же, как вы можете использовать редактор GPL. Это не влияет на каталоги сообщений или код.
    3. Я не вижу причин для того, чтобы внедрять хорошо отлаженные рабочие инструменты, такие какxgettext,msgfmt,msgmerge, которые делают очень хорошую работу, тем более что они свободно доступны для загрузки и поддерживают практически любую платформу. Все дистрибутивы Linux, BSD Flavors, Mac OS X и другие Unix, такие как операционные системы, предоставляют инструменты GNU Gettext в качестве стандартного пакета.
      Пользователи Windows могут получить утилиты GNU Gettext через проект MinGW. См.Использование инструментов Gettext в Windows.
  • Есть ли какие-то причины, чтобы предпочесть рост? Локальная реализация в оригинальной библиотеке времени выполнения GNU Gettext? В любом случае мне, вероятно, понадобятся некоторые инструменты GNU.
    Существует два важных различия между библиотекой времени выполнения GNU Gettext и Boost. Локальная реализация:
    1. Среда выполнения GNU Gettext поддерживает только одну локализацию процесса. Не безопасно использовать несколько локализаций и кодировок в одном и том же процессе. Это отлично подходит для приложений, которые напрямую взаимодействуют с одним пользователем, как и большинство приложений графического интерфейса, но проблематично для служб и серверов.
    2. GNU Gettext API поддерживает только 8-битные кодировки, что делает его неактуальным в средах, которые изначально используют широкие строки.
    3. Библиотека времени выполнения GNU Gettext распространяется по лицензии LGPL, что может быть неудобно для некоторых пользователей.

Статья Boost.Locale: Messages Formatting (Translation) раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 23:59:20/0.011765956878662/0