jsIn : A simple JavaScript i18n solution

jsIn is a lightweight (769Bytes! No other libraries/framework required!) and easy-to-use JavaScript code module to implement string translation for i18n (internationalization) purpose.

Features

  • Supports translation by string identifiers or by full sentences:
    __(‘page_title_text’);
    => The page title string.__(‘This is a product page.’);
    => 這是產品頁。
  • Supports Unicode in the string identifiers, look-up text and translated text:
    __(‘您好!!’);
    __(‘English with 中文’);
  • Supports place holders (i.e. inserting dynamic content into the translated text) :
    __(‘They are {%1}, {%2} and {%3}.’, ['John', 'Mary', 'Tom']);
    => They are John, Mary and Tom.
  • Lightweight: less than 1KB (769 bytes) after minified.
  • Simple and easy to use : use the magic __() function, meaning you could use existing i18n editors (e.g. poedit) to extract the language strings.
  • Independent : No other libraries or framework required.

Download

Full source + Minified source + Unit Test file : jsIn : A simple JavaScript i18n solution

Demo & unit test

You may take a look at the Demo and unit test page to see how jsIn is used.

Usage

1. Dictionary

Dictionary must be defined before any translation. Dictionaries are defined as JavaScript objects (usually in JSON format). The properties of the object are the text to be translated, and their corresponding values are the text after translation. For example :

jsIn.addDict({
    'hello_world': 'Hallo Welt!',
    'my_name_is' : 'Mein Name ist {%1}.'
});

Note: The properties are case-sensitive, meaning that “My name is” and “my name is” are two different dictionary entries.

Multiple dictionaries

jsIn accepts mixing different dictionaries by calling jsIn.addDict() multiple times. Each time when jsIn.addDict() is called, the new entries are added to the central dictionary. If there is already an entry with the same property name, the latest entry will overwrite the old entry. e.g.:

jsIn.addDict({
    'entry1':'text1',
    'entry2':'text2',
    'entry3':'text3'
});

jsIn.addDict({
    'entry3':'new text 3', //overwrite the previous entry
    'entry4':'text4',
    'entry5':'text5' });

will result in a dictionary like this:

{
    'entry1':'text1',
    'entry2':'text2',
    'entry3':'new text 3',
    'entry4':'text4',
    'entry5':'text5'
}

This feature of multiple dictionaries is very useful to divide the whole dictionary files into sections. For example, you may define the commonly used translation into a file(lang.common.js) which will be loaded in every page. Then you can define separate dictionaries files for different pages (e.g. lang.home.js, lang.about.js, lang.product.js, etc.) and only load the needed file according to the page being displayed.

2. Translation

Translation of string is as simple as calling the __() function:

//full sentence translation
alert(__('Hello world!'));         // 'Hello Welt!'
alert(__('My name is {%1}.',['John'] ));   // 'Mein Name ist John.'

//string identifier translation
alert(__('hello_world'));           //'Hello Welt!'
alert(__('my_name_is',['John'] )); //'Mein Name ist John.'

When jsIn couldn’t find the translation for a string, it will just output it as it is.

/* since 'This string has no translation.' is not defined in the dictionary, the whole string is outputted directly. */
alert(__('This string has no translation.'));

Place holder / Dynamic content insertion

jsIn also accepts the use of place holder to allow insertion of dynamic contents into the translated strings. For example:

var time = 'morning', name = 'John';
jsIn.addDict({
    'HelloUser' : 'Hello, {%1}, good {%2}!'
});

//shows 'Hello, John, good morning!'
alert(__('HelloUser', [name, time]));

The place holder must be in the format of “{%n}” such as {%1}, {%2}, {%3} etc. The inserting contents are provided in a one-dimension array format where the first value in the array will replace {%1}, the second value will replace {%2} and so on. If the number of values in the array is less than the number of the place holders, the non-matched place holders will be direct outputted as it is.

3. Options

showNotFoundError(boolean) : Whether treat the “no entry found” as an error.

If TRUE, jsIn will throw an error exception when it doesn’t find the entry in the dictionary.

If FALSE (default), jsIn will show the original string instead of throwing an error if the entry is not found in the dictionary.

Usage:

//set the option state:
jsIn.showNotFoundError(true);
jsIn.showNotFoundError(false);

//obtain the option state:
var state = jsIn.showNotFoundError();

Change log:

Version 1.2  [2011-07-27] :

  • Further optimized code for smaller size and better performance. Only 769 bytes after minified.

Version 1.1  [2011-07-19] :

  • Use full sentence format in JSON attributes, the indexing key conversion is no longer needed.
  • Performance is significantly improved.

Version 1.0  [2011-07-09] :

  • First release.

License

FREE license. You can do what you like. This source file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Questions? Bugs? Suggestions?

I’ll be very happy to hear anything about jsIn from you. Please contact me through the about page.