<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://dev.eiffel.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Leo</id>
		<title>EiffelStudio: an EiffelSoftware project - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://dev.eiffel.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Leo"/>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/Special:Contributions/Leo"/>
		<updated>2026-06-06T11:09:37Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.24.1</generator>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5559</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5559"/>
				<updated>2006-10-31T15:45:12Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously knows how to format things and finds translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|500px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost class, HOST_LOCALE, is responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them resembling a web drawn by an overcaffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted in the text for clarity.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses an implementation of HOST_LOCALE and a DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|500px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
Most major operating systems have an API that provides localisation information. Often they also allow clients to format dates, times and values directly. We decided that instead of directly using the formatting functions of the operating system, we would write our own formatters in Eiffel. Retrieving the required information, however, still has to be done in C. Depending on the operating system, this is a more-or-less simple process.&lt;br /&gt;
&lt;br /&gt;
The formatting information for a given locale is stored in objects of class LOCALE_INFO. Each LOCALE_INFO is initialized on creation with (what we think are sensible) default values, as not all platforms provide all the same information.&lt;br /&gt;
&lt;br /&gt;
LOCALE_MANAGER is able to retrieve the LOCALE_ID of the default locale, filled LOCALE_INFOS and a list of locales with formatting information from a HOST_LOCALE_IMP.&lt;br /&gt;
&lt;br /&gt;
The deferred class HOST_LOCALE* specifies the interface for operating system-specific implementations, and the right effective class, HOST_LOCALE_IMP, is included in the system through a conditional statement in the .ecf platform. This class normally makes use of C externals to actually access the formatting information, although the .NET implementation is an exception. The main jobs that it has are: assembling a list of supported locales, creating, filling and returning a LOCALE_INFO for a given locale, and identifying the locale set as default in the operating system preferences.&lt;br /&gt;
Currently there are HOST_LOCALE_IMP classes for .NET, Windows, and what should be more or less POSIX - only, for now, tested under linux.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|500px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The part of the library that provides translated strings is slightly more complicated. The strings come from a so-called data source (or datasource, depending on preference). The uri given to a LOCALE_MANAGER on creation is examined by a URI_PARSER, which decides what sort of data source this uri represents. It then creates an appropriate DATASOURCE_MANAGER* with this uri and returns it to the LOCALE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
From this point onwards the DATASOURCE_MANAGER* is responsible for the main operations involving translations: providing a list of locales and languages for which a translation is present, and providing the translation in form of  a DICTIONARY* for a given locale.&lt;br /&gt;
A DICTIONARY* is nothing more then a collection of translated strings, with functions to access them. There are several effective descendants, as the best way to store the strings may depend on several factors (singular/plural ration, data source itself, etc.). The LOCALE_MANAGER gets the relevant DICTIONARY* from the DATASOURCE_MANAGER* and passes it to the LOCALE on creation. The LOCALE can then retrieve translations.&lt;br /&gt;
&lt;br /&gt;
If there are translations for both a locale itself and it's language, the DATASOURCE_MANAGER* will of course return a DICTIONARY* containing the translations specifically for that locale. If there is no translation for the locale but one exists for it's language, that will be used.&lt;br /&gt;
&lt;br /&gt;
===File data source ===&lt;br /&gt;
&lt;br /&gt;
The file datasource works in the following way:&lt;br /&gt;
The FILE_MANAGER, an effective DATASOURCE_MANAGER*, has a chain-of-responsibility built from FILE_HANDLER*s.&lt;br /&gt;
There are two operations provided by this chain of responsibility: determining the scope of a file (i.e which language or locale it corresponds to) and providing a DICTIONARY* containing the strings from this file. &lt;br /&gt;
By using this chain and a list of files in the current directory, the FILE_MANAGER can list available locales, list available languages and provide DICTIONARY* objects. The precise type of DICTIONARY* provided is dependant on the type of file.&lt;br /&gt;
&lt;br /&gt;
Each FILE_HANDLER* works by using a FILE* object, which provides the actual parsing functionality for a given file type.&lt;br /&gt;
Currently the only supported file type is the .mo file format, so this is the only example I may provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective descendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Data sources==&lt;br /&gt;
&lt;br /&gt;
===New data sources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible data source, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a data source that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this) or of having a translation spanned over multiple .mo files for one locale.&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new data source.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new data sources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5333</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5333"/>
				<updated>2006-10-24T11:42:37Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call default_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.default_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is available for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_localised_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The difference between a translation and a localised translation is that a localised translation is specific to a region: fr_CA or de_CH, for example. A translation is specific only to a language: fr or de, for example)&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling locale_with_id, providing the desired LOCALE_ID.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translated (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translated_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
formatted_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translated(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, which we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translated_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translated_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.formatted_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument.&lt;br /&gt;
&lt;br /&gt;
=====Misuse=====&lt;br /&gt;
&lt;br /&gt;
It is not a good idea, generally speaking, to do something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := number_of_eels&lt;br /&gt;
io.put_string(my_locale.translated(&amp;quot;My hovercraft has &amp;quot;+n.out+&amp;quot;eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are two reasons for this:&lt;br /&gt;
&lt;br /&gt;
* What the translation function will see as an argument is runtime-dependant. It may correspond to an actual entry in the datasource, if you are careful, but in the example above it probably won't unless you have entries for every possible value of n. This is the reason for which we have the format_string feature in LOCALE - please use it!&lt;br /&gt;
&lt;br /&gt;
*When you want to generate a .po file to give to translators, this sort of thing is not going to make the command that extracts it very happy. What will happen is that it will extract the first constant STRING argument and ignore the rest, so your .po file will have an &amp;quot;My hovercraft has &amp;quot; entry and unless you correct this by hand very probably at runtime the i18n library will not be able to find a translation. &lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
DATE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
formatted_date(date:DATE):STRING_32 &lt;br /&gt;
formatted_time(time: TIME): STRING_32 &lt;br /&gt;
formatted_date_time(date_time:DATE_TIME):STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CURRENCY_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
formatted_currency (a_value: REAL_64): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
VALUE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
formatted_integer_8 (a_integer_8: INTEGER_8): STRING_32 &lt;br /&gt;
formatted_integer_16 (a_integer_16: INTEGER_16): STRING_32 &lt;br /&gt;
formatted_integer_32 (a_integer_32: INTEGER_32): STRING_32&lt;br /&gt;
formatted_integer_64 (a_integer_64: INTEGER_64): STRING_32 &lt;br /&gt;
formatted_real_32 (a_real_32: REAL_32): STRING_32 &lt;br /&gt;
formatted_real_64 (a_real_64: REAL_64): STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
&lt;br /&gt;
The LOCALE class makes 3 formatters accessible to clients: a VALUE_FORMATTER, a DATE_FORMATTER and a CURRENCY_FORMATTER, exposed as features under the names value_formatter, date_formatter and currency_formatter respectively.&lt;br /&gt;
Using these formatters is fairly straightforward: you simply call the appropriate function for  the type of object that you want to format.&lt;br /&gt;
&lt;br /&gt;
======Date formatting======&lt;br /&gt;
&lt;br /&gt;
The DATE_FORMATTER class can format EiffelTime DATE, TIME and DATE_TIME classes in a way appropriate to the locale. For example, to get a string representation of today's date in a given locale, you might write:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, n]&lt;br /&gt;
io.put_string(my_locale.formatted_date(create {DATE}.make_now))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently eras of non-gregorian calendars are not well supported.&lt;br /&gt;
&lt;br /&gt;
======Value and currency formatting======&lt;br /&gt;
&lt;br /&gt;
The VALUE_FORMATTER and CURRENCY_FORMATTER classes can format integers and reals according to the conventions of a given locale - number of digits after the decimal separator, the decimal separator itself, grouping of digits and so on.&lt;br /&gt;
&lt;br /&gt;
Using them is just as easy as DATE_FORMATTER: just call the function appropriate to the type of object who's value you want to format.&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
If you are using the es-i18n branch, this command is in the &amp;quot;Tools&amp;quot; menu (&amp;quot;Generate .po&amp;quot;). One click and it will prompt you for a location to write the .po file to. This is basically all there is to it.&lt;br /&gt;
It is helpful to understand how it works (see the 'Misuse' section): it extracts the arguments of calls to the translate and translate_plural functions. Largely it will not behave satisfactorily if the string is made up of several parts glued together at run-time.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_manager.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) or the language identifier of the target language (zh or de, for example)  and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5332</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5332"/>
				<updated>2006-10-24T11:38:26Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously knows how to format things and finds translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|400px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost class, HOST_LOCALE, is responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them resembling a web drawn by an overcaffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted in the text for clarity.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses an implementation of HOST_LOCALE and a DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|400px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
Most major operating systems have an API that provides localisation information. Often they also allow clients to format dates, times and values directly. We decided that instead of directly using the formatting functions of the operating system, we would write our own formatters in Eiffel. Retrieving the required information, however, still has to be done in C. Depending on the operating system, this is a more-or-less simple process.&lt;br /&gt;
&lt;br /&gt;
The formatting information for a given locale is stored in objects of class LOCALE_INFO. Each LOCALE_INFO is initialized on creation with (what we think are sensible) default values, as not all platforms provide all the same information.&lt;br /&gt;
&lt;br /&gt;
LOCALE_MANAGER is able to retrieve the LOCALE_ID of the default locale, filled LOCALE_INFOS and a list of locales with formatting information from a HOST_LOCALE_IMP.&lt;br /&gt;
&lt;br /&gt;
The deferred class HOST_LOCALE* specifies the interface for operating system-specific implementations, and the right effective class, HOST_LOCALE_IMP, is included in the system through a conditional statement in the .ecf platform. This class normally makes use of C externals to actually access the formatting information, although the .NET implementation is an exception. The main jobs that it has are: assembling a list of supported locales, creating, filling and returning a LOCALE_INFO for a given locale, and identifying the locale set as default in the operating system preferences.&lt;br /&gt;
Currently there are HOST_LOCALE_IMP classes for .NET, Windows, and what should be more or less POSIX - only, for now, tested under linux.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|400px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The part of the library that provides translated strings is slightly more complicated. The strings come from a so-called data source (or datasource, depending on preference). The uri given to a LOCALE_MANAGER on creation is examined by a URI_PARSER, which decides what sort of data source this uri represents. It then creates an appropriate DATASOURCE_MANAGER* with this uri and returns it to the LOCALE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
From this point onwards the DATASOURCE_MANAGER* is responsible for the main operations involving translations: providing a list of locales and languages for which a translation is present, and providing the translation in form of  a DICTIONARY* for a given locale.&lt;br /&gt;
A DICTIONARY* is nothing more then a collection of translated strings, with functions to access them. There are several effective descendants, as the best way to store the strings may depend on several factors (singular/plural ration, data source itself, etc.). The LOCALE_MANAGER gets the relevant DICTIONARY* from the DATASOURCE_MANAGER* and passes it to the LOCALE on creation. The LOCALE can then retrieve translations.&lt;br /&gt;
&lt;br /&gt;
If there are translations for both a locale itself and it's language, the DATASOURCE_MANAGER* will of course return a DICTIONARY* containing the translations specifically for that locale. If there is no translation for the locale but one exists for it's language, that will be used.&lt;br /&gt;
&lt;br /&gt;
===File data source ===&lt;br /&gt;
&lt;br /&gt;
The file datasource works in the following way:&lt;br /&gt;
The FILE_MANAGER, an effective DATASOURCE_MANAGER*, has a chain-of-responsibility built from FILE_HANDLER*s.&lt;br /&gt;
There are two operations provided by this chain of responsibility: determining the scope of a file (i.e which language or locale it corresponds to) and providing a DICTIONARY* containing the strings from this file. &lt;br /&gt;
By using this chain and a list of files in the current directory, the FILE_MANAGER can list available locales, list available languages and provide DICTIONARY* objects. The precise type of DICTIONARY* provided is dependant on the type of file.&lt;br /&gt;
&lt;br /&gt;
Each FILE_HANDLER* works by using a FILE* object, which provides the actual parsing functionality for a given file type.&lt;br /&gt;
Currently the only supported file type is the .mo file format, so this is the only example I may provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective descendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Data sources==&lt;br /&gt;
&lt;br /&gt;
===New data sources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible data source, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a data source that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this) or of having a translation spanned over multiple .mo files for one locale.&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new data source.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new data sources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5319</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5319"/>
				<updated>2006-10-21T23:56:21Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously knows how to format things and finds translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|400px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost classes, SYSTEM_LOCALES and HOST_LOCALE, are responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them resembling a web drawn by an overcaffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted in the text for clarity.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses an implementation of HOST_LOCALE and a DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
TODO: expand? formatters?&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|400px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
Most major operating systems have an API that provides localisation information. Often they also allow clients to format dates, times and values directly. We decided that instead of directly using the formatting functions of the operating system, we would write our own formatters in Eiffel. Retrieving the required information, however, still has to be done in C. Depending on the operating system, this is a more-or-less simple process.&lt;br /&gt;
&lt;br /&gt;
The formatting information for a given locale is stored in objects of class LOCALE_INFO. Each LOCALE_INFO is initialized on creation with (what we think are sensible) default values, as not all platforms provide all the same information.&lt;br /&gt;
&lt;br /&gt;
LOCALE_MANAGER is able to retrieve the LOCALE_ID of the default locale, filled LOCALE_INFOS and a list of locales with formatting information from a HOST_LOCALE_IMP.&lt;br /&gt;
&lt;br /&gt;
The deferred class HOST_LOCALE* specifies the interface for operating system-specific implementations, and the right effective class, HOST_LOCALE_IMP, is included in the system through a conditional statement in the .ecf platform. This class normally makes use of C externals to actually access the formatting information, although the .NET implementation is an exception. The main jobs that it has are: assembling a list of supported locales, creating, filling and returning a LOCALE_INFO for a given locale, and identifying the locale set as default in the operating system preferences.&lt;br /&gt;
Currently there are HOST_LOCALE_IMP classes for .NET, Windows, and what should be more or less POSIX - only, for now, tested under linux.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|400px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The part of the library that provides translated strings is slightly more complicated. The strings come from a so-called data source (or datasource, depending on preference). The uri given to a LOCALE_MANAGER on creation is examined by a URI_PARSER, which decides what sort of data source this uri represents. It then creates an appropriate DATASOURCE_MANAGER* with this uri and returns it to the LOCALE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
From this point onwards the DATASOURCE_MANAGER* is responsible for the main operations involving translations: providing a list of locales and languages for which a translation is present, and providing the translation in form of  a DICTIONARY* for a given locale.&lt;br /&gt;
A DICTIONARY* is nothing more then a collection of translated strings, with functions to access them. There are several effective descendants, as the best way to store the strings may depend on several factors (singular/plural ration, data source itself, etc.). The LOCALE_MANAGER gets the relevant DICTIONARY* from the DATASOURCE_MANAGER* and passes it to the LOCALE on creation. The LOCALE can then retrieve translations.&lt;br /&gt;
&lt;br /&gt;
If there are translations for both a locale itself and it's language, the DATASOURCE_MANAGER* will of course return a DICTIONARY* containing the translations specifically for that locale. If there is no translation for the locale but one exists for it's language, that will be used.&lt;br /&gt;
&lt;br /&gt;
===File data source ===&lt;br /&gt;
&lt;br /&gt;
The file datasource works in the following way:&lt;br /&gt;
The FILE_MANAGER, an effective DATASOURCE_MANAGER*, has a chain-of-responsibility built from FILE_HANDLER*s.&lt;br /&gt;
There are two operations provided by this chain of responsibility: determining the scope of a file (i.e which language or locale it corresponds to) and providing a DICTIONARY* containing the strings from this file. &lt;br /&gt;
By using this chain and a list of files in the current directory, the FILE_MANAGER can list available locales, list available languages and provide DICTIONARY* objects. The precise type of DICTIONARY* provided is dependant on the type of file.&lt;br /&gt;
&lt;br /&gt;
Each FILE_HANDLER* works by using a FILE* object, which provides the actual parsing functionality for a given file type.&lt;br /&gt;
Currently the only supported file type is the .mo file format, so this is the only example I may provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective descendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Data sources==&lt;br /&gt;
&lt;br /&gt;
===New data sources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible data source, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a data source that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this) or of having a translation spanned over multiple .mo files for one locale.&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new data source.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new data sources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5318</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5318"/>
				<updated>2006-10-21T23:55:31Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: modified  to reflect recent changes in library (language translations)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously knows how to format things and finds translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|400px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost classes, SYSTEM_LOCALES and HOST_LOCALE, are responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them resembling a web drawn by an overcaffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted in the text for clarity.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses an implementation of HOST_LOCALE and a DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
TODO: expand? formatters?&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|400px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
Most major operating systems have an API that provides localisation information. Often they also allow clients to format dates, times and values directly. We decided that instead of directly using the formatting functions of the operating system, we would write our own formatters in Eiffel. Retrieving the required information, however, still has to be done in C. Depending on the operating system, this is a more-or-less simple process.&lt;br /&gt;
&lt;br /&gt;
The formatting information for a given locale is stored in objects of class LOCALE_INFO. Each LOCALE_INFO is initialized on creation with (what we think are sensible) default values, as not all platforms provide all the same information.&lt;br /&gt;
&lt;br /&gt;
LOCALE_MANAGER is able to retrieve the LOCALE_ID of the default locale, filled LOCALE_INFOS and a list of locales with formatting information from a HOST_LOCALE_IMP.&lt;br /&gt;
&lt;br /&gt;
The deferred class HOST_LOCALE* specifies the interface for operating system-specific implementations, and the right effective class, HOST_LOCALE_IMP, is included in the system through a conditional statement in the .ecf platform. This class normally makes use of C externals to actually access the formatting information, although the .NET implementation is an exception. The main jobs that it has are: assembling a list of supported locales, creating, filling and returning a LOCALE_INFO for a given locale, and identifying the locale set as default in the operating system preferences.&lt;br /&gt;
Currently there are HOST_LOCALE_IMP classes for .NET, Windows, and what should be more or less POSIX - only, for now, tested under linux.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|400px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The part of the library that provides translated strings is slightly more complicated. The strings come from a so-called data source (or datasource, depending on preference). The uri given to a LOCALE_MANAGER on creation is examined by a URI_PARSER, which decides what sort of data source this uri represents. It then creates an appropriate DATASOURCE_MANAGER* with this uri and returns it to the LOCALE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
From this point onwards the DATASOURCE_MANAGER* is responsible for the main operations involving translations: providing a list of locales and languages for which a translation is present, and providing the translation in form of  a DICTIONARY* for a given locale.&lt;br /&gt;
A DICTIONARY* is nothing more then a collection of translated strings, with functions to access them. There are several effective descendants, as the best way to store the strings may depend on several factors (singular/plural ration, data source itself, etc.). The LOCALE_MANAGER gets the relevant DICTIONARY* from the DATASOURCE_MANAGER* and passes it to the LOCALE on creation. The LOCALE can then retrieve translations.&lt;br /&gt;
&lt;br /&gt;
If there are translations for both a locale itself and it's language, the DATASOURCE_MANAGER* will of course return a DICTIONARY* containing the translations specifically for that locale. If there is no translation for the locale but one exists for it's language, that will be used.&lt;br /&gt;
&lt;br /&gt;
===File data source ===&lt;br /&gt;
&lt;br /&gt;
The file datasource works in the following way:&lt;br /&gt;
The FILE_MANAGER, an effective DATASOURCE_MANAGER*, has a chain-of-responsibility built from FILE_HANDLER*s.&lt;br /&gt;
There are two operations provided by this chain of responsibility: determining the scope of a file (i.e whoch language or locale it corresponds to) and providing a DICTIONARY* containing the strings from this file. &lt;br /&gt;
By using this chain and a list of files in the current directory, the FILE_MANAGER can list available locales, list available languages and provide DICTIONARY* objects. The precise type of DICTIONARY* provided is dependant on the type of file.&lt;br /&gt;
&lt;br /&gt;
Each FILE_HANDLER* works by using a FILE* object, which provides the actual parsing functionality for a given file type.&lt;br /&gt;
Currently the only supported file type is the .mo file format, so this is the only example I may provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective descendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Data sources==&lt;br /&gt;
&lt;br /&gt;
===New data sources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible data source, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a data source that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this) or of having a translation spanned over multiple .mo files for one locale.&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new data source.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new data sources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Talk:Internationalization/Developer_guide&amp;diff=5317</id>
		<title>Talk:Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Talk:Internationalization/Developer_guide&amp;diff=5317"/>
				<updated>2006-10-21T23:49:16Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TODO: update picture, as SYSTEM_LOCALES has been scrapped.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5316</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5316"/>
				<updated>2006-10-21T23:48:06Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is available for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_localised_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(The difference between a translation and a localised translation is that a localised translation is specific to a region: fr_CA or de_CH, for example. A translation is specific only to a language: fr or de, for example)&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, which we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument.&lt;br /&gt;
&lt;br /&gt;
=====Misuse=====&lt;br /&gt;
&lt;br /&gt;
It is not a good idea, generally speaking, to do something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_eels&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft has &amp;quot;+n.out+&amp;quot;eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are two reasons for this:&lt;br /&gt;
&lt;br /&gt;
* What the translation function will see as an argument is runtime-dependant. It may correspond to an actual entry in the datasource, if you are careful, but in the example above it probably won't unless you have entries for every possible value of n. This is the reason for which we have the format_string feature in LOCALE - please use it!&lt;br /&gt;
&lt;br /&gt;
*When you want to generate a .po file to give to translators, this sort of thing is not going to make the command that extracts it very happy. What will happen is that it will extract the first constant STRING argument and ignore the rest, so your .po file will have an &amp;quot;My hovercraft has &amp;quot; entry and unless you correct this by hand very probably at runtime the i18n library will not be able to find a translation. &lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
DATE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_date(date:DATE):STRING_32 &lt;br /&gt;
format_time(time: TIME): STRING_32 &lt;br /&gt;
format_date_time(date_time:DATE_TIME):STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CURRENCY_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_currency (a_value: REAL_64): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
VALUE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_integer_8 (a_integer_8: INTEGER_8): STRING_32 &lt;br /&gt;
format_integer_16 (a_integer_16: INTEGER_16): STRING_32 &lt;br /&gt;
format_integer_32 (a_integer_32: INTEGER_32): STRING_32&lt;br /&gt;
format_integer_64 (a_integer_64: INTEGER_64): STRING_32 &lt;br /&gt;
format_real_32 (a_real_32: REAL_32): STRING_32 &lt;br /&gt;
format_real_64 (a_real_64: REAL_64): STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
&lt;br /&gt;
The LOCALE class makes 3 formatters accessible to clients: a VALUE_FORMATTER, a DATE_FORMATTER and a CURRENCY_FORMATTER, exposed as features under the names value_formatter, date_formatter and currency_formatter respectively.&lt;br /&gt;
Using these formatters is fairly straightforward: you simply call the appropriate function for  the type of object that you want to format.&lt;br /&gt;
&lt;br /&gt;
======Date formatting======&lt;br /&gt;
&lt;br /&gt;
The DATE_FORMATTER class can format EiffelTime DATE, TIME and DATE_TIME classes in a way appropriate to the locale. For example, to get a string representation of today's date in a given locale, you might write:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, n]&lt;br /&gt;
io.put_string(my_locale.format_date(create {DATE}.make_now))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently eras of non-gregorian calendars are not well supported.&lt;br /&gt;
&lt;br /&gt;
======Value and currency formatting======&lt;br /&gt;
&lt;br /&gt;
The VALUE_FORMATTER and CURRENCY_FORMATTER classes can format integers and reals according to the conventions of a given locale - number of digits after the decimal separator, the decimal separator itself, grouping of digits and so on.&lt;br /&gt;
&lt;br /&gt;
Using them is just as easy as DATE_FORMATTER: just call the function appropriate to the type of object who's value you want to format.&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
If you are using the es-i18n branch, this command is in the &amp;quot;Tools&amp;quot; menu (&amp;quot;Generate .po&amp;quot;). One click and it will prompt you for a location to write the .po file to. This is basically all there is to it.&lt;br /&gt;
It is helpful to understand how it works (see the 'Misuse' section): it extracts the arguments of calls to the translate and translate_plural functions. Largely it will not behave satisfactorily if the string is made up of several parts glued together at run-time.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_manager.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) or the language identifier of the target language (zh or de, for example)  and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/obstacles&amp;diff=5315</id>
		<title>Internationalization/obstacles</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/obstacles&amp;diff=5315"/>
				<updated>2006-10-21T23:33:11Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: added obstacle in ES&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Obstacles found during the semester project==&lt;br /&gt;
&lt;br /&gt;
===Library===&lt;br /&gt;
&lt;br /&gt;
No significant problems. There were some slight hiccups with UTF-16, as the gobo parser expects a BOM and so cannot parse UTF16LE or UTF-16BE. Unluckily for us, windows uses little-endian UTF-16.&lt;br /&gt;
&lt;br /&gt;
===EiffelStudio===&lt;br /&gt;
&lt;br /&gt;
*Formatters require a certain property to be a lowercase string and read this directly from INTERFACE_NAMES, meaning that if the i18n library supplies a translated string that is not lowercase, an exception violation happens.  This would superficially be relatively easy to fix, but it is not such a good idea to do this anyway, because with STRING_32 there may not even be a lowercase version of the string (asian scripts come to mind). This behaviour may also happen elsewhere, but I am not sure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Problems encountered during the SA project==&lt;br /&gt;
&lt;br /&gt;
===Problems we encountered during implementation===&lt;br /&gt;
&lt;br /&gt;
* Unicode (UTF-8) support was not fully implemented (e.g. for gtk)&lt;br /&gt;
* Facilities to write and read STRING_32 to/from files were not present&lt;br /&gt;
&lt;br /&gt;
===Difficulties to complete the translation of EiffelStudio:===&lt;br /&gt;
* Many strings are hard-coded anywhere inside EiffelStudio, making the translation difficult&lt;br /&gt;
* All the functions taking strings as arguments expect a STRING, where they should expect a STRING_GENERAL, and they return a STRING which may not be applicable in every case. A STRING_32 can also represent the same content of a STRING_8, thus it should be preferred.&lt;br /&gt;
* It seems that to_uppercase and to_lowercase procedures are not defined for STRING_32 and are used in the studio, these should have been implemented by the vision project and may be buggy.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/obstacles&amp;diff=5272</id>
		<title>Internationalization/obstacles</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/obstacles&amp;diff=5272"/>
				<updated>2006-10-18T02:11:34Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Obstacles found during the semester project==&lt;br /&gt;
&lt;br /&gt;
===Library===&lt;br /&gt;
&lt;br /&gt;
No significant problems. There were some slight hiccups with UTF-16, as the gobo parser expects a BOM and so cannot parse UTF16LE or UTF-16BE. Unluckily for us, windows uses little-endian UTF-16.&lt;br /&gt;
&lt;br /&gt;
===EiffelStudio===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Problems encountered during the SA project==&lt;br /&gt;
&lt;br /&gt;
===Problems we encountered during implementation===&lt;br /&gt;
&lt;br /&gt;
* Unicode (UTF-8) support was not fully implemented (e.g. for gtk)&lt;br /&gt;
* Facilities to write and read STRING_32 to/from files were not present&lt;br /&gt;
&lt;br /&gt;
===Difficulties to complete the translation of EiffelStudio:===&lt;br /&gt;
* Many strings are hard-coded anywhere inside EiffelStudio, making the translation difficult&lt;br /&gt;
* All the functions taking strings as arguments expect a STRING, where they should expect a STRING_GENERAL, and they return a STRING which may not be applicable in every case. A STRING_32 can also represent the same content of a STRING_8, thus it should be preferred.&lt;br /&gt;
* It seems that to_uppercase and to_lowercase procedures are not defined for STRING_32 and are used in the studio, these should have been implemented by the vision project and may be buggy.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=5271</id>
		<title>Internationalization</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=5271"/>
				<updated>2006-10-18T02:07:32Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: removed old milestones, added status&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
===Brief history===&lt;br /&gt;
&lt;br /&gt;
Orginally the internationalisation (i18n) project was started as a required project for an ETH Software Architecture course.&lt;br /&gt;
The result was less then perfect; pages referring to this first version have been given an 'SA' prefix.&lt;br /&gt;
Some members of this SA project team decided to rewrite the library as a semester project. Pages on the wiki not prefixed with 'SA' are either applicable to both or to the semester project.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=== Specific goals of the semester project ===&lt;br /&gt;
&lt;br /&gt;
The new i18n library should provide translation as well as date, time, value and currency formatting.&lt;br /&gt;
It should run on at least windows (with and without .NET) and linux.&lt;br /&gt;
&lt;br /&gt;
=Status=&lt;br /&gt;
&lt;br /&gt;
As of 16 October 2006 we have all features working and almost all tested. &lt;br /&gt;
Some difficulty exists with the windows installation procedure. The linux version works without problems.&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/User_guide|User guide]]: how to use the i18n library&lt;br /&gt;
* [[Internationalization/Developer_guide|Developer guide]]: developer manual for the i18n library&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: setbacks we have encountered&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
== Semester project ==&lt;br /&gt;
&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:Mingmei|Hong Zhang]]&lt;br /&gt;
* [[User:Trosim|Martino Trosi]]&lt;br /&gt;
* Supervisor: [[User:Schoelle| Bernd Schoeller]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Old SA project team ==&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:Mingmei |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=5243</id>
		<title>Internationalization</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=5243"/>
				<updated>2006-10-16T15:15:07Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
===Brief history===&lt;br /&gt;
&lt;br /&gt;
Orginally the internationalisation (i18n) project was started as a required project for an ETH Software Architecture course.&lt;br /&gt;
The result was less then perfect; pages referring to this first version have been given an 'SA' prefix.&lt;br /&gt;
Some members of this SA project team decided to rewrite the library as a semester project. Pages on the wiki not prefixed with 'SA' are either applicable to both or to the semester project.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=== Specific goals of the semester project ===&lt;br /&gt;
&lt;br /&gt;
''to be completed''&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
''add milestones of semesterproject''&lt;br /&gt;
&lt;br /&gt;
==Mx: ??? ==&lt;br /&gt;
* Write a summary of how [[Internationalization/posix_locale|POSIX locale]] information is stored&lt;br /&gt;
* Write a summary of how [[Internationalization/nls_locale|NLS (Windows) locale]] infomation is stored&lt;br /&gt;
* Write a summary of how [[Internationalization/dotnet_locale|.NET locale]] information is stored&lt;br /&gt;
* Write a small summary of date and time classes in EiffelBase&lt;br /&gt;
* Examine the .ts file format, notably plural form handling&lt;br /&gt;
* Examine the .xliff file format, notably plural form handling (we did some of this already)&lt;br /&gt;
* Enter classes &amp;amp; features into EiffelStudio so we have a starting point and a BON diagram&lt;br /&gt;
* Sit down and think about the current class names. Some of them need improving.&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/User_guide|User guide]]: how to use the i18n library&lt;br /&gt;
* [[Internationalization/Developer_guide|Developer guide]]: developer manual for the i18n library&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: setbacks we have encountered&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
== Semester project ==&lt;br /&gt;
&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:Mingmei|Hong Zhang]]&lt;br /&gt;
* [[User:Trosim|Martino Trosi]]&lt;br /&gt;
* Supervisor: [[User:Schoelle| Bernd Schoeller]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Old SA project team ==&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:Mingmei |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=5242</id>
		<title>Internationalization</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=5242"/>
				<updated>2006-10-16T15:13:26Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
===Brief history===&lt;br /&gt;
&lt;br /&gt;
Orginally the internationalisation (i18n) project was started as a required project for an ETH Software Architecture course.&lt;br /&gt;
The result was less then perfect; pages referring to this first version have been given an 'SA' prefix.&lt;br /&gt;
Some members of this SA project team decided to rewrite the library as a semester project. Pages on the wiki not prefixed with 'SA' are either applicable to both or to the semester project.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=== Specific goals of the semester project ===&lt;br /&gt;
&lt;br /&gt;
''to be completed''&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
''add milestones of semesterproject''&lt;br /&gt;
&lt;br /&gt;
==Mx: ??? ==&lt;br /&gt;
* Write a summary of how [[Internationalization/posix_locale|POSIX locale]] information is stored&lt;br /&gt;
* Write a summary of how [[Internationalization/nls_locale|NLS (Windows) locale]] infomation is stored&lt;br /&gt;
* Write a summary of how [[Internationalization/dotnet_locale|.NET locale]] information is stored&lt;br /&gt;
* Write a small summary of date and time classes in EiffelBase&lt;br /&gt;
* Examine the .ts file format, notably plural form handling&lt;br /&gt;
* Examine the .xliff file format, notably plural form handling (we did some of this already)&lt;br /&gt;
* Enter classes &amp;amp; features into EiffelStudio so we have a starting point and a BON diagram&lt;br /&gt;
* Sit down and think about the current class names. Some of them need improving.&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/user_guide|User guide]]: how to use the i18n library&lt;br /&gt;
* [[Internationalization/developer_guide|Developer guide]]: developer manual for the i18n library&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: setbacks we have encountered&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
== Semester project ==&lt;br /&gt;
&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:Mingmei|Hong Zhang]]&lt;br /&gt;
* [[User:Trosim|Martino Trosi]]&lt;br /&gt;
* Supervisor: [[User:Schoelle| Bernd Schoeller]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Old SA project team ==&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:Mingmei |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5241</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5241"/>
				<updated>2006-10-16T15:12:08Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: added translation section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously knows how to format things and finds translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|400px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost classes, SYSTEM_LOCALES and HOST_LOCALE, are responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them resembling a web drawn by an overcaffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted in the text for clarity.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses SYSTEM_LOCALE and DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
TODO: expand? formatters?&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|400px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
Most major operating systems have an API that provides localisation information. Often they also allow clients to format dates, times and values directly. We decided that instead of directly using the formatting functions of the operating system, we would write our own formatters in Eiffel. Retrieving the required information, however, still has to be done in C. Depending on the operating system, this is a more-or-less simple process.&lt;br /&gt;
&lt;br /&gt;
The formatting information for a given locale is stored in objects of class LOCALE_INFO. Each LOCALE_INFO is initialized on creation with (what we think are sensible) default values, as not all platforms provide all the same information.&lt;br /&gt;
&lt;br /&gt;
LOCALE_MANAGER is able to retrieve the LOCALE_ID of the default locale, filled LOCALE_INFOS and a list of locales with formatting information from a SYSTEM_LOCALES object. This class acts as a layer between LOCALE_MANAGER and the actual implementation. &lt;br /&gt;
''[An entirely useless layer, actually. It needs removing, as design changes have badly reduced it's utility]''&lt;br /&gt;
&lt;br /&gt;
The deferred class HOST_LOCALE* specifies the interface for operating system-specific implementations, and the right effective class, HOST_LOCALE_IMP, is included in the system through a conditional statement in the .ecf platform. This class normally makes use of C externals to actually access the formatting information, although the .NET implementation is an exception. The main jobs that it has are: assembling a list of supported locales, creating, filling and returning a LOCALE_INFO for a given locale, and identifying the locale set as default in the operating system preferences.&lt;br /&gt;
Currently there are HOST_LOCALE_IMP classes for .NET, Windows, and what should be more or less POSIX - only, for now, tested under linux.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|400px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The part of the library that provides translated strings is slightly more complicated. The strings come from a so-called data source (or datasource, depending on preference). The uri given to a LOCALE_MANAGER on creation is examined by a URI_PARSER, which decides what sort of data source this uri represents. It then creates an appropriate DATASOURCE_MANAGER* with this uri and returns it to the LOCALE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
From this point onwards the DATASOURCE_MANAGER* is responsible for the main operations involving translations: providing a list of locales for which a translation is present, and providing the translation in form of  a DICTIONARY* for a given locale.&lt;br /&gt;
A DICTIONARY* is nothing more then a collection of translated strings, with functions to access them. There are several effective descendants, as the best way to store the strings may depend on several factors (singular/plural ration, data source itself, etc.). The LOCALE_MANAGER gets the relevant DICTIONARY* from the DATASOURCE_MANAGER* and passes it to the LOCALE on creation. The LOCALE can then retrieve translations.&lt;br /&gt;
&lt;br /&gt;
===File data source ===&lt;br /&gt;
&lt;br /&gt;
The file datasource works in the following way:&lt;br /&gt;
The FILE_MANAGER, an effective DATASOURCE_MANAGER*, has a chain-of-responsibility built from FILE_HANDLER*s.&lt;br /&gt;
There are two operations provided by this chain of responsibility: determining the locale of a file and providing a DICTIONARY* containing the strings from this file. &lt;br /&gt;
By using this chain and a list of file in the current directory, the FILE_MANAGER can list available locales and provide DICTIONARY* objects. The precise type of DICTIONARY* provided is dependant on the type of file.&lt;br /&gt;
&lt;br /&gt;
Each FILE_HANDLER* works by using a FILE* object, which provides the actual parsing functionality for a given file type.&lt;br /&gt;
Currently the only supported file type is the .mo file format, so this is the only example I may provide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective descendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Data sources==&lt;br /&gt;
&lt;br /&gt;
===New data sources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible data source, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a data source that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this), of having multiple .mo files for one locale, or of having one .mo file for multiple locales (for example: a fr.mo file could cover fr_FR, fr_CH and fr_CA, although this might not be appreciated by some users ;) )&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new data source.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new data sources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5240</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5240"/>
				<updated>2006-10-16T13:49:57Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: added formatting info section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously knows how to format things and finds translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|400px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost classes, SYSTEM_LOCALES and HOST_LOCALE, are responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them resembling a web drawn by an overcaffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted in the text for clarity.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses SYSTEM_LOCALE and DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
TODO: expand? formatters?&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|400px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
Most major operating systems have an API that provides localisation information. Often they also allow clients to format dates, times and values directly. We decided that instead of directly using the formatting functions of the operating system, we would write our own formatters in Eiffel. Retrieving the required information, however, still has to be done in C. Depending on the operating system, this is a more-or-less simple process.&lt;br /&gt;
&lt;br /&gt;
The formatting information for a given locale is stored in objects of class LOCALE_INFO. Each LOCALE_INFO is initialized on creation with (what we think are sensible) default values, as not all platforms provide all the same information.&lt;br /&gt;
&lt;br /&gt;
LOCALE_MANAGER is able to retrieve the LOCALE_ID of the default locale, filled LOCALE_INFOS and a list of locales with formatting information from a SYSTEM_LOCALES object. This class acts as a layer between LOCALE_MANAGER and the actual implementation. &lt;br /&gt;
''[An entirely useless layer, actually. It needs removing, as design changes have badly reduced it's utility]''&lt;br /&gt;
&lt;br /&gt;
The deferred class HOST_LOCALE* specifies the interface for operating system-specific implementations, and the right effective class, HOST_LOCALE_IMP, is included in the system through a conditional statement in the .ecf platform. This class normally makes use of C externals to actually access the formatting information, although the .NET implementation is an exception. The main jobs that it has are: assembling a list of supported locales, creating, filling and returning a LOCALE_INFO for a given locale, and identifying the locale set as default in the operating system preferences.&lt;br /&gt;
Currently there are HOST_LOCALE_IMP classes for .NET, Windows, and what should be more or less POSIX - only, for now, tested under linux.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|400px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective descendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Data sources==&lt;br /&gt;
&lt;br /&gt;
===New data sources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible data source, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a data source that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this), of having multiple .mo files for one locale, or of having one .mo file for multiple locales (for example: a fr.mo file could cover fr_FR, fr_CH and fr_CA, although this might not be appreciated by some users ;) )&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new data source.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new data sources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5232</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5232"/>
				<updated>2006-10-14T17:10:26Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: still need to add 2 sections, but initial draft largely finished&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=General architecture of the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Where does the information come from?==&lt;br /&gt;
&lt;br /&gt;
The i18n library must obviously know how to format things and find translations for many different locales. Translations are application-dependant and thus we only have to deal with them on an infrastructural basis - the actual information is supplied by the user.&lt;br /&gt;
However formatting information is not. Instead, we can fetch this from the operating system.&lt;br /&gt;
&lt;br /&gt;
This leads us to divide the library into three main parts: &lt;br /&gt;
#A part which organises and provides translations from a user-supplied data source.&lt;br /&gt;
#A part which retrieves formatting information from the host operating system&lt;br /&gt;
#A part which provides an interface to the information&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_overview.png|thumb|right|400px|General structure of the i18n library]]&lt;br /&gt;
&lt;br /&gt;
An overview of the structure is provided to the right: the two central classes, LOCALE and LOCALE_MANAGER are the main interface classes. The rightmost classes, SYSTEM_LOCALES and HOST_LOCALE, are responsible for fetching the formatting information, and the leftmost class, DATASOURCE_MANAGER, must deal with finding the translation of strings. &lt;br /&gt;
&lt;br /&gt;
In addition there are several classes that are used to encapsulate information, not shown on diagrams to avoid them ressembling a web drawn by an over-caffeinated spider.&lt;br /&gt;
&lt;br /&gt;
Note: the 'I18N' prefix of class names is omitted here for clarity&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The main two classes of the interface are, as has been previously stated, LOCALE and LOCALE_MANAGER.&lt;br /&gt;
LOCALE represents all operations associated with a given locale: formatting and translation. &lt;br /&gt;
This is the class that clients use to actually localise things, but all it does is provide wrapper functions: the translations are retrieved from a DICTIONARY (more on this later) provided to it on creation, and the formatting is done by specialised formatting classes (DATE_FORMATTER, VALUE_FORMATTER, STRING_FORMATTER and CURRENCY_FORMATTER) which are also operated with information passed in a LOCALE_INFO object to the LOCALE on creation.&lt;br /&gt;
&lt;br /&gt;
Obviously it should not be the user's job to do all this initialisation. This is why there must be a class that is in charge of presenting the user with a choice of locales and giving the user a correctly initialised LOCALE for the locale ultimately chosen.&lt;br /&gt;
This class is LOCALE_MANAGER. A LOCALE_MANAGER uses SYSTEM_LOCALE and DATASOURCE_MANAGER to find out for which locales formatting information and/or translations are available and can provide the client with a list of supported locales.&lt;br /&gt;
A locale is identified by a LOCALE_ID object; this is not only used internally but also by the client when requesting a LOCALE object.&lt;br /&gt;
&lt;br /&gt;
TODO: expand? formatters?&lt;br /&gt;
&lt;br /&gt;
==Formatting information==&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_locale_information.png|thumb|right|400px|Section of the i18n library that retrieves locale information]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Translations==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Image:i18n_translation.png|thumb|right|400px|Section of the i18n library that retrieves translations]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
&lt;br /&gt;
We hope our library is reasonably extensible. In particular, we foresee the following areas of expansion:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New file formats==&lt;br /&gt;
&lt;br /&gt;
Currently we only support the .po/.mo file format. This is because we have limited time and resources and we also feel that the .mo file format is the best current choice, as it it provides plural form handling.&lt;br /&gt;
However, there are other file formats. Trolltech has their own format, there is a Solaris message catalog format, presumably some Windows formats, and OS X also has a native format.&lt;br /&gt;
&lt;br /&gt;
In order to add support for one of these formats - or your own! - it's necessary to write both FILE* and FILE_HANDLER* implementations. Then the new effective decendant of FILE_HANDLER* must be added to the chain-of-responsibility (called ''chain'') in the ''make'' feature of FILE_MANAGER.&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
===New datasources===&lt;br /&gt;
&lt;br /&gt;
Currently we only have one implementation of DATASOURCE_MANAGER*. But maybe a file is not suited to everything.&lt;br /&gt;
A possible datasource, however far-fetched, might be a database: all strings could be fetched via queries.&lt;br /&gt;
Or maybe all strings could be fetched via SOAP or RPC from a remote machine, to ensure up-to-date translations.&lt;br /&gt;
More realistically one could certainly imagine a datasource that checks the locally-stored translations and fetches the latest version remotely if there has been changes.&lt;br /&gt;
The easiest way to do such things is of course to write a new effective descendant of DATASTRUCTURE*.&lt;br /&gt;
This may or may not require a new implementation of DICTIONARY* - for a system that fetches strings on.demand rather then loading them all at initialisation, a new DICTIONARY* would certainly be advisable!&lt;br /&gt;
&lt;br /&gt;
To make the library know about a new DATASOURCE_MANAGER*, URI_PARSER must be told how to recognise an uri that requires it. It is advisable to choose a nice prefix.&lt;br /&gt;
&lt;br /&gt;
===FILE_MANAGER===&lt;br /&gt;
Currently FILE_MANAGER has the simplistic policy of only examining files in the current directory and trusting their name. It is very well possible that there is a project policy of placing each locale in it's own directory (KDE does this), of having multiple .mo files for one locale, or of having one .mo file for multiple locales (for example: a fr.mo file could cover fr_FR, fr_CH and fr_CA, although this might not be appreciated by some users ;) )&lt;br /&gt;
&lt;br /&gt;
A good place to implement such a project-dependant policy is a descendant of FILE_MANAGER, or an entirely new datasource.&lt;br /&gt;
&lt;br /&gt;
==New dictionaries==&lt;br /&gt;
&lt;br /&gt;
New dictionaries might be required by new datasources. Or maybe the translations used by your project can be stored in a more efficient way then the general case - one could imagine a dictionary that takes advantage of singular/plural distribution, or that is keyed to the way translations are stored in a particular file format.&lt;br /&gt;
To add a new dictionary, it's sufficient to write an implementation of DICTIONARY* and to make sure it's used.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5231</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5231"/>
				<updated>2006-10-14T15:31:07Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, which we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument.&lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
DATE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_date(date:DATE):STRING_32 &lt;br /&gt;
format_time(time: TIME): STRING_32 &lt;br /&gt;
format_date_time(date_time:DATE_TIME):STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CURRENCY_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_currency (a_value: REAL_64): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
VALUE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_integer_8 (a_integer_8: INTEGER_8): STRING_32 &lt;br /&gt;
format_integer_16 (a_integer_16: INTEGER_16): STRING_32 &lt;br /&gt;
format_integer_32 (a_integer_32: INTEGER_32): STRING_32&lt;br /&gt;
format_integer_64 (a_integer_64: INTEGER_64): STRING_32 &lt;br /&gt;
format_real_32 (a_real_32: REAL_32): STRING_32 &lt;br /&gt;
format_real_64 (a_real_64: REAL_64): STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
&lt;br /&gt;
The LOCALE class makes 3 formatters accessible to clients: a VALUE_FORMATTER, a DATE_FORMATTER and a CURRENCY_FORMATTER, exposed as features under the names value_formatter, date_formatter and currency_formatter respectively.&lt;br /&gt;
Using these formatters is fairly straightforward: you simply call the appropriate function for  the type of object that you want to format.&lt;br /&gt;
&lt;br /&gt;
======Date formatting======&lt;br /&gt;
&lt;br /&gt;
The DATE_FORMATTER class can format EiffelTime DATE, TIME and DATE_TIME classes in a way appropriate to the locale. For example, to get a string representation of today's date in a given locale, you might write:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, n]&lt;br /&gt;
io.put_string(my_locale.format_date(create {DATE}.make_now))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently eras of non-gregorian calendars are not well supported.&lt;br /&gt;
&lt;br /&gt;
======Value and currency formatting======&lt;br /&gt;
&lt;br /&gt;
The VALUE_FORMATTER and CURRENCY_FORMATTER classes can format integers and reals according to the conventions of a given locale - number of digits after the decimal separator, the decimal separator itself, grouping of digits and so on.&lt;br /&gt;
&lt;br /&gt;
Using them is just as easy as DATE_FORMATTER: just call the function appropriate to the type of object who's value you want to format.&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
TODO: add more details about clicky thing.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_manager.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5230</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5230"/>
				<updated>2006-10-14T15:29:29Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: added formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, which we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument.&lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
DATE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_date(date:DATE):STRING_32 &lt;br /&gt;
format_time(time: TIME): STRING_32 &lt;br /&gt;
format_date_time(date_time:DATE_TIME):STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CURRENCY_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_currency (a_value: REAL_64): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
VALUE_FORMATTER provides:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
format_integer_8 (a_integer_8: INTEGER_8): STRING_32 &lt;br /&gt;
format_integer_16 (a_integer_16: INTEGER_16): STRING_32 &lt;br /&gt;
format_integer_32 (a_integer_32: INTEGER_32): STRING_32&lt;br /&gt;
format_integer_64 (a_integer_64: INTEGER_64): STRING_32 &lt;br /&gt;
format_real_32 (a_real_32: REAL_32): STRING_32 &lt;br /&gt;
format_real_64 (a_real_64: REAL_64): STRING_32 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
&lt;br /&gt;
The LOCALE class makes 3 formatters accessible to clients: a VALUE_FORMATTER, a DATE_FORMATTER and a CURRENCY_FORMATTER, exposed as features under the names value_formatter, date_formatter and currency_formatter respectively.&lt;br /&gt;
 Using these formatters is fairly straightforward: you simply call the appropriate function for  the type of object that you want to format.&lt;br /&gt;
&lt;br /&gt;
======Date formatting======&lt;br /&gt;
&lt;br /&gt;
The DATE_FORMATTER class can format EiffelTime DATE, TIME and DATE_TIME classes in a way appropriate to the locale. For example, to get a string representation of today's date in a given locale, you might write:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, n]&lt;br /&gt;
io.put_string(my_locale.format_date(create {DATE}.make_now))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Currently eras of non-gregorian calendars are not well supported.&lt;br /&gt;
&lt;br /&gt;
======Value and currency formatting======&lt;br /&gt;
&lt;br /&gt;
The VALUE_FORMATTER and CURRENCY_FORMATTER classes can format integers and reals according to the conventions of a given locale - number of digits after the decimal separator, the decimal separator itself, grouping of digits and so on.&lt;br /&gt;
&lt;br /&gt;
Using them is just as easy as DATE_FORMATTER: just call the function appropriate to the type of object who's value you want to format.&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
TODO: add more details about clicky thing.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_manager.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:I18n_translation.png&amp;diff=5218</id>
		<title>File:I18n translation.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:I18n_translation.png&amp;diff=5218"/>
				<updated>2006-10-12T22:39:15Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: Structure of the part of the i18n that loads translations&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Structure of the part of the i18n that loads translations&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:I18n_locale_information.png&amp;diff=5217</id>
		<title>File:I18n locale information.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:I18n_locale_information.png&amp;diff=5217"/>
				<updated>2006-10-12T22:38:30Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: Structure of the part of the i28n library that deals with retrieving information from the OS&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Structure of the part of the i28n library that deals with retrieving information from the OS&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=File:I18n_overview.png&amp;diff=5216</id>
		<title>File:I18n overview.png</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=File:I18n_overview.png&amp;diff=5216"/>
				<updated>2006-10-12T22:37:37Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: overview of i18n library architecture&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;overview of i18n library architecture&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5215</id>
		<title>Internationalization/Developer guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/Developer_guide&amp;diff=5215"/>
				<updated>2006-10-12T22:22:54Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: outline&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=General architecture of the library=&lt;br /&gt;
=Possible expansion points=&lt;br /&gt;
==FILE_MANAGER==&lt;br /&gt;
==New file formats==&lt;br /&gt;
==New datasources==&lt;br /&gt;
==New datastructures==&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5214</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5214"/>
				<updated>2006-10-12T22:17:04Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
TODO!&lt;br /&gt;
=====Usage=====&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
TODO: add more details about clicky thing.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5213</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5213"/>
				<updated>2006-10-12T22:16:54Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;User documentation for the i18n library&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
TODO!&lt;br /&gt;
=====Usage=====&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
TODO: add more details about clicky thing.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5212</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5212"/>
				<updated>2006-10-12T22:16:16Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
TODO!&lt;br /&gt;
=====Usage=====&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
TODO: add more details about clicky thing.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER looks somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5211</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5211"/>
				<updated>2006-10-12T22:15:50Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Using your locale===&lt;br /&gt;
&lt;br /&gt;
Now you've got a LOCALE. After the initial burst of euphoria has faded away, what can you do with it?&lt;br /&gt;
&lt;br /&gt;
====String translation====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=====Usage=====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
====Formatting====&lt;br /&gt;
=====Interface=====&lt;br /&gt;
TODO!&lt;br /&gt;
=====Usage=====&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==String extraction==&lt;br /&gt;
&lt;br /&gt;
Somebody has to translate all these strings. Mostly, this isn't a programmer, so somehow you have to be able to give this translator a list of strings that you want translated. &lt;br /&gt;
&lt;br /&gt;
We can extract these strings from your application fairly easily by simply looking at the arguments for each call to translate or translate_plural. By clicking on a handy button in EiffelStudio, these strings will be extracted and placed in a [http://www.gnu.org/software/gettext/manual/html_node/gettext_9.html#SEC9 .po file].&lt;br /&gt;
&lt;br /&gt;
TODO: add more details about clicky thing.&lt;br /&gt;
&lt;br /&gt;
A .po file is a reasonably widespread format for storing strings to be translated. There are several tools to aid translation of these files, such as [http://www.poedit.org/ poEdit] for Windows and [http://kbabel.kde.org/ KBabel] or [http://gtranslator.sourceforge.net/ gtranslator] for KDE and Gnome. &lt;br /&gt;
There are also many tools to convert .po files to other formats, such as the xml [http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xliff xliff format]. &lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER look somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;br /&gt;
&lt;br /&gt;
How do you get these .mo files? Once your translator has finished translating a .po file, you can convert it into a .mo file by using the ''msgfmt'' tool, which is obtainable as part of the gettext package under unix and distributed with poEdit under Windows.&lt;br /&gt;
The resulting mo file should be named with the locale identifier of the locale it is intended for (zh_CN.mo or de_CH.mo, for example) and placed in the appropriate directory - this is to say, the one that you give to LOCALE_MANAGER as an uri.&lt;br /&gt;
&lt;br /&gt;
The .mo file should then be seen and used by the i18n library.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5210</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5210"/>
				<updated>2006-10-12T21:54:35Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you. With this LOCALE object you can do the really interesting things, like formatting dates and translating strings.&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
===String translation===&lt;br /&gt;
====Interface====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====Usage====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;br /&gt;
&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER look somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5209</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5209"/>
				<updated>2006-10-12T21:52:43Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you.&lt;br /&gt;
&lt;br /&gt;
Here is how you can use LOCALE objects for internationalisation:&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, and normally this has two components: language code and country code.&lt;br /&gt;
For example, the US english locale has language code &amp;quot;en&amp;quot; and country code &amp;quot;US&amp;quot;. &lt;br /&gt;
If you've found a locale id  that you like in the list returned by available_locales, you can check exactly what is vailable for it by using &lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
has_translations (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
has_formatting_info (a_locale_id: I18N_LOCALE_ID): BOOLEAN&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then retrieve the corresponding LOCALE object by calling get_locale.&lt;br /&gt;
===String translation===&lt;br /&gt;
====Interface====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====Usage====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;br /&gt;
&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER look somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5208</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5208"/>
				<updated>2006-10-12T21:45:03Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you.&lt;br /&gt;
&lt;br /&gt;
Here is how you can use LOCALE objects for internationalisation:&lt;br /&gt;
&lt;br /&gt;
===Choosing a locale===&lt;br /&gt;
&lt;br /&gt;
First you must have a LOCALE_MANAGER. For details on creating them, please see the '''Datasources''' section.&lt;br /&gt;
If you just want to use whatever locale is the default on the user's machine, as in most cases, then it's easy to get a LOCALE object: just call get_system_locale.&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
my_locale := locale_mananger.get_system_locale&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want a specific locale, it's going to be a bit more complicated.&lt;br /&gt;
A LOCALE_MANAGER knows what locales are available and exactly what information is available for a specific locale.&lt;br /&gt;
You can get a list of all locales that are available to some degree by calling the available_locales feature.&lt;br /&gt;
A locale is identified by a LOCALE_ID object, so &lt;br /&gt;
&lt;br /&gt;
===String translation===&lt;br /&gt;
====Interface====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====Usage====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;br /&gt;
&lt;br /&gt;
TODO!&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
The library has to load the translated strings from somewhere - sadly we can't do on the fly translation but if you can, please tell us!&lt;br /&gt;
Instead we load the strings from a datasource. This is appropriately generic: it could be anything, from a database to a system that queries a server via RPC or SOAP, but currently we only have one implementation: files. And in fact, we only support one type of file: the .mo file format. &lt;br /&gt;
The library can't guess the type of datasource you want to use, so you have to tell it when you create a LOCALE_MANAGER.&lt;br /&gt;
This is done via an ''uri''. Currently all uris are interpreted as directories where string catalog files may be found, and any .mo files in this directory will be used by the i18n library. This means that creating a LOCALE_MANAGER look somewhat like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
create my_locale_mananger.make(&amp;quot;/path/to/my/files&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Mo files===&lt;br /&gt;
&lt;br /&gt;
The mo file format is defined by the GNU [http://www.gnu.org/software/gettext/ gettext] library, a widely-used C library that allows localisation of text strings. We support UTF-8 encoded mo files.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5207</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5207"/>
				<updated>2006-10-12T21:27:28Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you.&lt;br /&gt;
&lt;br /&gt;
Here is how you can use LOCALE objects for internationalisation:&lt;br /&gt;
&lt;br /&gt;
===String translation===&lt;br /&gt;
====Interface====&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
translate (original: STRING_GENERAL): STRING_32&lt;br /&gt;
translate_plural (original_singular, original_plural: STRING_GENERAL; plural_form : INTEGER): STRING_32&lt;br /&gt;
format_string (original: STRING_GENERAL; token_values: TUPLE[STRING_GENERAL]): STRING_32&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
====Usage====&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5206</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5206"/>
				<updated>2006-10-12T21:24:55Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you.&lt;br /&gt;
&lt;br /&gt;
Here is how you can use LOCALE objects for internationalisation:&lt;br /&gt;
&lt;br /&gt;
===String translation===&lt;br /&gt;
&lt;br /&gt;
In naïvely written software, you can often spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5205</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5205"/>
				<updated>2006-10-12T21:24:48Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you.&lt;br /&gt;
&lt;br /&gt;
Here is how you can use LOCALE objects for internationalisation:&lt;br /&gt;
&lt;br /&gt;
===String translation===&lt;br /&gt;
&lt;br /&gt;
In naïvely written software, you can oten spot things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i18n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? &lt;br /&gt;
&lt;br /&gt;
Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What if you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5204</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5204"/>
				<updated>2006-10-12T21:23:31Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
''localisation'' is the process of adapting a piece of software to a specific place - the ''locale'', often expressed as a combination of language and country codes.&lt;br /&gt;
&lt;br /&gt;
This normally means not only displaying strings in the appropriate language, but also adapting number formatting, date and time formatting etc. to use local conventions.&lt;br /&gt;
&lt;br /&gt;
The i18n library provides formatting facilities for numbers, currency values and dates, and the ability to identify and load translated strings at run-time.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
The library provides most of it's services through one class: LOCALE. This presents all formatting and translation facilities for a given locale.&lt;br /&gt;
LOCALE objects can't be created directly: one must go though the LOCALE_MANAGER class. A LOCALE_MANAGER finds out what information for which locales is available, and offers a list to chose from. It will then load the information for the chosen locale into a LOCALE object and give it to you.&lt;br /&gt;
&lt;br /&gt;
Here is how you can use LOCALE objects for internationalisation:&lt;br /&gt;
&lt;br /&gt;
===String translation===&lt;br /&gt;
&lt;br /&gt;
In naïvely written software, one oftens sees things like&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
We'll use this example to illustrate the use of the string translation features of the i28n library.&lt;br /&gt;
&lt;br /&gt;
If, as above, there is just one constant string to translate, the solution is very easy: simply use the translate function.&lt;br /&gt;
The resulting code would look like this&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
io.put_string(my_locale.translate(&amp;quot;My hovercraft is full of eels&amp;quot;))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If the translate function can't find a translation for this string it will simply return the original string - better then nothing!&lt;br /&gt;
&lt;br /&gt;
But life is, of course, not always that simple. What if we have to deal with plurals? The &amp;quot;traditional&amp;quot; way of doing this is something like:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is not so easy to translate as the above. Why can't we just translate both strings? Depending on the language, there may be up to 4 different types of plural forms, used in strange and exotic ways. Clearly, it is important to know exactly _how_ many hovercraft there are so that we can choose the right plural form. This can be done by the translate_plural function, whoch we can use in this way:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
io.put_string(my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My hovercraft are full of eels&amp;quot;,n))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function will choose and return a translation in the correct plural form. If it can't find one, it will behave like translate and return either the original singular string or the original plural string, following English grammatical rules.&lt;br /&gt;
&lt;br /&gt;
Often even the above is not enough. What is you want to tell the world exactly how many hovercraft you have? You might write something like this:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel, N]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
if n = 1 then&lt;br /&gt;
	io.put_string(&amp;quot;My hovercraft is full of eels&amp;quot;)&lt;br /&gt;
else&lt;br /&gt;
	io.put_string(&amp;quot;My &amp;quot;+n.out+&amp;quot; hovercraft are full of eels&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
How can translate_plural handle this? It needs some reinforcements: the solution is to also use ''string templates''.&lt;br /&gt;
This means that we can embed codes like &amp;quot;$1&amp;quot; in a string and replace them in the translation by the actual values.&lt;br /&gt;
Let's see how this works:&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,n]&lt;br /&gt;
n := get_number_of_hovercraft&lt;br /&gt;
plural_string := my_locale.translate_plural(&amp;quot;My hovercraft is full of eels&amp;quot;,&amp;quot;My $1 hovercraft are full of eels&amp;quot;,n)&lt;br /&gt;
io.put_string(my_locale.format_string(plural_string, [n]))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
To replace the ''escape codes'', such as $1, $2, we use the function format_string. This replaces all the escape codes it finds by the values in a tuple that you give to it a an argument. &lt;br /&gt;
&lt;br /&gt;
===Formatting===&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5036</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5036"/>
				<updated>2006-10-09T15:47:01Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
We divide this task into two parts:&lt;br /&gt;
# Loading translated strings from a message catalog - or in our terminology, from a 'datasource' (One can imagine various datasources, but currently the only supported one is a file).&lt;br /&gt;
# Formatting numbers, currency values and dates: this information can be fetched directly from the operating system.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
===Locale===&lt;br /&gt;
&lt;br /&gt;
===Locale Manager===&lt;br /&gt;
&lt;br /&gt;
===Locale ID ===&lt;br /&gt;
&lt;br /&gt;
===Putting it all together===&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
===File===&lt;br /&gt;
&lt;br /&gt;
====File format====&lt;br /&gt;
&lt;br /&gt;
====File Manager====&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5035</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5035"/>
				<updated>2006-10-09T15:46:25Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
We divide this task into two parts:&lt;br /&gt;
# Loading translated strings from a message catalog - or in our terminology, from a 'datasource' (One can imagine various datasources, but currently the only supported one is a file). # Formatting numbers, currency values and dates: this information can be fetched directly from the operating system.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
===Locale===&lt;br /&gt;
&lt;br /&gt;
===Locale Manager===&lt;br /&gt;
&lt;br /&gt;
===Locale ID ===&lt;br /&gt;
&lt;br /&gt;
===Putting it all together===&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
===File===&lt;br /&gt;
&lt;br /&gt;
====File format====&lt;br /&gt;
&lt;br /&gt;
====File Manager====&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5034</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5034"/>
				<updated>2006-10-09T15:45:25Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
We divide this task into two parts:&lt;br /&gt;
# Loading translated strings from a message catalog - or in our terminology, from a 'datasource' (One can imagine various datasources, but currently the only supported one is a file).&lt;br /&gt;
## Formatting numbers, currency values and dates: this information can be fetched directly from the operating system.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
===Locale===&lt;br /&gt;
&lt;br /&gt;
===Locale Manager===&lt;br /&gt;
&lt;br /&gt;
===Locale ID ===&lt;br /&gt;
&lt;br /&gt;
===Putting it all together===&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
===File===&lt;br /&gt;
&lt;br /&gt;
====File format====&lt;br /&gt;
&lt;br /&gt;
====File Manager====&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5031</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5031"/>
				<updated>2006-10-09T02:15:06Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: outline&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
We divide this task into two parts:&lt;br /&gt;
# Loading translated strings from a message catalog - or in our terminology, from a 'datasource'.&lt;br /&gt;
One can imagine various datasources, but currently the only supported one is a file.&lt;br /&gt;
## Formatting numbers, currency values and dates.&lt;br /&gt;
This information can be fetched directly from the operating system.&lt;br /&gt;
&lt;br /&gt;
==Interface==&lt;br /&gt;
&lt;br /&gt;
===Locale===&lt;br /&gt;
&lt;br /&gt;
===Locale Manager===&lt;br /&gt;
&lt;br /&gt;
===Locale ID ===&lt;br /&gt;
&lt;br /&gt;
===Putting it all together===&lt;br /&gt;
&lt;br /&gt;
==Datasources==&lt;br /&gt;
&lt;br /&gt;
===File===&lt;br /&gt;
&lt;br /&gt;
====File format====&lt;br /&gt;
&lt;br /&gt;
====File Manager====&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5030</id>
		<title>Internationalization/User guide</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/User_guide&amp;diff=5030"/>
				<updated>2006-10-09T01:47:27Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=User documentation for the i18n library=&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The [[i18n]] library is intended to enable localisation of Eiffel programs.&lt;br /&gt;
&lt;br /&gt;
We divide this task into two parts:&lt;br /&gt;
# Loading translated strings from a message catalog - or in our terminology, from a 'datasource'&lt;br /&gt;
&lt;br /&gt;
# Formatting numbers, currency values and dates&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/file_format&amp;diff=4451</id>
		<title>Internationalization/file format</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/file_format&amp;diff=4451"/>
				<updated>2006-09-04T08:15:10Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
&lt;br /&gt;
A bref description of the most important file formats used for the translation of programs.&lt;br /&gt;
&lt;br /&gt;
==PO Files==&lt;br /&gt;
&lt;br /&gt;
===Format of PO files===&lt;br /&gt;
&lt;br /&gt;
A PO file has an entry for each string that has to be translated. There are two kind of them, a &amp;quot;normal&amp;quot; one and one that involves plural forms.&lt;br /&gt;
&lt;br /&gt;
====Normal entry====&lt;br /&gt;
&lt;br /&gt;
Here is the general structure of a &amp;quot;normal&amp;quot; entry:&lt;br /&gt;
&lt;br /&gt;
 white-space&lt;br /&gt;
 #  translator-comments&lt;br /&gt;
 #. extracted-comments&lt;br /&gt;
 #: references...&lt;br /&gt;
 #, flag...&lt;br /&gt;
 msgid untranslated-string&lt;br /&gt;
 msgstr translated-string&lt;br /&gt;
&lt;br /&gt;
Where the ''translator-comments'' are created and maintained exclusively by the translator, this comments have some white space immediately following the #. The other comments are created by the program that created the PO file.&lt;br /&gt;
''References'' are space separated lists of locations (sourcefile:linenumber) specifying where the translation unit is found in a source file.&lt;br /&gt;
After the special comment &amp;quot;#,&amp;quot; there can be some ''flags'', as ''fuzzy'' shows that the msgstr string might not be a correct translation, i.e. the translator is not sure of his work.&lt;br /&gt;
The 'untranslated-string' is the untranslated string as it appears in the original program source. The ''translated-string'' is (as the name suggests) the translated string, if there is no translation it is an empty string.&lt;br /&gt;
&lt;br /&gt;
====Plural form entry====&lt;br /&gt;
&lt;br /&gt;
 white-space&lt;br /&gt;
 #  translator-comments&lt;br /&gt;
 #. automatic-comments&lt;br /&gt;
 #: reference...&lt;br /&gt;
 #, flag...&lt;br /&gt;
 msgid untranslated-string-singular&lt;br /&gt;
 msgid_plural untranslated-string-plural&lt;br /&gt;
 msgstr[0] translated-string-case-0&lt;br /&gt;
 ...&lt;br /&gt;
 msgstr[N] translated-string-case-n&lt;br /&gt;
&lt;br /&gt;
===Supported character encodings===&lt;br /&gt;
&lt;br /&gt;
character encodings that can be used are limited to those supported by both GNU libc and GNU libiconv. These are: ASCII, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-13, ISO-8859-15, KOI8-R, KOI8-U, CP850, CP866, CP874, CP932, CP949, CP950, CP1250, CP1251, CP1252, CP1253, CP1254, CP1255, CP1256, CP1257, GB2312, EUC-JP, EUC-KR, EUC-TW, BIG5, BIG5-HKSCS, GBK, GB18030, SHIFT_JIS, JOHAB, TIS-620, VISCII, UTF-8.&lt;br /&gt;
&lt;br /&gt;
===Po Editors===&lt;br /&gt;
&lt;br /&gt;
* poEdit&lt;br /&gt;
* KBabel&lt;br /&gt;
* Gtranslator&lt;br /&gt;
* LocFactoryEditor (XLIFF and PO editor for Mac OSX)&lt;br /&gt;
&lt;br /&gt;
===Positive aspects===&lt;br /&gt;
&lt;br /&gt;
* Powerful plural handling&lt;br /&gt;
* Format created for translation purpose&lt;br /&gt;
* Easy for humans to read&lt;br /&gt;
* Used by gettext, kbabel, rosetta and many other programs&lt;br /&gt;
* Support and elaboration tools for almost all plattforms&lt;br /&gt;
&lt;br /&gt;
===Negative aspects===&lt;br /&gt;
&lt;br /&gt;
* The PO file format does not provide a way of identifying the source and target language within a file. By GNU standards, GNU software is written in American English (en-US), and this is reflected in Gettext by only having support for Germanic plural forms in the source language. It is therefore recommended to set the source-language attribute to en-US by default.&lt;br /&gt;
&lt;br /&gt;
==ts Files==&lt;br /&gt;
&lt;br /&gt;
===Format of ts files===&lt;br /&gt;
&lt;br /&gt;
The .ts file format is used Trolltech for the QT applications. They are XML conforming files. Here an example of a .ts file, generated by lupdate (a tool made by Trolltech that extracts translatable text from the C++ source code of the Qt application, see [[Internationalization/tool evaluation|here]] for further information):&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;!DOCTYPE TS&amp;gt;&amp;lt;TS&amp;gt;&lt;br /&gt;
     &amp;lt;context&amp;gt;&lt;br /&gt;
         &amp;lt;name&amp;gt;MyExample&amp;lt;/name&amp;gt;&lt;br /&gt;
         &amp;lt;message&amp;gt;&lt;br /&gt;
             &amp;lt;source&amp;gt;i18n=Internationalization&amp;lt;/source&amp;gt;&lt;br /&gt;
             &amp;lt;translation type=&amp;quot;unfinished&amp;quot;&amp;gt;&amp;lt;/translation&amp;gt;&lt;br /&gt;
         &amp;lt;/message&amp;gt;&lt;br /&gt;
     &amp;lt;/context&amp;gt;&lt;br /&gt;
 &amp;lt;/TS&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And after the translation (for example with Qt Linguist) it would look like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;!DOCTYPE TS&amp;gt;&amp;lt;TS&amp;gt;&lt;br /&gt;
     &amp;lt;context&amp;gt;&lt;br /&gt;
         &amp;lt;name&amp;gt;MyExample&amp;lt;/name&amp;gt;&lt;br /&gt;
         &amp;lt;message&amp;gt;&lt;br /&gt;
             &amp;lt;source&amp;gt;i18n=Internationalization&amp;lt;/source&amp;gt;&lt;br /&gt;
             &amp;lt;translation&amp;gt;i20e=Internazionalizzazione&amp;lt;/translation&amp;gt;&lt;br /&gt;
         &amp;lt;/message&amp;gt;&lt;br /&gt;
     &amp;lt;/context&amp;gt;&lt;br /&gt;
 &amp;lt;/TS&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The .ts file is than converted to the .qm file format, a compact binary format that provides extremely fast lookups for translations, with a tool named lrelease.&lt;br /&gt;
&lt;br /&gt;
The creation of .qm files can also be done with the GNU gettext tools: with &amp;quot;xgettext --qt&amp;quot; as string extractor for producing the .pot file. And then convert the translated file (.po) with the &amp;quot;msgfmt --qt&amp;quot; command for creating the .qm files.&lt;br /&gt;
&lt;br /&gt;
=== ts Editors ===&lt;br /&gt;
&lt;br /&gt;
*QT Linguistic&lt;br /&gt;
&lt;br /&gt;
===Positive aspects===&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;full&amp;quot; support for unicode character encodings&lt;br /&gt;
* In trolltech's opinion it's a human readable text&lt;br /&gt;
&lt;br /&gt;
===Negative aspects===&lt;br /&gt;
&lt;br /&gt;
* QT's translation framework does not support plurals&lt;br /&gt;
* Qt message catalog format supports Unicode only in the translated strings, not in the untranslated strings&lt;br /&gt;
&lt;br /&gt;
== xliff Files ==&lt;br /&gt;
&lt;br /&gt;
===Format of XLIFF files===&lt;br /&gt;
&lt;br /&gt;
XLIFF is the XML Localization Interchange File Format. It is intended to give any software provider a single interchange file format that can be understood by any localization provider.&lt;br /&gt;
&lt;br /&gt;
You can find a XLIFF Tree Structure [http://www.oasis-open.org/committees/xliff/documents/xliff-specification.htm#AppTree here]&lt;br /&gt;
&lt;br /&gt;
=== ts Editors ===&lt;br /&gt;
&lt;br /&gt;
*[http://www.heartsome.net/EN/xlfedit.html heartsome]&lt;br /&gt;
*[https://open-language-tools.dev.java.net/editor/about-xliff-editor.html XLIFF Translation Editor]&lt;br /&gt;
&lt;br /&gt;
===Positive aspects===&lt;br /&gt;
&lt;br /&gt;
* OASIS standard&lt;br /&gt;
&lt;br /&gt;
===Negative aspects===&lt;br /&gt;
&lt;br /&gt;
* complicated plural form handling&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
* [http://www.gnu.org/software/gettext/manual/html_mono/gettext.html Gettext manual (for PO files)]&lt;br /&gt;
* [http://librarian.launchpad.net/2395419/it.po Example of a PO file (from rosetta)]&lt;br /&gt;
* [http://news.com.com/2100-1013_3-5146581.html Microsoft and XML]&lt;br /&gt;
* [http://en.wikipedia.org/wiki/XML#Quick_syntax_tour XML syntax description on Wikipedia]&lt;br /&gt;
* [http://doc.trolltech.com/4.1/i18n.html Trolltech i18n]&lt;br /&gt;
* [http://translate.sourceforge.net/wiki/ open source i18n and l10n project]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=User_talk:Manus&amp;diff=4450</id>
		<title>User talk:Manus</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=User_talk:Manus&amp;diff=4450"/>
				<updated>2006-09-04T08:13:05Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vandalism==&lt;br /&gt;
&lt;br /&gt;
Hi Manus, I wanted to inform you that there are two users that did some vandalism:&lt;br /&gt;
* [[User:Ceas]] did [http://eiffelsoftware.origo.ethz.ch/index.php?title=Main_Page&amp;amp;diff=next&amp;amp;oldid=4215 this]&lt;br /&gt;
* [[User:Moralest]] did [http://eiffelsoftware.origo.ethz.ch/index.php?title=Main_Page&amp;amp;diff=4442&amp;amp;oldid=4401 this]&lt;br /&gt;
I propose to block their username... I've already removed the changes. [[User:Etienner|&amp;lt;font color=&amp;quot;Yellow&amp;quot;&amp;gt;'''E'''&amp;lt;/font&amp;gt;&amp;lt;font color=&amp;quot;Black&amp;quot;&amp;gt;'''T'''&amp;lt;/font&amp;gt;&amp;lt;font color=&amp;quot;Yellow&amp;quot;&amp;gt;'''N'''&amp;lt;/font&amp;gt;]] &amp;lt;sup&amp;gt;[[User talk:Etienner|'''&amp;lt;font color=&amp;quot;Yellow&amp;quot;&amp;gt;talk&amp;lt;/font&amp;gt;''']]&amp;lt;/sup&amp;gt;&lt;br /&gt;
&lt;br /&gt;
: Not worth it; those are certainlyjust bots, probably run from some zombie. [[User:Leo|Leo]] 10:13, 4 September 2006 (CEST)&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=4199</id>
		<title>Internationalization</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=4199"/>
				<updated>2006-08-16T00:31:33Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
===Brief history===&lt;br /&gt;
&lt;br /&gt;
Orginally the internationalisation (i18n) project was started as a required project for an ETH Software Architecture course.&lt;br /&gt;
The result was less then perfect; pages referring to this first version have been given an 'SA' prefix.&lt;br /&gt;
Some members of this SA project team decided to rewrite the library as a semester project. Pages on the wiki not prefixed with 'SA' are either applicable to both or to the semester project.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=== Specific goals of the semester project ===&lt;br /&gt;
&lt;br /&gt;
''to be completed''&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
''add milestones of semesterproject''&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/developer_manual|Developer manual]]: developer manual for the i18n library&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: setbacks we have encountered&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
== Semester project ==&lt;br /&gt;
&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* Supervisor: [[User:Schoelle| Bernd Schoeller]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Old SA project team ==&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization_SA_project&amp;diff=4198</id>
		<title>Internationalization SA project</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization_SA_project&amp;diff=4198"/>
				<updated>2006-08-16T00:26:16Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization SA project]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
==M2: May 5 ==&lt;br /&gt;
* [[Internationalization/feasibility|feasibility]]: look at string classes (unicode and not) and how strings are used in EiffelStudio (creation, composition) ''(Ivano, Carlo, Leo, Hong)''&lt;br /&gt;
* [[Internationalization/file_format|file format]]: compare existing file formats for dictionaries ''(Etienne, Andreas)''&lt;br /&gt;
* [[Internationalization/tool_evaluation|tool evaluation]]: list and compare existing translation tools ''(Christian, Martino)''&lt;br /&gt;
&lt;br /&gt;
==M3: June 13 ==&lt;br /&gt;
* write an initial .po to start translating and have a .mo for testing ''(Leo, Carlo)''&lt;br /&gt;
* [[Internationalization/mo parser|mo parser]]: extract translated strings from .mo files ''([[User:etienner|Etienne]], [[User:Trosim|Martino]])''&lt;br /&gt;
* [[Internationalization/translation function|translation function]]: map hard-coded strings to translated strings ''(Martino)''&lt;br /&gt;
** find a solution with templates&lt;br /&gt;
** globality: how to implement, the object should be shared between all modules (see [[Internationalization/class_structure|class structure]])&lt;br /&gt;
** find out how to use plurals (see [[Internationalization/plural_forms|plural forms]])&lt;br /&gt;
* Test unicode support in Vision2. [See test application in the [https://eiffelsoftware.origo.ethz.ch/svn/es/branches/soft-arch/Src/library/i18n/example/ SVN repository]]&lt;br /&gt;
* compile a [[Internationalization/l10n_features|list of basic features]] to provide (e.g. date/time format, system locale) ''[deferred]''&lt;br /&gt;
&lt;br /&gt;
==M4: June 28 ==&lt;br /&gt;
* internationalization of EiffelStudio: surround strings with our functions&lt;br /&gt;
* [[Internationalization/translation|translation]] of EiffelStudio in some languages, for demo purposes (Italian, German, Chinese, ...) (see [http://slhk.ath.cx/projects/estudio/ pootle] ''Note: this is dead now -Leo'')&lt;br /&gt;
* [[Internationalization/code_parser|code parser]]: extract strings to be translated from source code and generate .pot file ''(Leo)''&lt;br /&gt;
* language selection: add an entry in the preferences system&lt;br /&gt;
* create a function to detect current environment language and settings (aka [[Internationalization/locale|locale]])&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
= Possible future developments =&lt;br /&gt;
&lt;br /&gt;
* collaborate with the [[ESWizard]] team. Create wizards for programs with translation facilities.&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/requirements_specification|Requirements specification]]&lt;br /&gt;
* [[Internationalization/SA_developer_manual|Developer manual]]&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: why can't achieve all of our goals&lt;br /&gt;
&lt;br /&gt;
= l10n: completed and on the work =&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;3&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
!'''Language'''&lt;br /&gt;
!'''Status'''&lt;br /&gt;
|-&lt;br /&gt;
|Arabic&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Chinese&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Italian&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Rhaeto-Romanic&lt;br /&gt;
|Active - Ready for use&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/class_structure&amp;diff=4197</id>
		<title>Internationalization/class structure</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/class_structure&amp;diff=4197"/>
				<updated>2006-08-16T00:24:23Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
&lt;br /&gt;
''TODO: upload semesterproject UML diagam''&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/developer_manual&amp;diff=4196</id>
		<title>Internationalization/developer manual</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/developer_manual&amp;diff=4196"/>
				<updated>2006-08-16T00:23:46Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization]]&lt;br /&gt;
&lt;br /&gt;
{{Warning|This is the developer manual for the i18n library developed as a Software Architecture project. }}&lt;br /&gt;
&lt;br /&gt;
= How to design the software =&lt;br /&gt;
There is only a few things which can help you using our library, the most important one is dividing completely the logic of the program from the content.&lt;br /&gt;
In other words, you should write a class which contains all the strings you use in the program; so applying out system will be very easy.&lt;br /&gt;
&lt;br /&gt;
= How to use the library =&lt;br /&gt;
&lt;br /&gt;
Here you can find instructions on how to use our library; how to initialize the system and how to make the translations actually appear in your application.&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
To initialize the library you should have a class that inherits from the SHARED_I18N_LOCALIZATOR; this will bring you all the necessary infrastructure to start localizing your software.&lt;br /&gt;
&lt;br /&gt;
What to do?&lt;br /&gt;
* create datasource&lt;br /&gt;
* create datastructure&lt;br /&gt;
* load localizator&lt;br /&gt;
&lt;br /&gt;
=== Creating a datasource ===&lt;br /&gt;
&lt;br /&gt;
We equip you with a simple factory to create the sources, simply create an I18N_DATASOURCE_FACTORY&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datasource_factory: I18N_DATASOURCE_FACTORY&lt;br /&gt;
&lt;br /&gt;
create datasource_factory.make&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you now have the possibility to create a new source based on an mo file, as follows&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datasource: I18N_DATASOURCE&lt;br /&gt;
&lt;br /&gt;
datasource_factory.use_mo_file(mo_file_path)&lt;br /&gt;
if datasource_factory.last_datasource /= Void then&lt;br /&gt;
  datasource := datasource_factory.last_datasource&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
if something went wrong, you can alway fallback with an empty datasource&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datasource_factory.use_empty_source&lt;br /&gt;
datasource := datasource_factory.last_datasource&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The datasource is ready, you should create a datastructure for storing the strings.&lt;br /&gt;
&lt;br /&gt;
=== Creating a datastructure ===&lt;br /&gt;
&lt;br /&gt;
We provide you with a simple factory to create datastructures, so follow the example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datastructure_factory: I18N_DATASTRUCTURE_FACTORY&lt;br /&gt;
&lt;br /&gt;
create datastructure_factory.make&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now create, for example, an hash table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datastructure: I18N_DATASTRUCTURE&lt;br /&gt;
&lt;br /&gt;
datastructure_factory.use_hash_table&lt;br /&gt;
if datastructure_factory.last_datastructure /= Void then&lt;br /&gt;
  datastructure := datastructure_factory.last_datastructure&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and, even in this case, if something went wrong, you can create a dummy datastructure&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datastructure_factory.use_dummy&lt;br /&gt;
datastructure := datastructure_factory.last_datastructure&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that you have the datastructure ready, you can load the localizator.&lt;br /&gt;
&lt;br /&gt;
=== Loading the localizator ===&lt;br /&gt;
&lt;br /&gt;
It's important that you do this part before trying to localize any string, if not, the localizator would serve you what you pass as argument.&lt;br /&gt;
&lt;br /&gt;
Pass the source to the localizator&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
i18n_use_datasource(datasource)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then pass the datastructure&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
i18n_use_datastructure(datastructure)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and finally load the localizator with the new source and structure&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
i18n_load&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You now have a working localization environment!&lt;br /&gt;
&lt;br /&gt;
{{Warning|If you don't assign a source AND a structure AND then call load, the system will continue to use the old ones.}}&lt;br /&gt;
&lt;br /&gt;
== Localization ==&lt;br /&gt;
&lt;br /&gt;
Here you can find some instructions to translate the strings of you program, including substituting variables into templates.&lt;br /&gt;
&lt;br /&gt;
=== Translating simple strings ===&lt;br /&gt;
&lt;br /&gt;
If you have a simple string to translate, like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
simple_string: STRING&lt;br /&gt;
&lt;br /&gt;
simple_string := &amp;quot;A simple string&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you only have to enclose the string by the simple i18n() function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
simple_string := i18n(&amp;quot;A simple string&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the system will then be charged of the translation in whatever language you've chosen.&lt;br /&gt;
&lt;br /&gt;
=== Translating plurals ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you must change the translated string in relation with a variable; this piece of code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string: STRING&lt;br /&gt;
i: INTEGER&lt;br /&gt;
&lt;br /&gt;
if i = 1 then&lt;br /&gt;
  string := &amp;quot;There is 1 file&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
  string := &amp;quot;There are more files&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will be written as follows using our system&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := i18n_pl(&amp;quot;There is 1 file&amp;quot;, &amp;quot;There are more files&amp;quot;, i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the right form will be selected and displayed for you.&lt;br /&gt;
&lt;br /&gt;
=== Translating with templates ===&lt;br /&gt;
&lt;br /&gt;
{{Warning|We encourage you to use a stand alone template engine and not rely on our built-in functions, which will not be maintained.}}&lt;br /&gt;
&lt;br /&gt;
You can use our library to translate something like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := &amp;quot;Number &amp;quot; + i.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in this way&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := i18n_comp(&amp;quot;Number $1&amp;quot;, [i])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and of course you can do the same with the plural forms&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
if i = 1 then&lt;br /&gt;
  string := &amp;quot;There is 1 file&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
  string := &amp;quot;There are &amp;quot; + i.out + &amp;quot; files&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := i18n_comp_pl(&amp;quot;There is 1 file&amp;quot;, &amp;quot;There are $1 files&amp;quot;, [i], i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we've so covered all the possibilities.&lt;br /&gt;
&lt;br /&gt;
= How to translate / use translation files =&lt;br /&gt;
&lt;br /&gt;
== Editing PO files == &lt;br /&gt;
&lt;br /&gt;
You can edit the PO files created with your preferred editor; some possible tools are listed [[Internationalization/tool_evaluation|here]].&lt;br /&gt;
&lt;br /&gt;
== Issues with MO files ==&lt;br /&gt;
&lt;br /&gt;
Into the header section of the PO file must be present the &amp;quot;Plural-Forms&amp;quot; header.&lt;br /&gt;
&lt;br /&gt;
It looks like this line:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Plural-Forms: nplurals=2; plural=(n!=1);&amp;quot;&lt;br /&gt;
&lt;br /&gt;
with &amp;quot;nplural&amp;quot; being the number of plurals of the destination language and &amp;quot;plural&amp;quot; the C-like function for finding the right plural form starting with an integer.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/SA_developer_manual&amp;diff=4195</id>
		<title>Internationalization/SA developer manual</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/SA_developer_manual&amp;diff=4195"/>
				<updated>2006-08-16T00:22:18Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: copy/paste-moved from Internationalization/developer manual&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization SA project]]&lt;br /&gt;
&lt;br /&gt;
= How to design the software =&lt;br /&gt;
There is only a few things which can help you using our library, the most important one is dividing completely the logic of the program from the content.&lt;br /&gt;
In other words, you should write a class which contains all the strings you use in the program; so applying out system will be very easy.&lt;br /&gt;
&lt;br /&gt;
= How to use the library =&lt;br /&gt;
&lt;br /&gt;
Here you can find instructions on how to use our library; how to initialize the system and how to make the translations actually appear in your application.&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
&lt;br /&gt;
To initialize the library you should have a class that inherits from the SHARED_I18N_LOCALIZATOR; this will bring you all the necessary infrastructure to start localizing your software.&lt;br /&gt;
&lt;br /&gt;
What to do?&lt;br /&gt;
* create datasource&lt;br /&gt;
* create datastructure&lt;br /&gt;
* load localizator&lt;br /&gt;
&lt;br /&gt;
=== Creating a datasource ===&lt;br /&gt;
&lt;br /&gt;
We equip you with a simple factory to create the sources, simply create an I18N_DATASOURCE_FACTORY&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datasource_factory: I18N_DATASOURCE_FACTORY&lt;br /&gt;
&lt;br /&gt;
create datasource_factory.make&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you now have the possibility to create a new source based on an mo file, as follows&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datasource: I18N_DATASOURCE&lt;br /&gt;
&lt;br /&gt;
datasource_factory.use_mo_file(mo_file_path)&lt;br /&gt;
if datasource_factory.last_datasource /= Void then&lt;br /&gt;
  datasource := datasource_factory.last_datasource&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
if something went wrong, you can alway fallback with an empty datasource&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datasource_factory.use_empty_source&lt;br /&gt;
datasource := datasource_factory.last_datasource&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The datasource is ready, you should create a datastructure for storing the strings.&lt;br /&gt;
&lt;br /&gt;
=== Creating a datastructure ===&lt;br /&gt;
&lt;br /&gt;
We provide you with a simple factory to create datastructures, so follow the example&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datastructure_factory: I18N_DATASTRUCTURE_FACTORY&lt;br /&gt;
&lt;br /&gt;
create datastructure_factory.make&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can now create, for example, an hash table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datastructure: I18N_DATASTRUCTURE&lt;br /&gt;
&lt;br /&gt;
datastructure_factory.use_hash_table&lt;br /&gt;
if datastructure_factory.last_datastructure /= Void then&lt;br /&gt;
  datastructure := datastructure_factory.last_datastructure&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and, even in this case, if something went wrong, you can create a dummy datastructure&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
datastructure_factory.use_dummy&lt;br /&gt;
datastructure := datastructure_factory.last_datastructure&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that you have the datastructure ready, you can load the localizator.&lt;br /&gt;
&lt;br /&gt;
=== Loading the localizator ===&lt;br /&gt;
&lt;br /&gt;
It's important that you do this part before trying to localize any string, if not, the localizator would serve you what you pass as argument.&lt;br /&gt;
&lt;br /&gt;
Pass the source to the localizator&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
i18n_use_datasource(datasource)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then pass the datastructure&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
i18n_use_datastructure(datastructure)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and finally load the localizator with the new source and structure&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
i18n_load&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You now have a working localization environment!&lt;br /&gt;
&lt;br /&gt;
{{Warning|If you don't assign a source AND a structure AND then call load, the system will continue to use the old ones.}}&lt;br /&gt;
&lt;br /&gt;
== Localization ==&lt;br /&gt;
&lt;br /&gt;
Here you can find some instructions to translate the strings of you program, including substituting variables into templates.&lt;br /&gt;
&lt;br /&gt;
=== Translating simple strings ===&lt;br /&gt;
&lt;br /&gt;
If you have a simple string to translate, like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
simple_string: STRING&lt;br /&gt;
&lt;br /&gt;
simple_string := &amp;quot;A simple string&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you only have to enclose the string by the simple i18n() function&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
simple_string := i18n(&amp;quot;A simple string&amp;quot;)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the system will then be charged of the translation in whatever language you've chosen.&lt;br /&gt;
&lt;br /&gt;
=== Translating plurals ===&lt;br /&gt;
&lt;br /&gt;
Sometimes you must change the translated string in relation with a variable; this piece of code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string: STRING&lt;br /&gt;
i: INTEGER&lt;br /&gt;
&lt;br /&gt;
if i = 1 then&lt;br /&gt;
  string := &amp;quot;There is 1 file&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
  string := &amp;quot;There are more files&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will be written as follows using our system&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := i18n_pl(&amp;quot;There is 1 file&amp;quot;, &amp;quot;There are more files&amp;quot;, i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
the right form will be selected and displayed for you.&lt;br /&gt;
&lt;br /&gt;
=== Translating with templates ===&lt;br /&gt;
&lt;br /&gt;
{{Warning|We encourage you to use a stand alone template engine and not rely on our built-in functions, which will not be maintained.}}&lt;br /&gt;
&lt;br /&gt;
You can use our library to translate something like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := &amp;quot;Number &amp;quot; + i.out&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in this way&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := i18n_comp(&amp;quot;Number $1&amp;quot;, [i])&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and of course you can do the same with the plural forms&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
if i = 1 then&lt;br /&gt;
  string := &amp;quot;There is 1 file&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
  string := &amp;quot;There are &amp;quot; + i.out + &amp;quot; files&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
would look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;[eiffel,N]&lt;br /&gt;
string := i18n_comp_pl(&amp;quot;There is 1 file&amp;quot;, &amp;quot;There are $1 files&amp;quot;, [i], i)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
we've so covered all the possibilities.&lt;br /&gt;
&lt;br /&gt;
= How to translate / use translation files =&lt;br /&gt;
&lt;br /&gt;
== Editing PO files == &lt;br /&gt;
&lt;br /&gt;
You can edit the PO files created with your preferred editor; some possible tools are listed [[Internationalization/tool_evaluation|here]].&lt;br /&gt;
&lt;br /&gt;
== Issues with MO files ==&lt;br /&gt;
&lt;br /&gt;
Into the header section of the PO file must be present the &amp;quot;Plural-Forms&amp;quot; header.&lt;br /&gt;
&lt;br /&gt;
It looks like this line:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Plural-Forms: nplurals=2; plural=(n!=1);&amp;quot;&lt;br /&gt;
&lt;br /&gt;
with &amp;quot;nplural&amp;quot; being the number of plurals of the destination language and &amp;quot;plural&amp;quot; the C-like function for finding the right plural form starting with an integer.&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/class_structure&amp;diff=4194</id>
		<title>Internationalization/class structure</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/class_structure&amp;diff=4194"/>
				<updated>2006-08-16T00:21:12Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization SA project]]&lt;br /&gt;
&lt;br /&gt;
''TODO: upload semesterproject UML diagam''&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/SA_class_structure&amp;diff=4193</id>
		<title>Internationalization/SA class structure</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/SA_class_structure&amp;diff=4193"/>
				<updated>2006-08-16T00:20:27Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization SA project]]&lt;br /&gt;
&lt;br /&gt;
== Class structure ==&lt;br /&gt;
&lt;br /&gt;
[[Image:Internationalization-ClassDiagram.png|Class Diagram]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Class description ==&lt;br /&gt;
&lt;br /&gt;
{{Warning|The information below is not up-to-date, revision coming soon.}}&lt;br /&gt;
&lt;br /&gt;
That's the actual structure of the whole thing:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SHARED_I18N_LOCALIZATOR =&amp;gt; I18N_LOCALIZATOR =&amp;gt; I18N_TEMPLATE_FORMATTER, (I18N_DATASTRUCTURE =&amp;gt; I18N_MO_PARSER, I18N_PLURAL_FORMS)&lt;br /&gt;
::^&lt;br /&gt;
::|&lt;br /&gt;
CLASS_TO_LOCALIZE&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The CLASS_TO_LOCALIZE simply inherits from our SHARED_I18N_LOCALIZATOR, which only purpose is to return always the same &amp;quot;localizator: I18N_LOCALIZATOR&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
This class will in turn ask the archive for the translated strings and then pass it, along with all the arguments, to the template formatter, which will produce the final displayable string.&lt;br /&gt;
&lt;br /&gt;
The datastructure will use the mo_parser for the initial filling of the datastructure (proposal: do it incrementally); the plural forms resolver will be used to find out which plural form should be used.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All this structure is already in place; we don't know yet how to open the right file, should be implemented by an environment variable or for example with a drop-down menu in the configuration dialog?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SHARED_I18N_LOCALIZATOR&lt;br /&gt;
&lt;br /&gt;
* translator: I18N_LOCALIZATOR&lt;br /&gt;
* i18n(string): STRING&lt;br /&gt;
* i18n_comp(string, args): STRING (or what you want)&lt;br /&gt;
i18n (i18n_pl) and i18n_comp (i18n_comp_pl) are interfaces to the translator&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I18N_LOCALIZATOR&lt;br /&gt;
* archive: I18N_DATASTRUCTURE&lt;br /&gt;
* ask(string): STRING (simple interface to ask the archive)&lt;br /&gt;
* solve_template(string, args): STRING (function that compose a string from template+arguments)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I18N_DATASCTRUCTURE&lt;br /&gt;
* mo_parser: I18N_MO_PARSER&lt;br /&gt;
* load(n) (interface to the parser)&lt;br /&gt;
* translate(STRING): STRING (interface to the I18N_LOCALIZATOR)&lt;br /&gt;
* data_structure: HASH|ARRAY (where the strings are effectively stored)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I18N_MO_PARSER&lt;br /&gt;
* open(file)&lt;br /&gt;
* load(n): STRING&lt;br /&gt;
* load_translated(n): STRING&lt;br /&gt;
* load_hash_entry(n): STRING&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I18N_PLURAL_FORMS (more on this [[Internationalization/plural_forms|here]])&lt;br /&gt;
* get_plural_form(n): INTEGER (interface to the datastructure)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I18N_TEMPLATE_FORMATTER&lt;br /&gt;
* solve_template(a_template: STRING_32; a_args: TUPLE): STRING_32 (interface to the localizator)&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization/SA_project_milestones&amp;diff=4192</id>
		<title>Internationalization/SA project milestones</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization/SA_project_milestones&amp;diff=4192"/>
				<updated>2006-08-16T00:18:56Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Internationalization SA project]]&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
==M2: May 5 ==&lt;br /&gt;
* [[Internationalization/feasibility|feasibility]]: look at string classes (unicode and not) and how strings are used in EiffelStudio (creation, composition) ''(Ivano, Carlo, Leo, Hong)''&lt;br /&gt;
* [[Internationalization/file_format|file format]]: compare existing file formats for dictionaries ''(Etienne, Andreas)''&lt;br /&gt;
* [[Internationalization/tool_evaluation|tool evaluation]]: list and compare existing translation tools ''(Christian, Martino)''&lt;br /&gt;
&lt;br /&gt;
==M3: June 13 ==&lt;br /&gt;
* write an initial .po to start translating and have a .mo for testing ''(Leo, Carlo)''&lt;br /&gt;
* [[Internationalization/mo parser|mo parser]]: extract translated strings from .mo files ''([[User:etienner|Etienne]], [[User:Trosim|Martino]])''&lt;br /&gt;
* [[Internationalization/translation function|translation function]]: map hard-coded strings to translated strings ''(Martino)''&lt;br /&gt;
** find a solution with templates&lt;br /&gt;
** globality: how to implement, the object should be shared between all modules (see [[Internationalization/class_structure|class structure]])&lt;br /&gt;
** find out how to use plurals (see [[Internationalization/plural_forms|plural forms]])&lt;br /&gt;
* Test unicode support in Vision2. [See test application in the [https://eiffelsoftware.origo.ethz.ch/svn/es/branches/soft-arch/Src/library/i18n/example/ SVN repository]]&lt;br /&gt;
* compile a [[Internationalization/l10n_features|list of basic features]] to provide (e.g. date/time format, system locale) ''[deferred]''&lt;br /&gt;
&lt;br /&gt;
==M4: June 28 ==&lt;br /&gt;
* internationalization of EiffelStudio: surround strings with our functions&lt;br /&gt;
* [[Internationalization/translation|translation]] of EiffelStudio in some languages, for demo purposes (Italian, German, Chinese, ...) (see [http://slhk.ath.cx/projects/estudio/ pootle])&lt;br /&gt;
* [[Internationalization/code_parser|code parser]]: extract strings to be translated from source code and generate .pot file ''(Leo)''&lt;br /&gt;
* language selection: add an entry in the preferences system&lt;br /&gt;
* create a function to detect current environment language and settings (aka [[Internationalization/locale|locale]])&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization_SA_project&amp;diff=4191</id>
		<title>Internationalization SA project</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization_SA_project&amp;diff=4191"/>
				<updated>2006-08-16T00:18:45Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization SA project]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
==M2: May 5 ==&lt;br /&gt;
* [[Internationalization/feasibility|feasibility]]: look at string classes (unicode and not) and how strings are used in EiffelStudio (creation, composition) ''(Ivano, Carlo, Leo, Hong)''&lt;br /&gt;
* [[Internationalization/file_format|file format]]: compare existing file formats for dictionaries ''(Etienne, Andreas)''&lt;br /&gt;
* [[Internationalization/tool_evaluation|tool evaluation]]: list and compare existing translation tools ''(Christian, Martino)''&lt;br /&gt;
&lt;br /&gt;
==M3: June 13 ==&lt;br /&gt;
* write an initial .po to start translating and have a .mo for testing ''(Leo, Carlo)''&lt;br /&gt;
* [[Internationalization/mo parser|mo parser]]: extract translated strings from .mo files ''([[User:etienner|Etienne]], [[User:Trosim|Martino]])''&lt;br /&gt;
* [[Internationalization/translation function|translation function]]: map hard-coded strings to translated strings ''(Martino)''&lt;br /&gt;
** find a solution with templates&lt;br /&gt;
** globality: how to implement, the object should be shared between all modules (see [[Internationalization/class_structure|class structure]])&lt;br /&gt;
** find out how to use plurals (see [[Internationalization/plural_forms|plural forms]])&lt;br /&gt;
* Test unicode support in Vision2. [See test application in the [https://eiffelsoftware.origo.ethz.ch/svn/es/branches/soft-arch/Src/library/i18n/example/ SVN repository]]&lt;br /&gt;
* compile a [[Internationalization/l10n_features|list of basic features]] to provide (e.g. date/time format, system locale) ''[deferred]''&lt;br /&gt;
&lt;br /&gt;
==M4: June 28 ==&lt;br /&gt;
* internationalization of EiffelStudio: surround strings with our functions&lt;br /&gt;
* [[Internationalization/translation|translation]] of EiffelStudio in some languages, for demo purposes (Italian, German, Chinese, ...) (see [http://slhk.ath.cx/projects/estudio/ pootle])&lt;br /&gt;
* [[Internationalization/code_parser|code parser]]: extract strings to be translated from source code and generate .pot file ''(Leo)''&lt;br /&gt;
* language selection: add an entry in the preferences system&lt;br /&gt;
* create a function to detect current environment language and settings (aka [[Internationalization/locale|locale]])&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
= Possible future developments =&lt;br /&gt;
&lt;br /&gt;
* collaborate with the [[ESWizard]] team. Create wizards for programs with translation facilities.&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/requirements_specification|Requirements specification]]&lt;br /&gt;
* [[Internationalization/developer_manual|Developer manual]]&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: why can't achieve all of our goals&lt;br /&gt;
&lt;br /&gt;
= l10n: completed and on the work =&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;3&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
!'''Language'''&lt;br /&gt;
!'''Status'''&lt;br /&gt;
|-&lt;br /&gt;
|Arabic&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Chinese&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Italian&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Rhaeto-Romanic&lt;br /&gt;
|Active - Ready for use&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=4190</id>
		<title>Internationalization</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization&amp;diff=4190"/>
				<updated>2006-08-16T00:17:45Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: removed some sa-specific stuff&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=== Specific goals of the semester project ===&lt;br /&gt;
&lt;br /&gt;
''to be completed''&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/developer_manual|Developer manual]]&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: why can't achieve all of our goals&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
== Semester project ==&lt;br /&gt;
&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* Supervisor: [[User:Schoelle| Bernd Schoeller]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Old SA project team ==&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	<entry>
		<id>https://dev.eiffel.com/index.php?title=Internationalization_SA_project&amp;diff=4189</id>
		<title>Internationalization SA project</title>
		<link rel="alternate" type="text/html" href="https://dev.eiffel.com/index.php?title=Internationalization_SA_project&amp;diff=4189"/>
				<updated>2006-08-16T00:14:22Z</updated>
		
		<summary type="html">&lt;p&gt;Leo: old Internationalization page - copy/paste move because I don't have proper move permissions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Projects]]&lt;br /&gt;
[[Category:Internationalization]]&lt;br /&gt;
[[Category:Internationalization SA project]]&lt;br /&gt;
[[Image:ebabylon.png|right|frame| Our Eiffel Tower of Babylon]]&lt;br /&gt;
&lt;br /&gt;
=Overview=&lt;br /&gt;
&lt;br /&gt;
''&amp;quot;Many [people] would simply love seeing their computer screen showing a lot less of English, and far more of their own language.&amp;quot;'' -- gettext doc&lt;br /&gt;
&lt;br /&gt;
Our aim is not only to provide a framework to ease the translation of Eiffel-written applications, allowing the user to chose his/her preferred language at runtime, but also to let the developer access information and formats based on users' locale.&lt;br /&gt;
&lt;br /&gt;
==What is internationalisation?==&lt;br /&gt;
&lt;br /&gt;
The first thing that comes to mind is translation. But internationalisation isn't restricted to enabling translation: it includes making it possible to localise notations (time, date, numbers), measures, paper size, and much more.&lt;br /&gt;
&lt;br /&gt;
==What should we achieve?==&lt;br /&gt;
*Applications should be able to load localized strings at runtime and be provided with localized format strings (e.g date format).&lt;br /&gt;
*Developers can use tools that automagically extract strings from source code and can try to get them translated in a file to distribute along with the application.&lt;br /&gt;
*Users will still be unhappy and get depressed ''but in their own language'', which we can all agree is a significant step forward.&lt;br /&gt;
&lt;br /&gt;
=Milestones=&lt;br /&gt;
&lt;br /&gt;
==M2: May 5 ==&lt;br /&gt;
* [[Internationalization/feasibility|feasibility]]: look at string classes (unicode and not) and how strings are used in EiffelStudio (creation, composition) ''(Ivano, Carlo, Leo, Hong)''&lt;br /&gt;
* [[Internationalization/file_format|file format]]: compare existing file formats for dictionaries ''(Etienne, Andreas)''&lt;br /&gt;
* [[Internationalization/tool_evaluation|tool evaluation]]: list and compare existing translation tools ''(Christian, Martino)''&lt;br /&gt;
&lt;br /&gt;
==M3: June 13 ==&lt;br /&gt;
* write an initial .po to start translating and have a .mo for testing ''(Leo, Carlo)''&lt;br /&gt;
* [[Internationalization/mo parser|mo parser]]: extract translated strings from .mo files ''([[User:etienner|Etienne]], [[User:Trosim|Martino]])''&lt;br /&gt;
* [[Internationalization/translation function|translation function]]: map hard-coded strings to translated strings ''(Martino)''&lt;br /&gt;
** find a solution with templates&lt;br /&gt;
** globality: how to implement, the object should be shared between all modules (see [[Internationalization/class_structure|class structure]])&lt;br /&gt;
** find out how to use plurals (see [[Internationalization/plural_forms|plural forms]])&lt;br /&gt;
* Test unicode support in Vision2. [See test application in the [https://eiffelsoftware.origo.ethz.ch/svn/es/branches/soft-arch/Src/library/i18n/example/ SVN repository]]&lt;br /&gt;
* compile a [[Internationalization/l10n_features|list of basic features]] to provide (e.g. date/time format, system locale) ''[deferred]''&lt;br /&gt;
&lt;br /&gt;
==M4: June 28 ==&lt;br /&gt;
* internationalization of EiffelStudio: surround strings with our functions&lt;br /&gt;
* [[Internationalization/translation|translation]] of EiffelStudio in some languages, for demo purposes (Italian, German, Chinese, ...) (see [http://slhk.ath.cx/projects/estudio/ pootle])&lt;br /&gt;
* [[Internationalization/code_parser|code parser]]: extract strings to be translated from source code and generate .pot file ''(Leo)''&lt;br /&gt;
* language selection: add an entry in the preferences system&lt;br /&gt;
* create a function to detect current environment language and settings (aka [[Internationalization/locale|locale]])&lt;br /&gt;
&lt;br /&gt;
==M5: July ?? ==&lt;br /&gt;
* Refactoring of whole library&lt;br /&gt;
* Use our library for EiffelStudio&lt;br /&gt;
* Clean up Wiki and improve Developer manual&lt;br /&gt;
* Add support for other aspects of localisation - dates, number format etc. ''(possibly we can defer this a bit)''&lt;br /&gt;
** Compile a [[Internationalization/l10n_features | list of basic features]] to provide (e.g. date/time format, system locale) ''(deferred from M3)''&lt;br /&gt;
&lt;br /&gt;
= Possible future developments =&lt;br /&gt;
&lt;br /&gt;
* collaborate with the [[ESWizard]] team. Create wizards for programs with translation facilities.&lt;br /&gt;
&lt;br /&gt;
= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[Internationalization/requirements_specification|Requirements specification]]&lt;br /&gt;
* [[Internationalization/developer_manual|Developer manual]]&lt;br /&gt;
* [[Internationalization/obstacles|Obstacles]]: why can't achieve all of our goals&lt;br /&gt;
&lt;br /&gt;
= l10n: completed and on the work =&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;0&amp;quot; cellspacing=&amp;quot;3&amp;quot; cellpadding=&amp;quot;5&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
!'''Language'''&lt;br /&gt;
!'''Status'''&lt;br /&gt;
|-&lt;br /&gt;
|Arabic&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Chinese&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Italian&lt;br /&gt;
|Active&lt;br /&gt;
|-&lt;br /&gt;
|Rhaeto-Romanic&lt;br /&gt;
|Active - Ready for use&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=Relevant Links=&lt;br /&gt;
[http://www.debian.org/doc/manuals/intro-i18n/ Introduction to i18n]&lt;br /&gt;
&lt;br /&gt;
==What other people have done==&lt;br /&gt;
[http://doc.trolltech.com/4.1/i18n.html internationalisation with QT]&lt;br /&gt;
&lt;br /&gt;
[http://oss.erdfunkstelle.de/kde-i18n/tiki-index.php?page=miniHowtoGui howto for internationalisation of KDE programs ]&lt;br /&gt;
&lt;br /&gt;
[http://l10n.kde.org/docs/translation-howto/ another KDE howto (doesn't Gnome do any internationalisation?)]&lt;br /&gt;
&lt;br /&gt;
=Team=&lt;br /&gt;
&lt;br /&gt;
Everyone interested in this project is welcome to [http://origo.ethz.ch/cgi-bin/mailman/listinfo/es-i18n join our mailinglist] es-i18n@origo.ethz.ch&lt;br /&gt;
&lt;br /&gt;
* Project Leader: [[User:Carlo|Carlo Vanini]]&lt;br /&gt;
* [[User:leo| Leo Fellmann]]&lt;br /&gt;
* [[User:kiwi| Ivano Somaini]]&lt;br /&gt;
* [[User:murbi|Andreas Murbach]]&lt;br /&gt;
* [[User:etienner|Etienne Reichenbach]]&lt;br /&gt;
* [[User:hong |Hong Zhang]]&lt;br /&gt;
* [[User:cconti | Christian Conti]]&lt;br /&gt;
* [[User:Trosim |Martino Trosi]]&lt;br /&gt;
* [[User:Schoelle| Bernd Schoeller]]&lt;/div&gt;</summary>
		<author><name>Leo</name></author>	</entry>

	</feed>