-
Notifications
You must be signed in to change notification settings - Fork 24
Introduction to Internationalization
- Introduction
- Configuration
- Using the View Tag
- Persisting Changes to Current Locale
- But Wait, There's More!
Internationalization (or "i18n", since it starts with an 'i', ends with an 'n' and has 18 letters) is an important part of any framework. By allowing users to freely create multilingual and cross-cultural content, we're helping them to reach out to audiences that might otherwise be alienated or confused by the traditional single-locale website.
There are many issues to consider when adding i18n to a framework. There must be a notion of preparing certain data correctly on a per-culture basis. For example, dates are formatted differently in German than they are in English, and formatted very differently in Japanese. Time formatting is different, currencies are different -- even simply displaying a numeral can be a challenge!
We are also concerned with how i18n will be used internally to the framework. For example, with the upcoming version 1.9, we are going to bring validation into the framework. Returning keys from validation errors keeps a user's code much more manageable than returning error messages.
Large parts of the design of internationalization for Mach-II were borrowed from Java's Spring Framework. After evaluating several i18n approaches, theirs was deemed the cleanest and most full-featured. Also since ColdFusion is built on Java, leveraging the technologies that Spring itself uses will make development all the easier; for example, Spring makes heavy use of the java.util.MessageFormat object and java.util.ResourceBundle, which are available to us in ColdFusion.
Now, let's look at some features.
There are two aspects to configuration: resource bundles and the GlobalizationConfigProperty. We'll cover the latter first.
The GlobalizationConfigProperty is a built-in property that communicates to the framework all of the i18n configuration for your application. Using this property you will set up resource bundles, debugging information, and various other data such that the GlobalizationManager will have an idea of how you're using i18n in your application. Here is an example configuration of the GlobalizationConfigManager:
Currently (as of 1.9 M1) only the 'bundles' configuration item is supported.
<property name="i18n" type="MachII.globalization.GlobalizationLoaderProperty">
<parameters>
<parameter name="bundles">
<array>
<element value="./config/resources/test"/>
<element value="./config/resources/secondTest"/>
</array>
</parameter>
</parameters>
</property>
Parameter | Required | Default | Description |
---|---|---|---|
bundles | yes | none | An array specifying the resource bundles to be used with this instance of GlobalizationManager |
A resource bundle is an abstract concept of a package of localization files. For example, you could have content_en_US.properties
and content_en_GB.properties
files to differentiate between American English and British English. In this case, these two files would be a Resource Bundle called "content". You might also hear "content" be referred to as a 'basename' or a 'family' name.
Resource bundles are comprised of several files ending in .properties, of the format:
resourceBundleName_language_REGION.properties
where 'language' is all lower-case (examples: en, es, de) and REGION is all upper-case (examples: US, GB, ES). For example, a .properties file for American English would be named myResourceBundle_en_US.properties
.
Resource bundles should be named intelligently with defaults in mind. For example, if you plan on delivering content localized for American English, British English, and German, you must name your .properties files such that if a user from an unsupported locale uses your application they are given the correct default. Using the given example (and choosing to default to American English) you would name your .properties files resources.properties (for American English), resources_en_GB.properties, and resources_de.properties. Note that there's no REGION in the German file: we want to support all German language speakers in one file regardless of region.
Much like in Java, the .properties files used in Mach-II's i18n are formatted as key = value. For example, in your greetings_en_US.properties you might have:
morning.greeting=Good morning.
and in the greetings_de_DE.properties you might have
morning.greeting = Guten Morgen.
Properties files can also have arguments:
morning.greet.person = Good morning, {0} {1}
The arguments are numbered starting with '0'. If there were more arguments in that given key/value pair they would've been numbered {2}, {3}, and so on.
Now that we have our GlobalizationManager configured and all our Resource Bundles in place, let's look at how we actually display messages. It's very simple:
<cfimport prefix="view" taglib="/MachII/customtags/view" />
<view:message key="morning.greeting"/>
To resolve arguments that you specified in the .properties files, simply use the 'arguments' and 'argumentSeparator' attributes:
<view:message key="morning.greet.person" arguments="Mister;Fantastic" argumentSeparator=";"/>
You can also assign the resultant message directly to a variable instead of outputting it. To do so, simply use the 'var' attribute:
<view:message key="morning.greeting" var="session.greetingText"/>
And finally, you can guarantee that some text be displayed even if no key by that name is found by using the 'text' attribute:
<view:message key="evening.greeting" text="No evening greeting found!"/>
The following table represents the various attributes that can be applied to a message
tag:
Name | Required | Default | Description |
---|---|---|---|
key | required | n/a | The key for a specific globalization message as declared in a .properties file |
arguments | optional | "" | A delimited list of arguments to be used during a parameterized globalization message rendering |
argumentSeparator | optional | , |
The delimiter for the arguments attribute |
var | optional | n/a | If specified, the local variable to which the rendered message will be assigned |
display | optional |
true if var isn't used; false otherwise |
Whether to display the rendered message |
text | optional | "" | The text that will be displayed if the key attribute doesn't exist in the resource bundle |
Sometimes you'll have a situation where you'll want the user to be able to change locales without messing with their system settings. Usually this will be accomplished by passing in a GET or POST parameter indicating the new locale. By default, this parameter is _locale
, but it can be changed via the localeUrlParam
parameter in your i18n
property declaration.
There are multiple ways to persist the new locale. Currently they are via session
variable or a cookie. These are declared in your i18n
property declaration by adding the localePersistenceClass
parameter. The default is MachII.globalization.persistence.SessionPersistenceMethod
, which stores changes to the user's locale in her session
variable.
Here is an example i18n
property declaration including these two parameters:
<property name="i18n" type="MachII.globalization.GlobalizationLoaderProperty">
<parameters>
<!-- The default is 'MachII.globalization.persistence.SessionPersistenceMethod' -->
<parameter name="localePersistenceClass"
value="MachII.globalization.persistence.CookiePersistenceMethod"/>
<!-- The default is '_locale' -->
<parameter name="localeUrlParam" value="__LOCALE__"/>
<parameter name="bundles">
<array>
<element value="./config/resources/test"/>
</array>
</parameter>
</parameters>
</property>
That is all the functionality that exists for i18n in Mach-II 1.9 M1. However, for 1.9 M2 there will be more functionality, including formatting tags for dates, times, numbers, and currency; there will be a debug feature; and even a way for users to set their own locales.
Be on the watch for these features, and don't be shy about submitting bugs and requests through the mailing lists. If there are any questions or comments, please feel free to add them directly to this document.