Translating

From Multi Theft Auto: Wiki
Revision as of 19:47, 20 December 2010 by EAi (talk | contribs) (Created page with "It's proposed that we have a way of translating MTA into different languages, and allowing our community to contribute their translations. ==How== The library ''gettext'' seems ...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

It's proposed that we have a way of translating MTA into different languages, and allowing our community to contribute their translations.

How

The library gettext seems to be the standard way of doing this, at least in the Linux world.

Writing our own seems to be a bad idea - we don't know enough about languages to do this.

The code

Gettext works by wrapping strings in calls to the gettext function. So:

[c++]
Print ( "Press Q to shut down the server!\n" );

Becomes:

[c++]
Print ( gettext("Press Q to shut down the server!\n") );

Though, we probably don't want to include new line characters, so it becomes:

[c++]
Print ( "%s\n", gettext("Press Q to shut down the server!"));

Plus, it can be convenient to have a shorthand, and it seems that defining _ as gettext is conventional, so you end up with:

[c++]
Print ( "%s\n", _("Press Q to shut down the server!"));

Maybe we should make a short hand version of Print that always does a new line?

Generating the translation template

From the code you can generate the template that lists the strings that need to be generated. gettext comes with a tool for this, and I've wrapped it up in a script that makes it more convenient. It's currently utils/build_gettext_catalog.py (though not yet committed).

This scans all the cpp and h files in the MTA10 and MTA10_SERVER directories and passes them into the xgettext executable which generates a pot file, which looks something like the following:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2010-12-20 19:27+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. Couldn't load our mod
msgid "Press Q to shut down the server!"
msgstr ""

Notice that comments from the code are extracted and placed above the strings, so we can provide guidance for what each string's purpose is.

Editing

The template itself isn't edited, I think. You can create a copy of it and generate a new translation by filling in the msgstr strings. There are editors, such as the cross platform poedit that deals with these files and handles various useful things such as validating them and merging them when new strings are added to the template. This seems pretty easy to use. It notices things such as missing formatting specifiers (%s etc) in strings.

Once you've edited the file, you can save it as a .po file. This is basically identical to the .pot file, just has translations in it.

These files are turned into .mo files which are compiled versions. Poedit does this for you, but I've made a script that does it in the utils directory.

Where?

I've placed the translations in a root Translations directory (alongside MTA10 and MTA10_SERVER). The translations are shared between client and server, I'm not sure if this is a good or bad thing, but it could be changed. It might save work and disk space somewhat, though we probably want the translations to be placed in the server and client directories anyway.

Making it work

To make it work, you link against libintl.lib (in vendor/gettext/libs) and have the dll libintl3.dll along side the executables.

Currently I've only tested this in the CServerImpl.cpp file, adding this at the top:

[c++]
#include <libintl.h>
#define _ gettext

Then this in the constructor:

[c++]
char* s = setlocale(LC_ALL, "");
bindtextdomain("messages", "translations/"); // specifies the directory to look in
textdomain( "messages");

Files

We would ship the .mo files. Each language would have a directory in the Translations directory, e.g. en_US, fr_FR etc, inside which is a directory LC_MESSAGES, inside which is a messages.mo file. We can't really change anything except where this directory is and what the .mo file is called, the locale and the LC_MESSAGES directories have to be there. It seems.