i18n - ryzom/ryzomcore GitHub Wiki


title: Internationalization description: published: true date: 2023-03-01T05:16:45.102Z tags: editor: markdown dateCreated: 2022-03-07T10:50:58.243Z

There are three tools you can use in implementing internationalization in NeL-based applications. There's the CI18N class, the STRING_MANAGER and finally unicode string class ucstring which was covered in an earlier section. The ucstring class is useful for providing unicode strings but in and of itself performs no internationalization.

The CI18N Class

The CI18N class is probably the most useful internationalization tool provided by NeL. A quick introduction to this in the form of code will illustrate how easy it is to use this tool:

Internationalization Sample

fr.uxt

// This is the name of the language.
LanguageName    [Français]
Hi                              [Bonjour]
PresentI18N             [%s est fière de vous présenter le système d'internationalisation de NeL]
ExitStr                 [Appuyez sur <entrée> pour quitter]

en.uxt

// This is the name of this language.
LanguageName    [English]
Hi                              [Hello]
PresentI18N             [%s is proud to present you NeL Internationalisation system]
ExitStr                 [Press <return> to exit]

sample.cpp

int main (int argc, char **argv)
{
	createDebug();
	InfoLog->displayRawNL("Please, choose 'en', 'fr' or 'de' and press <return>");

	std::string langName;
	std::getline(std::cin, langName);

	// load the language
	CI18N::load(langName);

	InfoLog->displayRawNL(CI18N::get("Hi").toString().c_str());
	InfoLog->displayRawNL(CI18N::get("PresentI18N").toString().c_str(), "Nevrax");
	InfoLog->displayRawNL(CI18N::get("ExitStr").toString().c_str());
	getchar();

	return EXIT_SUCCESS;
}

As you can see above you only need to create a key-value pair for a string ID (in the example this is referenced in the get() method) and the internationalized string.

Internationalization File Format

The file format for the NeL internationalization system is pretty simple but is very powerful. It allows you to comment your files as well as providing you a powerful preprocessing system. These files should always be named languagecode.uxt where valid language codes are flexible but good examples are en, fr, and de as seen in the sample above.

Labels and and label texts are the core component and most important part of the file format. As soon in the above example and following examples a label is the first set of alphanumeric characters on the line. The label text is indicated by enclosing it following label with the [ and ] characters. Label text can have newlines in them, allowing the response to be several lines long. You can also indicate the use of things or explain the purpose behind the file using comments. Comments come in the form of simple C-style comments.

In addition to a useful comment system the file format also has a system of preprocessor definitions. These allow you some limited programmatic flexibility (through defines and if-statements) as well as tremendously useful include system. It is important to note that the if-statements adhere to scope and therefore can be nested. Listed below are the available preprocessor definitions. The preprocessor if-statements have increased importance when using the #optional statement as well as the load proxy (discussed in the section about the CI18N class) as these inject some dynamics into the loading of your internationalization strings.

The system disables preprocessing by default - you will need to implement an CI18N::ILoadProxy class and use the setLoadProxy() method so that you can calls readTextFile() with your own arguments. See the discussion below about load proxies.

Preprocessor Command Description and Use
#include filename Includes the file specified into the internationalization file at the point this command is specified.
#optional filename Includes the filed specified into the internationalization file at the point this command is specified, however the file inclusion is optional and does not error if the file is not found.
#define value Inserts value into a list of predefined values.
#ifdef value If value is defined (see #define) then start a new scope, otherwise bypass loading labels between this statement and the corresponding #endif.
#ifndef value If value is defined (see #define) then start a new scope, otherwise bypass loading labels between this statement and the corresponding #endif.
#endif Ends an if-statement scope.

Using the CI18N Class

The CI18N class is a relatively simple string manipulation class. In the example provided above we saw how simple it was to load a flat file, specify the current language code, and then begin getting internationalized strings. In a typical application you will first load a translation file using the load(languageCode) method and then use the get(labelName) method to retrieve translated strings. The get() method returns a ucstring and can contain printf style tokens (e.g. %s.) In the above example you saw how we used printf tokens to send the translated string and arguments to a variable argument method such as printf or nlinfo.

There are a couple handy helper methods that you may find yourself using. The most commonly used is the hasTranslation(labelName) method. This is a quick way of checking to see if a label is available before you attempt to use it, especially if the label's availability is governed by and #optional include or one of the various if-statement preprocessor definitions. One thing that is important to note if you are a long-time NeL user is that the getLanguageNames() method is no longer in the API. NeL lifted the artificial limitation of language codes.

One of the last large features of this system is the "load proxy" interface. The internationalization system allows you to proxy string loading into a custom class that implements the CI18N::ILoadProxy interface. This is used to bypass the default call to the readTextFile() method. Using an implementation of this interface you can call the readTextFile() method how you see fit, process the file text before you load it, or load in custom text using the readTextBuffer() method. There are a few common reasons for doing this such as loading the file and then merging "newer" data from a server or overriding the parameters to readTextFile() so that it performs preprocessing.

The STRING_MANAGER Utility - TODO

ddd

Source

⚠️ **GitHub.com Fallback** ⚠️