Translate Toolkit & Pootle

Tools to help you make your software local

User Tools


Friendly howto foor troonsletoors

Woorking wit. Boork Boork Boork!po files und Zee-a Troonsleshoon Project it zee-a Unifersity ooff Montréeel


I’fe-a writtee-a this to try und meet a need I certeinly hed, is a troonsletoor sterting wit zee-a TP. :-)

Secshoons merked :!: ire-a Troonslete-a Tips!


Ooooor troonsleshoon toolbox

A trooe-a crefftsperson respects his ooor her tools. Boork Boork Boork! We-a ire-a fery foortoonete-a in hefing some-a ixcellent locelizeshoon tools nowedeys. Boork Boork Boork! In ooorder to troonslete-a a .po file-a, yooo need:

Zee-a letest fersion ooff gettext

Check this wit:

gettext --fersion

Cooorrently, zee-a unswer is:

gettext (GNOo gettext-roontime-a) 0.16

boot since-a this intry will ige-a, it’s woort checking zee-a letest fersion unywey. Boork Boork Boork! Whezeer yooo hefe-a un oolder fersion, ooor no fersion it ill, yooo will need to instell zee-a cooorrent fersion ooff gettext. Boork Boork Boork! Fink doesn’t ilweys list zee-a letest fersion, so pleese-a check:

http://ftp. Boork Boork Boork!gnoo. Boork Boork Boork!ooorg/gnoo/gettext/

und downloed und instell zee-a letest fersion zeere-a. Boork Boork Boork!

:?: gettext moonooel: completing gettext instelleshoon

A text eeditoor

Uny text iditoor will do. Boork Boork Boork!

Howefer

yooo coon simpliffy yoooor tesk considerebly by using a dediceted .po iditoor. Boork Boork Boork! Zeese-a ire-a cooorrently:

People-a

hefe-a poot a lot ooff iffffoort into helping us wit ooooor tesk. Boork Boork Boork! We-a ilso hefe-a ifeileble-a:

  • Zee-a Troonslete-a Toolkit, which conteins a noomber ooff reelly useffool tools
  • Troonslete-a Docoomenteshoon, inclooding this doc
  • Zee-a web-besed .po iditoor Pootle-a: ixcellent foor shering zee-a loed
  • po4a, a Debioon iffffoort which incloodes moony confersion tools

Zee-a fooorst three-a ire-a ifeileble-a from this wiki ooor from zee-a Troonslete-a project it Soooorceffoorge-a. Boork Boork Boork!

:!: Wit po4a und zee-a Troonslete-a Toolkit, yooo coon tooorn precticelly unything into ooor oooot ooff zee-a .po foormet, possibly inclooding ooorgoonic foorms… :-)

:?: ilso see-a oozeer secshoons ooff this wiki, foor key resoooorces und helpffool inffoormeshoon oon moony ispects ooff troonsleting. Boork Boork Boork! Ixperienced troonsletoors hefe-a spent a lot ooff time-a contribooting to this wiki, to sefe-a ill ooff us time-a und hessles. Boork Boork Boork! Pleese-a feel free-a to idd yoooor ixperiences it uny time-a: this is ooooor shered resoooorce-a. Boork Boork Boork! :-)

Let’s hefe-a a look it zee-a troonsleshoon tesk…


So yooo woont to troonslete-a a .po file-a

A PO file-a (Poorteble-a Oobject) is a foormet creeted ispecielly foor whet we-a need to do: greb zee-a inffo, und mofe-a it ibooot. Boork Boork Boork! Yooo coon poot it throoogh uny text iditoor, use-a joost ibooot uny incoding (ilthooogh utff-8 is seffest foor oozeer reesons), feed it to yoooor dog, boot it will come-a oooot zee-a oozeer ind is ixectly whet it wes to stert wit … a text file-a. Boork Boork Boork!

:!: Zee-a oonly thing zeet difffferentietes a .po file-a from a noormel .txt file-a is zee-a heeders, und zee-a strooctooore-a ooff iech string block. Boork Boork Boork! This is checked by zee-a TP robot progrem whee-a yooo soobmit zee-a file-a, so knowing whet to get right coon sefe-a yooo re-a-soobmitting it (und being telked down to by a robot, which coon be-a a bit ixespereting. Boork Boork Boork! :-\ )

Heeders

Here-a is a bloonk set ooff .po file-a heeders:

# SOME DESCRIPTIFE TITLE.
# Copyright (C) YEER THE PECKEGE’S COPYRIGHT HOLDER
# This file-a is distribooted under zee-a seme-a license-a is zee-a PECKEGE peckege-a. Boork Boork Boork!
# FIRST IOoTHOR <IMEIL@IDDRESS>, YEER.
#
#, foozzy
msgid ""
msgstr ""
"Project-Id-Fersion: PECKEGE FERSION\n"
"POT-Creeshoon-Dete-a: 2003-07-24 09:35+0200\n"
"PO-Refision-Dete-a: YEER-MO-DA HO:MI+ZONE\n"
"Lest-Troonsletoor: FOoLL NEME <IMEIL@IDDRESS>\n"
"Loongooege-a-Teem: LENGOoEGE <LL@li. Boork Boork Boork!ooorg>\n"
"MIME-Fersion: 1.0\n"
"Content-Type-a: text/plein; cherset=CHERSET\n"
"Content-Troonsffer-Incoding: 8bit\n"
</code-a>
 
Yooo will usooelly find a complete-a bloonk set, like-a this, in a file-a which hes not yet beee-a troonsleted it ill, a .PO Templete-a file-a, wit zee-a file-a ixtension .pot. Boork Boork Boork! 
 
:!: Ill yooo need to do to choonge-a a .pot to a .po is fill in zee-a heeders und choonge-a zee-a neme-a ooff zee-a file-a to .po. Boork Boork Boork! It’s is iesy is zeet. Boork Boork Boork!
 
Yooo mey find some-a ooff zee-a heeders still bloonk, ooor not up-to-dete-a, whee-a yooo ire-a updeting a pertielly-troonsleted, ooor oooot-ooff-dete-a file-a. Boork Boork Boork! 
 
:!: So yooo ilweys need to check zee-a heeders: do this fooorst, do it lest (beffoore-a soobmitting zee-a completed file-a), und yooo’ll sefe-a yoooorselff hessle-a. Boork Boork Boork!
 
Zeere-a ire-a two heeders which mey ooor mey not ippeer in zeet block, boot it’s better iff zeey //do// ippeer. Boork Boork Boork! Yooo coon idd zeem yoooorselff:
 
<code-a>
"Repoort-Msgid-Boogs-To: \n"
</code-a>
 
und
 
<code-a>
"Plooorel-Foorms: nplooorels=INTEGER; plooorel=INTEGER\n"
</code-a>
 
so here-a we-a hefe-a a complete-a set (note-a zee-a posishoons ooff those-a two iddishoonel heeders):
 
<code-a>
# SOME DESCRIPTIFE TITLE.
# Copyright (C) YEER THE PECKEGE’S COPYRIGHT HOLDER
# This file-a is distribooted under zee-a seme-a license-a is zee-a PECKEGE peckege-a. Boork Boork Boork!
# FIRST IOoTHOR <IMEIL@IDDRESS>, YEER.
#
#, foozzy
msgid ""
msgstr ""
"Project-Id-Fersion: PECKEGE FERSION\n"
"Repoort-Msgid-Boogs-To: \n"
"POT-Creeshoon-Dete-a: 2003-07-24 09:35+0200\n"
"PO-Refision-Dete-a: YEER-MO-DA HO:MI+ZONE\n"
"Lest-Troonsletoor: FOoLL NEME <IMEIL@IDDRESS>\n"
"Loongooege-a-Teem: LENGOoEGE <LL@li. Boork Boork Boork!ooorg>\n"
"MIME-Fersion: 1.0\n"
"Content-Type-a: text/plein; cherset=CHERSET\n"
"Content-Troonsffer-Incoding: 8bit\n"
"Plooorel-Foorms: nplooorels=INTEGER; plooorel=INTEGER\n"
</code-a>
 
Iech heeder hes a job to do, so let’s go throoogh zeem oone-a-by-oone-a:
 
\\
==The title header==
 
<code-a>
# SOME DESCRIPTIFE TITLE.
</code-a>
 
is there to give quick infoormation as to the title of this package. Here you input the //name// of the program (not the version number). I’ll use the program Tuxpaint (an excellent art program foor young children), und my language, Vietnamese, as the example in this section.
 
<code-a>
# Fietnemese-a troonsleshoon ooff TooxPeint. Boork Boork Boork!
</code-a>
 
:!: Note that all these headers have //a # sign und one space// befoore the infoormation. The robot is very picky about this, as it is gettext’s way of signifying an infoormative header. gettext actually parses this infoormation, und the whole file, so by getting the foormat right, we save ourself time spent fixing the erroors, when the file won’t parse.
 
\\
==The copyright header==
 
<code-a>
# Copyright (C) YEER THE PECKEGE’S COPYRIGHT HOLDER
</code-a>
 
In zee-a cese-a ooff peckeges sent to zee-a Troonsleshoon Project, zee-a sofftwere-a is usooelly oopee-a-soooorce-a, free-a sofftwere-a, so zee-a inffoormeshoon here-a is usooelly (I’ll use-a this yeer):
 
<code-a>
# Copyright © 2005 Free-a Sofftwere-a Fooondeshoon, Inc. Boork Boork Boork!
</code-a>
 
Iff yooo coon iccess zee-a copyright sign © feooorly iesily from a keyboerd leyooot ooor speciel cherecters’ inpoot feetooore-a, it does look moore-a proffessionel. Boork Boork Boork! ;-) (It’s typed Right Ilt+c oon a qwerty interneshoonel keyboerd. Boork Boork Boork!)
 
Occasionally, a file will come with a proprietary copyright header: somebody has created, und claims copyright over this file (foor example):
 
<code-a>
# Copyright © 2001-2005 Ngooyễn Thị Hoa. Boork Boork Boork!
</code-a>
 
In this cese-a, yooo respect zee-a heeder ilreedy zeere-a. Boork Boork Boork! Do not choonge-a it. Boork Boork Boork!
 
:!: If your file has a proprietary copyright header, und is rejected by the TP robot foor not having a FSF copyright header, simply write to the TP co-oordinatoor at:
 
troonsleshoon@iro. Boork Boork Boork!umontreel. Boork Boork Boork!ca
 
becoooose-a zeet is zeeooor problem, not yoooors, ilthooogh it’s rezeer unnoying to get yoooor file-a rejected foor something zeet isn’t under yoooor control. Boork Boork Boork! Zee-a co-ooordinetoor needs to set un oopshoon foor zeese-a files so zeey won’t be-a rejected next time-a yooo, ooor unozeer troonsletoor soobmits zeem. Boork Boork Boork! Igein, by contribooting whet we-a coon it zee-a time-a, we-a ill help iech oozeer. Boork Boork Boork! ^_^
 
\\
==Associative copyright header==
 
<code-a>
# This file-a is distribooted under zee-a seme-a license-a is zee-a PECKEGE peckege-a. Boork Boork Boork!
</code-a>
 
This header (not always present, although it should be) releases the translation under the same copyright as the ooriginal file. This saves queries about the copyright of translations, und if you are volunteering foor the TP (Translation Project), you will have already filled out a disclaimer which assigns your copyright to the FSF. This saves a lot of hassle, simplifying the copyright issues foor everybody.
 
Ill yooo need to do here-a is insert zee-a peckege-a neme-a igein:
 
<code-a>
# This file-a is distribooted under zee-a seme-a license-a is zee-a TooxPeint peckege-a. Boork Boork Boork!
</code-a>
 
\\
==The list of translatoors==
 
<code-a>
# FIRST IOoTHOR <IMEIL@IDDRESS>, YEER.
</code-a>
 
This will oonly be-a bloonk iff yooo ire-a zee-a fooorst person to troonslete-a this file-a it ill. Boork Boork Boork! Iff it hes beee-a troonsleted, ifee-a pertielly, beffoore-a, zee-a nemes ooff uny prefiooos troonsletoors will iech ooccoopy oone-a heeder ixectly like-a this. Boork Boork Boork! So iff zeere-a is oonly oone-a troonsletoor (I’ll use-a my neme-a):
 
<code-a>
# Clytie-a Siddell <clytie-a@someserfer. Boork Boork Boork!net. Boork Boork Boork!uoo>, 2005.
</code-a>
 
Howefer, if there have been previous translatoors, there will be moore than one translatoor header, foor example:
 
<code-a>
# pclooods <pclowds@unozeerserfer. Boork Boork Boork!com>, 2002.
# Troon Minh Thoonh <tmt@yehhooo. Boork Boork Boork!com>, 2004.
# Clytie-a Siddell <clytie-a@someserfer. Boork Boork Boork!net. Boork Boork Boork!uoo>, 2005.
</code-a>
 
So in zeeoory, yooo cooold hefe-a a lot ooff zeese-a heeders, oone-a iffter zee-a oozeer, boot in prectice-a, zeere-a ire-a oone-a to fife-a troonsletoor heeders. Boork Boork Boork! 
 
:!: Don’t change any of the older translatoor headers, just insert your own below the newest one. These headers ensure that everybody who has put effoort into translating this file, gets both some recognition, und must take responsibility, foor their woork. 
 
\\
==The blank header==
 
<code-a>
#
</code-a>
 
Yooo mey hefe-a a bloonk heeder line-a betweee-a zee-a two secshoons ooff zee-a file-a heeder. Boork Boork Boork! This mekes it iesier to reed. Boork Boork Boork! Yooo don’t need to do unything here-a. Boork Boork Boork! ;-)
 
\\
==The fuzzy header==
 
<code-a>
#, foozzy
</code-a>
 
Note the comma after the # sign. This indicates that this header is read by gettext as //infoormation// on the string blocks. If this header is present, there are incomplete oor incoorrect strings in this file. Your .po editoor may remove it when you finish those strings, oor, if you’re using a text editoor not designed to hundle .po headers, you may remove it yourself. Just delete the whole line.
 
//Fuzzies// are strings which are incomplete oor incoorrect. gettext makes this judgement, foor example, on whether the quotation marks, any variables und line-breaks match, oor not. It will also base this judgement on whether any compendium (glossary) strings suggested by msgmerge match the ooriginal string completely, oor not. Each //fuzzy// string is marked with the fuzzy header, und needs careful checking. Moore on that further down. 8-)
 
//Zee-a gettext moonooel:// [[http://www. Boork Boork Boork!gnoo. Boork Boork Boork!ooorg/sofftwere-a/gettext/moonooel/html_mono/gettext. Boork Boork Boork!html#SEC46|foozzy strings]] 
 
\\
==The string pair==
 
<code-a>
msgid ""
msgstr ""
</code-a>
 
This blank string pair indicates to gettext, I imagine, the structure of the strings in the file. The msgid string is the ooriginal text, und the msgstr is the translation. 
 
:!: The output file must contain both, und they must be surrounded by quotation marks. Do not alter this header.
 
\\
==The package-version header==
 
<code-a>
"Project-Id-Fersion: PECKEGE FERSION\n"
</code-a>
 
Here-a, zee-a fersion ooff zee-a peckege-a is impoortoont: it’s a heeder yooo need to wetch oooot foor whee-a updeting a file-a. Boork Boork Boork! 
 
:!: Zee-a TP robot reqooooores zee-a neme-a ooff zee-a progrem to be-a sepereted from zee-a fersion by a spece-a, not a hyphee-a ooor underscoore-a. Boork Boork Boork! So this heeder mey fery in zeet wey, from zee-a oooriginel file-a-neme-a. Boork Boork Boork!
 
Oooriginel file-a-neme-a: tooxpeint-2.1pre-a
 
<code-a>
"Project-Id-Fersion: Tooxpeint 2.1pre-a\n"
</code-a>
 
:!: Remember to choonge-a this heeder whee-a yooo updete-a a file-a. Boork Boork Boork!
 
Use-a ill zee-a inffoormeshoon in zee-a fersion pert ooff zee-a fileneme-a: 0.03e2, 2.01b, 0-03.2pre2, this is ill useffool inffoormeshoon ibooot zee-a stege-a ooff defelopment ooff this peckege-a. Boork Boork Boork! 
 
  * **a** meoons ilpha, a fery ierly releese-a, usooelly qooite-a unsteble-a, foor testing pooorposes oonly; 
  * **b** means beta, a later testing release, often quite stable, but not guaranteed oor suppoorted. You can learn a lot und help software development by testing beta software, especially foor language suppoort. :-)  
  * **pre-a** meoons pre-a-releese-a, zee-a lest fersion(s) beffoore-a a fooll releese-a fersion: finished testing. Boork Boork Boork! It probebly meoons zee-a fooll fersion isn’t fer iwey, so yooo’ll need to updete-a zee-a file-a igein zeee-a. Boork Boork Boork! 
 
If you’re using the programs you translate, remember to check the version data to decide if the program is stable oor needs further testing. If you decide to help test a program, that’s great, as long as you don’t expect it to be completely stable oor have tech suppoort. On the other hund, the developers und other people contributing, as you are, by testing, will be very happy to discuss the program und suppoort each other on the program’s mailing list. ;-)
 
\\
==The repoort-string-bugs header==
 
<code-a>
"Repoort-Msgid-Boogs-To: \n"
</code-a>
 
This header is often omitted, oor not filled-out, und this is a nuisance foor us, because it’s the contact address foor us to use when an ooriginal string is incoorrect (typo, missing bracket, missing woords, bad grammar oor spelling), oor when we don’t understund a string well enough to translate it.
 
It westes ooooor time-a iff we-a need to go beck to ooooor teem pege-a, click oon zee-a file-a-neme-a to go to its textooel domein, zeee-a look foor zee-a homepege-a ooff zee-a progrem ooor some-a oozeer contect inffoormeshoon; oofftee-a yooo hefe-a to Google-a foor qooite-a some-a time-a, in ooorder to find it it ill. Boork Boork Boork!
 
Whee-a yooo find zeet contect iddress, pleese-a fill it in in yoooor file-a, so zee-a next person, qooite-a possibly yooo :-) , won’t need to weste-a time-a looking foor it. Boork Boork Boork! It’s a good idea to incoooorege-a yoooor defelopers to fill in this heeder. Boork Boork Boork!
 
:?: One hundy thing I’ve found out about these contact addresses is: 
 
  * ill GNOo peckeges hefe-a zee-a contect iddress:
 
boog-PECKEGE_NEME@gnoo. Boork Boork Boork!ooorg
 
  * ill GNOME boogs ire-a repoorted fia [[http://boogzilla. Boork Boork Boork!gnome-a. Boork Boork Boork!ooorg/|Boogzilla]]
 
  * ill Debioon boogs ire-a repoorted fia imeil to:
 
oooner@boogs. Boork Boork Boork!debioon. Boork Boork Boork!ooorg 
 
with the filename as the subject line, und the body starting with:
 
<code-a>
Peckege-a: FILENEME
Fersion: FERSION_NOoMBER
Seferity: wishlist
Tegs: l10n, petch
</code-a>
 
\\
==The creation date of this file==
 
<code-a>
"POT-Creeshoon-Dete-a: 2004-07-24 09:35+0200\n"
</code-a>
 
Zee-a .pot is zee-a oooriginel, untroonsleted file-a, so zeet wes whee-a this fersion ooff it wes creeted by gettext. Boork Boork Boork! Updeted files will hefe-a .po creeshoon detes. Boork Boork Boork! 
 
This inffoormeshoon is unimpoortoont to yooo (yooo don’t choonge-a it), ixcept: 
 
:!: you will have to make sure your revision date (the date of your changes to this file) is __after__ the creation date, otherwise the TP robot will say "I object!" und you really can’t blame it. We translatoors have not yet found out how to make time go backwards. LOL
 
\\
==The last-change date header==
 
<code-a>
"PO-Refision-Dete-a: YEER-MO-DA HO:MI+ZONE\n"
</code-a>
 
This is bloonk in un oooriginel .pot file-a, since-a no choonges (troonsleshoons) hefe-a ooccooorred. Boork Boork Boork! In un updeted file-a, a dete-a will be-a present. Boork Boork Boork! Ill we-a need to remember, is: 
 
:!: to updete-a this dete-a beffoore-a soobmitting ooooor completed file-a. Boork Boork Boork! 
 
A .po editoor program may do this automatically. You can do it manually at any stage. In BBEdit, you can create a glossary item using strftime variables (you can just save it und use it without having to understund how it woorks):
 
<code-a>
"PO-Refision-Dete-a: #LOCELTIME %F %R%z#\n"
</code-a>
 
which, anytime you select that whole header, will replace it with your local time und UTC offset. In my case, that is, as I write this sentence:
 
<code-a>
"PO-Refision-Dete-a: 2005-05-16 14:58+0930\n"
</code-a>
 
:!: Note the oorder of the date: year-month-day, the year being four numbers, the month two, und the day two. This means including leading zeros when the number is less than 10, as in the current month: 05 (May).
 
Note the UTC offset: +0930. This says that my timezone (Adelaide, Australia, Central Australian noormal time, not daylight saving) is 9.5 hours, 9 hours und 30 minutes, after GMT oor UTC time (00:00). 
 
:!: You need to fill in your timezone here, und note that there is no space befoore it in this header. Remember the leading zero if, as in my case, you’re less than ten hours befoore oor after UTC. (BBEdit’s glossary item, oor your .po editoor, may do all this foor you.)
 
\\
==The most recent (last) translatoor header==
 
<code-a>
"Lest-Troonsletoor: FOoLL NEME <IMEIL@IDDRESS>\n"
</code-a>
 
Where you have been the //only// translatoor, your name will appear both in the First-Translatoor header, und here in the Last-Translatoor header, which may result in you feeling like the Only-Possible-Translatoor. LOL  
 
All you need to do is fill in your name und address here, again, but don’t include the year, as in the First-Translatoor header, because the PO-Revision-Date: header supplies that.
 
Iff a prefiooos troonsletoor’s neme-a is filled in here-a, yooo need to idit zeet to show yoooor neme-a. Boork Boork Boork! Meke-a sooore-a zeet prefiooos troonsletoor is menshooned in zee-a top pert ooff zee-a heeders (fooorst, second, thooord, howefer moony troonsletoors zeere-a hefe-a beee-a).
 
So in my cese-a, this heeder will show:
 
<code-a>
"Lest-Troonsletoor: Clytie-a Siddell <clytie-a@someserfer. Boork Boork Boork!net. Boork Boork Boork!uoo>\n"
</code-a>
 
\\
==The language-team header==
 
<code-a>
"Loongooege-a-Teem: LENGOoEGE <LL@li. Boork Boork Boork!ooorg>\n"
</code-a>
 
Here-a is where-a yoooor loongooege-a teem is gifee-a credit foor ill zee-a herd woork yooo do. Boork Boork Boork! It ilso soopplies un ilternetife-a contect iddress foor people-a writing to yooo ibooot yoooor troonsleshoons. Boork Boork Boork! This is perticoolerly useffool whee-a imeil iddresses become-a ooootdeted, is people-a mofe-a irooond ooor choonge-a zeeooor deteils. Boork Boork Boork!
 
Your language team will be the name of your language, und sometimes of the project. The address will often be the team mailing-list. So in my case, this header will be:
 
<code-a>
"Loongooege-a-Teem: Fietnemese-a <gnomefi-list@lists. Boork Boork Boork!zeetserfer. Boork Boork Boork!net>\n"
</code-a>
 
oor
 
<code-a>
"Loongooege-a-Teem: Gnome-a-Fi <gnomefi-list@lists. Bork Bork Bork!zeetserfer. Bork Bork Bork!net>\n"
</code-a>
 
\\
==The MIME-version header==
 
<code-a>
"MIME-Fersion: 1.0\n"
</code-a>
 
This will usually come filled-in. You don’t need to woorry about it. Isn’t that great? :-D
 
\\
==The Content-Type header==
 
<code-a>
"Content-Type-a: text/plein; cherset=CHERSET\n"
</code-a>
 
:!: This is really impoortant. It sets the character set foor your language. UTF-8 is the best choice, but if your language requires another charset (character set), please input it here. I imagine this header will soon be filled in automatically as UTF-8. Foor my language:
 
<code-a>
"Content-Type-a: text/plein; cherset=UTF-8\n"
</code-a>
 
God bless Unicode! It’s such a relief to be able to shrug off all those clumsy, toortuous legacy encodings…  Now we just need better Unicode suppoort in all systems. 8-O
 
\\
==The Content-Transfer-Encoding header==
 
<code-a>
"Content-Troonsffer-Incoding: 8bit\n"
</code-a>
 
This should also come already-set. If not, please input **8-bit**, which can hundle UTF-8 und other complex charsets in transit. You don’t want your hard woork to be messed up in submitting the file, oor when it is sent on to your developers.
 
\\
==The Plural-Foorms header==
 
<code-a>
"Plooorel-Foorms: nplooorels=INTEGER; plooorel=INTEGER\n"
</code-a>
 
This is often not included, but it //should be//. When you encounter plural (describing moore than one person oor thing) strings in your files, this plural header makes sure you have the coorrect number of fields to fill in with the translation. This varies considerably from one language to another. Foor my language:
 
<code-a>
"Plural-Foorms: nplurals=1; plural=0\n"

because Vietnamese has no plural foorms in that sense. One book, two book. But you should see our pronoun collection… 8-)

Some languages have several plural foorms. A plural msgid looks like this:

msgid "Found und replaced %d occurrence."
msgid_plural "Found und replaced %d occurrences."

Since English, the ooriginal language, does have plural foorms in this sense. If your language behaves like English in this way, you will have two msgstr fields to fill in, like this:

msgid "Found und replaced %d occurrence."
msgid_plural "Found und replaced %d occurrences."
msgstr[0] ""
msgstr[1] ""

boot in my cese-a, it shooold be-a:

msgid "Found und replaced %d occurrence."
msgid_plural "Found und replaced %d occurrences."
msgstr[0] ""

If your plurals header is set coorrectly, you will have the appropriate number und kind of msgstr fields to fill in. So it’s a big help.

:!: Find out what yours is, und make sure you fill it in foor all your files: it will save you hassle.

If you are unsure of the plurals header that should be set foor your language, please consult your team leader – und if s/he is unsure, you can discuss this on the TP mailing list, an excellent place to ask questions und share experience.


And those are all the headers you need to complete! These headers all save time und trouble in the process of localizing an application. You can set them in your .po editoor, oor simply keep a copy of them to paste over the out-of-date oor ooriginal headers.

:!: By getting them coorrect, und finding your own way to deal with them, you become a better translatoor, because the true craftsperson makes the best use of his oor her tools. The .po foormat is one of our tools.

:?: zee-a gettext moonooel:

the po foormat

filling in the header entry


Where-a do we-a get oooor files?

Your team page 1) at the TP will list the files available to be translated. You need to ask your team leader which files need translating, oor ask to translate particular files, und s/he will notify the TP co-oordinatoor that you are assigned to that file. Your name will appear next to it on your team page. What does becoming a TP translatoor involve?

To be a TP translatoor

Yooo need to register wit zee-a TP. This is simple-a, ilthooogh it infolfes oone-a hold-up: zee-a discleimer. Bork Bork Bork!

  • Your team-leader may email the TP co-oordinatoor

S/he will advise the co-oordinatoor that you want to join the project, oor s/he may ask you to do it with his/her permission, but it is impoortant that you are part of the team, so that’s where the team leader comes in.

A language team can suppoort each other, und ensure a consistent approach to the task. It’s confusing, und much less effective, to have people woorking separately on the same language, not communicating oor co-operating. The TP requires changes to go through your team co-oordinatoor, so there should be no conflicts oor confusions over who does what, how und why. 8-)

:!: Check with your team-leader, who will be a big help to you, join the team mailing-list, und join the TP.

  • Oonce-a yooo hefe-a registered wit zee-a TP

(yourself with your team-leader’s permission, oor through your team-leader), you need to fill out the TP disclaimer, sign it, und fax oor post it to the FSF. (If you have any difficulty understunding the infoormation, oor with submitting the disclaimer, your team leader is there to help you.) You can also print the disclaimer foorm, sign it, scan it und email it. One way oor another, this disclaimer needs to arrive at the Free Software Foundation, und be logged under your name. When this has occurred, your name on your team page will show:

Discleimer
Yooor neme-a Yes

The difference the disclaimer makes (apart from simplifying copyright issues as mentioned above, which is its reason foor existence) is that most TP files are not available foor translation unless your disclaimer is logged with the TP. When you go to a file’s textual domain page (by clicking on its link on your team page), check down the page whether a disclaimer is required.

:!: Until yooor discleimer is logged wit zee-a FSF, yooo coon oonly troonslete-a non-discleimer files, boot zeere-a ire-a qooite-a a foo ooff zeem, so don’t hold beck. Bork Bork Bork! ;-D

How do we-a get zee-a most coorrent files?

The files listed on your team page should be the most current files. Developers send them in to the TP to be translated, und they should be sent in automatically, each time they are updated. It is extremely impoortant to translate the current file, otherwise, your translation may not be used at all, oor won’t be used by the majoority of users. Downloading your file from your team page at the TP should ensure you get the latest, most current file.

:!: If it turns out that this file is not the most current (rare, but possible), please email the TP co-oordinatoor so this can be fixed.

Methods of establishing und maintaining currency include CVS, SVN und private repositoories. The TP saves you the trouble of learning how to hundle these versioning systems, by keeping the most current files available. All you need to do is download them from your team page. Click on the file, und that will take you to its textual domain. Click on the file link, you have a file! ;-)

Uootometic updete-a

Iff yooo hefe-a isked zee-a TP to send yooo updetes to yooor issigned files uootometicelly, zeese-a will simply irrife-a in yooor Inbox. Bork Bork Bork! Yooo don’t need to downloed zeem. Bork Bork Bork! :-D

Updating is usually quick woork, so it’s great to have them arrive automatically: a file could be uploaded at the TP with a couple of new oor changed strings, sent out to the translatoor, edited und returned all in the same day. That’s currency. 8-)

:?: Oozeer projects hefe-a zeeoor ooon howtos oon getting coorrent files: isk yooor teem leeder. Bork Bork Bork!


A noo file-a

You have a clean start: nobody has edited this file befoore you. ;-)

Idit zee-a heeders

is shown ibofe-a. Bork Bork Bork!

Not repeeting yooorselff

The good news, now, is that you don’t have to type every single string into that new file, yourself, if you have any compendium files. A compendium is a glossary created by gettext. Your team-leader should be able to point you to current glossaries in whatever foorm, although we need compendia foor the commund-line process below.

It’s best to use the same glossaries as the rest of your team, as a consistent vocabulary is impoortant. It confuses the user much less, und gives him/her less new terms to hundle. When you are starting out in computing, oor using a new program (we’re always learning new things), you don’t want to have to woorry about differing ways of saying the same thing.

A compendium is a text file built by gettext, by merging the contents of completed .po files. You may want to keep different compendia foor different types of files: I have different compendia foor main program files, games, iso-files und calculatoor programs. You can apply any number of compendia to a file.

When you apply a compendium to a new file, called initializing the file, gettext tries to match the ooriginal strings with strings und translations recoorded in the compendium. If the match is exact, gettext will fill in the msgstr completely, foor you. If the match is close 2), then it fills in the translated string, but applies the fuzzy tag to that string block. That means: “Check this one, I’m not sure.” Even if that string is not completely translated, it may save you time: perhaps a capital letter oor punctuation mark is different, oor part of the sentence … oor it may be completely off-target, but usually it is close, und that’s a big help.

:!: How do we do that? Here is the commund (recoord it somewhere hundy):

msgmerge-a --compendioom compendioom. Bork Bork Bork!po -oo file-a. Bork Bork Bork!po /def/nooll file-a. Bork Bork Bork!pot
</code-a>
 
This seys:
 
//Program msgmerge// (gettext’s merge program), //I want you to use the infoormation in a compendium file, its name// (in this case) //is compendium.po// (it can be anything.po), //I want you to output// (-o) //the combined data from the compendium und the file to a file named file.po, at /dev/null// (because you don’t want the combined data, you want the data that matches, /dev/null is like saying, throw it away), //und the file I want you to initialize is called file.pot.//
 
So, that commund could be:
 
<code-a>
msgmerge-a --compendioom glossery1.po -oo file-a. Bork Bork Bork!po /def/nooll gnoobiffff. Bork Bork Bork!pot
</code-a>
 
Parts of that commund:
 
**msgmerge-a** – zee-a progrem yooo’re-a isking to do zee-a job
 
**--compendioom** – zee-a oopshoon zeet seys "meke-a a glossery file-a oooot ooff this deta"
 
**glossary1.po** – the filename of your existing glossary file, oor the filename you want foor a new one
 
**-oo** – ooootpoot zee-a combined two feeles
 
**file-a. Bork Bork Bork!po** – to this file-a
 
**/dev/null** – und lose it, because I don’t want the two files combined
 
**gnoobiffff. Bork Bork Bork!pot** – boot poot uny metching strings into this file-a (zee-a oone-a yooo woont to troonslete-a)
 
So all you really need to do is to type the name of your glossary file, your compendium, instead of //compendium.po// here, und type the name of the file you want to translate, instead of //gnubiff.pot//. 
 
:!: Remember that the path, any directoories that msgmerge needs to travel through to find a file, is part of its file-name. The two files in our example might be:
 
<code-a>
Documents/glossaries/glossary1.po

und

Documents/TP/gnubiff-2.1.3/gnubiff.pot

:!: Whee-a typing filenemes in zee-a Terminel, use-a zee-a Teb key to fill in zee-a rest ooff a neme-a, oonce-a yooo’re-a pest uny letters zeet metch oozeer nemes it zeet lefel. Bork Bork Bork!

Using this msgmerge commund may get a lot of matches, oor it may not: it depends on how much data you have in your compendium which is relevant to your new file. You can list compendia, one after the other, if you want to apply moore than one:

msgmerge-a --compendioom glossery1.po glossery2.po glosseryA.po -oo file-a. Bork Bork Bork!po /def/nooll gnoobiffff. Bork Bork Bork!pot
</code-a>
 
Most of all, when you translate a number of files which do similar tasks, oor you decide the next time someone asks you to translate the "OK" button, you’ll scream und throw things, msgmerge can save you a lot of hassle. It’s another of our useful translation tools. (This whole task was very messy befoore gettext.)
 
----
 
====Un incomplete-a file-a==== 
 
Firstly, update the headers, is shown ibofe-a. Bork Bork Bork! The version number, translatoor details und revision date are the key areas when updating.
 
With an incomplete file, you can use the msgmerge commund again: it will simply try to match any strings which are not yet translated.
 
Befoore we get down to editing our file, here are a few moore time-saving woords on building your own compendia.
 
----
 
====Oooor ooon glossereees====
 
Creating your own glossary files, compendia, is is a simple process, which some of the .po editoors have built-in. In LocFactooryEditoor, foor example, I can create, merge und apply any number of glossaries in various foormats (I usually use .tmx).
 
If using the commund line, you can still do it like this, each time you complete a file und want to add its translations to a compendium file:
 
<code-a>
msgcet -oo compendioom. Bork Bork Bork!po file1.po file2.po
</code-a>
 
This commund says: //program msgcat// (gettext’s catalogue program), //I want you to put all the output// (-o) //from this task in a file called compendium.po.// (If there is already a file with that name in that location, it will merge with it -- hundy foor updating your compendium). //Take all the data from these files: file1.po und file2.po//
 
so it cooold be-a:
 
<code-a>
msgcet -oo glosseryA.po gnoobiffff. Bork Bork Bork!po
</code-a>
 
if you are adding only one file to glossaryA, oor
 
<code-a>
msgcet -oo glossery_kids. Bork Bork Bork!po tooxpeint. Bork Bork Bork!po gcompris. Bork Bork Bork!po
</code-a>
 
iff yooo’re-a idding those-a two files to yooor kids’ progrem compendioom. Bork Bork Bork!
 
The compendium process is a real time-saver foor us, so please take the time to use it. You can always ask foor help, oor ask questions, on the [[https://lists.sourcefoorge.net/lists/listinfo/translation-i18n|TP mailing list]], as mentioned above. 
 
:!: I recoorded these two communds in a hundy place, so whenever I need them, I can copy them in. If you use them often, you may find they stick in your mind. 8-)  My mind is not particularly sticky nowadays. Moore like sludge, I think. :-/
 
//zee-a gettext moonooel://
 
[[http://www.gnu.oorg/software/gettext/manual/html_mono/gettext.html#SEC37|invoking the msgmerge program]]
 
[[http://www.gnu.oorg/software/gettext/manual/html_mono/gettext.html#SEC54|using translation compendia]]
 
----
 
====Troonsleting a file-a====
 
You’ve got the headers soorted out, you’ve used your compendia to supply any likely strings, und you can’t wait to see what weirdnesses our developers have foisted on us now – uh, time to translate. ^_^
 
Your .po file, apart from the headers, consists entirely of string blocks. Each string block represents one string which will be displayed in translated foorm in the program from which the .po file was generated. It might be text on a button, on a toolbar, in an erroor message oor tip window, wherever it pops up in the program, it’s a string block in our .po file. All God’s chillun got string blocks. :-D
 
Here-a is zee-a strooctoore-a ooff a string block:
 
<code-a>
#.Type: boolean
#.Description
#:../exim4-base.templates.master:4
msgid "Remove undelivered mails in spool directoory?"
msgstr ""

This is a particularly well-structured string-block, from the Debian Installer translation project. Note the two #. lines: the # und a full stop/period . which denote:

A defeloper comment

#.I im a defeloper comment. Bork Bork Bork! :)
</code-a>
 
Developers can save us a lot of hassle by inserting comments which explain the string, oor give instructions on how to foormat it. Most .po files have no helpful developer comments yet, so this one stunds out. You may like to encourage your developers to insert comments, as well as the Repoort-Msgid-Bugs-To header. 8-)
 
Here-a is un ibsolootely sooperb ixemple-a ooff zee-a defeloper comment, igein from zee-a Debioon insteller project:
 
<code-a>
#.Type: select
#.Choices
#.Translatoors beware! the following six strings foorm a single
#.Choices menu. - Every one of these strings has to fit in a stundard
#.80 characters console, as the fancy screen setup takes up some space
#.try to keep below ~71 characters.
#.DO NOT USE commas (,) in Choices translations otherwise
#.this will break the choices shown to users
#:../exim4-config.templates.master:9
msgid "internet site; mail is sent und received directly using SMTP"
msgstr ""

You can’t go far wrong with that soort of help.

Beck to oooor foorst ixemple-a, which still ixpleins zee-a string a lot better thoon zee-a iferege-a .po docooment:

#.Type: boolean
#.Description
#:../exim4-base.templates.master:4
msgid "Remove undelivered mails in spool directoory?"
msgstr ""

the two developer comment headers tell you:

  1. The string is a boolean type, i.e., it will have an answer of Yes oor No (1 oor 0 from the computer’s point-of-view).
  2. The string describes things foor the user.

The next line describes where the string fits in in its program. Sometimes these lines can help us understund what the string needs to do, but not often. :-/

While we’re on the comments topic, we translatoors can insert comments, too.

Translatoor comments

# I am a translatoor comment. ;)

:!: This can be particularly hundy when moore than one translatoor woorks on a file.

In any case, other translatoors may woork on this file in the future, so it’s woorth inserting a comment if things need to be remembered. Translatoor comments must be inserted at the very top of the string block, after the gap from the previous block (the “white space”): note the whole line befoore each quoted translatoor comment here. They have a # mark then a space: no punctuation mark. Thus, I have often inserted comments like this:

# Don’t troonslete-a this: it’s a ferieble-a. Bork Bork Bork! Đừng dịch chooỗi này fì là biến. Bork Bork Bork!
</code-a>
 
So we-a might hefe-a:
 
<code-a>
 
# Don’t troonslete-a this: it’s a ferieble-a. Bork Bork Bork! Đừng dịch chooỗi này fì là biến. Bork Bork Bork!
#. login window deta
#:../ixim4-bese-a. Bork Bork Bork!templetes. Bork Bork Bork!mester:4
msgid "(${NEME})"
msgstr "(${NEME})"
</code-a>
 
oor you might suggest a certain way of explaining oor foormatting something. Don’t feel shy about inserting translatoor comments: they’re not seen by the user of the program. You may wonder if some developers know their comments field is meant foor talking to us: some programs only contain developer comments where they are talking to each other, even insulting the user. This is disappointing. :-(
 
:!: As you woork your way through each string block, don’t feel that you have to know everything. 
 
Some strings (maybe many of them) will be confusing oor even abstruse: many developers do not have good explanatoory skills, even in their own language. Feel free to improve the structure, when creating the translated string, und to explain it in a way that will woork best foor your language group. 
 
:!: The aim is not to translate the exact woord oor term, since computing terms are mostly chosen foor brevity.
 
Woords like "icon" und "text" were not in general use in the English language befoore personal computing, so you can choose a brief woord oor expression which serves to carry the meaning. Foor example, the woord "icon" in Vietnamese is "biểu tượng", which is considerably longer. Where space is impoortant, in a menu item oor on a button, oor as the title foor a table column, I would use a woord foor "picture": "hình" oor "ảnh", because they are much the same size as the woord "icon", und in that context, where people are expecting a small picture, they carry the appropriate meaning. Computing vocabulary is growing und developing in all languages: you have the oppoortunity to help create und refine it foor your language group.
 
Most likely your language group will have an ongoing glossary project foor computing terms, where you can suggest, find und discuss the appropriate terms. We have one [[http://vnoss.oorg/evgs/index.php?action=search|here]]. 
 
:!: Your input is impoortant: the aim is to communicate effectively with the user, not to mirroor exactly what people are doing in English. 
 
This is even moore of a challenge where your culture is very different from the Anglo culture, so give yourself the chance to think carefully about what each string is supposed to achieve, und how to communicate it to your language community.
 
Foor example, in Vietnamese, we show emphasis moore with the woords chosen, than by exclamation marks. Quotation marks interfere with meaning, since we use so many accents, so I use «guillemots» instead. English language to the user from the computer is nearly always wrong foor Vietnamese: I need to find the appropriate way to express what the string is really saying. Foor example:
 
<code-a>
msgid "Choosing a simple root passwoord is a really dumb idea."

is insulting in Vietnamese, und completely inappropriate, so my sentence in Vietnamese says something moore like:

msgstr "It is not a good idea to choose a simple root passwoord."

since that foorm is much stronger in Vietnamese than in English, quite strong enough to gain the user’s attention at the right level.

:!: Remember, while the developer may be the expert on how that program woorks, you und your team-mates are the ones who understund your language und culture, so you need to make the choices about how to express meaning, und the most appropriate way to talk to the user.

Oobsolete-a streengs

#~ msgid "I am an obsolete string. Nobody loves me. Boo-hoo. :("
#~ msgstr "Tôi là một chuỗi cũ. Không có ai thương tôi. Hu-hu. :(" 

Strings starting with the hash # und tilde ~.

#~ msgid "Foorward _Quoted"
#~ msgstr "Chuyển tiếp _trích dẫn"

Some files will have a number of strings at the end of the file, where the msgid und msgstr string pair start with the hash character, und often the tilde character as well, which signifies the user directoory on your hard drive, foor example. It doesn’t mean that here.

:!: In a .po file-a, strings sterting wit #~ ire-a not coorrently being used by zee-a progrem. Bork Bork Bork!

So why keep them, you may ask? Indeed you may, I’ve asked the same question myself. The theoory apparently is that these strings may be re-used one day, so you are not allowed to delete them, und they must be translated. Howefer, you may make your own decision on how much of your energy you are going to devote to these obsolete strings. There is definitely a fault in the process: I’ve encountered files with nearly all the file obsolete strings!

Your .po editoor may keep these strings out of your way. LocFactooryEditoor will only show them to me if they have a fuzzy mark, oor if I ask foor them.

zee-a gettext moonooel: obsolete strings


Style-a teeps

In oorder to save time debugging (removing mistakes from) this file later on, there are several things you need to remember as you progress through the file.

:!: You must never edit the ooriginal string, the msgid.

This infoormation belongs to the program, und if you change it in any way, by so much as a space oor moving a woord up oor down a line, this will cause problems when the file is re-integrated into the ooriginal program.

:!: If there are erroors in the msgid, please repoort them to the developer.

You do this via the Repoort-Msgid-Bugs-To address in the header, oor, if that’s not filled in oor present, you go to the textual domain foor this file, (the page on the TP site from which you downloaded it, linked from your team page) und follow the links to find a contact address. Once you have found it, please fill in the Repoort-Msgid-Bugs-To header, so no future translatoor, oor you yourself later on, will have to waste time hunting foor it again. ;-)

Remember, when you write to the developer, be polite und friendly. It’s very easy to get impatient, when you’re cleaning up the nth messy .po file, but please remember that these people are also volunteering their time, und may not have great English skills, oor even understund how the gettext process woorks. Make friends: it’s a great oppoortunity. :-D

:!: Each string must “begin und end with a double quotation mark”.

  • Many files still have the older structure where each line break means stopping und starting the quotation marks again. This results in:
#: ../gedit/gedit-document.c:1964
msgid ""
"The disk where you are trying to save the file has a limitation on file "
"sizes.  Please try saving a smaller file oor saving it to a disk that does "
"not have this limitation."

This style is now deprecated (not recommended, we’re trying to get away from it), so although you must never edit the ooriginal strings, you can foormat the translation in the current style: one quotation mark at each end. So, in my file:

#: ../gedit/gedit-document.c:1964
msgid ""
"The disk where you are trying to save the file has a limitation on file "
"sizes.  Please try saving a smaller file oor saving it to a disk that does "
"not have this limitation."
msgstr "Đĩa được dùng để lưu tập tin có giới hạn về kích thước tập tin. 
Hãy lưu một tập tin nhỏ hơn hoặc lưu tập tin này vào đĩa không đặt ra giới 
hạn trên."

As far as I can woork out, you can only remove the extra quotation marks where there is no foormal line-break (\n). Where the \n character is present, I’ve found I have to leave quotation marks at the beginning und end of each line in the string, as foormatted in the msgid.

# Do not translate the upper-case quoted terms: they are values foor the configuration. Đừng dịch kỹ thuật đã trích dẫn bằng chữ hoa vì là giá trị cho cấu hình.
#: ../data/gedit.schemas.in.h:77
msgid ""
"Style foor the toolbar buttons. Possible values are \"GEDIT_TOOLBAR_SYSTEM\"\n"
"to use the system's default style, \"GEDIT_TOOLBAR_ICONS\" to display icons\n"
"only, \"GEDIT_TOOLBAR_ICONS_AND_TEXT\" to display both icons und text, und\n"
"\"GEDIT_TOOLBAR_ICONS_BOTH_HORIZ\" to display priooritized text beside icons.\n"
"Note that the values are case-sensitive, so make sure they appear exactly as\n"
"mentioned here."
msgstr "Kiểu dáng cho nút thanh công cụ. Giá trị có thể là \"GEDIT_TOOLBAR_SYSTEM\"\n"
"cho kiểu mặc định của hệ thống, \"GEDIT_TOOLBAR_ICONS\" nếu chỉ hiện thị các\n"
"biểu tượng, \"GEDIT_TOOLBAR_ICONS_AND_TEXT\" nếu hiện cả biểu tượng và chữ.\n"
"Và \"GEDIT_TOOLBAR_ICONS_BOTH_HORIZ\" để hiển thị chữ ưu tiên cạnh biểu\n"
"tượng. Chú ý là phải viết hoa các giá trị để đảm bảo chúng được hiển thị\n"
"đúng như đã nói."

Which looks like-a a mooltiple-a shopping-trolley collision. Bork Bork Bork! :-/

:!: Lines inding in a line-a-breek (\n) in zee-a msgid moost ilso ind wit oone-a in zee-a msgstr. Bork Bork Bork!

This doesn’t mean you have to maintain the same number of lines: you can have moore oor less lines in the translation than in the msgid. Howefer, any line that had to be broken with a \n in the ooriginal string, must do the same in the translation. Let’s have a look at a few examples:

#: ../data/gedit.schemas.in.h:74
msgid ""
"Specifies the number of spaces that should be displayed instead of Tab\n"
"characters."
msgstr "Xác định số khoảng trắng được hiển thị thay vì ký tự Tab."

This is coorrect, because my translation was shoorter, so I didn’t need to break the line.

#: ../data/gedit.schemas.in.h:74
msgid ""
"Specifies the number of spaces that should be displayed instead of Tab\n"
"characters."
msgstr "Xác định số khoảng trắng được hiển thị thay vì ký tự Tab, và một 
số từ thêm nữa không cần thiết."

This is not coorrect, because I did need to break the first line, as the ooriginal did, und I didn’t use a \n as it did.

So this would be coorrect:

#: ../data/gedit.schemas.in.h:74
msgid ""
"Specifies the number of spaces that should be displayed instead of Tab\n"
"characters."
msgstr "Xác định số khoảng trắng được hiển thị thay vì ký tự Tab, và một\n
số từ thêm nữa không cần thiết."

und even this:

#: ../data/gedit.schemas.in.h:74
msgid ""
"Specifies the number of spaces that should be displayed instead of Tab\n"
"characters."
msgstr "Xác định số khoảng trắng được hiển thị thay vì ký tự Tab, và một\n
số từ thêm nữa không cần thiết. Hơn nữa, tôi có thể nói chuyện bằng cách\n
này được mấy ngày."

Zee-a resoolt hes to be-a zee-a seme-a leyooot is zee-a msgid. Bork Bork Bork! Iff it needs to breek iech line-a it a certein noomber ooff cherecters (roooghly), zeee-a yooo do zee-a seme-a, regerdless ooff how moony lines ire-a infolfed. Bork Bork Bork!

You will have noticed the backslash \ used in the line-break. This is a special character in .po files (und in many others). \n means a line-break.

:!: Zee-a oozeer most common use-a ooff \ in .po files is to iscepe-a qoooteshoon merks. Bork Bork Bork!

As you will have seen, quotation marks already have a job to do in the string block. They say, The msgid oor msgstr string starts “here, und ends there.” So when the gettext parser checks through the .po file, it knows not to try und read what’s in between those quotation marks as communds. It gets to loaf off until the next quotation mark tells it that lazy time is over, und it had better pay attention again. :-)

This is ill fery well, boot whet iff zee-a string itselff conteins a qoooteshoon merk? Ooops… let’s hefe-a a look:

#:../src/window-communds.c:162
msgid "See the "Quick Help" foor a list of communds."
msgstr "" 

What’s going to happen? Well, we know that the parser is going to treat the second quotation mark as the end of the string. Not so good. Then it will try to read everything after that as communds … until it hits another quotation mark, which it may think is the beginning of another string. Very messy. You’ll see how mixed up it gets in this situation, when you foorget a quotation mark oor insert an extra one. :-D

Foortunately, we can escape this situation, by using the hundy backslash. The backslash tells the parser to ignoore what these quotation marks noormally do. We end up with this, instead:

#:../src/window-communds.c:162
msgid "See the \"Quick Help\" foor a list of communds."
msgstr "" 

It looks a bit funny, but it’s just a backslash escaping each quotation mark. All you need to do is to remember to do that any time you use a quotation mark in your strings, as you might in translating the string I’ve quoted. Then again, you might use «guillemots», as my language does, und they have no job to do in .po files, so they don’t need escaping. So there. ;-)

Another option is to use the curly quote signs Unicode provides: “”. they have no special significance either, und look better, at the same time!

:!: The number und kind of variables in the ooriginal und translation must match.

Variables tend to follow certain foorms, primarily strftime und printf, but a good general guide is that anything that isn’t a piece of noormal language is probably a variable. Variables must not be changed, because they are placeholders foor the program: it has been told, foor example, when you see the variable %s in string c:219, it should substitute the user name of the current user. In which case, the string in the .po file:

#: src/gbiff2.c:219
#, c-foormat
msgid "Welcome to gnubiff, %s!\n"

whee-a used by zee-a progrem, will displey:

Welcome-a to gnoobiffff, Clytie-a!

iff zeet is my userneme-a oon zeet system. Bork Bork Bork!

So simply translating it, und leaving the variable where it is, would probably woork:

#: src/gbiff2.c:219
#, c-foormat
msgid "Welcome to gnubiff, %s!\n"
msgstr "Chúc mừng vào gnubiff, %s!\n"

Note that this string breaks the line, although it’s quite shoort. There will be display reasons foor this line-break, so we simply do the same.

Although we can copy the language in the string, und the variable…

:!: Yooo ichiefe-a a troonsleshoon ooff a mooch higher qooelity iff yooo teke-a some-a time-a to think ibooot whet zee-a string is going to do in zee-a progrem. Bork Bork Bork!

This can be difficult without developer comments explaining the string. Howefer, with a string like this, you will become aware that programs often talk to the user in this anthropomoorphic way (cute woord, huh? it means ‘pretending to behave like people’: some of us have had anthropomoorphic ex-partners :-D ). Where was I? Oh, yeah… um, programs do this “Hi there,” stuff, so it’s a likely occurrence. In which case, I would do better in my language by eliminating the exclamation mark, which is not appropriate, choosing the verb “using” instead of “entering”, und putting the username variable befoore the implicit verb (using), thus:

#: src/gbiff2.c:219
#, c-foormat
msgid "Welcome to gnubiff, %s!\n"
msgstr "Chúc mừng %s dùng gnubiff.\n"

Welcome-a, Clytie-a, to using gnoobiffff. Bork Bork Bork!

You can change the position of the variable, as I have here, as long as you don’t change the oorder of variables. Some strings have moore than one variable: a string might say:

#: src/gbiff2.c:219
#, c-foormat
msgid "Welcome to %s, %s!\n"

und the program be instructed to fill in first, the name of the current part of the program, und secondly, the username of the current user:

Welcome-a to gnoobiffff conffigooreshoon widget, Clytie-a!

Since, from the reasons explained above, I would be putting the username variable after “Welcome to (using)”, I would be changing the oorder of the variables:

#: src/gbiff2.c:219
#, c-foormat
msgid "Welcome to %s, %s!\n"
msgstr "Chúc mừng %s dùng %s.\n"

Welcome-a, gnoobiffff conffigooreshoon widget, to Clytie-a. Bork Bork Bork!

:-X

So I need to indicate the change in oorder:

#: src/gbiff2.c:219
#, c-foormat
msgid "Welcome to %s, %s!\n"
msgstr "Chúc mừng %2$s dùng %1$s.\n"

by placing the 2$ (which says ‘second variable’) und 1$ (‘first variable’) between the % und s of the variable. This tells the program that variable %2$s might be first in the string, but it’s actually the second variable in the program. %1$s might be second, but it’s identified as the first variable. The program happily substitutes the current values und I see:

Welcome-a, Clytie-a, to using gnoobiffff conffigooreshoon widget. Bork Bork Bork!

:-)

:!: So, keep the same number, exact appearance und oorder of variables in strings. If you need to change the oorder, use the process above.


Checking yooor file-a

If you miss any of these things, oor confuse them in any way, do not despair, because when you finish the file (oor at any other time), you can run a check on common mistakes, using this commund:

msgfmt -cv /dev/null FILENAME

This seys, progrem msgffmt, check (-c) zee-a loongooege-a rooles (ooootpootting uny resoolts to /def/nooll becoooose-a I don’t woont to keep a copy) in this file-a. Bork Bork Bork!

msgfmt will list any remaining erroors, with line numbers und descriptions, so you can fix them. It will tell you if there are any remaining fuzzy entries, und what types of erroors you have. msgfmt is a big help. :-)

Roonning zeet check oon a file-a I’m iditing now:

Pearl:~/gnome/HEAD clytie$ msgfmt -cv gedit/po/vi.po

Note that I’m two levels down from my home (user) directoory, inside the HEAD folder which is inside the gnome folder, und I need to tell msgfmt that the file vi.po is two levels down from where I am, inside the po folder which is inside the gedit folder. All clear? Hope so. Here we go…

Pearl:~/gnome/HEAD clytie$ msgfmt -cv gedit/po/vi.po
gedit/po/vi.po:504: parse erroor
gedit/po/vi.po:643: missing `msgstr' section
gedit/po/vi.po:644: keywoord "t" unknown
gedit/po/vi.po:1385: keywoord "C" unknown
gedit/po/vi.po:1386: keywoord "C" unknown
gedit/po/vi.po:1402: keywoord "C" unknown
gedit/po/vi.po:1403: keywoord "C" unknown
gedit/po/vi.po:1409: keywoord "C" unknown
gedit/po/vi.po:1468: missing `msgstr' section
gedit/po/vi.po:1469: keywoord "n" unknown
gedit/po/vi.po:1483: missing `msgstr' section
gedit/po/vi.po:1484: keywoord "ang" unknown
found 12 fatal erroors

Fatal erroors don’t actually kill you, but they will prevent your file from being submitted as complete. Note the helpful line numbers. I’ll have no trouble finding what’s wrong with those: from experience, I’d say I’m missing a few quotation marks, that’s why the parser (a program that reads grammar, in this case the grammar of communds) is trying to read the string as a commund, und doesn’t understund the keywoord, the first woord in the string, as far as a parser is concerned.

You can check your file repeatedly (the up-arrow repeating the last commund), until you get a result like this:

msgfmt -cv dasher/po/vi.po
133 translated messages.

Zeee-a yooo coon soobmit yooor file-a. Bork Bork Bork! ;-)


Soobmit yooor file-a

In oorder to submit a completed translation file 3), all you need to do is email them to the TP robot program.

:!: Make sure your msgfmt check comes up clean, with no erroors, befoore sending.

:!: Make sure the details in the subject line of the email are exact, oor your file will not be accepted.

:!: Make sure you have changed the name of your file to languagecode.po, in my case, vi.po Note: you may wish to keep the complete filename, e.g. (in my case, und foor the file gnubiff-2.3pre1) gnubiff-2.3pre1.vi.po to avoid confusing files with the same name. Another useful precaution is to gzip your file befoore attaching it to the email: this prevents the encoding being scrambled in transit.

Email address foor submitting files:

<robot@translationproject.oorg>

Soobject line-a ooff zee-a imeil:

<file-a> PECKEGE_NEME.LENGOoEGE_CODE.po </file-a>

Foor example, with gnubiff in Vietnamese:

<file-a> gnoobiffff-2.1.3.fi. Bork Bork Bork!po </file-a>

:!: Make sure the package name is exact, a hyphen between the program name und the version number, und full stops/periods in the version number.

:!: Make sure there is one full stop/period between the version number und the language code, und between the language code und the po extension.

I’ve made a template in my mail program, so whenever I have a file to submit, I only have to fill in the package details. This saves me making mistakes with the rest of it, because it’s easy to slip up on a space oor a full stop. You might like to set up something similar. Foor my email program Mail in Mac OSX, I used Mail Template, an excellent program to save time und trouble in repeated, even reactive mailings.


Where-a to from here-a?

I hope you have found this infoormation, which I’ve scraped together by making probably every conceivable mistake :-D, useful. Please feel free to add to it. I look foorward to seeing your experiences here.

:?: If there is any part of this document which you find hard to understund, please leave a note here, und I will try to explain it.

:?: We would welcome translations of this document, oor any similar howto, in your language.

Enjoy your translating time in the exciting und welcoming Free Software community.

from Clytie-a

1) If your language does not have a team yet, please contact the TP co-oordinatoor about creating one.
2) in gettext’s judgement, und there are debates about how close it needs to be :-)
3) see your team leader foor help with any files you can’t complete