Only this pageAll pages
Powered by GitBook
1 of 10

v1.x

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Configuration

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}

How do I change Locales?

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:

  1. Using the i18n mixin method setfwLocale().

  2. Using the i18n service setfwLocale().

Below you can see an example:

function changeLocale( event, rc, prc ){
    setFWLocale( rc.locale );
    event.setNextEvent('main.home');
}

Or use via injection

component{

    property name="i18n" inject="i18n@cbi18n";

    function changeLocale(){
        i18n.setFWLocale( 'en_US' );
    }

}

Resource Bundle Tools

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

A great utility for localization is , which can help you build your resource bundles.

Eclipse Resource Bundle Editor Plugin: is another FANTASTIC editor for eclipse.

IBM's which is awesome too.

Attesoro
http://sourceforge.net/projects/eclipse-rbe/
Resource Bundle Manager

Configuration With No Resource Bundles

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.

Best Practices

  • 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

<cfprocessingdirective pageencoding="utf-8">
  • This module uses the core java resource bundle flavor so you have to use a proper resource bundle tool to manage these.

Custom Resource Services

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.

Installation

INSTRUCTIONS

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

Settings

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**",
    // Extra resource bundles to load
    resourceBundles = {
        alias = "path"
    }
};

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.

Mixin Helpers

The module registers the following methods for handlers/layouts/views/interceptors:

/**
* 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()

Home

This module will enhance your ColdBox applications with i18n capabilities, resource bundles and localization.

LICENSE

Apache License, Version 2.0.

IMPORTANT LINKS

SYSTEM REQUIREMENTS

  • Lucee 4.5+

  • Railo 4+ (Deprecated)

  • ColdFusion 9+

Professional Open Source

  • Custom Development

  • Professional Support & Mentoring

  • Training

  • Server Tuning

  • Security Hardening

  • Code Reviews

HONOR GOES TO GOD ABOVE ALL

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

Documentation:

Source:

ForgeBox:

The ColdBox ORM Module is a professional open source software backed by offering services like:

https://github.com/ColdBox/cbox-i18n/wiki
https://github.com/ColdBox/cbox-i18n
http://forgebox.io/view/i18n
Ortus Solutions, Corp
Much More

Resources

(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.

http://www.melody-soft.com/html/unifier.html
http://www.i18ngurus.com/
http://www.xencraft.com/resources/webi18ntutorial.pdf
http://www.adobe.com/support/coldfusion/internationalization/internationalization_cfmx/
http://coldfusion.sys-con.com/read/43795.htm
http://sourceforge.net/projects/eclipse-rbe/
Attesoro
rbManager from icu4j
RBman

Coding for i18n

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.

Mapped Models

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

Mixin Helpers

The module registers the following methods for handlers/layouts/views/interceptors:

/**
* 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()

Bundle Aliases

You can leverage the getResource() or $r() method to retrieve resources from specific bundles by using the bundle argument or the @bundle convention.

// Direct
#getResource( resource="common.ok", bundle="cbcore" )#

// Convetion
#getResource( "common.ok@cbcore")#

We do like our @bundle convention as it looks prettier and you type a lot less.

Examples

Here are some examples of usage

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' );
}

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:

<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>

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.

Ortus Solutions, Corp