View Single Post
Author Message
SniperBeamer
AMX Mod X Founder
Join Date: Jun 2003
Location: Good Old Europe
Old 07-30-2004 , 17:38   Multi-Lingual System
#1

This writeup is intended to introduce users to how AMX Mod X 0.20's Multi-Lingual system works. If you are not a developer, you can probably disregard this.

I. Overview
II. Scripting
III. Modules
IV. Implementation

I. Overview

The AMX Mod X Multi-Lingual system is designed for optimized formatting of phrases to be delivered to clients. Each plugin and module is responsible for "reinforcing" a set of dictionary translations which can be used across many AMX Mod X functions. Each server sets a default language for translations to take place, and clients may set their own language as a setinfo ("_language").

AMX Mod X 0.20 will come with a plugin that allows users to select their language upon joining a server, if they do not already have one set. The Admin Menu will also let you choose the server's default language.
Language definitions are stored as formatted strings inside a "dictionary file". A dictionary file is a simple text file that looks like this (we'll call this one "greetings.txt"):
Code:
[en]
Hello = Hello, %s!
Bye = Goodbye, %s!
[es]
Hello = Hola, %s!
Bye = Adios, %s!
[de]
Hello = Guten Tag, %s!
Bye = Auf Wiedersehen, %s!
Three options are available for formatting - %s (String), %d (integer number), %f (float/decimal number). Dictionary files are loaded by plugins and cached by the AMX Mod X core.

II. Scripting
Dictionary Text Files are "reinforcements" for the master dictionary - which is an optimized binary file stored in the data folder. A plugin should make sure their definitions are already registered in the master dictionary with "register_dictionary", like so:
Code:
public plugin_init() {    register_plugin("Language Test", "1.0", "BAILOPAN")    register_dictionary("greetings.txt") }
For more information on how this works, see the Implementation section.
To format a message to a certain language phrase, there is a new descriptor available for all commands which accept the style of "format" (such as client_print, server_print, et cetera). The descriptor is L and is used like so:
Code:
format(buffer[], maxLength, "%L", clientID, languageKey[], [ ... ])
Here is an example:
Code:
public client_putinserver(id) {    new name[24]    get_user_name(id, name, 24)    client_print(id, print_chat, "%L", id, "Hello", name) }
Taking this step by step:
1. "%L" tells the string formatter to start a language translation. "%L" must always occur by itself like it is here.
2. "id" tells the language translation to use the language of the specific client "id". The client's setinfo _language is read, and if no language is found, the server's default is used (cvar amxx_language).
3. "Hello" tells the language translation to look up the definition for "Hello" (case insensitive). The definition from our dictionary is "Hello, %s" if the client is using English.
4. "name" tells the language translation to insert the client's name into the translation string as the first parameter (%s). This will result in "Hello, !".
5. The final formatted string is sent to the client. There are special exceptions to this rule. This will send a message to all clients in their own language:
Code:
client_print(0, print_chat, "%L", LANG_PLAYER, key[], [ ... ])
This will send a message to all clients in the server's language:
Code:
client_print(0, print_chat, "%L", LANG_SERVER, key[], [ ... ])
The special modifier -1 is only useable in functions that apply to
all users. Note that you cannot do something like:
Code:
//This is illegal, %L must appear alone. client_cmd(0, print_chat, "echo %L", id, "Hello", name)

Also, as a side note, the "id" parameter can be the two letter code for a language, like "en" or "de", although most of the time this will be unnecessary.

Lastly, there are some commands you will most likely never need to
use. They are:
Code:
// Return the number of languages loaded native get_langsnum(); // Return the name of a loaded language (0 to x-1) // two letter code native get_lang(id, name[3]); //registers a dictionary file, making sure the words are in the dictionary // the file should be in "addons/amxx/data/lang/", but only the name  needs to be // given.  (e.g. register_dictionary("file.txt") will be addons/amxx/data/file.txt). native register_dictionary(const filename[]); //returns 1 if the language is loaded, 0 otherwise. native lang_exists(const name[]);

III. Module Functions

The AMX Mod X MDK (Module Development Kit) has been updated with
two new functions:
Code:
void MF_MergeDefinitionFile(const char *file);
void MF_MergeDefinition(const char *language, const char *key, const char *definition);
Also, MF_FormatAmxString() can now accept the "%L" format listed above.

IV. Implementation
All dictionary results are cached in memory and on the disk in a binary file called "languages.dat", in addons/amxx/data or datadir. It's optimized for lookup by storing key pairs of hashes to offsets. More information will be available on this later.

Credits:
PM OnoTo, BAILOPAN, original concept by T(+)rget
__________________
SniperBeamer is offline