Only this pageAll pages
Powered by GitBook
1 of 19

v3.x

Loading...

Intro

Loading...

Loading...

Loading...

Loading...

GETTING STARTED

Loading...

Loading...

Loading...

Usage

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Release History

A synopsis of the major version history of the project.

In this section you will find the release notes for each version we release under this major version. If you are looking for the release notes of previous major versions use the version switcher at the top left of this documentation book. Here is a breakdown of our major version releases.

Version 3.0

Dropped support for Adobe 2016, migration to new modules template, and integrations with ColdBox 7 features.

Version 2.0

The module has been rewritten in CFScript.

cbi18n v1 already had java resource bundles. v2 added support for JSON resource bundles. Both flat and nested JSON bundles are supported.

In this version we introduced the concept of property inheritance. It means that key-values pairs included in less specific files are inherited by those which are higher in the inheritance tree. For example: Let's assume you are using a en_US locale. if you have key-values in a generic myResource.properties file, you can override them in a myResource_en.properties and an even more specific myResource_en_US.properties file. This opens up the possibility to define a generic language resource and define country specific translations in a more specific resource file.

Version 1.0

A ( very old ) initial release.

For locale storage we now use a service from the module.

cbstorages

Overview

The cbi18n module was built to provide localization and internationalization features to any ColdBox application. It will not only allow you to represent resources in multiple languages, but will also track the user's locale for you. It has a plethora of utilities for localizing strings, dates, currencies and much more.

There are two main models that are registered for you with the following WireBox Id's:

  • i18n@cbi18n : Service that tracks user's locale, changing of locales, and a plethora of localized functions. It also bootstraps the resource bundles used in the application.

  • ResourceService@cbi18n In charge of retrieving language keys from locale specific resource bundles, whether they are Java property files or JSON bundles.

They can either be injected, called via our mixin helpers or added via our ColdBox Delegates:

// Mixins
i18n()
resourceService()

// Injection
property name="i18n" inject="i18n@cbi18n";
property name="resourceService" inject="resourceService@cbi18n"

// Delegates
component delegates="Resourceful@cbi18n"{
 
 ...
    return "Hello + #getResource( 'myResource' )#";
 ...
}

Once you have access to those objects you can leverage their methods to your ❤️'s content.

Your locale is #getFwLocale()#!

// localized button
#html.submitButton( $r( '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( $r( 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
#$r( 'common.ok@cbcore' )#

// function change a user's locale
function changeLocale(event,rc,prc){
	setFwlocale( rc.locale );
	relocate( 'home' );
}

Please see the API docs for the latest methods available to you:

Author

Author

Luis Fernando Majano Lainez

Luis has a passion for Jesus, tennis, golf, volleyball, and anything electronic. Random Author Facts:

  • He played volleyball in the Salvadorean National Team at the tender age of 17

  • The Lord of the Rings and The Hobbit are something he reads every 5 years. (Geek!)

  • His first ever computer was a Texas Instrument TI-86 that his parents gave him in 1986. After some time digesting his very first BASIC book, he had written his own tic-tac-toe game at the age of 9. (Extra geek!)

  • He has a geek love for circuits, microcontrollers, and overall embedded systems.

  • He has of late (during old age) become a fan of organic gardening.

Keep Jesus number one in your life and in your heart. I did and it changed my life from desolation, defeat and failure to an abundant life full of love, thankfulness, joy and overwhelming peace. As this world breathes failure and fear upon any life, Jesus brings power, love and a sound mind to everybody!

“Trust in the LORD with all your heart, and do not lean on your own understanding.” – Proverbs 3:5

Contributors

Wil de Bruin

Wil de Bruin is a Software and System Engineer who has been developing software systems since 1990. He was born in The Netherlands in the '60s and lives in Wageningen, the Netherlands.

He built his own wood-fired oven where he bakes the best pizzas in town. He is the administrator of the Dutch bread-baking forum, and bakes lots of bread for family, friends, neighbors, and parties.

Introduction

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

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

Some Features

  • Switching locales on the fly, stored in cookies, sessions or any other cbstorages provider

  • Resource bundles: java properties files or JSON (nested or flat)

  • Inherited resource bundles e.g main.properties, main_en.properties ormain_en_US.properties.

  • Many locale-specific functions: date and time formats and parsing, country codes, currency symbols

  • Custom resource services

  • ColdBox 7 Delegates

Versioning

And constructed with the following guidelines:

  • Breaking backward compatibility bumps the major (and resets the minor and patch)

  • New additions without breaking backward compatibility bumps the minor (and resets the patch)

  • Bug fixes and misc changes bumps the patch

License

Apache License, Version 2.0.

Important links

System requirements

  • Lucee 5+

  • Adobe ColdFusion 2018+

Discussion & Help

The Box products community for further discussion and help can be found here:

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

About this Book

  • The majority of code examples in this book are done in cfscript.

  • All ColdFusion examples are designed to run on the open-source Lucee Platform or Adobe ColdFusion 11+

External Trademarks & Copyrights

Flash, Flex, ColdFusion, and Adobe are registered trademarks and copyrights of Adobe Systems, Inc.

Notice of Liability

The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software, and resources described in it.

Contributing

Charitable Proceeds

Shalom Children's Home

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education, and life skills training in a Christian environment. The home is supported by a child sponsorship program.

We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador who either have no families or have been abandoned. This is a good earth to seed and plant.

Luis F. Majano

Luis Majano is a Computer Engineer with over 15 years of software development and systems architecture experience. He was born in in the late 70s, during a period of economical instability and civil war. He lived in El Salvador until 1995 and then moved to Miami, Florida where he completed his Bachelor of Science in Computer Engineering at . Luis resides in The Woodlands, Texas with his beautiful wife Veronica, daughter Alexia and son Lucas!

He is the CEO of , a consulting firm specializing in web development, ColdFusion (CFML), Java development, and all open-source professional services under the ColdBox, CommandBox, and ContentBox stack. He is the creator of ColdBox, ContentBox, WireBox, TestBox, LogBox, and anything “BOX”, and contributes to many open-source projects. You can read his blog at

He is CTO of the Dutch hosting company and is next to providing managed servers for Lucee, ColdFusion, and many other platforms, he develops software and provides consultancy and training. He has been working with ColdFusion since v1.5 and uses Coldbox for the 2.x days.

The ColdBox cbi18n Module is maintained under the guidelines as much as possible. Releases will be numbered in the following format:

Documentation:

Source:

ForgeBox:

The ColdBox cbi18n module is a professional open source software backed by offering services like:

The source code for this book is hosted in GitHub: . You can freely contribute to it and submit pull requests. The contents of this book is copyrighted by and cannot be altered or reproduced without the author's consent. All content is provided "As-Is" and can be freely distributed.

The majority of code generation and running of examples are done via CommandBox: The ColdFusion (CFML) CLI, Package Manager, REPL -

We highly encourage contributions to this book and our open-source software. The source code for this book can be found in our where you can submit pull requests.

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - . So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

Shalom Children’s Home () is one of the ministries that are dear to our hearts located in El Salvador. During the 12-year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

San Salvador, El Salvador
Florida International University
Ortus Solutions
www.luismajano.com
Site4u
<major>.<minor>.<patch>

Installation

Leverage CommandBox to install into your ColdBox application:

# Latest version
install cbi18n

# Bleeding Edge
install cbi18n@be

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

Mixins Helper methods

This module will register the following methods in your handlers/interceptors/layouts/views

  • getFWLocale() gets the users currently set locale (or default locale)

  • setFWLocale() set the locale for a specific user

  • getResource() retrieve a resource from a resource bundle with replacements

  • $r() shortcut/alias to getResource()

  • i18n() gets the i18n Model

  • resourceService() gets the Resource Service

Delegates

You can use the Resourceful@cbi18n delegate to add resource traits to your objects and access to the getResource() method.

component name="SecurityService" delegates="Resourceful@cbi18n" {

   // Then just use the getResource() method
}

System requirements

  • Lucee 5+

  • Adobe ColdFusion 2018+

What's New With 3.0.0

October 10, 2022

Added

  • New module template updates

Changed

  • Dropped 2016 Support

Configuration

Global Configuration

The module can be configured by adding a cbi18n key in the moduleSettings structure within the config/Coldbox.cfc

config/Coldbox.cfc
moduleSettings = {


		cbi18n = {
			// The default resource to load and aliased as `default`
			"defaultResourceBundle" : "includes/i18n/main",
			// The locale to use when none defined
			"defaultLocale"         : "en_US",
			// The default storage for the locale
			"localeStorage"         : "cookieStorage@cbstorages",
			// What to emit to via the resource methods if a translation is not found
			"unknownTranslation"    : "**NOT FOUND**",
			// If true, we will log to LogBox the missing translations
			"logUnknownTranslation" : true,
			// A-la-carte resources to load by name
			"resourceBundles"       : {},
			// Your own CFC instantiation path
			"customResourceService" : ""
		}
		
};

Key

Type

Required

Default

Description

defaultResourceBundle

string

no

This is the path for a resource bundle that will be treated as the default resource bundle with an alias of default . The path must NOT include language or variants, just the name of path prefixincludes/i18n/main_en_US.properties should be specified as includes/i18n/main

resourceBundles

struct

no

{}

key-value struct of resource alias name and bundle path without the lang_COUNTRY.(properties|json) part.

defaultLocale

string

no

en_US

default locale

localeStorage

string

no

cookieStorage@cbstorages

cbstorages service where current locale is stored

unknownTranslation

string

no

if no unknowTranslation is set getResource will fail on unknown resourceKeys

logUnknownTranslation

boolean

no

false

will log unknown translations to logbox

WARNING

When specifying resources in a MODULE, you should never specify a defaultResourceBundle, because it will conflict with your main settings. If you specify additional resourceBundles it is wise to choose an aliasname which will not conflict with other modules or your main settings

A resource bundle can be a .properties file containing your translations (java resources) OR a .json file. For instance, using the default settings above, you would need to create a includes/i18n/main_en_US.properties file with your translations. If you want to use JSON files, you should use an includes/i18n/main_en_US.json file.

ColdBox will auto-detect the extension of the resource bundle and deal with it appropriately. The supported extension types are:

  • .properties - Java resource bundle

  • .json - JSON resource bundle (flat or nested)

Java Properties

includes/i18n/main_en_US.properties
main.readthedocs=Read The Docs!
greeting=Hello {name}

JSON Flat

includes/i18n/jsontest_en_US.json
{
    "sub.IntroMessage": "Normal JSON"
}
includes/i18n/jsontest_es_SV.json
{
    "sub.IntroMessage": "JSON Normal"
}

JSON Nested

includes/i18n/nested_en_US.json
{
    "sub": {
        "IntroMessage": "Nested JSON"
    }
}
includes/i18n/nested_es_SV.json
{
    "sub": {
        "IntroMessage": "JSON Incrustado"
    }
}

Module Configuration

Every ColdBox module has the i18n capabilities available to them as well. They can use it to register their own resource bundles. The previous version allowed for a setting called i18n this is now called cbi18n to comply with the same global naming convention. Just update your key root in your Moduleconfig.cfc.

ModuleConfig.cfc
cbi18n = {
  resourceBundles = {
     "bundleIdentifier" = "#moduleMapping#/includes/module"
  }
};

The keys in the resourceBundles struct represents the bundle that can be passed to getResource or appended on the resource string with an @ sign.

i18n.getResource( "myTranslationKey@bundleIdentifier" );
// same as
i18n.getResource( resource = "myTranslationKey", bundle = "bundleIdentifier" );

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 = "cookieStorage@cbstorages"
};

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 from where the user's locale information is stored.

Semantic Versioning
https://coldbox-i18n.ortusbooks.com/
https://github.com/coldbox-modules/cbi18n
https://forgebox.io/view/cbi18n
https://community.ortussolutions.com/c/box-modules/cbi18n
Ortus Solutions, Corp
Much More
https://github.com/ortus-docs/cbi18n-docs
Ortus Solutions, Corp
https://www.ortussolutions.com/products/commandbox
GitHub repository
https://www.harvesting.org/
https://www.harvesting.org/

Java vs JSON resources

For existing projects you probably have existing resource files, probably JSON files or java resources. For new projects you can ask yourself if you would choose JSON or java properties. Here are some pros and cons

  • JSON is a simple file format, supported by many editors.

  • Many frontend Javascript frameworks also support JSON

  • If you use many different locales it can become complex to make sure all keys are entered in all resource bundles. You might need specialized editors to keep track of all translated keys.

  • It is not hard to generate your own JSON resource files from a database.

  • if you already used cbi18n v1 you probably have java properties files.

  • there are very capable (free) resource editors available for java properties.

  • Several web based translation facilities provide export to java properties and/or json resources

Property inheritance

So let's say I want to provide translations for english and Dutch. Because we want to provide Dutch translations for both Netherlands and Belgium we want to use the following locales: nl_NL(dutch) and nl_BE (flemish). Instead of duplicating the nl_NL resource file myResource_nl_NL.properties to myResource_nl_BE.properties we can create a general myResource_nl.properties file and specify a myResource_nl_BE.properties file which only differs for a few keys. If we retrieve a resource with getResource(resource = "some.key", locale="nl_BE) it will try to lookup this key in the following order

  • myResource_nl_BE.(properties|json)

  • myResource_nl.(properties|json)

  • myResource.(properties|json)

As you can see this lookup order does not stop at myResource.nl.(properties|json). It even goes up to a resource file without language indication. This can be especially useful if you create your app in one language, and only have incomplete translations for other languages. So let's say you create an english language app, you could just create a myResource.(properties|json) file and assume your main language is english. If you want to provide French as a second language but don't have the full translation yet (because it is a community effort for example) you can add myResource.fr.(properties|json) as a resource file, so you can provide a growing number of translated resource keys.

It is even possible to be more specific by adding country variants, e.g myResource.en_GB_someVariant.properties

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:

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.

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

all bundles, including the default one, have names (aliases). If you want you can specify a resource in your default bundle as

Examples

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.

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:

Or use via injection

Resource Bundle Tools

JSON resource editors

  • most code editors can be used for JSON editing, but if you have large resource files or many locales you can probably better use a specialized tool, which keeps track of missing translations

Java resource editors

Below you can see some screenshots of the eclipse resource bundle editor plugin. I really recommend this tool.

INFO Make sure your files are all utf-8 encoding. It's also good i18n practice to liberally use cfprocessingdirective

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:

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:

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:

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.

A very basic list of resource editors will be discussed .

In many languages there are country or region specific words. You wonder if you should provide resource bundles for each country while only a small subset of words is different. For this scenario you can use property inheritance which is nicely explained .

is a very capable and affordable resource editor, for both JSON and java properties. It can edit JSON flavours for vue and angular libraries and also has support for other resource bundle formats. However it can not convert between formats. Only conversion between flat and nested JSON files is supported.

the Eclipse Resource Bundle Editor plugin is a FANTASTIC editor for eclipse: More info here

is another free resource editor, a bit more limited and dated, but still usable.

is a very capable and affordable resource editor, for both JSON and java properties.

in the next paragraph
Generated Documentation (cbi18n v3.0.0)
/**
* 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()

/**
 * Get Access to the i18n Model
 */
function i18n()

/**
 * Get the resource service model
 */
function resourceService()
// Direct
#getResource( resource="common.ok", bundle="cbcore" )#

// Convention
#getResource( "common.ok@cbcore")#
#getResource( "some.resource@default")#
// OR
#getResource( "some.resource")#
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>
function changeLocale( event, rc, prc ){
    setFWLocale( rc.locale );
    relocate('main.home');
}
component{

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

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

}
component 
  name="MyCustomResourceService" 
  extends="cbi18n.models.ResourceService" 
  singleton=true{
  
  property name="Controller" inject="coldbox";
  property name="Wirebox" inject="wirebox";

}
public void function loadBundle( 
    required string rbLocale=VARIABLES.i18n.getfwLocale() 
){
    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;
}
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 );
    }
}

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.

here
BabelEdit
https://essiembre.github.io/eclipse-rbe/
Attesoro
BabelEdit

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.xencraft.com/resources/webi18ntutorial.pdf
http://coldfusion.sys-con.com/read/43795.htm
https://github.com/essiembre/eclipse-rbe
Attesoro
Ortus Solutions, Corp
Shalom Children's Home