420 lines
40 KiB
HTML
420 lines
40 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
||
<meta name="generator" content="Doxygen 1.8.6"/>
|
||
<title>Boost.Locale: Messages Formatting (Translation)</title>
|
||
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
||
<script type="text/javascript" src="jquery.js"></script>
|
||
<script type="text/javascript" src="dynsections.js"></script>
|
||
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
||
<script type="text/javascript" src="resize.js"></script>
|
||
<script type="text/javascript" src="navtree.js"></script>
|
||
<script type="text/javascript">
|
||
$(document).ready(initResizable);
|
||
$(window).load(resizeHeight);
|
||
</script>
|
||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||
</head>
|
||
<body>
|
||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||
<div id="titlearea">
|
||
<table cellspacing="0" cellpadding="0">
|
||
<tbody>
|
||
<tr style="height: 56px;">
|
||
<td id="projectlogo"><img alt="Logo" src="boost-small.png"/></td>
|
||
<td style="padding-left: 0.5em;">
|
||
<div id="projectname">Boost.Locale
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<!-- end header part -->
|
||
<!-- Generated by Doxygen 1.8.6 -->
|
||
<div id="navrow1" class="tabs">
|
||
<ul class="tablist">
|
||
<li><a href="index.html"><span>Main Page</span></a></li>
|
||
<li class="current"><a href="pages.html"><span>Related Pages</span></a></li>
|
||
<li><a href="modules.html"><span>Modules</span></a></li>
|
||
<li><a href="namespaces.html"><span>Namespaces</span></a></li>
|
||
<li><a href="annotated.html"><span>Classes</span></a></li>
|
||
<li><a href="files.html"><span>Files</span></a></li>
|
||
<li><a href="examples.html"><span>Examples</span></a></li>
|
||
</ul>
|
||
</div>
|
||
</div><!-- top -->
|
||
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
||
<div id="nav-tree">
|
||
<div id="nav-tree-contents">
|
||
<div id="nav-sync" class="sync"></div>
|
||
</div>
|
||
</div>
|
||
<div id="splitbar" style="-moz-user-select:none;"
|
||
class="ui-resizable-handle">
|
||
</div>
|
||
</div>
|
||
<script type="text/javascript">
|
||
$(document).ready(function(){initNavTree('messages_formatting.html','');});
|
||
</script>
|
||
<div id="doc-content">
|
||
<div class="header">
|
||
<div class="headertitle">
|
||
<div class="title">Messages Formatting (Translation) </div> </div>
|
||
</div><!--header-->
|
||
<div class="contents">
|
||
<div class="textblock"><ul>
|
||
<li><a class="el" href="messages_formatting.html#messages_formatting_into">Introduction</a></li>
|
||
<li><a class="el" href="messages_formatting.html#msg_loading_dictionaries">Loading dictionaries</a></li>
|
||
<li><a class="el" href="messages_formatting.html#message_translation">Message Translation</a><ul>
|
||
<li><a class="el" href="messages_formatting.html#indirect_message_translation">Indirect Message Translation</a></li>
|
||
<li><a class="el" href="messages_formatting.html#plural_forms">Plural Forms</a></li>
|
||
<li><a class="el" href="messages_formatting.html#multiple_gettext_domain">Working with multiple messages domains</a></li>
|
||
<li><a class="el" href="messages_formatting.html#direct_message_translation">Direct translation (Convenience Interface)</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="el" href="messages_formatting.html#extracting_messages_from_code">Extracting messages from the source code</a></li>
|
||
<li><a class="el" href="messages_formatting.html#custom_file_system_support">Custom Filesystem Support</a></li>
|
||
<li><a class="el" href="messages_formatting.html#msg_non_ascii_keys">Non US-ASCII Keys</a></li>
|
||
<li><a class="el" href="messages_formatting.html#msg_qna">Questions and Answers</a></li>
|
||
</ul>
|
||
<h1><a class="anchor" id="messages_formatting_into"></a>
|
||
Introduction</h1>
|
||
<p>Messages formatting is probably the most important part of the localization - making your application speak in the user's language.</p>
|
||
<p>Boost.Locale uses the <a href="http://www.gnu.org/software/gettext/">GNU Gettext</a> localization model. We recommend you read the general <a href="http://www.gnu.org/software/gettext/manual/gettext.html">documentation</a> of GNU Gettext, as it is outside the scope of this document.</p>
|
||
<p>The model is following:</p>
|
||
<ul>
|
||
<li>First, our application <code>foo</code> is prepared for localization by calling the <a class="el" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a> function for each message used in user interface. <br/>
|
||
For example: <div class="fragment"><div class="line">cout << <span class="stringliteral">"Hello World"</span> << endl;</div>
|
||
</div><!-- fragment --> Is changed to <br/>
|
||
<div class="fragment"><div class="line">cout << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Hello World"</span>) << endl;</div>
|
||
</div><!-- fragment --></li>
|
||
<li>Then all messages are extracted from the source code and a special <code>foo.po</code> file is generated that contains all of the original English strings. <br/>
|
||
<pre class="fragment"> ...
|
||
msgid "Hello World"
|
||
msgstr ""
|
||
...</pre></li>
|
||
<li>The <code>foo.po</code> file is translated for the supported locales. For example, <code>de.po</code>, <code>ar.po</code>, <code>en_CA.po</code> , and <code>he.po</code>. <br/>
|
||
<pre class="fragment"> ...
|
||
msgid "Hello World"
|
||
msgstr "שלום עולם"</pre> And then compiled to the binary <code>mo</code> format and stored in the following file structure: <br/>
|
||
<pre class="fragment"> de
|
||
de/LC_MESSAGES
|
||
de/LC_MESSAGES/foo.mo
|
||
en_CA/
|
||
en_CA/LC_MESSAGES
|
||
en_CA/LC_MESSAGES/foo.mo
|
||
...</pre> <br/>
|
||
When the application starts, it loads the required dictionaries. Then when the <code>translate</code> function is called and the message is written to an output stream, a dictionary lookup is performed and the localized message is written out instead.</li>
|
||
</ul>
|
||
<h1><a class="anchor" id="msg_loading_dictionaries"></a>
|
||
Loading dictionaries</h1>
|
||
<p>All the dictionaries are loaded by the <a class="el" href="classboost_1_1locale_1_1generator.html">generator</a> class. Using localized strings in the application, requires specification of the following parameters:</p>
|
||
<ol type="1">
|
||
<li>The search path of the dictionaries</li>
|
||
<li>The application domain (or name)</li>
|
||
</ol>
|
||
<p>This is done by calling the following member functions of the <a class="el" href="classboost_1_1locale_1_1generator.html">generator</a> class:</p>
|
||
<ul>
|
||
<li><a class="el" href="classboost_1_1locale_1_1generator.html#a12823bbdb209690bfb77caa6404fd91b">add_messages_path</a> - add the root path to the dictionaries. <br/>
|
||
For example: if the dictionary is located at <code>/usr/share/locale/ar/LC_MESSAGES/foo</code>.mo, then path should be <code>/usr/share/locale</code>. <br/>
|
||
</li>
|
||
<li><a class="el" href="classboost_1_1locale_1_1generator.html#a15020562d16dbbe276325b0162d54565">add_messages_domain</a> - add the domain (name) of the application. In the above case it would be "foo".</li>
|
||
</ul>
|
||
<dl class="section note"><dt>Note</dt><dd>At least one domain and one path should be specified in order to load dictionaries.</dd></dl>
|
||
<p>This is an example of our first fully localized program:</p>
|
||
<div class="fragment"><div class="line"><span class="preprocessor">#include <boost/locale.hpp></span></div>
|
||
<div class="line"><span class="preprocessor">#include <iostream></span></div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="keyword">using namespace </span>std;</div>
|
||
<div class="line"><span class="keyword">using namespace </span>boost::locale;</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="keywordtype">int</span> main()</div>
|
||
<div class="line">{</div>
|
||
<div class="line"> <a class="code" href="classboost_1_1locale_1_1generator.html">generator</a> gen;</div>
|
||
<div class="line"></div>
|
||
<div class="line"> <span class="comment">// Specify location of dictionaries</span></div>
|
||
<div class="line"> gen.<a class="code" href="classboost_1_1locale_1_1generator.html#a12823bbdb209690bfb77caa6404fd91b">add_messages_path</a>(<span class="stringliteral">"."</span>);</div>
|
||
<div class="line"> gen.<a class="code" href="classboost_1_1locale_1_1generator.html#a15020562d16dbbe276325b0162d54565">add_messages_domain</a>(<span class="stringliteral">"hello"</span>);</div>
|
||
<div class="line"></div>
|
||
<div class="line"> <span class="comment">// Generate locales and imbue them to iostream</span></div>
|
||
<div class="line"> locale::global(gen(<span class="stringliteral">""</span>));</div>
|
||
<div class="line"> cout.imbue(locale());</div>
|
||
<div class="line"></div>
|
||
<div class="line"> <span class="comment">// Display a message using current system locale</span></div>
|
||
<div class="line"> cout << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Hello World"</span>) << endl;</div>
|
||
<div class="line">}</div>
|
||
</div><!-- fragment --><h1><a class="anchor" id="message_translation"></a>
|
||
Message Translation</h1>
|
||
<p>There are two ways to translate messages:</p>
|
||
<ul>
|
||
<li>using <a class="el" href="group__message.html#boost_locale_translate_family">boost::locale::translate()</a> family of functions: <br/>
|
||
These functions create a special proxy object <a class="el" href="classboost_1_1locale_1_1basic__message.html">basic_message</a> that can be converted to string according to given locale or written to <code>std::ostream</code> formatting the message in the <code>std::ostream's</code> locale. <br/>
|
||
It is very convenient for working with <code>std::ostream</code> object and for postponing message translation</li>
|
||
<li>Using <a class="el" href="group__message.html#boost_locale_gettext_family">boost::locale::gettext()</a> family of functions: <br/>
|
||
These are functions that are used for direct message translation: they receive as a parameter an original message or a key and convert it to the <code>std::basic_string</code> in given locale. <br/>
|
||
These functions have similar names to thous used in the GNU Gettext library.</li>
|
||
</ul>
|
||
<h2><a class="anchor" id="indirect_message_translation"></a>
|
||
Indirect Message Translation</h2>
|
||
<p>The basic function that allows us to translate a message is <a class="el" href="group__message.html#boost_locale_translate_family">boost::locale::translate()</a> family of functions.</p>
|
||
<p>These functions use a character type <code>CharType</code> as template parameter and receive either <code>CharType const *</code> or <code>std::basic_string<CharType></code> as input.</p>
|
||
<p>These functions receive an original message and return a special proxy object - <a class="el" href="classboost_1_1locale_1_1basic__message.html">basic_message<CharType></a>. This object holds all the required information for the message formatting.</p>
|
||
<p>When this object is written to an output <code>ostream</code>, it performs a dictionary lookup of the message according to the locale imbued in <code>iostream</code>.</p>
|
||
<p>If the message is found in the dictionary it is written to the output stream, otherwise the original string is written to the stream.</p>
|
||
<p>For example:</p>
|
||
<div class="fragment"><div class="line"><span class="comment">// Translate a simple message "Hello World!"</span></div>
|
||
<div class="line">std::cout << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">boost::locale::translate</a>(<span class="stringliteral">"Hello World!"</span>) << std::endl;</div>
|
||
</div><!-- fragment --><p>This allows the program to postpone translation of the message until the translation is actually needed, even to different locale targets.</p>
|
||
<div class="fragment"><div class="line"><span class="comment">// Several output stream that we write a message to</span></div>
|
||
<div class="line"><span class="comment">// English, Japanese, Hebrew etc.</span></div>
|
||
<div class="line"><span class="comment">// Each one them has installed std::locale object that represents</span></div>
|
||
<div class="line"><span class="comment">// their specific locale</span></div>
|
||
<div class="line">std::ofstream en,ja,he,de,ar;</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="comment">// Send single message to multiple streams</span></div>
|
||
<div class="line"><span class="keywordtype">void</span> send_to_all(<a class="code" href="group__message.html#ga556e3e7696302902b2242a7a94516dee">message</a> <span class="keyword">const</span> &msg)</div>
|
||
<div class="line">{</div>
|
||
<div class="line"> <span class="comment">// in each of the cases below</span></div>
|
||
<div class="line"> <span class="comment">// the message is translated to different</span></div>
|
||
<div class="line"> <span class="comment">// language</span></div>
|
||
<div class="line"> en << msg;</div>
|
||
<div class="line"> ja << msg;</div>
|
||
<div class="line"> he << msg;</div>
|
||
<div class="line"> de << msg;</div>
|
||
<div class="line"> ar << msg;</div>
|
||
<div class="line">}</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="keywordtype">int</span> main()</div>
|
||
<div class="line">{</div>
|
||
<div class="line"> ...</div>
|
||
<div class="line"> send_to_all(<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Hello World"</span>));</div>
|
||
<div class="line">}</div>
|
||
</div><!-- fragment --><dl class="section note"><dt>Note</dt><dd></dd></dl>
|
||
<ul>
|
||
<li><a class="el" href="classboost_1_1locale_1_1basic__message.html">basic_message</a> can be implicitly converted to an apopriate std::basic_string using the global locale: <br/>
|
||
<div class="fragment"><div class="line">std::wstring msg = <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(L<span class="stringliteral">"Do you want to open the file?"</span>);</div>
|
||
</div><!-- fragment --></li>
|
||
<li><a class="el" href="classboost_1_1locale_1_1basic__message.html">basic_message</a> can be explicitly converted to a string using the <a class="el" href="group__message.html#ga11c5f400e03e0b16b9a60bd3fae3f168">str()</a> member function for a specific locale. <br/>
|
||
<div class="fragment"><div class="line">std::locale ru_RU = ... ;</div>
|
||
<div class="line">std::string msg = <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Do you want to open the file?"</span>).str(ru_RU);</div>
|
||
</div><!-- fragment --></li>
|
||
</ul>
|
||
<h2><a class="anchor" id="plural_forms"></a>
|
||
Plural Forms</h2>
|
||
<p>GNU Gettext catalogs have simple, robust and yet powerful plural forms support. We recommend to read the original GNU documentation <a href="http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms">here</a>.</p>
|
||
<p>Let's try to solve a simple problem, displaying a message to the user:</p>
|
||
<div class="fragment"><div class="line"><span class="keywordflow">if</span>(files == 1)</div>
|
||
<div class="line"> cout << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"You have 1 file in the directory"</span>) << endl;</div>
|
||
<div class="line"><span class="keywordflow">else</span></div>
|
||
<div class="line"> cout << <a class="code" href="group__format.html#gad7914df7b54382c1ad7f5360676fe2e8">format</a>(<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"You have {1} files in the directory"</span>)) % files << endl;</div>
|
||
</div><!-- fragment --><p>This very simple task becomes quite complicated when we deal with languages other than English. Many languages have more than two plural forms. For example, in Hebrew there are special forms for single, double, plural, and plural above 10. They can't be distinguished by the simple rule "is n 1 or not"</p>
|
||
<p>The correct solution is to give a translator an ability to choose a plural form on its own. Thus the translate function can receive two additional parameters English plural form a number: <code>translate(single,plural,count)</code></p>
|
||
<p>For example:</p>
|
||
<div class="fragment"><div class="line">cout << <a class="code" href="group__format.html#gad7914df7b54382c1ad7f5360676fe2e8">format</a>(<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>( <span class="stringliteral">"You have {1} file in the directory"</span>,</div>
|
||
<div class="line"> <span class="stringliteral">"You have {1} files in the directory"</span>,</div>
|
||
<div class="line"> files)) % files << endl;</div>
|
||
</div><!-- fragment --><p>A special entry in the dictionary specifies the rule to choose the correct plural form in the target language. For example, the Slavic language family has 3 plural forms, that can be chosen using following equation:</p>
|
||
<div class="fragment"><div class="line">plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;</div>
|
||
</div><!-- fragment --><p>Such equation is stored in the message catalog itself and it is evaluated during translation to supply the correct form.</p>
|
||
<p>So the code above would display 3 different forms in Russian locale for values of 1, 3 and 5:</p>
|
||
<pre class="fragment">У вас есть 1 файл в каталоге
|
||
У вас есть 3 файла в каталоге
|
||
У вас есть 5 файлов в каталоге
|
||
</pre><p>And for Japanese that does not have plural forms at all it would display the same message for any numeric value.</p>
|
||
<p>For more detailed information please refer to GNU Gettext: <a href="http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms">11.2.6 Additional functions for plural forms</a></p>
|
||
<h2><a class="anchor" id="adding_context_information"></a>
|
||
Adding Context Information</h2>
|
||
<p>In many cases it is not sufficient to provide only the original English string to get the correct translation. You sometimes need to provide some context information. In German, for example, a button labeled "open" is translated to "öffnen" in the context of "opening a file", or to "aufbauen" in the context of opening an internet connection.</p>
|
||
<p>In these cases you must add some context information to the original string, by adding a comment.</p>
|
||
<div class="fragment"><div class="line">button->setLabel(<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"File"</span>,<span class="stringliteral">"open"</span>));</div>
|
||
</div><!-- fragment --><p>The context information is provided as the first parameter to the <a class="el" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a> function in both singular and plural forms. The translator would see this context information and would be able to translate the "open" string correctly.</p>
|
||
<p>For example, this is how the <code>po</code> file would look:</p>
|
||
<div class="fragment"><div class="line">msgctxt <span class="stringliteral">"File"</span></div>
|
||
<div class="line">msgid <span class="stringliteral">"open"</span></div>
|
||
<div class="line">msgstr <span class="stringliteral">"öffnen"</span></div>
|
||
<div class="line"></div>
|
||
<div class="line">msgctxt <span class="stringliteral">"Internet Connection"</span></div>
|
||
<div class="line">msgid <span class="stringliteral">"open"</span></div>
|
||
<div class="line">msgstr <span class="stringliteral">"aufbauen"</span></div>
|
||
</div><!-- fragment --><dl class="section note"><dt>Note</dt><dd>Context information requires more recent versions of the gettext tools (>=0.15) for extracting strings and formatting message catalogs.</dd></dl>
|
||
<h2><a class="anchor" id="multiple_gettext_domain"></a>
|
||
Working with multiple messages domains</h2>
|
||
<p>In some cases it is useful to work with multiple message domains.</p>
|
||
<p>For example, if an application consists of several independent modules, it may have several domains - a separate domain for each module.</p>
|
||
<p>For example, developing a FooBar office suite we might have:</p>
|
||
<ul>
|
||
<li>a FooBar Word Processor, using the "foobarwriter" domain</li>
|
||
<li>a FooBar Spreadsheet, using the "foobarspreadsheet" domain</li>
|
||
<li>a FooBar Spell Checker, using the "foobarspell" domain</li>
|
||
<li>a FooBar File handler, using the "foobarodt" domain</li>
|
||
</ul>
|
||
<p>There are three ways to use non-default domains:</p>
|
||
<ul>
|
||
<li>When working with <code>iostream</code>, you can use the parameterized manipulator <a class="el" href="group__manipulators.html#gab522188e3d82f1d2898b290b9132925e">as::domain(std::string const &)</a>, which allows switching domains in a stream: <br/>
|
||
<div class="fragment"><div class="line">cout << <a class="code" href="group__manipulators.html#gab522188e3d82f1d2898b290b9132925e">as::domain</a>(<span class="stringliteral">"foo"</span>) << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Hello"</span>) << <a class="code" href="group__manipulators.html#gab522188e3d82f1d2898b290b9132925e">as::domain</a>(<span class="stringliteral">"bar"</span>) << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Hello"</span>);</div>
|
||
<div class="line"><span class="comment">// First translation is taken from dictionary foo and the other from dictionary bar</span></div>
|
||
</div><!-- fragment --></li>
|
||
<li>You can specify the domain explicitly when converting a <code>message</code> object to a string: <div class="fragment"><div class="line">std::wstring foo_msg = <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(L<span class="stringliteral">"Hello World"</span>).str(<span class="stringliteral">"foo"</span>);</div>
|
||
<div class="line">std::wstring bar_msg = <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(L<span class="stringliteral">"Hello World"</span>).str(<span class="stringliteral">"bar"</span>);</div>
|
||
</div><!-- fragment --></li>
|
||
<li>You can specify the domain directly using a <a class="el" href="messages_formatting.html#direct_message_translation">convenience</a> interface: <div class="fragment"><div class="line">MessageBox(<a class="code" href="group__message.html#ga0c4c54c5562ecc56396ef1c53582c799">dgettext</a>(<span class="stringliteral">"gui"</span>,<span class="stringliteral">"Error Occurred"</span>));</div>
|
||
</div><!-- fragment --></li>
|
||
</ul>
|
||
<h2><a class="anchor" id="direct_message_translation"></a>
|
||
Direct translation (Convenience Interface)</h2>
|
||
<p>Many applications do not write messages directly to an output stream or use only one locale in the process, so calling <code>translate("Hello World").str()</code> for a single message would be annoying. Thus Boost.Locale provides GNU Gettext-like localization functions for direct translation of the messages. However, unlike the GNU Gettext functions, the Boost.Locale translation functions provide an additional optional parameter (locale), and support wide, u16 and u32 strings.</p>
|
||
<p>The GNU Gettext like functions prototypes can be found <a class="el" href="group__message.html#boost_locale_gettext_family">in this section</a>.</p>
|
||
<p>All of these functions can have different prefixes for different forms:</p>
|
||
<ul>
|
||
<li><code>d</code> - translation in specific domain</li>
|
||
<li><code>n</code> - plural form translation</li>
|
||
<li><code>p</code> - translation in specific context</li>
|
||
</ul>
|
||
<div class="fragment"><div class="line">MessageBoxW(0,<a class="code" href="group__message.html#gab2362c5a15141d3d58dbf731e6ef6bad">pgettext</a>(L<span class="stringliteral">"File Dialog"</span>,L<span class="stringliteral">"Open?"</span>).c_str(),<a class="code" href="group__message.html#ga1121f0001ff0f3b9455390b6412c6a2c">gettext</a>(L<span class="stringliteral">"Question"</span>).c_str(),MB_YESNO);</div>
|
||
</div><!-- fragment --><h1><a class="anchor" id="extracting_messages_from_code"></a>
|
||
Extracting messages from the source code</h1>
|
||
<p>There are many tools to extract messages from the source code into the <code></code>.po file format. The most popular and "native" tool is <code>xgettext</code> which is installed by default on most Unix systems and freely downloadable for Windows (see <a class="el" href="gettext_for_windows.html">Using Gettext Tools on Windows</a>).</p>
|
||
<p>For example, we have a source file called <code>dir.cpp</code> that prints:</p>
|
||
<div class="fragment"><div class="line">cout << <a class="code" href="group__format.html#gad7914df7b54382c1ad7f5360676fe2e8">format</a>(<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Listing of catalog {1}:"</span>)) % file_name << endl;</div>
|
||
<div class="line">cout << <a class="code" href="group__format.html#gad7914df7b54382c1ad7f5360676fe2e8">format</a>(<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"Catalog {1} contains 1 file"</span>,<span class="stringliteral">"Catalog {1} contains {2,num} files"</span>,files_no)) </div>
|
||
<div class="line"> % file_name % files_no << endl;</div>
|
||
</div><!-- fragment --><p>Now we run:</p>
|
||
<pre class="fragment">xgettext --keyword=translate:1,1t --keyword=translate:1,2,3t dir.cpp
|
||
</pre><p>And a file called <code>messages.po</code> created that looks like this (approximately):</p>
|
||
<div class="fragment"><div class="line"><span class="preprocessor">#: dir.cpp:1</span></div>
|
||
<div class="line"><span class="preprocessor"></span>msgid <span class="stringliteral">"Listing of catalog {1}:"</span></div>
|
||
<div class="line">msgstr <span class="stringliteral">""</span></div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="preprocessor">#: dir.cpp:2</span></div>
|
||
<div class="line"><span class="preprocessor"></span>msgid <span class="stringliteral">"Catalog {1} contains 1 file"</span></div>
|
||
<div class="line">msgid_plural <span class="stringliteral">"Catalog {1} contains {2,num} files"</span></div>
|
||
<div class="line">msgstr[0] <span class="stringliteral">""</span></div>
|
||
<div class="line">msgstr[1] <span class="stringliteral">""</span></div>
|
||
</div><!-- fragment --><p>This file can be given to translators to adapt it to specific languages.</p>
|
||
<p>We used the <code>–keyword</code> parameter of <code>xgettext</code> to make it suitable for extracting messages from source code localized with Boost.Locale, searching for <code><a class="el" href="group__message.html#ga58e9599005608845d2b022d499dc97f6" title="Translate a message, msg is not copied. ">translate()</a></code> function calls instead of the default <code><a class="el" href="group__message.html#ga1121f0001ff0f3b9455390b6412c6a2c">gettext()</a></code> and <code><a class="el" href="group__message.html#gaab79a005dda921603eead4839c116c52">ngettext()</a></code> ones. The first parameter <code>–keyword=translate:1,1t</code> provides the template for basic messages: a <code>translate</code> function that is called with 1 argument (1t) and the first message is taken as the key. The second one <code>–keyword=translate:1,2,3t</code> is used for plural forms. It tells <code>xgettext</code> to use a <code><a class="el" href="group__message.html#ga58e9599005608845d2b022d499dc97f6" title="Translate a message, msg is not copied. ">translate()</a></code> function call with 3 parameters (3t) and take the 1st and 2nd parameter as keys. An additional marker <code>Nc</code> can be used to mark context information.</p>
|
||
<p>The full set of xgettext parameters suitable for Boost.Locale is:</p>
|
||
<div class="fragment"><div class="line">xgettext --keyword=<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>:1,1t --keyword=<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>:1c,2,2t \</div>
|
||
<div class="line"> --keyword=<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>:1,2,3t --keyword=<a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>:1c,2,3,4t \</div>
|
||
<div class="line"> --keyword=<a class="code" href="group__message.html#ga1121f0001ff0f3b9455390b6412c6a2c">gettext</a>:1 --keyword=<a class="code" href="group__message.html#gab2362c5a15141d3d58dbf731e6ef6bad">pgettext</a>:1c,2 \</div>
|
||
<div class="line"> --keyword=<a class="code" href="group__message.html#gaab79a005dda921603eead4839c116c52">ngettext</a>:1,2 --keyword=<a class="code" href="group__message.html#ga5023a270956a2febe1cd86c717d570a7">npgettext</a>:1c,2,3 \</div>
|
||
<div class="line"> source_file_1.cpp ... source_file_N.cpp</div>
|
||
</div><!-- fragment --><p>Of course, if you do not use "gettext" like translation you may ignore some of these parameters.</p>
|
||
<h2><a class="anchor" id="custom_file_system_support"></a>
|
||
Custom Filesystem Support</h2>
|
||
<p>When the access to actual file system is limited like in ActiveX controls or when the developer wants to ship all-in-one executable file, it is useful to be able to load <code>gettext</code> catalogs from a custom location - a custom file system.</p>
|
||
<p>Boost.Locale provides an option to install <a class="el" href="classboost_1_1locale_1_1message__format.html" title="This facet provides message formatting abilities. ">boost::locale::message_format</a> facet with customized options provided in <a class="el" href="structboost_1_1locale_1_1gnu__gettext_1_1messages__info.html" title="This structure holds all information required for creating gnu-gettext message catalogs,. ">boost::locale::gnu_gettext::messages_info</a> structure.</p>
|
||
<p>This structure contains <code>boost::function</code> based <a class="el" href="structboost_1_1locale_1_1gnu__gettext_1_1messages__info.html#a4dfe37c5a392e5106e65b396a5288b76">callback</a> that allows user to provide custom functionality to load message catalog files.</p>
|
||
<p>For example:</p>
|
||
<div class="fragment"><div class="line"><span class="comment">// Configure all options for message catalog</span></div>
|
||
<div class="line"><span class="keyword">namespace </span>blg = boost::locale::gnu_gettext;</div>
|
||
<div class="line">blg::messages_info info;</div>
|
||
<div class="line">info.language = <span class="stringliteral">"he"</span>;</div>
|
||
<div class="line">info.country = <span class="stringliteral">"IL"</span>;</div>
|
||
<div class="line">info.encoding=<span class="stringliteral">"UTF-8"</span>;</div>
|
||
<div class="line">info.paths.push_back(<span class="stringliteral">""</span>); <span class="comment">// You need some even empty path</span></div>
|
||
<div class="line">info.domains.push_back(<a class="code" href="group__manipulators.html#gab522188e3d82f1d2898b290b9132925e">blg::messages_info::domain</a>(<span class="stringliteral">"my_app"</span>));</div>
|
||
<div class="line">info.callback = some_file_loader; <span class="comment">// Provide a callback</span></div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="comment">// Create a basic locale without messages support</span></div>
|
||
<div class="line"><a class="code" href="classboost_1_1locale_1_1generator.html">boost::locale::generator</a> gen;</div>
|
||
<div class="line">std::locale base_locale = gen(<span class="stringliteral">"he_IL.UTF-8"</span>);</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="comment">// Install messages catalogs for "char" support to the final locale</span></div>
|
||
<div class="line"><span class="comment">// we are going to use</span></div>
|
||
<div class="line">std::locale real_locale(base_locale,blg::create_messages_facet<char>(info));</div>
|
||
</div><!-- fragment --><p>In order to setup <a class="el" href="structboost_1_1locale_1_1gnu__gettext_1_1messages__info.html#a1afc3be03d4848042e3208d4ca5aec85">language</a>, <a class="el" href="structboost_1_1locale_1_1gnu__gettext_1_1messages__info.html#ae939e0c5dbabba7fb4cc2872f4e7dac2">country</a> and other members you may use <a class="el" href="classboost_1_1locale_1_1info.html">boost::locale::info</a> facet for convenience,</p>
|
||
<div class="fragment"><div class="line"><span class="comment">// Configure all options for message catalog</span></div>
|
||
<div class="line"><span class="keyword">namespace </span>blg = boost::locale::gnu_gettext;</div>
|
||
<div class="line">blg::messages_info info;</div>
|
||
<div class="line"></div>
|
||
<div class="line">info.paths.push_back(<span class="stringliteral">""</span>); <span class="comment">// You need some even empty path</span></div>
|
||
<div class="line">info.domains.push_back(<a class="code" href="group__manipulators.html#gab522188e3d82f1d2898b290b9132925e">blg::messages_info::domain</a>(<span class="stringliteral">"my_app"</span>));</div>
|
||
<div class="line">info.callback = some_file_loader; <span class="comment">// Provide a callback</span></div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="comment">// Create an object with default locale</span></div>
|
||
<div class="line">std::locale base_locale = gen(<span class="stringliteral">""</span>);</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="comment">// Use boost::locale::info to configure all parameters</span></div>
|
||
<div class="line"></div>
|
||
<div class="line"><a class="code" href="classboost_1_1locale_1_1info.html">boost::locale::info</a> <span class="keyword">const</span> &properties = std::use_facet<boost::locale::info>(base_locale);</div>
|
||
<div class="line">info.<a class="code" href="classboost_1_1locale_1_1info.html#a7c56b9df3aba82649afc66c06192c7df">language</a> = properties.<a class="code" href="classboost_1_1locale_1_1info.html#a7c56b9df3aba82649afc66c06192c7df">language</a>();</div>
|
||
<div class="line">info.country = properties.<a class="code" href="classboost_1_1locale_1_1info.html#a249c20e36da6827a8dc8b12a8342a7dc">country</a>();</div>
|
||
<div class="line">info.encoding = properties.<a class="code" href="classboost_1_1locale_1_1info.html#a1979a5d7b90604c45e856a139c68f5ba">encoding</a>();</div>
|
||
<div class="line">info.variant = properties.<a class="code" href="classboost_1_1locale_1_1info.html#a2e949e4362c8f0195e2a645fe875f1b4">variant</a>();</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="comment">// Install messages catalogs to the final locale</span></div>
|
||
<div class="line">std::locale real_locale(base_locale,blg::create_messages_facet<char>(info));</div>
|
||
</div><!-- fragment --><h1><a class="anchor" id="msg_non_ascii_keys"></a>
|
||
Non US-ASCII Keys</h1>
|
||
<p>Boost.Locale assumes that you use English for original text messages. And the best practice is to use US-ASCII characters for original keys.</p>
|
||
<p>However in some cases it us useful in insert some Unicode characters in text like for example Copyright "©" character.</p>
|
||
<p>As long as your narrow character string encoding is UTF-8 nothing further should be done.</p>
|
||
<p>Boost.Locale assumes that your sources are encoded in UTF-8 and the input narrow string use UTF-8 - which is the default for most compilers around (with notable exception of Microsoft Visual C++).</p>
|
||
<p>However if your narrow strings encoding in the source file is not UTF-8 but some other encoding like windows-1252, the string would be misinterpreted.</p>
|
||
<p>You can specify the character set of the original strings when you specify the domain name for the application.</p>
|
||
<div class="fragment"><div class="line"><span class="preprocessor">#include <boost/locale.hpp></span></div>
|
||
<div class="line"><span class="preprocessor">#include <iostream></span></div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="keyword">using namespace </span>std;</div>
|
||
<div class="line"><span class="keyword">using namespace </span>boost::locale;</div>
|
||
<div class="line"></div>
|
||
<div class="line"><span class="keywordtype">int</span> main()</div>
|
||
<div class="line">{</div>
|
||
<div class="line"> <a class="code" href="classboost_1_1locale_1_1generator.html">generator</a> gen;</div>
|
||
<div class="line"></div>
|
||
<div class="line"> <span class="comment">// Specify location of dictionaries</span></div>
|
||
<div class="line"> gen.<a class="code" href="classboost_1_1locale_1_1generator.html#a12823bbdb209690bfb77caa6404fd91b">add_messages_path</a>(<span class="stringliteral">"."</span>);</div>
|
||
<div class="line"> <span class="comment">// Specify the encoding of the source string</span></div>
|
||
<div class="line"> gen.<a class="code" href="classboost_1_1locale_1_1generator.html#a15020562d16dbbe276325b0162d54565">add_messages_domain</a>(<span class="stringliteral">"copyrighted/windows-1255"</span>);</div>
|
||
<div class="line"></div>
|
||
<div class="line"> <span class="comment">// Generate locales and imbue them to iostream</span></div>
|
||
<div class="line"> locale::global(gen(<span class="stringliteral">""</span>));</div>
|
||
<div class="line"> cout.imbue(locale());</div>
|
||
<div class="line"> </div>
|
||
<div class="line"> <span class="comment">// In Windows 1255 (C) symbol is encoded as 0xA9</span></div>
|
||
<div class="line"> cout << <a class="code" href="group__message.html#ga58e9599005608845d2b022d499dc97f6">translate</a>(<span class="stringliteral">"© 2001 All Rights Reserved"</span>) << endl;</div>
|
||
<div class="line">}</div>
|
||
</div><!-- fragment --><p>Thus if the programs runs in UTF-8 locale the copyright symbol would be automatically converted to an appropriate UTF-8 sequence if the key is missing in the dictionary.</p>
|
||
<h2><a class="anchor" id="msg_qna"></a>
|
||
Questions and Answers</h2>
|
||
<ul>
|
||
<li>Do I need GNU Gettext to use Boost.Locale? <br/>
|
||
Boost.Locale provides a run-time environment to load and use GNU Gettext message catalogs, but it does not provide tools for generation, translation, compilation and management of these catalogs. Boost.Locale only reimplements the GNU Gettext libintl. <br/>
|
||
You would probably need: <br/>
|
||
<ol type="1">
|
||
<li>Boost.Locale itself – for runtime.</li>
|
||
<li>A tool for extracting strings from source code, and managing them: GNU Gettext provides good tools, but other implementations are available as well.</li>
|
||
<li>A good translation program like <a href="http://userbase.kde.org/Lokalize">Lokalize</a>, <a href="http://www.poedit.net/">Pedit</a> or <a href="http://projects.gnome.org/gtranslator/">GTranslator</a>.</li>
|
||
</ol>
|
||
</li>
|
||
<li>Why doesn't Boost.Locale provide tools for extracting and management of message catalogs. Why should I use GPL-ed software? Are my programs or message catalogs affected by its license? <br/>
|
||
<ol type="1">
|
||
<li>Boost.Locale does not link to or use any of the GNU Gettext code, so you need not worry about your code as the runtime library is fully reimplemented.</li>
|
||
<li>You may freely use GPL-ed software for extracting and managing catalogs, the same way as you are free to use a GPL-ed editor. It does not affect your message catalogs or your code.</li>
|
||
<li>I see no reason to reimplement well debugged, working tools like <code>xgettext</code>, <code>msgfmt</code>, <code>msgmerge</code> that do a very fine job, especially as they are freely available for download and support almost any platform. All Linux distributions, BSD Flavors, Mac OS X and other Unix like operating systems provide GNU Gettext tools as a standard package.<br/>
|
||
Windows users can get GNU Gettext utilities via MinGW project. See <a class="el" href="gettext_for_windows.html">Using Gettext Tools on Windows</a>.</li>
|
||
</ol>
|
||
</li>
|
||
<li>Is there any reason to prefer the Boost.Locale implementation to the original GNU Gettext runtime library? In either case I would probably need some of the GNU tools. <br/>
|
||
There are two important differences between the GNU Gettext runtime library and the Boost.Locale implementation: <br/>
|
||
<ol type="1">
|
||
<li>The GNU Gettext runtime supports only one locale per process. It is not thread-safe to use multiple locales and encodings in the same process. This is perfectly fine for applications that interact directly with a single user like most GUI applications, but is problematic for services and servers.</li>
|
||
<li>The GNU Gettext API supports only 8-bit encodings, making it irrelevant in environments that natively use wide strings.</li>
|
||
<li>The GNU Gettext runtime library distributed under LGPL license which may be not convenient for some users. </li>
|
||
</ol>
|
||
</li>
|
||
</ul>
|
||
</div></div><!-- contents -->
|
||
</div><!-- doc-content -->
|
||
|
||
<li class="footer">
|
||
© Copyright 2009-2012 Artyom Beilis, Distributed under the <a href="http://www.boost.org/LICENSE_1_0.txt">Boost Software License</a>, Version 1.0.
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</body>
|
||
</html>
|