Update:Remora Localization: Difference between revisions
No edit summary |
|||
Line 1: | Line 1: | ||
= Localizing 101 = | == Localizing 101 == | ||
''Note:'' Expressions are converted to tags according to the standards mentioned at the end of the page (<code>error_blah</code> and such) so that multiple occurances of the same expression only have to be localized once. | ''Note:'' Expressions are converted to tags according to the standards mentioned at the end of the page (<code>error_blah</code> and such) so that multiple occurances of the same expression only have to be localized once. | ||
''Note 2:'' I assume you have the GNU gettext tools installed, otherwise the scripts won't work and, more importantly, the wrath of the merciless babelfish[TM] will come upon you. | ''Note 2:'' I assume you have the GNU gettext tools installed, otherwise the scripts won't work and, more importantly, the wrath of the merciless babelfish[TM] will come upon you. | ||
== PHP and gettext == | == L10n standards == | ||
* If the string is a "widget" as defined in the shavictionary: (labels, common navigational elements like "Home" or "Top" or "Next") | |||
**element_name_additional | |||
*If the string is prose for explanations, error messages, instructions | |||
**type_name_additional | |||
*If the string is structural text like headers, titles, breadcrumbs, etc. | |||
**If the string is not in a form: | |||
***namespace_pagename_name_additional | |||
**If the string is inside of a form: | |||
***namespace_pagename_formname_element_name_additional | |||
Where: | |||
*namespace is the location in cake of the view, so if it's under /views/developers/ the namespace is "developers" | |||
*pagename is the name of the file, with underscores taken out | |||
*formname is just what you think the form should be called with "form" appended, since cake is actually naming them... (should we make this more specific?) | |||
*name is a unique name for the element (preferably its id) | |||
*element is the closest tag or parameter, so for an images alt tag it would be "alt". For a label it would be "label" | |||
*additional is anything else needed to make a string unique | |||
*type is a global category, like "error" | |||
== Static Strings (PHP and gettext) == | |||
Use php's [http://php.net/gettext gettext] functions to make localized strings, for example: | Use php's [http://php.net/gettext gettext] functions to make localized strings, for example: | ||
: <code>echo _('error_empty_glass');</code> | : <code>echo _('error_empty_glass');</code> | ||
Line 13: | Line 36: | ||
: Some more %s was ordered. | : Some more %s was ordered. | ||
and PHP will put in the value of $beer for %s. | and PHP will put in the value of $beer for %s. | ||
==Dynamic Strings== | |||
We need strings from the database to be localizable as well. This includes all english content in the remora code (Categories, etc.) but also the addons themselves (title, description, etc.) | |||
The ''translations'' table is the hub of our localization. It was born out of the Pear::Translation2 specs, but we decided that the pear class wouldn't fit our needs. The ''translations'' table has 3 primary columns, and then all the additional comments are supported languages. The 3 main columns are: | |||
* `id` - The unique id of the row in the foreign table (that you are getting the translation for) | |||
* `pk_column` - The name of the foreign table (as seen by cake!) | |||
* `translated_column` - The name of the column in the foreign table that you want the translation for. | |||
For example, if I wanted the name of second category in french, I could run: | |||
SELECT `fr` FROM `translations` WHERE `id`=2 AND `pk_column`="Addontypes" AND `translated_column`="name"; | |||
== Updating locales == | == Updating locales == | ||
Line 31: | Line 67: | ||
: <code>./locale/compile-mo.sh ./locale</code> | : <code>./locale/compile-mo.sh ./locale</code> | ||
This will make a .mo file in the same directory of every .po file. | This will make a .mo file in the same directory of every .po file. | ||
Revision as of 07:42, 26 October 2006
Localizing 101
Note: Expressions are converted to tags according to the standards mentioned at the end of the page (error_blah
and such) so that multiple occurances of the same expression only have to be localized once.
Note 2: I assume you have the GNU gettext tools installed, otherwise the scripts won't work and, more importantly, the wrath of the merciless babelfish[TM] will come upon you.
L10n standards
- If the string is a "widget" as defined in the shavictionary: (labels, common navigational elements like "Home" or "Top" or "Next")
- element_name_additional
- If the string is prose for explanations, error messages, instructions
- type_name_additional
- If the string is structural text like headers, titles, breadcrumbs, etc.
- If the string is not in a form:
- namespace_pagename_name_additional
- If the string is inside of a form:
- namespace_pagename_formname_element_name_additional
- If the string is not in a form:
Where:
- namespace is the location in cake of the view, so if it's under /views/developers/ the namespace is "developers"
- pagename is the name of the file, with underscores taken out
- formname is just what you think the form should be called with "form" appended, since cake is actually naming them... (should we make this more specific?)
- name is a unique name for the element (preferably its id)
- element is the closest tag or parameter, so for an images alt tag it would be "alt". For a label it would be "label"
- additional is anything else needed to make a string unique
- type is a global category, like "error"
Static Strings (PHP and gettext)
Use php's gettext functions to make localized strings, for example:
echo _('error_empty_glass');
To do string replacement, use sprintf like this:
echo sprintf(_('glass_refill'), $beer);
Localizers can then translate it similar to:
- Some more %s was ordered.
and PHP will put in the value of $beer for %s.
Dynamic Strings
We need strings from the database to be localizable as well. This includes all english content in the remora code (Categories, etc.) but also the addons themselves (title, description, etc.)
The translations table is the hub of our localization. It was born out of the Pear::Translation2 specs, but we decided that the pear class wouldn't fit our needs. The translations table has 3 primary columns, and then all the additional comments are supported languages. The 3 main columns are:
- `id` - The unique id of the row in the foreign table (that you are getting the translation for)
- `pk_column` - The name of the foreign table (as seen by cake!)
- `translated_column` - The name of the column in the foreign table that you want the translation for.
For example, if I wanted the name of second category in french, I could run:
SELECT `fr` FROM `translations` WHERE `id`=2 AND `pk_column`="Addontypes" AND `translated_column`="name";
Updating locales
extracting
After l10n strings have been added to the code files/views, they have to be extracted. There's a shell script that goes through the controllers, models and views (.php and .thtml files) and searches for gettext strings. The extracted strings are stored into ./messages.po
.
- Execute from the app dir:
./locale/extract-po.sh
merging
To bring the respective .po files of the individual locales up to date, execute from the app directory:
./locale/merge-po.sh messages.po ./locale
- where
messages.po
is the file created by the extraction step and./locale
is the directory in which all the locales lie. The merge script will merge the new strings from messages.po into every *.po file underneath ./locale, then.
"compiling"
After translation, plain text .po files (PO = portable object) have to be translated into binary .mo files (MO = machine object). There's a third script you can run for that:
./locale/compile-mo.sh ./locale
This will make a .mo file in the same directory of every .po file.