HOW TO ADD A NEW LANGUAGE 1. Prerequisites You need the Java Development Kit on your PC. It's available from java.sun.com. http://java.sun.com/javase/downloads/index.jsp You need a Unicode capable editor. A suitable choice is TotalEdit, available for free on http://en.softonic.com/s/totaledit Or use any other editor you like, and any other encoding as well if it is suitable for your language. The encoding is put into the file later on. I will assume this is happening on Windows; if you prefer another operating system, the procedures are not much different. In fact they are the same. :-) 2. Preparations You have received a ZIP file together with this HOWTO. Unzip it to a directory of your choice. Then open a command shell (Windows: click "Start", then choose "cmd" or type it in the search field and hit Enter). CD to the directory in question (if you have created it on your desktop, you'll likely have to type "cd Desktop" followed by "cd "). Now "unjar" the contents of the Java archive contained in the directory. The command is "jar xf freedom.jar". If the command fails you haven't properly installed the JDK. 3. Intro to internationalization (i18n for short) of YF 3.1 Properties file format CD to de/resolution/emsc/lang. There is one important file in this directory: "Strings.properties". This is the file that contains all default texts -- whatever the YF client displays anywhere is (or should be) in this file. The file's encoding is ISO-8859-1, not because I happen to like it but because Java requires all properties files to use this encoding or a subset of it (like US-ASCII). If your language uses characters that are not available in ISO-8859-1 you need to use a different encoding -- we'll come to that later. The Strings.properties file only contains ASCII characters. If you encounter problems with ISO-8859-1 encoded files (i.e. some characters just would not display properly) please try using the conversion tool as shown below ("File encoding"). Let's have a look at Strings.properties first. Open it in your favourite editor and make sure the encoding is correct (with TotalEdit, select "Format" and choose "Windows (ANSI)" which is pretty close to ISO-8859-1). All lines starting with "#" are comments and only for your orientation. (When you translate, just copy them as they are, they help me find my way in your translation.) The first important line is "encoding = US-ASCII". This helps me and the packaging scripts to convert the file properly. In this case no conversion is needed but the string is in there anyway. The second important line is the name of the "locale". A "locale" is a definition set describing local languages, writing and formatting rules, as well as things like currencies and such. The default file doesn't use a locale so I've put "none" here. We'll come to that later. The whole remainder of the file consists of "key=value" records. It doesn't matter whether there is whitespace around the equal sign. The "key" is the hard-coded string in the YF client code that is used to look up the real text on the right hand side. Special characters are prefixed by a backslash (\), one example is the line feed for multi-line texts. Generally, the value ends with the line, and if you don't want that you need to put a backslash at the end of the line. Whether you put a space in front of it or not doesn't matter in most cases; don't worry about it. Some texts contain placeholders. They are numbered from 0 to whatever and put in curly braces ({}). If there is just a number in the braces, the argument is a plain string and simply replaces the placeholder. For example, the message "Could not delete file {0}, permission denied" contains such a string argument. There are more sophisticated placeholders too. http://java.sun.com/javase/6/docs/api/java/text/MessageFormat.html will tell you all you need to know about them. In short, there can be up to three arguments to a placeholder, separated by comma. The first one is always the argument index, the second is the format type, the third is the format style. Format type can be any of "number", "date", "time" or "choice". The format style can be any of "short", "medium", "long", "full", "integer", "currency" or "percent" -- and it can be a pattern, which we need for choice formatting. Search for "YourPackageWillExpireSoon", there is a good (i.e. complex) example there. We use choice arguments if there are several wordings for different argument values, e.g. plural forms. The format style pattern consists of choices separated by a "pipe" (|). Each choice can be a value followed by a hash (#) followed by the text to use if the argument has this particular value, or it can be a simple text (potentially containing more placeholders!) that is used as a default choice. So in {1,choice,0#0 days|1#one day|{1,number,integer} days} will examine the value of argument #1. If it is 0, it will print "0 days", if it is 1 it will print "one day", and if it is any other value it will print this value as an integer number followed by the word "days". Not very complicated is it? Anyway, you'll quickly get the knack for it. 3.2 How a ResourceBundle works A ResourceBundle is a set of properties files -- we are only dealing with one ResourceBundle here and it's called "de.resolution.emsc.lang.Strings", consisting of the files "Strings.properties" and "Strings_xx.properties, and -- if existent -- "Strings_xx_YY.prpoerties. "xx" is an ISO639 language code (e.g. en for english, de for german, fr for french). YY is an ISO3166 country code. An example would be "en_GB" and "en_US" -- en_GB would be a "localisation" for an English speaker in Great Britain and en_US a "localization" for an English speaker in the United States of America. Many languages have subtle differences depending on the country, and we can accommodate for it. Let's assume the YF client has been told by the user to display everything in "en_GB". It would then start every lookup in the file Strings_en_GB.properties. If it cannot find what it is looking for, the file "Strings_en.properties" would be searched. If nothing is found there, the last resort would be the file "Strings.properties", and if it cannot find the key there it will fail with an error. What does this mean for a translator? Well, it means that if your translation would be the same as in the more general properties file, you don't have to put in a translation! It's good if you do it nevertheless because it becomes difficult otherwise to check the translations for completeness, so please ensure that the "language level" (Strings_xx.properties) contains all keys. You can find the language and country code for your translation in the Wikipedia (http://en.wikipedia.org/wiki/ISO3166). Use the Alpha-2 codes (i.e. the two-letter codes). Note that the language uses lower case letters and the country uses upper case letters. When starting a new translation, only use the language code. 3.3 What is the difference between the locale and the translation? The locale is a set of rules how to display things properly for the reader. The translation is what to display. Simple as cake. :-) Well, almost. We use the same codes to refer to locales as we do for languages. "en_GB" is not only a set of rules but also a set of translations. For those cases where a locale exists for your language (and maybe country) you don't have to worry -- just use it. A list of supported locales in Java can be found on Sun's web page: http://java.sun.com/javase/6/docs/technotes/guides/intl/index.html (click on "Supported Locales"). If at least the language code is there it will all be very straightforward (example: if there is a locale for "ar_DZ" there is one for "ar" as well, in which case you'd put all language stuff in a "Strings_ar.properties" file unless there are some things specific to a country). But what do you do for languages that are not supported by Java? Well, I haven't done this before either and can only make suggestions. Let's take Farsi as an example (the language known as Persian, spoken in Iran). I am told that written Farsi resembles Arabic very much (there are some additional letters for Farsi), in fact most "ar" locales will be able to display it properly. So call the translation file "Strings_fa.properties" and put a "locale = ar" line in it. The YF client is (or should be, it's not yet tested) clever enough to understand what you mean by that: display Farsi texts using the arabic writing system and fonts. 3.4 File encoding For languages that can be encoded with ISO-8859-1 or a subset of it you can simply write a properties file in ISO-8859-1. But what do you do for other languages? Well, you can use Unicode characters but you have to quote them with their hexadecimal value (e.g. \u00f6 for o-umlaut). This is boring to type and in most cases it's not practical (unless you use editors like NetBeans who hide this mess from you whereever possible and display the characters instead). So please create a file "Strings_xx.properties.src" instead (xx of course replaced by your language code), in any encoding that is most suitable for you. I recommend UTF-8 because there's support for virtually every text symbol on earth in it and many editors support it. Be sure you put "encoding = UTF8" (it does not matter whether you spell it "UTF8" or "UTF-8") in your file! My bundling scripts rely on it. There's a tool called "native2ascii" in the JDK. (http://java.sun.com/javase/6/docs/technotes/tools/windows/native2ascii.html) Simply type native2ascii -encoding UTF8 Strings_xx.properties.src Strings_xx.properties to convert your src file into a properties file suitable for Java. If you ever need to do it the other way round, add the -reverse option: native2ascii -reverse -encoding UTF8 Strings_xx.properties Strings_xx.properties.src This way you can work with your editor in a convenient way (especially for languages full of non-ISO-8859-1 characters) and native2ascii will do all the dirty encoding work for you. You can use any encoding found on this page in the second column: http://java.sun.com/javase/6/docs/technotes/guides/intl/encoding.doc.html But if you can, please use UTF8. It does not matter whether you use DOS style line endings (CR-LF) or Unix style line endings (LF). If you have difficulties encoding some characters you may always use their Unicode escape sequences. Have a look at this web page: http://www.isthisthingon.org/unicode/index.php Search for the character you need (probably just type it in the "UTF8 String" field), then take the last four digits of "Unicode (Hex)" and prepend \u. Example: Suppose you were unable to encode the letter A. Its Unicode representation is 00041 so use \u0041 instead. 4. Getting started Start by copying the default file to a file for your new language in the right encoding. Let's say you want to start a turkish translation, and you want to do it in UTF8, so you'd do this: native2ascii -reverse -encoding UTF8 Strings.properties Strings_tr.properties.src You'll probably say you could just copy the file as well since it only contains ASCII and ASCII is a subset of UTF8. That's right. And I can't come up with a case where you can't so I guess you'll simply do copy Strings.properties Strings_tr.properties.src instead. :-) Now edit the file and change the settings for locale and encoding in it. 4.1 The first test Find the key "Status" and translate it to your language. Remove the english text and replace it. Never change the key, only the value on the right hand side of the equal sign. Save the file. Now run the converter: native2ascii -encoding UTF8 Strings_tr.properties.src Strings_tr.properties Then run the YF client. The easiest way to do this is to open another command shell on the root level of your working directory (where you unzipped the files) and type java emsgui --locale=tr (two minus signs). You should now see your translation as the header of the status panel. 4.2 The sections I have used "##" as a section marker. This doesn't have any technical meaning; it is merely a note for myself in which class file the string is used (first). Please preserve it, if possible. 4.3 How do I know my translation is complete? If you've started from the defaults file and translated everything in there, it's as complete as the defaults file. At one point I will add new stuff to the defaults file; I will then run a script that will figure out which translations are missing, and I will send them to you (if I may). 4.4 How does the translation make it into the official YF client? Email it to me (c.blum@resolution.de or info@your-freedom.net). 4.5 What do I do if I don't know how to translate something? Just mark it for now. I usually put "###TRANSLATE###" in front of the key (no spaces), this will make it show up nicely in my diff'ing script. For everything that is not translated the default will be used automatically (i.e. the english text).