Internationalisation (i18n)
Updated i18n functionality has been pushed to the FarCry 5.1 release. Once the initial 5.0 release is stabilised and the volatility of label changes has come down, we'll activate and test all the great i18n code that has been created to date.
Overview
The webtop and COAPI (meaning all forms that use formtools) have been updated so that every label and description is translated.
A resource bundle is a file that provides translations for in a particular language and region. As well as key-translation pairs, they typically also contain meta-information about a key-translation such as comments, creator, and modifier.
In FarCry resource bundles are stored in /packages/resources/ in core, a plugin, or your project. Their filenames are in the form admin.properties (the default resource bundle) or admin_xx_yy.properties (where "xx" and "YY" is the locale, the language and region codes, of the translation).
When a resource is requested - for example the label on a "Cancel" button - the system first looks in the bundle for the user's locale, then in the default or base bundle.
Translators
Translating is very straight forward. Open the base resource bundle (admin.properties) for the core/plugin/project in a resource bundle editor like RB Manager or the Eclipse ResourceBundle Editor. Use the tool to create a bundle for the locale you require e.g. en_AU (Australian english), and start translating the key-translation pairs.
Regarding keys: At the moment no comments are stored for resources to say where they are used or how. Instead that information is encoded in the resource key. For example webtop labels and descriptions are stored inside a structure corresponding to the webtop structure - webtop.admin@label, content type forms are stored in a structure like coapi.typename.properties.property@label. Other keys reflect the area of the webtop (e.g. fixtree) or part of FarCry framework (e.g. workflow) they are used for, the use (e.g. workflow.buttons), the specific page element (e.g. workflow.buttons.save), then the element attribute (e.g. workflow.buttons.save@label).
To test the translation you need to make sure that the locale you have set up will be loaded in your test project. The project locales are set in the farcryConstructor file in your project www directory. Once this setting is up to date and you have saved your new bundle in the relevant /resources directory, restart the application.
Log into the webtop, edit your profile, select the new locale from the list, and save. When you reload the webtop you should find that is using your translations.
Some webtop elements are available as translated content but aren't included in the base bundle, and others are completely hard coded. An online tracking solution for these elements is in the works, but for the moment they should just be documented in a ticket.
Developers
Resource bundles are accessed by FarCry automatically through the webtop and the content type translations, and manually through the application.rb component.
Webtop
Previously the webtop was translated by setting the label attribute in the xml to a variable (refering to the resource bundle struct in memory). With the refactoring, the label attribute is used to specify the DEFAULT VALUE. If the menu item has no corresponding resource, the default will be used. If it does it will be translated. This process also applies to the Inline Webtop Documentation feature.
By default the menu item is mapped to a resource key in the format webtop.sectionid.subsectionid etc. The attribute is then added to this base key to differentiate it from other translated attributes. e.g. webtop.sectionid.subsectionid@label.
The base key used for a menu item can be overridden by setting the rbkey attribute. This means that if you have an equivelent item in two places on your webtop you can override one to refer to the other. NOTE: this is not recommended - context is a significant factor when translating.
COAPI
Translations of type, rule, and form text can currently be accessed through various i18n methods. In most cases these won't be necessary as all formtool tags are now automatically translated.
Manual access
application.rb.getResource(key, default, locale)
Argument |
Description |
Default Value |
---|---|---|
key |
The key being requested |
For consistency should be in the form category.subcategory.item@attribute, e.g. myplugin.thatform.thisdescription@text |
default |
The default value (used if the key isn't found) |
The key string |
application.rb.formatRBString(rbString, substituteValues, default)
Argument |
Description |
Default Value |
---|---|---|
rbString |
The key being requested. Not changed to key for backwards compatability |
See getResource |
substituteValues |
Either a simple value to replace one value or an array to replace several. Variables defined in the resource string as {1} ... {n} |
Required |
default |
The default value (used if the key isn't found) |
The key string |
Creating the base bundle
Developers who want to support community efforts to translate their plugins should include a complete base resource bundle in their project. To recap: this is a file called /packages/resources/admin.properties in your plugin. This isn't necessary if the code is not going to be released or if you're happy for other developers to complete this next step. By default FarCry handles the lack of a resource bundle invisibly by returning the default values provided in code.
The Resource Bundle Plugin provides functionality for automatically generating bundles based on default values, base bundles, or even with the Google Translate API. But it is important to remember that the automatic generation of the base bundle only handles resources that have been "touched". This means that a button label (for example) will only be known to the plugin if you have actually accessed the form.
Examples
Custom Admin
To i18n the webtop custom admin XML file you can define items as in the following example.
<?xml version="1.0" encoding="utf-8"?> <webtop> <section mergeType="merge" id="content"> <subsection mergeType="merge" id="farGallery" label="[Image Gallery]"> <menu mergeType="merge" id="farSubSection" label="[Image Gallery]" labelType="value"> <menuitem mergeType="merge" id="farimagegallerylist" label="[Image Galleries]" link="/admin/customadmin.cfm?module=customlists/farimagegallery.cfm&plugin=farcryimagegallery" /> </menu> </subsection> </section> </webtop>
For clarity, I tend to use the brackets around items that should be translated. It helps to locate items that haven't been done yet. The admin.properties file to translate the above entry is as follows:
webtop.content.farGallery@label=Image\ Gallery webtop.content.farGallery.farSubSection@label=Image\ Gallery webtop.content.farGallery.farSubSection.farimagegallerylist@label=Image\ Galleries
The first item, webtop, is used to denote that this is for the webtop section of the site. The rest of the key is somewhat like an xpath statement to the thing you want to translate. They are the IDs of each node in the XML, and then the final statement is the name of the attribute preceded with an @ sign.
Content Types
To translate the labels for your content types is similar to how you do the webtop translations except the key's path is slightly different. Using the example of this content type:
<cfcomponent name="Image Gallery" displayname="Image Gallery" extends="farcry.core.packages.types.types" hint="A collection of images" bObjectBroker="true" ObjectBrokerMaxObjects="10000"> <cfproperty name="title" type="string" hint="" ftseq="10" ftFieldset="General" ftLabel="[Title]" ftHint="Enter the title of your gallery." ftvalidation="required" /> ...
To change the label displayed on the add / edit form, the i18n the path would look like this:
coapi.farImageGallery.properties.title@\[title\]=Title
The coapi part is used to signify that it is a content type, and the farImageGallery is the name of the content type (the name of the file, farImageGallery.cfc). The next part properites is a constant to allow access to the content types properties and must be typed exactly as is: properties. The title in the example is the property name (as defined by the name attribute on the cfproperty). The final part of the path statement is the value of the ftLabel preceded with an @ symbol. It is important to note that this is the value of the ftLabel not the term ftLabel. It is also important to note that the [ and ] characters are escaped. If you do not use those charaters in the ftLabel value, then it is simply the value by it self (... title@Title=... for example).
Refreshing Locale Changes
If you make changes to any of the locale files, you will need to reload the application to see the changes. The easiest way to to a reload is to log into the webtop, and click on the Admin tab. From there select the Developer Utilities from the drop down on the left.
You should be looking at Reinitialise screen. From that screen you can tick the webtop and resource bundles check boxes, and then click Update Application. See screen grab below.
Switching Locales for Testing
As mentioned above, to create a new locale translation you'll need to create a file called admin_xx_YY.properties where xx_YY is the locale specification. However, once you create this file, you'll need to activate the locale to see the translation for the new locale. For the following example, we will use simplified Chinese - the locale for simplified Chinese is zh_CN.
1) Create a file named admin_zh_CN.properites in your packages/resources directory. This directory can be in a plugin or in your project depending for which you are providing translations.
This step is harder than it first appears because the underlying libraries FarCry uses are based on the i18n libraries for Java. Sadly, this means that the files must be encoded in iso-8859-1 which mean complex encodings like Chinese must use the Unicode translated equivalents.
For example, instead of typing things like "题目" in the file you need to type "\u9898\u76EE". Translating using Unicode escapes by hand is very tedious and time consuming. Luckly, since FarCry uses the resource bundle standards, however, tools are availiable to make translation much easier. Once such tool is the resource bundle editor for Eclipse: http://sourceforge.net/projects/eclipse-rbe/ See the screen grab below
Download and use a 3rd party tool to do translations. Any Java resource bundle editor will work. I tend to use the Eclipse plugin http://sourceforge.net/projects/eclipse-rbe/
2) Add the locale so it can be chosen. Edit the file farcryConstructor.cfm in your project, and add the locale to the THIS.locales variable. For example, this:
<cfset THIS.locales = "en_AU,en_US" />
becomes this
<cfset THIS.locales = "en_AU,en_US,zh_CN" />
3) Update the application. Use the webtop admin tool to update the entire application (See "Refreshing Locale Changes" above)
4) Edit the profile of account in which you are logged in, and set the locale to your new locale. You can do this from the profile screen (see screen grab below)
After your locale is switched the labels you have defined in the local properties file should then be in use. As seen in the following screen shot. Note, not all labels have been translated (and the ones that have are somewhat bad), but it conveys the point.