Main  /  Edit  /  History  /   /  Users Area

Internationalization and Localization

Introduction

CppCMS has a sophisticated internationalization and localization support. During CppCMS development localization tools were submitted to Boost Project and accepted as Boost.Locale 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 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:

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:

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 user 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 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:

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" ]
}

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.


JSON RPC | Top | Advanced Caching

About

CppCMS is a web development framework for performance demanding applications.

Support This Project

SourceForge.net Logo

Поддержать проект

CppCMS needs You


Navigation

Main Page



Valid CSS | Valid XHTML 1.0