29. Localization
Locale
The Locale
class is the hub API for Fantom's localization infrastructure. Locales are used to represent a language via an ISO 639 two letter code. A locale may also optionally represent a specific country or region via a ISO 3166 two letter code. Common locales include:
Language Only: en English es Spanish fr French de German it Italian ja Japanese ko Korean zh Chinese Language and Country: en-US United States en-GB United Kingdom es-ES Spain es-MX Mexico fr-FR France de-DE Germany en-CA Canada (English) fr-CA Canada (French) zh-CN China (Simplified) zh-TW Taiwan
When the Fantom VM is started it will create a default locale based on the underlying platform. For example on a Java VM, the default Fantom locale will be initialized from java.util.Locale
(which in turn is initialized from the operating system's default locale).
Locales are configured as an actor local variable. Use Locale.cur
and Locale.setCur
to get and set the current thread's locale.
By convention Locale
is never passed as a parameter to Fantom APIs. Rather the locale is implied by the current actor. As a general rule APIs which are locale sensitive will include the term locale
in their method name.
Use Locale.use
to execute a body of code using a different locale:
echo(Locale.cur) Locale("zh-CN").use { echo(Locale.cur) } echo(Locale.cur)
Localized Properties
All the strings displayed to users should typically be pulled out into localized props files to enable easy language translation. Each pod may define one localized property map with as many keys are desired. Localized properties are defined in props files
as pod resource files under the locale
directory. An example set of localized props files:
locale/en.props locale/en-US.props locale/en-CA.props locale/fr.props locale/fr-CA.props
The Env.locale
API is used to lookup a localized property. Typically you will use the Pod.locale
convenience method:
Button(pod.locale("ok")) Button(pod.locale("cancel"))
Looking up localization is delegated to the current Env
. But the standard resolution rules are:
Env.props(pod, `locale/{locale}.props`)
Env.props(pod, `locale/{lang}.props`)
Env.props(pod, `locale/en.props`)
- Fallback to
pod::key
unlessdef
specified
Env.props
first looks in the pod's etc directory for overrides, then checks if the pod contains a resource file.
Best practice is to ensure that all properties are mapped in en.props
file as your fallback defaults. Then store localized translations in language files such as fr.props
, de.props
, etc. Typically you will only use country specific files such as en-US
or en-GB
for regional terms.
Locale Literals
String interpolation supports a special mode used to make working with localized props easy. The following interpolation formats are supported:
$<key>
unqualified key$<pod::key>
qualified key$<key=def>
unqualified key with default value
The simplest locale literal is an unqualified key which is just a shortcut for Pod.locale
using the enclosing type:
// original code class Foo { Void main() { echo("$<bar.baz>") } } // translated into class Foo { Void main() { echo(#Foo.pod.locale("bar.baz")) } }
You can also use a qualified key to lookup a localized prop in an external pod:
// original code "$<fwt::cancel.name>" // translated into Pod.find("fwt").locale("cancel.name")
The last format lets you actually define the key's value right in your Fantom source code:
// orginal code "$<fileNotFound=File not found>: $file" // translates into EnclosingType#.pod.locale("fileNotFound", "File not found") + ": $file" // and automatically adds the key/value pair to locale/en.props fileNotFound=File not found
If your pod doesn't have an explicit "locale/en.props" resource then it is automatically created. If it does exist then interpolated key/values are automatically merged into the existing props file. It is a compile time error to declare a key's value in multiple places; each key must be defined exactly once in either en.props or in an interpolated string.