Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
file to load the translations. Each locale would also need a corresponding translation file. For example, if you were supporting the You can add a i18n structure of settings to your ColdBox.cfc or to any other module configuration file: ModuleConfig.cfc to configure the module:
i18n = {
// The base path of the default resource bundle to load
defaultResourceBundle = "includes/i18n/main",
// The default locale of the application
defaultLocale = "en_US",
// The storage to use for user's locale: session, client, cookie, request
localeStorage = "cookie",
// The value to show when a translation is not found
unknownTranslation = "**NOT FOUND**",
logUnknownTranslation = true | false,
// Extra resource bundles to load
resourceBundles = {
alias = "path"
},
//Specify a Custom Resource Service, which should implement the methods or extend the base i18n ResourceService ( e.g. - using a database to store i18n )
customResourceService = ""
};The defaultResourceBundle specifies a file path to find your bundle. For example, a defaultResourceBundle of includes/i18n/main and a defaultLocale of en_US would look for a includes/i18n/main_en_US.propertieses_SV locale, you would need a includes/i18n/main_es_SV.properties file as well.
Each module in your ColdBox Application can have its own resource bundles that can be loaded by this module and thus providing modular i18n resources.
A resource bundle is a .properties file containing your translations. For instance, using the default settings above, you would need to create a includes/i18n/main_en_US.properties file with your translations. Here is an example:
main.readthedocs=Read The Docs!
greeting=Hello {name}You can also use the config declaration for just tracking user locales and no resource bundles support
//i18n & Localization
i18n = {
defaultLocale = "en_es",
localeStorage = "cookie"
};You eliminate the resource bundle element or leave it blank. The framework will not load the resource bundles.
IMPORTANT All language resource bundles are stored in the configuration structure of your application and are lazy loaded in. So if a language is not used, then it does not get loaded. This is separate to where the user's locale information is stored.
Well, it would not make any sense to use i18n for just one locale, would it? That is why you need to be able to change the application's locale programmatically. You can do this in two ways:
Using the i18n mixin method setfwLocale().
Using the i18n service setfwLocale().
Below you can see an example:
Or use via injection
(vista-compatibleUnifier converts a batch of plain text or HTML files in various characters set encoding to Unicode in UTF-16 or UTF-8 encoding)
: A great Resource Bundles utility.
Eclipse (not CFEclipse or CFBuilder) doesn't add a BOM to UTF-8 encoded files, make sure you utf-8 as the default encoding for files.
Always use cfprocessingdirective
This module uses the core java resource bundle flavor so you have to use a proper resource bundle tool to manage these.
function changeLocale( event, rc, prc ){
setFWLocale( rc.locale );
event.setNextEvent('main.home');
}component{
property name="i18n" inject="i18n@cbi18n";
function changeLocale(){
i18n.setFWLocale( 'en_US' );
}
}<cfprocessingdirective pageencoding="utf-8">If you elect not to use property files for your resource bundles, or need to expand your i18n implementation to include content pulled from other sources, the module allows for the specification of a customResourceService in the configuration.
To begin, create a custom resource service which extends the core i18n resource service:
component name="MyCustomResourceService" extends="cbi18n.models.ResourceService" singleton=true{
property name="Controller" inject="coldbox";
property name="Wirebox" inject="wirebox";
}To override the resource bundle used, you would declare a new loadResourceBundle method. To override the implementation of the getResource( i18nResourceLabel ) you would declare a new getResource method. An example, using your database to retrieve an i18n resource bundle:
public void function loadBundle(
required string rbLocale=VARIABLES.i18n.getfwLocale()
) output="false"{
var bundles = "";
// Lazy Load?
if( NOT VARIABLES.controller.settingExists("RBundles") ){
VARIABLES.controller.setSetting("RBundles",structnew());
}
//set bundles ref
bundles = VARIABLES.controller.getSetting("RBundles");
var rb = structNew();
//cache our resource bundle query
var qRb = new query( datasource=application, cachedWithin=CreateTimeSpan(0, 6, 0, 0) );
qRb.addParam( name="locale", value=arguments.rbLocale, cfsqltype="cf_sql_varchar" );
qRb.setSQL( "SELECT * from customI18nTable WHERE locale=:locale" );
var rbResult = = qRb.execute().getResult();
for( var resource in rbResult ){
rb[ resource.label ] = resource.value;
}
bundles[ arguments.rbLocale ] = rb;
}Lets say we want to account for a more complex metadata structure in our resource bundles. For example, allow a draft value to allow for administrators to see which items in our bundle are pending review but display the default value to the public. We might also want to add any new resource requests containing a default value as drafts in the system (which we won't cover here). For special circumstances, such as these, we would need to change the implementation of the getResource method to account for this draft functionality:
public string function getResource(
// The resource (key) to retrieve from the main loaded bundle.
required any resource,
//A default value to send back if the resource (key) not found
any default,
//Pass in which locale to take the resource from. By default it uses the user's current set locale
any locale="#VARIABLES.i18n.getfwLocale()#",
//An array, struct or simple string of value replacements to use on the resource string
any values,
//default
any bundle="default"
){
//prevent errors via empty label strings from being passed
if( !len( trim(resource) ) ) return resource;
//protect from a bad locale value being passed
if( !len( trim( arguments.locale ) ) ) arguments.locale = VARIABLES.i18n.getfwLocale();
var thisLocale = arguments.locale;
var resourceString = "";
var rBundles = Controller.getSetting("RBundles");
var currentUser = Wirebox.getInstance( "SessionService" ).getCurrentUser();
if( !structKeyExists( rBundles, arguments.locale ) ){
loadBundle( rbLocale=arguments.locale, rbAlias=arguments.bundle );
}
var resourceBundle = rBundles[ arguments.locale ];
if( structKeyExists( resourceBundle, arguments.resource ){
var resource = resourceBundle[ arguments.resource ];
if( resource.published ){
return formatResourceObject( resourceObj=resource, args=arguments );
} else if( !resource.published && currentUser.isAdministrator() ) {
return formatDraftResource( resourceObj=resource, args=arguments );
}
} else if( !isNull( arguments.default ) ) {
if( !isNull( arguments.values ) ){
return formatRBString( arguments.default, arguments.values );
} else {
return arguments.default;
}
} else {
return renderUnknownTranslation( arguments.resource );
}
}The ability to extend and implement custom resource services provides you with a great deal of flexibility in your internationalization efforts. Use cases might include database-driven i18n resources, distributed caching implementations, and variable bundle formats used in third-party tools and plugins.
Now that you have completed the initialization of the i18n settings in the configuration file, you are ready to code for them. There are several methods that are available to all handlers, interceptors, layouts and views that deal with i18n via runtime mixins. You can use these methods directly or go to the services directly if you inject them.
This module registers the following models in WireBox:
i18n@cbi18n : Helper with all kinds of methods for localization
resourceService@cbi18n : Service to interact with language resource bundles
The module registers the following methods for handlers/layouts/views/interceptors:
You can leverage the getResource() or $r() method to retrieve resources from specific bundles by using the bundle argument or the @bundle convention.
We do like our @bundle convention as it looks prettier and you type a lot less.
Here are some examples of usage
INFO Please note that the i18N services are singleton objects and lives throughout your entire application span.
You can place the i18n@cbi18n service in the prc scope and then use this utility for i18n specific methods anywhere in your layouts and views, below is a simple example:
INFO There are tons of great utility methods in the i18n service that will allow you to work with localization and internationalization. Please view them via the API Docs for the latest methods and arguments.
/**
* Get the user's currently set locale or default locale according to settings
*/
function getFWLocale()
/**
* Set the locale for a specific user
* @locale The locale to set. Must be Java Style Standard: en_US, if empty it will default to the default locale
* @dontLoadRBFlag Flag to load the resource bundle for the specified locale (If not already loaded)
*
* @return i18n Service
*/
function setFWLocale( string locale="", boolean dontloadRBFlag=false )
/**
* Retrieve a resource from a resource bundle with replacements or auto-loading
* @resource The resource (key) to retrieve from the main loaded bundle.
* @defaultValue A default value to send back if the resource (key) not found
* @locale Pass in which locale to take the resource from. By default it uses the user's current set locale
* @values An array, struct or simple string of value replacements to use on the resource string
* @bundle The bundle alias to use to get the resource from when using multiple resource bundles. By default the bundle name used is 'default'
*/
function getResource(
required resource,
defaultValue,
locale,
values,
bundle,
)
// Alias to getResource
function $r()// Direct
#getResource( resource="common.ok", bundle="cbcore" )#
// Convetion
#getResource( "common.ok@cbcore")#Your locale is #getFwLocale()#!
// localized button
#html.submitButton( value=getResource( 'btn.submit' ) )#
// Localized string with replacements via arrays
#html.h2( $r(resource="txt.hello", values=[ "Luis", "Majano" ] ) )#
// txt.hello resource
txt.hello="Hello Mr {1} {2}! I hope you have an awesome day Mr. {2}!"
// Localized string with replacements via structs
#html.h2( getResource(resource="txt.hello", values={ name="Luis", age="35" } ) )#
// txt.hello resource
txt.hello="Hello Mr {name}! You are {age} years old today!"
// Localized string from a bundle, notice the @cbcore alias
#getResource( 'common.ok@cbcore' )#
// function change a user's locale
function changeLocale(event,rc,prc){
setFwlocale( rc.locale );
setNextEvent( 'home' );
}<cfoutput >
<strong>Locale:</strong> <br />#prc.i18n.getFWLocale()#<br />
<strong>Language:</strong> <br />#prc.i18n.getFWLanguage()#<br />
<strong>Language Code:</strong> <br />#prc.i18n.getFWLanguageCode()#<br />
<strong>Language ISO3 Code:</strong> <br />#prc.i18n.getFWISO3LanguageCode()#<br />
<strong>Country:</strong> <br />#prc.i18n.getFWCountry()#<br />
<strong>Country Code:</strong> <br />#prc.i18n.getFWCountryCode()#<br />
<strong>Country ISO3 Code3:</strong> <br />#prc.i18n.getFWISO3CountryCode()#<br />
<strong>TimeZone:</strong> <br />#prc.i18n.getServerTZ()#<br />
<strong>i18nDateFormat:</strong> <br />#prc.i18n.i18nDateFormat(prc.i18n.toEpoch(now()),1)#<br />
<strong>i18nTimeFormat:</strong> <br />#prc.i18n.i18nTimeFormat(prc.i18n.toEpoch(now()),2)#<br />
<hr>
<strong>I18NUtilVersion:</strong> <br />#prc.i18n.getVersion().I18NUtilVersion#<br>
<strong>I18NUtilDate:</strong> <br />#prc.i18n.dateLocaleFormat(prc.i18n.getVersion().I18NUtilDate)#<br>
<strong>Java version:</strong> <br />#prc.i18n.getVersion().javaVersion#<br>
</cfoutput>A great utility for localization is Attesoro, which can help you build your resource bundles.
Eclipse Resource Bundle Editor Plugin: http://sourceforge.net/projects/eclipse-rbe/ is another FANTASTIC editor for eclipse.
IBM's Resource Bundle Manager which is awesome too.
Below you can see some screenshots of the eclipse resource bundle editor plugin. I really recommend this tool also
INFO Make sure your files are all utf-8 encoding. It's also good i18n practice to liberally use cfprocessingdirective
Just drop into your modules folder or use the box-cli to install
box install cbi18n
This module registers the following models in WireBox:
i18n@cbi18n : Helper with all kinds of methods for localization
resourceService@cbi18n : Service to interact with language resource bundles
You can add a i18n structure of settings to your ColdBox.cfc or to any other module configuration file: ModuleConfig.cfc to configure the module:
Each module in your ColdBox Application can have its own resource bundles that can be loaded by this module.
Resource bundles are .properties files that contain your translations.
The module registers the following methods for handlers/layouts/views/interceptors:
i18n = {
// The base path of the default resource bundle to load
defaultResourceBundle = "includes/i18n/main",
// The default locale of the application
defaultLocale = "en_US",
// The storage to use for user's locale: session, client, cookie, request
localeStorage = "cookie",
// The value to show when a translation is not found
unknownTranslation = "**NOT FOUND**",
// Extra resource bundles to load
resourceBundles = {
alias = "path"
}
};/**
* Get the user's currently set locale or default locale according to settings
*/
function getFWLocale()
/**
* Set the locale for a specific user
* @locale The locale to set. Must be Java Style Standard: en_US, if empty it will default to the default locale
* @dontLoadRBFlag Flag to load the resource bundle for the specified locale (If not already loaded)
*
* @return i18n Service
*/
function setFWLocale( string locale="", boolean dontloadRBFlag=false )
/**
* Retrieve a resource from a resource bundle with replacements or auto-loading
* @resource The resource (key) to retrieve from the main loaded bundle.
* @defaultValue A default value to send back if the resource (key) not found
* @locale Pass in which locale to take the resource from. By default it uses the user's current set locale
* @values An array, struct or simple string of value replacements to use on the resource string
* @bundle The bundle alias to use to get the resource from when using multiple resource bundles. By default the bundle name used is 'default'
*/
function getResource(
required resource,
defaultValue,
locale,
values,
bundle,
)
// Alias to getResource
function $r()This module will enhance your ColdBox applications with i18n capabilities, resource bundles and localization.
Apache License, Version 2.0.
Documentation: https://github.com/ColdBox/cbox-i18n/wiki
ForgeBox: http://forgebox.io/view/i18n
Lucee 4.5+
Railo 4+ (Deprecated)
ColdFusion 9+
The ColdBox ORM Module is a professional open source software backed by Ortus Solutions, Corp offering services like:
Custom Development
Professional Support & Mentoring
Training
Server Tuning
Security Hardening
Code Reviews
Because of His grace, this project exists. If you don't like this, then don't read it, it's not for you.
"Therefore being justified by faith, we have peace with God through our Lord Jesus Christ: By whom also we have access by faith into this grace wherein we stand, and rejoice in hope of the glory of God." Romans 5:5
