Hello, we apologize but forum registrations are non-functional at this time. This issue should be fixed around mid-December. Until then, please stop by our Discord channel if you'd like to get in touch with the team. Thanks!

Getting gettext & translation into Allacrost

For discussion of the code running behind the game

Moderator: Staff

User avatar
MoOshiCow
Developer
Posts: 18
Joined: Thu Jul 05, 2007 12:42 pm
Location: (currently) Pittsburgh, USA
Contact:

Getting gettext & translation into Allacrost

Post by MoOshiCow » Sat Jul 28, 2007 10:36 pm

Well I've finally got something started with internationalizing Allacrost..

While, I haven't committed anything into subversion yet,
I think I need to organize how all of this translating stuff is going to work out..

This is basically what I have modified so far:
main.cpp -
some initializing code for gettext
utils.cpp -
added a function ustring TranslateString(text, domain)
which takes in the text to be translated and the domain that gettext
will look into (basically the .mo file it will work with..)
and returns a translated ustring of the text

map_dialogue.cpp
the AddText() function now calls TranslateString(text) to
invoke a call to gettext().

And basically we follow one of the gettext tutorials..
to create .po files for our translators to edit:

run the command:

Code: Select all

xgettext dat/maps/*.lua --keyword=AddText
which creates a .po file called messages.po which has extracted all
the strings in the .lua file that calls the AddText() function.
(In other words, all the dialog scripts..)

Then we run:

Code: Select all

msginit -l ko -o dialogue.po -i messages.po
basically the -l flag specifies the language..
the -o flag specifies the output filename..
and the -i is the input filename

now we have a dialogue.po for our ko (korean) translation..

after we...(or i guess this calls for translators!)
use some editing tool to edit the .po file (POEdit was my choice)
we create a dialogue.mo file..(POEdit kind of created one for me..nice of them..)

The command:

Code: Select all

msgfmt dialogue.po
should make a dialogue.mo for us..and the .mo file needs to be in a folder /ko/LC_MESSAGES inside the directory that we specified in the initialization of gettext (main.cpp)..

Right now i have it in a ./po folder..but that can be changed..
I was asked by roots to put it in a folder called "txt" in the demo folder of our subversion directory..
But i guess i'm supposed to ask everyone about adding new folders/files into our subversion directory..
This folder will probably be our standard directory for translation-related files to be in...


So at this point of time..
I got our game to display different dialogs depending on what language you are running your OS as..(got to change this so you can change the language with the program)

we don't have any asian fonts in..so it doesn't display
asian translations correctly...but we're good to go with any language
that uses the english alphabet = D

Well this is the start of the internationalization of Allacrost..
stay tuned for more~
ettin
Junior Member
Posts: 45
Joined: Thu Aug 31, 2006 3:23 pm

Re: Getting gettext & translation into Allacrost

Post by ettin » Tue Jul 31, 2007 12:22 pm

MoOshiCow wrote:Well I've finally got something started with internationalizing Allacrost..
Good.
MoOshiCow wrote:

Code: Select all

xgettext dat/maps/*.lua --keyword=AddText
msginit -l ko -o dialogue.po -i messages.po
msgfmt dialogue.po
Fortunately, all this kind of stuff can be easily automated ;)
I can take a look at the auto* files once this is available in svn trunk.
MoOshiCow wrote: Right now i have it in a ./po folder..but that can be changed..
I was asked by roots to put it in a folder called "txt" in the demo folder of our subversion directory..
Why "txt"? I certainly do not expect translations to be in a folder called like that. (Most gettext based projects use "po" btw, it is kind of standard.)
MoOshiCow wrote: we don't have any asian fonts in..so it doesn't display
asian translations correctly...but we're good to go with any language
that uses the english alphabet = D
http://www.allacrost.org/forum/viewtopic.php?t=1744
User avatar
Roots
Dictator
Posts: 8669
Joined: Wed Jun 16, 2004 12:07 pm
Location: Austin TX
Contact:

Re: Getting gettext & translation into Allacrost

Post by Roots » Sat Aug 04, 2007 11:14 pm

Sorry its taken me so long to respond to this thread, I've been wrapped up in other things.


Everything you said sounds good. I would make the TranslateString() method a member of the GameSettings class. Also the second argument to the method (domain) won't be necessary when attached to the GameSettings class, since GameSettings keeps track of what the currently set domain is. Keep in mind that C++ files also store strings that need to be translated in addition to Lua files. I'm pretty sure that gettext can handle both C++ and Lua source files though. :)

ettin wrote:
MoOshiCow wrote: Right now i have it in a ./po folder..but that can be changed..
I was asked by roots to put it in a folder called "txt" in the demo folder of our subversion directory..
Why "txt"? I certainly do not expect translations to be in a folder called like that. (Most gettext based projects use "po" btw, it is kind of standard.)
Because all of our top level directories are three letter abbreviations (src, dat, snd, mus, img, doc). That's our standard. :) Besides, for most people txt is a lot more obvious about what it contains than po.
Image
rujasu
Developer
Posts: 758
Joined: Sat Feb 24, 2007 10:40 pm
Location: Maryland, USA

Post by rujasu » Sun Aug 05, 2007 12:03 pm

I don't think that there's any two or three letter combination that really suggests "gettext" or "translation" to me. I'd lean toward "po" if that's standard.
User avatar
Roots
Dictator
Posts: 8669
Joined: Wed Jun 16, 2004 12:07 pm
Location: Austin TX
Contact:

Post by Roots » Sun Aug 05, 2007 12:07 pm

rujasu wrote:I don't think that there's any two or three letter combination that really suggests "gettext" or "translation" to me. I'd lean toward "po" if that's standard.
"txt" is obvious that it contains some kind of text (translation text in this specific case). "po" is not obvious at all unless you are already familiar with gettext, which the majority of people here and the people who will play Allacrost, are not.
Image
User avatar
gorzuate
Developer
Posts: 2575
Joined: Wed Jun 16, 2004 9:03 pm
Location: Hermosa Beach, CA
Contact:

Post by gorzuate » Sun Aug 05, 2007 2:30 pm

Roots wrote:
rujasu wrote:I don't think that there's any two or three letter combination that really suggests "gettext" or "translation" to me. I'd lean toward "po" if that's standard.
"txt" is obvious that it contains some kind of text (translation text in this specific case). "po" is not obvious at all unless you are already familiar with gettext, which the majority of people here and the people who will play Allacrost, are not.
I really don't care what we go with. What does po stand for anyway? That just seems weird. But I did want to say that of the people who will play Allacrost, how many of them will be concerned with the directory structure? How many times have you looked at the directory structure of Wesnoth? (An answer of none-to a few times is what I'm looking for here, otherwise my point is moot).
Image
User avatar
Jetryl
Artist
Posts: 1485
Joined: Fri Aug 26, 2005 1:35 am
Location: Southern Minnesota, USA

Post by Jetryl » Sun Aug 05, 2007 9:30 pm

Roots wrote:
rujasu wrote:I don't think that there's any two or three letter combination that really suggests "gettext" or "translation" to me. I'd lean toward "po" if that's standard.
"txt" is obvious that it contains some kind of text (translation text in this specific case). "po" is not obvious at all unless you are already familiar with gettext, which the majority of people here and the people who will play Allacrost, are not.
Players won't be seeing these, and devs are used to having different file extensions for different kinds of files. po is the standard for gettext files, just like .lua is the standard for lua files. PO files are a sort of code/script file; they contain many control statements, which must follow a specific syntax. They are not just a text file. For example, the following is an except from one of wesnoth's .po files:

Code: Select all

#: data/abilities.cfg:44
msgid ""
"Cures:\n"
"A curer can cure a unit of poison, although that unit will receive no "
"additional healing on the turn it is cured of the poison."
msgstr ""
"治療:\n"
"治療者は、毒を受けたユニットを治療することができる。ただし、毒から治療された"
"そのターン内には、さらなる回復は受けられない。"
Let's just use the standard unless we have a damn good reason not to. I think that regular .txt files, such as README, should not have the same extension as translation script files, .po.


http://filext.com/file-extension/PO

PO = GNU Gettext Portable Object
User avatar
Roots
Dictator
Posts: 8669
Joined: Wed Jun 16, 2004 12:07 pm
Location: Austin TX
Contact:

Post by Roots » Sun Aug 05, 2007 10:45 pm

I am perfectly fine with making the files .po (in fact, I expected them to be .po). All that I want is a "txt" directory instead of a "po" directory that holds all the .po files. The same reason we have a "snd/" directory instead of a "wav/" directory, and a "mus/" directory instead of a "ogg/" directory. The directory name describes the type of contents; not the type of file extension.
Image
User avatar
Jetryl
Artist
Posts: 1485
Joined: Fri Aug 26, 2005 1:35 am
Location: Southern Minnesota, USA

Post by Jetryl » Sun Aug 05, 2007 11:50 pm

Roots wrote:I am perfectly fine with making the files .po (in fact, I expected them to be .po). All that I want is a "txt" directory instead of a "po" directory that holds all the .po files. The same reason we have a "snd/" directory instead of a "wav/" directory, and a "mus/" directory instead of a "ogg/" directory. The directory name describes the type of contents; not the type of file extension.
Hmm, if that's the case, sure, I'd be fine with "/txt", though I'd suggest "/trans" for translations.
User avatar
MoOshiCow
Developer
Posts: 18
Joined: Thu Jul 05, 2007 12:42 pm
Location: (currently) Pittsburgh, USA
Contact:

Re: Getting gettext & translation into Allacrost

Post by MoOshiCow » Mon Aug 06, 2007 8:43 pm

Roots wrote: Everything you said sounds good. I would make the TranslateString() method a member of the GameSettings class. Also the second argument to the method (domain) won't be necessary when attached to the GameSettings class, since GameSettings keeps track of what the currently set domain is.
I guess my first question is...
where is this GameSettings class defined..I cant seem to find it --a
or are we talking about the GameSystem class?

also..

I'm not sure, if this is the standard way of doing this..
but I was thinking that we should split up the .po files
according to what category/mode/process it is associated with..
like we have:

dialogue.po - which contains all the strings for character dialogue scripts
boot_menu.po - which contains all the strings for the boot menu to display
game_menu.po - which contains all the strings for the game menu to display

and so on..of course we'll have to decide on what to name each file and such..
but i do think this would be an easier interface for translators than dumping all the translatable strings into one translate.po or something..

So then..I was thinking that the TranslateString() function can take in
a "domain" argument to know which .mo file it needs to look up
when gettext() is called...
(i put quotes around domain...cuz maybe thats not what this actually is supposed to be called..)
User avatar
Roots
Dictator
Posts: 8669
Joined: Wed Jun 16, 2004 12:07 pm
Location: Austin TX
Contact:

Re: Getting gettext & translation into Allacrost

Post by Roots » Mon Aug 06, 2007 9:07 pm

MoOshiCow wrote:
Roots wrote: Everything you said sounds good. I would make the TranslateString() method a member of the GameSettings class. Also the second argument to the method (domain) won't be necessary when attached to the GameSettings class, since GameSettings keeps track of what the currently set domain is.
I guess my first question is...
where is this GameSettings class defined..I cant seem to find it --a
or are we talking about the GameSystem class?
Yeah GameSystem, my bad. It was called GameSettings for a long time and since the two names are familiar, I often slip up.


MoOshiCow wrote: I'm not sure, if this is the standard way of doing this..
but I was thinking that we should split up the .po files
according to what category/mode/process it is associated with..
like we have:

dialogue.po - which contains all the strings for character dialogue scripts
boot_menu.po - which contains all the strings for the boot menu to display
game_menu.po - which contains all the strings for the game menu to display

and so on..of course we'll have to decide on what to name each file and such..
but i do think this would be an easier interface for translators than dumping all the translatable strings into one translate.po or something..
So you're saying we could have an arbitrary number of these .po files, depending on how we want to split it up? I thought the .po files were generated automagically for some reason (ie a .po file is created for each source file which contains translatable text). If that's the case, I suggest we just split things up according to our namespace names. If the translated string is contained within namespace "hoa_map", the .po file will be "map.po".

Of course that just solves the question of where to put the C++ strings. The Lua code isn't in any particular namespace per-say. I think we should probably just create a .po file for each .lua file with translatable text. That means a different .po file for each map. All item translations will be contained in items.po, weapons in weapons.po, etc. for global definition stuff.

Yeah, I think a 1-to-1 scheme with our Lua files and a namespace scheme for our C++ files would do well to form our .po file count. Anyone disagree?
MoOshiCow wrote: So then..I was thinking that the TranslateString() function can take in
a "domain" argument to know which .mo file it needs to look up
when gettext() is called...
(i put quotes around domain...cuz maybe thats not what this actually is supposed to be called..)
When you mentioned domain earlier, I thought domain implied the regional translation (ie english, german, polish, etc.). So it instead means "which file name to lookup the translated string in"? That makes things a little more confusing than I thought they'd be for our code. :eyespin:


Question: do all .po/.mo files (not too sure about the difference yet, but I think .mo is compiled form of .po?) have to be contained within the same directory (e.g. "txt/")? Or can they be in subdirectories, like "txt/maps", "txt/objects", etc?
Image
User avatar
MoOshiCow
Developer
Posts: 18
Joined: Thu Jul 05, 2007 12:42 pm
Location: (currently) Pittsburgh, USA
Contact:

Re: Getting gettext & translation into Allacrost

Post by MoOshiCow » Tue Aug 07, 2007 4:33 pm

Roots wrote: When you mentioned domain earlier, I thought domain implied the regional translation (ie english, german, polish, etc.). So it instead means "which file name to lookup the translated string in"? That makes things a little more confusing than I thought they'd be for our code. :eyespin:
Hmm...so yeah..I'm thinking maybe this is a little confusing..

CURRENTLY:
-instead of adding gettext("string") for every single string that needs to be translated in the .lua files...I went to the source where all the strings are being processed..and called TranslateString() on the variable passed within the program..
So for example, dialogues..
All dialogues call the AddText() function defined in map_dialogue.cpp...so by calling TranslateString(text) within AddText()...i can get the resulting translated string..
Similarly if i wanted to translate the item names, descriptions..
I would go into global_objects.cpp and call TranslateString() and pass the appropriate variable to get the resulted translation..
Which is why i have such a thing as the "domain" variable..

When initiating gettext you can call

Code: Select all

bindtextdomain( "domain name", "./folder that .mo files are in")
This is what allows us to work with multiple .mo files..
The domain name is basically the .mo filename we're working with..

And so for example...we could set up things like:
bindtextdomain("dialogue", "./txt")
bindtextdomain("item", "./txt")

And when we call TranslateString() in map_dialouge.cpp we can pass the domain variable "dialogue" to indicate that we're working with the dialogue.mo file..
Similarly, we pass "item" in global_objects.cpp to indicate we are working with the item.mo file..
and so on..

The plus side of this approach is that we dont have to put gettext("string") or _("string)...
around every single string in our src files and .lua files that needed to be translated..
because we can use variables passed within the program...

But this also means that I cant just simply extract all the translatable strings within one .lua file to one .po file...
because different strings call different functions...and are used by different parts of our program..
So in terms of extracting the strings...it might be a harder task than this second approach..

OTHER APPROACH:

-Put TranslateString("string") around all the strings that need to be translated in src files and .lua files...
-This means i probably need to bind the function TranslateString() using luabind...i think this goes in defs.cpp
-Then we simply extract using xgettext ALL the translatable strings..
-We can probably split them up into multiple .mo files as well
-But we still need to pass TranslateString() a domain name to indicate which .mo file to look up when calling gettext

I think..actually this is closer to what Roots told me to do in this post:
http://www.allacrost.org/forum/viewtopi ... c&start=60

So..I should ask which approach sounds better?

Also on a note to the language like (english, german, polish, etc)
I found out that the environment variable $LANGUAGE
is what determines what gettext considers..so by calling:

Code: Select all

setenv ("LANGUAGE", _language.c_str(), 1);
and setting _lanugage to "ko" for testing purposes..
i was able to get the program to display my "korean" translation
in an English OS setting...so I guess all we need to do is get this into
the boot menu options..
Roots wrote: Question: do all .po/.mo files (not too sure about the difference yet, but I think .mo is compiled form of .po?) have to be contained within the same directory (e.g. "txt/")? Or can they be in subdirectories, like "txt/maps", "txt/objects", etc?
From my testing..I dont think we can create subdirectories..
This is how my txt folder is setup right now:
(if i move the .mo file to any other folder it doesnt seem to work)
(The filenames are just what i made up)

./txt
dialogue.pot
boot.pot
./ko
./LC_MESSAGES
dialogue.po
boot.po
dialogue.mo
boot.mo

something like that..
the general setup is that the .mo file needs to be in:

./txt/$language/LC_MESSAGES/

the difference between .pot files and .po files is that the
.po file has the headers with all the information about the file..
Example:

# Korean translations for Hero of Allacrost - Demo package.
# Copyright (C) 2007 THE Hero of Allacrost - Demo'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Hero of Allacrost - Demo package.
# DongHa Lee <dhlee85@yahoo.com>, 2007.
#
msgid ""
msgstr ""
"Project-Id-Version: Hero of Allacrost - Demo 0.2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-08-03 20:18-0400\n"
"PO-Revision-Date: 2007-08-03 20:23-0400\n"
"Last-Translator: DongHa Lee <dhlee85@yahoo.com>\n"
"Language-Team: Korean <translation-team-ko@lists.sourceforge.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"

So, basically we use the .pot files to create different versions of .po files for different languages..using msginit command mentioned in the first thread of this topic..

And as for .po/.mo they're basically the same thing...
PO files are what translators edit
MO files are what the gettext() functions read, and is the only thing
that needs to be in the specific folder mentioned above..
(the .po file could be somewhere else)
but i put them in the same folder because if you use poEDIT
to edit the .po files they create .mo files in the same folder for you
so it's more convenient to put them in the same folder
Viliam
Contributor
Posts: 35
Joined: Tue Sep 05, 2006 4:25 pm
Location: Bratislava, Slovakia
Contact:

Post by Viliam » Wed Aug 08, 2007 5:32 pm

MoOshiCow, I am not sure why do you want to define functions "TranslateString" and "AddText". Is that only for Lua or also for C++? Traditionally, the translating function is called "_". More precisely, this is a macro for function "gettext". This function is provided by the gettext library.

Please look at this example code. It supports gettext with both C++ and Lua code. And the extracting process is the same for both languages. So maybe you would like to use some of this.


OK, I look forward to translating the next 0.3 demo! ;-)
User avatar
MoOshiCow
Developer
Posts: 18
Joined: Thu Jul 05, 2007 12:42 pm
Location: (currently) Pittsburgh, USA
Contact:

Post by MoOshiCow » Wed Aug 08, 2007 6:14 pm

Viliam wrote:MoOshiCow, I am not sure why do you want to define functions "TranslateString" and "AddText". Is that only for Lua or also for C++? Traditionally, the translating function is called "_". More precisely, this is a macro for function "gettext". This function is provided by the gettext library.
Well AddText() isnt what i added...its what Allacrost lua files call to add dialogue text into our script engine...and has nothing to do with gettext()

And TranslateString("string") is basically a helper function for gettext("string") or _("string")..
or to be precise it is a helper function that calls
dgettext(domain, "string") and also MakeUnicodeString() which is a
function that converts regular strings to ustrings,
which is what Allacrost uses to display text on to the screen

I guess I could simply call MakeUnicodeString(_("string")) for all lua, c++ translatable strings...
but Roots wanted this sort of helper function within our utils..
so i just made this TranslateString() function..

But this is essentially doing what you are describing..just with a helper function..that does some extra things

and when i extract...i could give xgettext --keyword=TranslateString() or something like that to extract the strings..

However...I also found out...you dont have to put _() or TranslateString() around each and every string..
So for the dialogue for example..
since they all call AddText("Some sort of dialouge text here")
I can go to AddText() and call TranslateString(text) where text is the input variable for AddText()..
and then extract the translatable strings by doing:

xgettext dat/maps/*lua --keyword=AddText

but if i do this...since AddText() is called by multiple .lua files..
like...all *.lua files in ./dat/maps/ each have dialogue text in them..

so it wouldnt make sense to create a .po file for each .lua file...
but would make more sense to create something like dialogue.po
for all the strings that call AddText() and such..

So I was asking in the above post...
whether i should change my methods so that it makes more sense to split the .po files for each .lua file...

Otherwise...I could dump all translatable strings into one .po file..and throw away all this "domain" stuff...but i think it would be better if we could organize our translation process a bit = D
Viliam
Contributor
Posts: 35
Joined: Tue Sep 05, 2006 4:25 pm
Location: Bratislava, Slovakia
Contact:

Post by Viliam » Thu Aug 09, 2007 4:05 pm

OK. I think you are right. I just want to note that there will be probably many places where strings can be translated; not only in dialogs. Maybe not now, but later almost surely. For example:

* names of characters (not exactly translations, but at least transliterations into non-Latin alphabets)
* names of enemies
* names of items
* names of spells, abilities
* names of towns

Maybe there will later be more than one dialog type. The standard dialog type could be for speech between characters, but there could be some special dialogs like "You have found a secret location; + 10 experience points." Texts like this could also be in Lua files.


So what I want to say is, that not all translatable texts will appear inside AddText function. So it is probably good to have a separate function like _ for translating only. (Maybe two functions, if you will later also support gettext plural forms.)
User avatar
Roots
Dictator
Posts: 8669
Joined: Wed Jun 16, 2004 12:07 pm
Location: Austin TX
Contact:

Post by Roots » Thu Aug 09, 2007 5:56 pm

Viliam wrote:So what I want to say is, that not all translatable texts will appear inside AddText function. So it is probably good to have a separate function like _ for translating only. (Maybe two functions, if you will later also support gettext plural forms.)
Our equivalent of the "_" function is the TranslateString() function. (I know "_" is a common practice among gettext implementations, but it is a very poor macro name for several reasons).


But yeah, I don't think we should have a separate file for dialogue; it just doesn't make sense. I think there should be a .po file for maps in general (including the map name, NPC names, dialogue, other text such as reporting treasure contents, etc.).


Actually, I'd like to ask for suggestions for our .po file structure (how many should we have, how should they be broken up, etc). Here's my suggestion (and I'm assuming that these can only be placed in a single directory because I think that was stated before):

- engine.po: contains all translations for strings embedded in the C++ code
- objects.po: all translations for global objects (items, weapons, armor, etc)
- actors.po: all translations for characters and enemies
- maps.po: all translations for anything that is contained within Lua map files
- misc.po: contains anything that is not categorized in the above files


I don't have any experience with this so I don't know if its a good idea to have a few files or a lot of files. maps.po will undoubted contain the large majority of the text, so maybe each map should have its own .po file? :shrug: I don't know. Villiam, do you have any suggestions here? You're the only one with real gettext translation experience so your input is invaluable to us. :angel:
Image
Linds
Developer
Posts: 145
Joined: Tue Jan 09, 2007 2:21 am
Location: Sydney, Australia

Post by Linds » Fri Aug 10, 2007 4:37 am

I really think each map should have its own. Maps will be added map by map so constant edits from different sources will make this nightmarish to merge with one file.

Also, _() is so ubiquitous now that using anything else is probably more confusing for the observer.
User avatar
MoOshiCow
Developer
Posts: 18
Joined: Thu Jul 05, 2007 12:42 pm
Location: (currently) Pittsburgh, USA
Contact:

Post by MoOshiCow » Fri Aug 10, 2007 11:09 am

I think splitting up each map file, sounds reasonable..
As mentioned, it's probably easier to add new map files that way..

And for the _(), we can probably just define _ as TranslateString or whatever we're using..
if we feel that _() is more comfortable..
User avatar
gorzuate
Developer
Posts: 2575
Joined: Wed Jun 16, 2004 9:03 pm
Location: Hermosa Beach, CA
Contact:

Post by gorzuate » Fri Aug 10, 2007 11:25 am

I pity the poor translator who would have to deal with one humongous map.po file...
Image
Viliam
Contributor
Posts: 35
Joined: Tue Sep 05, 2006 4:25 pm
Location: Bratislava, Slovakia
Contact:

Post by Viliam » Sat Aug 11, 2007 7:56 am

I think that dividing texts into multiple PO files makes best sense if those files can be translated independently. For example each file would be translated by a different person, with minimum coordination. (Of course some coordination is always necessary, because some words/phrases appear too often, so they will be in each PO file.) Also in situations where context is important, it would be good to separate the contexts.

My experience with multiple PO files is only from Battle for Wesnoth. There the situation is different from here; the game has multiple independent single-player campaigns. So it makes sense to create a PO file for each campaign; and other PO file(s) for campaign-independent texts. It has a side benefit that if packagers choose to make a package with different set of campaigns, they can easily pick only PO files for the used campaigns. Other separate PO files are for tutorial (de facto another single-player campaign), manual, and map editor. The remaining strings are further divided into two PO files, but now I am not sure how is that decided (probably program-specific texts vs content-specific texts).

Even in such "model" situation, placing words in PO files is not 100% certain. For example if there is a standard unit "Elvish Archer" appearing in multiple campaigns, and also multiplayer, it is included into campaign-independent file. If someone makes a unit only for purposes of one campaign, for example "Skeletal Dragon", then this unit belongs to campaign-specific file. But if later someone else likes this unit and decides to use it in another campaign... then either the translation will be duplicated, or the text must be moved to campaign-independent file. In addition to campaign-specific units, there can be campaign-specific items, abilities, and many other things. The position of these is sometimes unknown.


Now largest part of this model is probably unusable for Hero of Allacrost, because here is only "one campaign". The only thing I feel certain about, is to separate the program-specific strings, like the names of buttons, preferences, etc... the texts which do not belong to the game universe (e.g. "Graphical settings", "Full screen", "Save", "Load", "Error reading file %s.")

Next dividing line could be universe-depending strings vs plot-depending strings. (If you imagine that in future there could be multiple campaigns, the division is more visible.) Universe-depending strings are names of monsters and items; plot-depending strings are names of heroes and locations, dialogs, maybe special items. For example "Green Slime", "Short Sword" are plot-independent; "Claudius" and "Laila, what's wrong?" are plot-dependent (they would probably not appear in another plot).


I guess most of you feel that more detailed division will be better, because the PO files will be smaller, and therefore easier to handle. I don't completely agree with this... or more precisely, it depends on relations between strings in these groups. There are two possibilities: either all files will be translated by the same person, or the files will be translated by different persons.

If it is one person, translating 1000 strings in 1 file, or 1000 strings in 10 files is almost the same work. The advantage of having 100 strings per file: it is easier to see what is related to what. But this is partially done by gettext libraries which put strings in PO files in the same order as they appear in source file; so strings from the same map (same Lua file) will be close to each other anyway. So there is an advantage, but it is a small one. Now if the same text will appear in multiple maps, will it be repeated? (Or you could put it to map-independent file. For example dialogs in shops, messages when someone dies,...) Maybe the texts from different maps are related to each other. Map one: "Claudius, go find the Magical Something and use it to open the castle gate!" Map two: "In the middle of magic fountain you see a beautiful shining Magical Something." Map three: "As you wave the Magical Something above your head, you see the castle gate opening..." If this is separated to 3 files, it is not very helpful; and it add a bit work, if I want to do a search whether I have translated "Magical Something" consistently.

If the files are translated by multiple people, then they need some coordination, a shared vocabulary. Otherwise the "Magical Something" from map 1 will be translated as "Magic Thing" in map 2, and maybe "Magician's Item" in map 3. Or worse; if there are two items with similar names, they may receive the same translation.

But on the other hand, there will probably be much more texts in Hero of Allacrost when compared with Battle for Wesnoth. So having one huge file for translating can be very discouraging. So... I have no clear opinion on this. I only say that program-specific strings should be separated, and plot-independent strings probably too.


One argument for using "_" macro/function: It will be probably the most frequently used function in the Lua files. Really, you have to put it before each dialog line, before each displayed text, everywhere except for algorithms. So it would be better if the name is short; easier to write, easier to read -- or more importantly: to skip when reading. You probably would not want 20% of the Lua files to be the word "TranslateString" repeated endlessly. If you really don't like "_", maybe try "T" or "TS" instead.
Post Reply