Interested in a Multilanguage Toolkit for Torque?
by Thomas Huehn · in Torque Game Engine · 01/25/2010 (7:17 pm) · 15 replies
Some month ago I made a Multilanguage Toolkit. It's an Windows program with a database to store the strings, handle different projects and export the needed files UTF-8 encoded:

It works together with the stock TGE LangFile with small modification and includes some script functions to make the life easier.
Example:
To setup the languages, first parameter is the directory and second the languages:
initLangTable("towers/shared/lang","english deutsch");
It set the first language as default and load the others.
In Gui's the text is written in the default language and translated with:
For other translations you could simple make echo(T("Hello")); and it gets translated into the current language. When "Hello" in the Translation-Table, of cause.
In short words it remove the hassle to work with id's in gui and code, because it translate the text. The Application also make it easier to edit multiple languages instead of working in different .lang files.
It's only tested with TGE but I guess it would also work with TGB/T2D, TGEA and T3D.
My final question is would this worth to make a product out of this ?

It works together with the stock TGE LangFile with small modification and includes some script functions to make the life easier.
Example:
To setup the languages, first parameter is the directory and second the languages:
initLangTable("towers/shared/lang","english deutsch");
It set the first language as default and load the others.
In Gui's the text is written in the default language and translated with:
function GuiControl::onAdd(%this)
{
//Auto Translate :D
if (%this.getClassname() !$="GuiTextEditCtrl")
LangPrepareSingleGuiControl(%this);
}For other translations you could simple make echo(T("Hello")); and it gets translated into the current language. When "Hello" in the Translation-Table, of cause.
In short words it remove the hassle to work with id's in gui and code, because it translate the text. The Application also make it easier to edit multiple languages instead of working in different .lang files.
It's only tested with TGE but I guess it would also work with TGB/T2D, TGEA and T3D.
My final question is would this worth to make a product out of this ?
About the author
Contact: torque [AT] ohmtal [DOT] com
#2
01/25/2010 (9:04 pm)
That looks like a really nice idea :D
#3
I could see this 'greatly' improving multi-language support for TGE and any games developed. :)
01/25/2010 (10:07 pm)
Awesome work Thomas!I could see this 'greatly' improving multi-language support for TGE and any games developed. :)
#4
By the way... nice to see a developer from germany (like me). Or austria/switzerland?
01/26/2010 (3:46 am)
It is perfect for games like RPG's where the developer has to handle a huge amount of text. Can the text be multiline? By the way... nice to see a developer from germany (like me). Or austria/switzerland?
#5
I've changed the database from paradox to sqlite. It's written in delphi and paradox tables need the borland database engine so I thought sqlite would be better.
I prepared it to add it as a resource, when I found out it's not possible to add an file attachment to a resource like it was in the past :(
@thomas
It does not support multiline, but for ml-text you could do a <br>. For long text like the help files I used separated files. And, yes I'm from germany ;)
01/28/2010 (6:42 am)
Thanks for replies. I've changed the database from paradox to sqlite. It's written in delphi and paradox tables need the borland database engine so I thought sqlite would be better.
I prepared it to add it as a resource, when I found out it's not possible to add an file attachment to a resource like it was in the past :(
@thomas
It does not support multiline, but for ml-text you could do a <br>. For long text like the help files I used separated files. And, yes I'm from germany ;)
#6
01/28/2010 (7:55 am)
Have a look around for a link to eb's public Torque file system. He announced it in one of his blogs - it's a kind of ad-hoc replacement to hosting files here ;).
#8
What you have to keep in mind is the player of the game itself. They should not have a chance to edit the text. Only the developer of the game.
01/28/2010 (4:11 pm)
@Thomas Huehn: Instead of using the BDE you could use ODBC. But i am not sure how flexible it is. I tried it with Delphi and Microsoft Access and it worked fine. What you have to keep in mind is the player of the game itself. They should not have a chance to edit the text. Only the developer of the game.
#9
05/13/2010 (6:48 am)
@Thomas Huehn: Any progress? I would definitely be interested in this tool.
#10
05/13/2010 (9:54 am)
Now that is cool! I would be interested in this myself.
#11
05/13/2010 (10:11 am)
Hmm.. hey, you know what would be cool.. if we could keep a rather large common, general db with multiple languages. :) I could translate into Hungarian - I know the demand for Hungarian translation would be huge. :)
#12
So here it is, please report suggestion and bugs here ;)
1.) Language String Editor (LSE)
This tool helps with managing the strings and script creation. It can handle multiple projects and support up to 30 different languages per project.
It exports [LANGUAGE].cs and [LANGUAGE].lang to the destination directory and compile the .lang files to .lso with the stock langc.exe.
The langc.exe is not included. You must copy it from you torque/tools directory to the directory where LSE is located.
2.) Engine changes:
To make translation easier we need to add a function to LangFile and LangTable:
In lang.h add:
To the public sections of class LangFile and class LangTable.
In lang.cc add after:
Add After:
this
You also should add a bugfix to LangFile::~LangFile():
05/13/2010 (12:13 pm)
Sorry I prepared everything in january and while I was busy I forgot to post it. I hope I did not forget anything in order to get it work.So here it is, please report suggestion and bugs here ;)
1.) Language String Editor (LSE)
This tool helps with managing the strings and script creation. It can handle multiple projects and support up to 30 different languages per project.
It exports [LANGUAGE].cs and [LANGUAGE].lang to the destination directory and compile the .lang files to .lso with the stock langc.exe.
The langc.exe is not included. You must copy it from you torque/tools directory to the directory where LSE is located.
2.) Engine changes:
To make translation easier we need to add a function to LangFile and LangTable:
In lang.h add:
S32 getIdFromString(const UTF8 *str);
To the public sections of class LangFile and class LangTable.
In lang.cc add after:
const UTF8 * LangFile::getString(U32 id)
{
if(id == LANG_INVALID_ID || id >= mStringTable.size())
return NULL;
return mStringTable[id];
}this:S32 LangFile::getIdFromString(const UTF8 *str)
{
for (U32 i = 0; i<mStringTable.size(); i++) {
if (dStricmp(str,mStringTable[i]) == 0)
return i;
}
return -1;
}Add After:
const UTF8 *LangTable::getString(const U32 id) const
{
const UTF8 *s = NULL;
if(mCurrentLang >= 0)
s = mLangTable[mCurrentLang]->getString(id);
if(s == NULL && mDefaultLang >= 0 && mDefaultLang != mCurrentLang)
s = mLangTable[mDefaultLang]->getString(id);
return s;
}this
const S32 LangTable::getIdFromString(const UTF8 *str) const
{
S32 result = -1;
if(mDefaultLang >= 0)
result = mLangTable[mDefaultLang]->getIdFromString(str);
return result;
}You also should add a bugfix to LangFile::~LangFile():
LangFile::~LangFile()
{
// [tom, 3/1/2005] Note: If this is freed in FreeTable() then when the file
// is loaded, the language name will be blitzed.
// Programming after 36 hours without sleep != good.
//XXTH FIX! SAFE_DELETE(mLangName);
// SAFE_DELETE(mLangFile);
SAFE_DELETE_ARRAY(mLangName);
SAFE_DELETE_ARRAY(mLangFile);
freeTable();
}
#13
3. Script functions
Create a file, lets say langtool.cs and place it in common/shared for example and then include it in common/main.cs.
05/13/2010 (12:16 pm)
..... continuation ...... 3. Script functions
Create a file, lets say langtool.cs and place it in common/shared for example and then include it in common/main.cs.
//------------------------------------------------------------------------------
// Lang tool!
//------------------------------------------------------------------------------
/*
initLangTable
==============
Init LangTable and set $GLOBALS::LANGUAGES for use in gui.
Example
exec("common/shared/langtool.cs");
initLangTable("towers/shared/lang","english deutsch");
*/
function initLangTable(%path,%languages)
{
$GLOBALS::LANGUAGES = %languages;
%cnt = getWordCount(%languages);
if (%cnt == 0)
return false;
// Init Language tool:
$I18N::DEFAULT = new LangTable();
%default = getWord(%languages,0);
exec(%path @ "/" @ %default @ ".cs");
for (%i=0; %i<%cnt; %i++)
$I18N::DEFAULT.addLanguage(%path @ "/" @ getWord(%languages,%i) @ ".lso", getWord(%languages,%i));
$I18N::DEFAULT.setDefaultLanguage(0);
$I18N::DEFAULT.setCurrentLanguage(0);
if ($pref::langID $= "" || $pref::langID >= %cnt)
$pref::langID = 0;
if ($pref::langID != 0 )
$I18N::DEFAULT.setCurrentLanguage($pref::langID);
}
//------------------------------------------------------------------------------
function setNewCurrentLanguage(%id)
{
if ($pref::langID == %id || !isObject($I18N::DEFAULT))
return false;
$pref::langID = %id;
$I18N::DEFAULT.setCurrentLanguage(%id);
return true;
}
//------------------------------------------------------------------------------
// Translate! Stupid short Name *lol*
function Tr(%id)
{
$I18N::DEFAULT.getString(%id);
}
function T(%string)
{
if (!isObject($I18N::DEFAULT))
return %string;
%id = getLangIDfromString(%string);
if (%id >= 0)
return $I18N::DEFAULT.getString(%id);
else if (isDebugBuild() && !$Game::DisableTranslationWarning )
error("CANT FIND TRANSLATION FOR:" SPC %string);
return %string;
}
//------------------------------------------------------------------------------
function getLangIDfromString(%string)
{
return $I18N::DEFAULT.getIdFromString(%string);
}
//------------------------------------------------------------------------------
// THIS MUST HAVE ALL VARIABLES IN STYLE $L_[NO] starting with 1!
// can be called on GuiControl::OnAdd :D
function LangPrepareSingleGuiControl(%gui)
{
%gui.langTableMod = "DEFAULT";
if (%gui.text !$= "")
{
%id = getLangIdfromString(%gui.text);
if (%id >=0)
%gui.TextID = "L_" @ (%id+1);
}
// now look at tool tip:
if (%gui.tooltip !$= "")
{
%id = getLangIdfromString(%gui.tooltip);
if (%id >=0)
%gui.tooltip = Tr(%id);
}
}
//------------------------------------------------------------------------------
// THIS MUST HAVE ALL VARIABLES IN STYLE $L_[NO] starting with 1!
function LangPrepareGui(%gui, %initial)
{
if (%initial)
%gui.langTableMod = "DEFAULT";
if (%gui.text !$= "")
{
%id = getLangIdfromString(%gui.text);
if (%id >=0)
%gui.TextID = "L_" @ (%id+1);
}
if (%gui.getCount() > 0) //recursive walk the gui!
for (%i = 0; %i< %gui.getCount(); %i++)
LangPrepareGui(%gui.getObject(%i), false);
}
#14
4.) Usage:
After you exported with LSE and included the previous scripts you are able to use it like this:
Second parameter is a blank separated list of the languages you have and want to use. First language must be the default language.
With setNewCurrentLanguage(%id) you are able to switch to a other language. %id = 0 is the default language and %id = 1 would be "deutsch" in the previous example.
In script you can now use T("Hello") and it will get translated into the current language.
To automatic translate the gui controls you need to add:
Note:
I ported LSE to use sqlite instead of paradox database so it is not that well tested.
Current Download URL is dl.ohmtal.eu/files/tools/lse_20100128.zip
I you find it useful donations are welcome ;) auteria.com/index.php?c=donation
05/13/2010 (12:18 pm)
..... continuation ......4.) Usage:
After you exported with LSE and included the previous scripts you are able to use it like this:
initLangTable("towers/shared/lang","english deutsch");First parameter is the relative directory to the place where the language files are exported.Second parameter is a blank separated list of the languages you have and want to use. First language must be the default language.
With setNewCurrentLanguage(%id) you are able to switch to a other language. %id = 0 is the default language and %id = 1 would be "deutsch" in the previous example.
In script you can now use T("Hello") and it will get translated into the current language.
To automatic translate the gui controls you need to add:
function GuiControl::onAdd(%this)
{
//Auto Translate :D
if (%this.getClassname() !$="GuiTextEditCtrl")
LangPrepareSingleGuiControl(%this);
}Note:
I ported LSE to use sqlite instead of paradox database so it is not that well tested.
Current Download URL is dl.ohmtal.eu/files/tools/lse_20100128.zip
I you find it useful donations are welcome ;) auteria.com/index.php?c=donation
#15
First question (Answered): How do you add another language using the tool? ... "Insert" - got it, only button I didn't try yesterday!
Second question: In regard to automatically translating text objects ... the "function GuiControl::onAdd(%this) .. " function is working and being called for text that is being added. I can't seem to get any text to automatically update, any ideas? or do you need more info?
Sorry if these are answered somewhere else but I couldn't find the answer. Any help would be appreciated.
Thanks!
05/23/2011 (5:07 pm)
I have a couple of questions, hopefully they are silly and someone can answer them quickly. I just got this translation tool working with the current project I am working on (T3D).First question (Answered): How do you add another language using the tool? ... "Insert" - got it, only button I didn't try yesterday!
Second question: In regard to automatically translating text objects ... the "function GuiControl::onAdd(%this) .. " function is working and being called for text that is being added. I can't seem to get any text to automatically update, any ideas? or do you need more info?
Sorry if these are answered somewhere else but I couldn't find the answer. Any help would be appreciated.
Thanks!
Torque Owner JakeT
Magellan Interactive LLC