<!--toc--> |
|
## Introduction |
|
CppCMS has a sophisticated internationalization and |
localization support. During CppCMS development localization |
tools were submitted to [Boost Project](http://www.boost.org) |
and accepted as [Boost.Locale](http://www.boost.org/libs/locale/index.html) library. |
|
So you can find exactly the same code in `boost::locale` |
and `booster::locale` namespace. The only difference is |
the namespace. So I strongly recommend reading extensive |
localization tutorials you can find for Boost.Locale |
as they are applicable as-is for CppCMS's `booster::locale`. |
|
So please refer to [Boost.Locale](http://www.boost.org/libs/locale/index.html) documentation for any problems or questions you have. |
|
In this tutorial we would see how Boost.Locale is integrated |
to CppCMS and how to use it for CppCMS development. |
|
## Concepts |
|
All locale related information is hold in `std::locale` object. CppCMS allows to use context specific locale and |
change it according to the needs. |
|
## Example |
|
Lets create a simple web site that greets us in two languages English and Hebrew. |
|
We would have following URLs: |
|
- `/hello` - redirects to `/hello/en_US` |
- `/hello/en_US` - greeting in English |
- `/hello/he_IL` - greeting in Hebrew |
|
We would see how to set the application's locale and |
how to translate different messages from the |
templates and from the application itself. |
|
## Preparing the Sources |
|
### View |
|
Let's define our view's render function |
|
<html> |
<head> |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" > |
</head> |
<% if rtl %> |
<body dir="rtl"> |
<% else %> |
<body> |
<% end %> |
<h1><% gt "We want to say" %></h1> |
<p><%= message %></p> |
<p><a href="he_IL">he</a>/<a href="en_US">en</a></p> |
</body> |
<html> |
|
|
Now let's note different parts step by step: |
|
- Line 3: we use `UTF-8` encoding - which is the recommended default encoding |
- Line 10: `<% gt "We want to say" %>` - show localized message. |
|
"We want to say" would be translated to the locale we |
want to use using special dictionaries or if there is |
no translation - original string would be displayed. |
|
- line 5: `<% if rtl %>` - check if the language is Right-To-Left language like Hebrew. If it is we change the directionality of the text. Using this condition we can also |
alter different layout parameters. |
|
The condition would be true of the "LTR" message is |
translated to "RTL" message in our templates. |
|
|
The rest is the usual. |
|
### Content |
|
It would be very simple: |
|
struct message : public cppcms::base_content { |
std::string message; |
}; |
|
We would see how we would be able to localize the `message` |
as well. |
|
### Controller |
|
We define our `hello` class: |
|
hello(cppcms::service &srv) : |
cppcms::application(srv) |
{ |
dispatcher().assign("^/(en_US|he_IL)/?$",&hello::say_hello,this,1); |
dispatcher().assign("^(.*)$",&hello::redirect,this); |
} |
|
In the first assignment we map between the URL and the function: `say_hello`, we path the locale (he\_IL or en\_US) as a parameter. |
|
We also define a simple redirect function that would redirects use to `en_US` by default: |
|
void redirect() |
{ |
response().set_redirect_header(request().script_name() + "/en_US"); |
} |
|
Now let's see how we handle a language: |
|
void say_hello(std::string lang) |
{ |
context().locale(lang + ".UTF-8"); |
content::message c; |
c.message=translate("Hello World"); |
render("message",c); |
} |
|
First we define current locale as `en_US.UTF-8` or `he_IL.UTF-8`. |
|
Now the correct locale would be associated with |
the output stream and with the current request/response context. |
|
Then we translate a "Hello World" message using |
`cppcms::application::translate(...)` member functions |
that use current `context()`'s locale. |
|
Then we finally render the content. Because |
we setup the correct locale this |
would let the template engine know in which locale |
the message "We want to say" should be translated. |
|
Please note, even when we do not define the locale explicitly, the default system locale would be used |
or the first locale defined in `localization.locales` list. |
|
|
## Extracting Messages |
|
Now when we prepared all the sources we want to |
extract all the messages we want to translate. |
|
Full Boost.Locale tutorial about message translation |
can be found [here](http://www.boost.org/doc/libs/1_48_0/libs/locale/doc/html/messages_formatting.html) but let's |
see the process in few words. |
|
The messages are distributed all over our source code: cpp files templates and so on. We can use `xgettext` tool that |
is a part of `gettext` project to extract such messages, |
however we need to have all C++ sources. |
|
So we need to compile our view: |
|
cppcms_tmpl_cc -d hello view.tmpl -o view.cpp |
|
And then extract the messages from both `view.cpp` and |
our `hello.cpp` using xgettext as following: |
|
xgettext --keyword=translate:1,1t view.cpp hello.cpp |
|
What we get is a file called `messages.po` that would |
look like: |
|
msgid "" |
msgstr "" |
"Project-Id-Version: PACKAGE VERSION\n" |
"Report-Msgid-Bugs-To: \n" |
... |
"Content-Type: text/plain; charset=CHARSET\n" |
"Content-Transfer-Encoding: 8bit\n" |
|
#: view.tmpl:9 |
msgid "LTR" |
msgstr "" |
|
#: view.tmpl:14 |
msgid "We want to say" |
msgstr "" |
|
#: hello.cpp:25 |
msgid "Hello World" |
msgstr "" |
|
|
That includes three messages: |
|
- "LTR" - the directionality of the language. |
- "We want to say" - extracted from the templates |
- "Hello World" - extracted from the sources. |
|
Now we can translate them to Hebrew and create |
a file "hello.po" that looks like: |
|
msgid "" |
msgstr "" |
"Content-Type: text/plain; charset=utf-8\n" |
"Content-Transfer-Encoding: 8bit\n" |
|
#: view.tmpl:6 |
msgid "LTR" |
msgstr "RTL" |
|
#: view.tmpl:11 |
msgid "We want to say" |
msgstr "אנחנו רוצים לומר" |
|
#: hello.cpp:21 |
msgid "Hello World" |
msgstr "שלום עולם" |
|
|
Note: "LTR" is - translated to RTL as Hebrew is right-to-left language. |
|
We create an appropriate directory structure to search |
files in: |
|
locale/he/LC_MESSAGES/ |
|
|
Then we compile it to the binary mo file as: |
|
msgfmt hello.po -o locale/he/LC_MESSAGES/hello.mo |
|
This `hello.mo` file can be used by the localization Engine. |
|
|
## Configuration |
|
Now we need to tell CppCMS what locale to use and were |
to take the localization catalogs: |
|
It is done via configuration file as following: |
|
"localization" : { |
"messages" : { |
"paths" : [ "./locale" ], |
"domains" : [ "hello" ] |
}, |
"locales" : [ "he_IL.UTF-8", "en_US.UTF-8" ] |
} |
|
|
- `localization.messages.paths` specifies the path to |
the `locale` directory the holds `he/LC_MESSAGES/hello.mo` |
catalog. |
- `localization.messages.domains` specifies the catalog name - in our case `hello` and |
- `localization.locales` defines locales we want to support |
in our application. The first one becomes the default |
one. |
|
## Running Our Sample |
|
So once we got following files: |
|
./config.js |
# Configuration File |
./hello |
# Executable |
./locale |
./locale/he |
./locale/he/LC_MESSAGES |
./locale/he/LC_MESSAGES/hello.mo |
# Messages Catalog |
|
|
We can run our application |
|
./hello -c config.js |
|
And see how localization works `:-)` by visiting |
<!--toc-->
|
|
## Introduction
|
|
CppCMS has a sophisticated internationalization and
|
localization support. During CppCMS development localization
|
tools were submitted to [Boost Project](http://www.boost.org)
|
and accepted as [Boost.Locale](http://www.boost.org/libs/locale/index.html) library.
|
|
So you can find exactly the same code in `boost::locale`
|
and `booster::locale` namespace. The only difference is
|
the namespace. So I strongly recommend reading extensive
|
localization tutorials you can find for Boost.Locale
|
as they are applicable as-is for CppCMS's `booster::locale`.
|
|
So please refer to [Boost.Locale](http://www.boost.org/libs/locale/index.html) documentation for any problems or questions you have.
|
|
In this tutorial we would see how Boost.Locale is integrated
|
to CppCMS and how to use it for CppCMS development.
|
|
## Concepts
|
|
All locale related information is hold in `std::locale` object. CppCMS allows to use context specific locale and
|
change it according to the needs.
|
|
## Example
|
|
Lets create a simple web site that greets us in two languages English and Hebrew.
|
|
We would have following URLs:
|
|
- `/hello` - redirects to `/hello/en_US`
|
- `/hello/en_US` - greeting in English
|
- `/hello/he_IL` - greeting in Hebrew
|
|
We would see how to set the application's locale and
|
how to translate different messages from the
|
templates and from the application itself.
|
|
## Preparing the Sources
|
|
### View
|
|
Let's define our view's render function
|
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
|
</head>
|
<% if rtl %>
|
<body dir="rtl">
|
<% else %>
|
<body>
|
<% end %>
|
<h1><% gt "We want to say" %></h1>
|
<p><%= message %></p>
|
<p><a href="he_IL">he</a>/<a href="en_US">en</a></p>
|
</body>
|
<html>
|
|
|
Now let's note different parts step by step:
|
|
- Line 3: we use `UTF-8` encoding - which is the recommended default encoding
|
- Line 10: `<% gt "We want to say" %>` - show localized message.
|
|
"We want to say" would be translated to the locale we
|
want to use using special dictionaries or if there is
|
no translation - original string would be displayed.
|
|
- line 5: `<% if rtl %>` - check if the language is Right-To-Left language like Hebrew. If it is we change the directionality of the text. Using this condition we can also
|
alter different layout parameters.
|
|
The condition would be true of the "LTR" message is
|
translated to "RTL" message in our templates.
|
|
|
The rest is the usual.
|
|
### Content
|
|
It would be very simple:
|
|
struct message : public cppcms::base_content {
|
std::string message;
|
};
|
|
We would see how we would be able to localize the `message`
|
as well.
|
|
### Controller
|
|
We define our `hello` class:
|
|
hello(cppcms::service &srv) :
|
cppcms::application(srv)
|
{
|
dispatcher().assign("^/(en_US|he_IL)/?$",&hello::say_hello,this,1);
|
dispatcher().assign("^(.*)$",&hello::redirect,this);
|
}
|
|
In the first assignment we map between the URL and the function: `say_hello`, we path the locale (he\_IL or en\_US) as a parameter.
|
|
We also define a simple redirect function that would redirects use to `en_US` by default:
|
|
void redirect()
|
{
|
response().set_redirect_header(request().script_name() + "/en_US");
|
}
|
|
Now let's see how we handle a language:
|
|
void say_hello(std::string lang)
|
{
|
context().locale(lang + ".UTF-8");
|
content::message c;
|
c.message=translate("Hello World");
|
render("message",c);
|
}
|
|
First we define current locale as `en_US.UTF-8` or `he_IL.UTF-8`.
|
|
Now the correct locale would be associated with
|
the output stream and with the current request/response context.
|
|
Then we translate a "Hello World" message using
|
`cppcms::application::translate(...)` member functions
|
that use current `context()`'s locale.
|
|
Then we finally render the content. Because
|
we setup the correct locale this
|
would let the template engine know in which locale
|
the message "We want to say" should be translated.
|
|
Please note, even when we do not define the locale explicitly, the default system locale would be used
|
or the first locale defined in `localization.locales` list.
|
|
|
## Extracting Messages
|
|
Now when we prepared all the sources we want to
|
extract all the messages we want to translate.
|
|
Full Boost.Locale tutorial about message translation
|
can be found [here](http://www.boost.org/doc/libs/1_48_0/libs/locale/doc/html/messages_formatting.html) but let's
|
see the process in few words.
|
|
The messages are distributed all over our source code: cpp files templates and so on. We can use `xgettext` tool that
|
is a part of `gettext` project to extract such messages,
|
however we need to have all C++ sources.
|
|
So we need to compile our view:
|
|
cppcms_tmpl_cc -d hello view.tmpl -o view.cpp
|
|
And then extract the messages from both `view.cpp` and
|
our `hello.cpp` using xgettext as following:
|
|
xgettext --keyword=translate:1,1t view.cpp hello.cpp
|
|
What we get is a file called `messages.po` that would
|
look like:
|
|
msgid ""
|
msgstr ""
|
"Project-Id-Version: PACKAGE VERSION\n"
|
"Report-Msgid-Bugs-To: \n"
|
...
|
"Content-Type: text/plain; charset=CHARSET\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
|
#: view.tmpl:9
|
msgid "LTR"
|
msgstr ""
|
|
#: view.tmpl:14
|
msgid "We want to say"
|
msgstr ""
|
|
#: hello.cpp:25
|
msgid "Hello World"
|
msgstr ""
|
|
|
That includes three messages:
|
|
- "LTR" - the directionality of the language.
|
- "We want to say" - extracted from the templates
|
- "Hello World" - extracted from the sources.
|
|
Now we can translate them to Hebrew and create
|
a file "hello.po" that looks like:
|
|
msgid ""
|
msgstr ""
|
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
|
#: view.tmpl:6
|
msgid "LTR"
|
msgstr "RTL"
|
|
#: view.tmpl:11
|
msgid "We want to say"
|
msgstr "אנחנו רוצים לומר"
|
|
#: hello.cpp:21
|
msgid "Hello World"
|
msgstr "שלום עולם"
|
|
|
Note: "LTR" is - translated to RTL as Hebrew is right-to-left language.
|
|
We create an appropriate directory structure to search
|
files in:
|
|
locale/he/LC_MESSAGES/
|
|
|
Then we compile it to the binary mo file as:
|
|
msgfmt hello.po -o locale/he/LC_MESSAGES/hello.mo
|
|
This `hello.mo` file can be used by the localization Engine.
|
|
|
## Configuration
|
|
Now we need to tell CppCMS what locale to use and were
|
to take the localization catalogs:
|
|
It is done via configuration file as following:
|
|
"localization" : {
|
"messages" : {
|
"paths" : [ "./locale" ],
|
"domains" : [ "hello" ]
|
},
|
"locales" : [ "he_IL.UTF-8", "en_US.UTF-8" ]
|
}
|
|
|
- `localization.messages.paths` specifies the path to
|
the `locale` directory the holds `he/LC_MESSAGES/hello.mo`
|
catalog.
|
- `localization.messages.domains` specifies the catalog name - in our case `hello` and
|
- `localization.locales` defines locales we want to support
|
in our application. The first one becomes the default
|
one.
|
|
## Running Our Sample
|
|
So once we got following files:
|
|
./config.js
|
# Configuration File
|
./hello
|
# Executable
|
./locale
|
./locale/he
|
./locale/he/LC_MESSAGES
|
./locale/he/LC_MESSAGES/hello.mo
|
# Messages Catalog
|
|
|
We can run our application
|
|
./hello -c config.js
|
|
And see how localization works `:-)` by visiting
|
<http://localhost:8080/hello> URL. |