-/**
+/*!
* jQuery Internationalization library
*
* Copyright (C) 2012 Santhosh Thottingal
( function ( $ ) {
'use strict';
- var nav, I18N,
+ var I18N,
slice = Array.prototype.slice;
/**
* @constructor
this.locale = this.options.locale;
this.messageStore = this.options.messageStore;
this.languages = {};
-
- this.init();
};
I18N.prototype = {
/**
- * Initialize by loading locales and setting up
- * String.prototype.toLocaleString and String.locale.
+ * Localize a given messageKey to a locale.
+ * @param {String} messageKey
+ * @return {String} Localized message
*/
- init: function () {
- var i18n = this;
-
- // Set locale of String environment
- String.locale = i18n.locale;
-
- // Override String.localeString method
- String.prototype.toLocaleString = function () {
- var localeParts, localePartIndex, value, locale, fallbackIndex,
- tryingLocale, message;
-
- value = this.valueOf();
- locale = i18n.locale;
- fallbackIndex = 0;
+ localize: function ( messageKey ) {
+ var localeParts, localePartIndex, locale, fallbackIndex,
+ tryingLocale, message;
- while ( locale ) {
- // Iterate through locales starting at most-specific until
- // localization is found. As in fi-Latn-FI, fi-Latn and fi.
- localeParts = locale.split( '-' );
- localePartIndex = localeParts.length;
+ locale = this.locale;
+ fallbackIndex = 0;
- do {
- tryingLocale = localeParts.slice( 0, localePartIndex ).join( '-' );
- message = i18n.messageStore.get( tryingLocale, value );
+ while ( locale ) {
+ // Iterate through locales starting at most-specific until
+ // localization is found. As in fi-Latn-FI, fi-Latn and fi.
+ localeParts = locale.split( '-' );
+ localePartIndex = localeParts.length;
- if ( message ) {
- return message;
- }
+ do {
+ tryingLocale = localeParts.slice( 0, localePartIndex ).join( '-' );
+ message = this.messageStore.get( tryingLocale, messageKey );
- localePartIndex--;
- } while ( localePartIndex );
-
- if ( locale === 'en' ) {
- break;
+ if ( message ) {
+ return message;
}
- locale = ( $.i18n.fallbacks[i18n.locale] && $.i18n.fallbacks[i18n.locale][fallbackIndex] ) ||
- i18n.options.fallbackLocale;
- $.i18n.log( 'Trying fallback locale for ' + i18n.locale + ': ' + locale );
+ localePartIndex--;
+ } while ( localePartIndex );
- fallbackIndex++;
+ if ( locale === 'en' ) {
+ break;
}
- // key not found
- return '';
- };
+ locale = ( $.i18n.fallbacks[ this.locale ] &&
+ $.i18n.fallbacks[ this.locale ][ fallbackIndex ] ) ||
+ this.options.fallbackLocale;
+ $.i18n.log( 'Trying fallback locale for ' + this.locale + ': ' + locale + ' (' + messageKey + ')' );
+
+ fallbackIndex++;
+ }
+
+ // key not found
+ return '';
},
/*
* If the data argument is null/undefined/false,
* all cached messages for the i18n instance will get reset.
*
- * @param {String|Object} source
- * @param {String} locale Language tag
- * @returns {jQuery.Promise}
+ * @param {string|Object} source
+ * @param {string} locale Language tag
+ * @return {jQuery.Promise}
*/
load: function ( source, locale ) {
var fallbackLocales, locIndex, fallbackLocale, sourceMap = {};
source = 'i18n/' + $.i18n().locale + '.json';
locale = $.i18n().locale;
}
- if ( typeof source === 'string' &&
- source.split( '.' ).pop() !== 'json'
+ if ( typeof source === 'string' &&
+ // source extension should be json, but can have query params after that.
+ source.split( '?' )[ 0 ].split( '.' ).pop() !== 'json'
) {
- // Load specified locale then check for fallbacks when directory is specified in load()
- sourceMap[locale] = source + '/' + locale + '.json';
- fallbackLocales = ( $.i18n.fallbacks[locale] || [] )
+ // Load specified locale then check for fallbacks when directory is
+ // specified in load()
+ sourceMap[ locale ] = source + '/' + locale + '.json';
+ fallbackLocales = ( $.i18n.fallbacks[ locale ] || [] )
.concat( this.options.fallbackLocale );
- for ( locIndex in fallbackLocales ) {
- fallbackLocale = fallbackLocales[locIndex];
- sourceMap[fallbackLocale] = source + '/' + fallbackLocale + '.json';
+ for ( locIndex = 0; locIndex < fallbackLocales.length; locIndex++ ) {
+ fallbackLocale = fallbackLocales[ locIndex ];
+ sourceMap[ fallbackLocale ] = source + '/' + fallbackLocale + '.json';
}
return this.load( sourceMap );
} else {
* @return {string}
*/
parse: function ( key, parameters ) {
- var message = key.toLocaleString();
+ var message = this.localize( key );
// FIXME: This changes the state of the I18N object,
// should probably not change the 'this.parser' but just
// pass it to the parser.
- this.parser.language = $.i18n.languages[$.i18n().locale] || $.i18n.languages['default'];
+ this.parser.language = $.i18n.languages[ $.i18n().locale ] || $.i18n.languages[ 'default' ];
if ( message === '' ) {
message = key;
}
// NOTE: It should only change language for this one call.
// Then cache instances of I18N somewhere.
if ( options && options.locale && i18n && i18n.locale !== options.locale ) {
- String.locale = i18n.locale = options.locale;
+ i18n.locale = options.locale;
}
if ( !i18n ) {
i18n = new I18N();
$.data( document, 'i18n', i18n );
}
- String.locale = i18n.locale;
+
return this.each( function () {
var $this = $( this ),
- messageKey = $this.data( 'i18n' );
+ messageKey = $this.data( 'i18n' ),
+ lBracket, rBracket, type, key;
if ( messageKey ) {
- $this.text( i18n.parse( messageKey ) );
+ lBracket = messageKey.indexOf( '[' );
+ rBracket = messageKey.indexOf( ']' );
+ if ( lBracket !== -1 && rBracket !== -1 && lBracket < rBracket ) {
+ type = messageKey.slice( lBracket + 1, rBracket );
+ key = messageKey.slice( rBracket + 1 );
+ if ( type === 'html' ) {
+ $this.html( i18n.parse( key ) );
+ } else {
+ $this.attr( type, i18n.parse( key ) );
+ }
+ } else {
+ $this.text( i18n.parse( messageKey ) );
+ }
} else {
$this.find( '[data-i18n]' ).i18n();
}
} );
};
- String.locale = String.locale || $( 'html' ).attr( 'lang' );
+ function getDefaultLocale() {
+ var nav, locale = $( 'html' ).attr( 'lang' );
- if ( !String.locale ) {
- if ( typeof window.navigator !== undefined ) {
- nav = window.navigator;
- String.locale = nav.language || nav.userLanguage || '';
- } else {
- String.locale = '';
+ if ( !locale ) {
+ if ( typeof window.navigator !== undefined ) {
+ nav = window.navigator;
+ locale = nav.language || nav.userLanguage || '';
+ } else {
+ locale = '';
+ }
}
+ return locale;
}
$.i18n.languages = {};
parse: function ( message, parameters ) {
return message.replace( /\$(\d+)/g, function ( str, match ) {
var index = parseInt( match, 10 ) - 1;
- return parameters[index] !== undefined ? parameters[index] : '$' + match;
+ return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match;
} );
},
emitter: {}
};
/* Static members */
I18N.defaults = {
- locale: String.locale,
+ locale: getDefaultLocale(),
fallbackLocale: 'en',
parser: $.i18n.parser,
messageStore: $.i18n.messageStore