Update jquery.i18n from upstream, use its default message store

In Iddef0805ab a custom message store was introduced for ULS, but
there were updates in jquery.i18n that allows us to use default
message store again.

(see https://github.com/wikimedia/jquery.i18n/pull/40)

Change-Id: I86cb7a44efa83e5811824cd1104c6be11b1e2925
This commit is contained in:
Santhosh Thottingal
2013-07-23 15:32:45 +05:30
parent f144cd5c16
commit 2159822145
7 changed files with 116 additions and 299 deletions

View File

@@ -16,13 +16,13 @@
( function ( $ ) {
'use strict';
var nav,
var nav, I18N,
slice = Array.prototype.slice;
/**
* @constructor
* @param {Object} options
*/
var I18N = function ( options ) {
I18N = function ( options ) {
// Load defaults
this.options = $.extend( {}, I18N.defaults, options );
@@ -43,13 +43,13 @@
var i18n;
i18n = this;
i18n.messageStore.init( i18n.locale );
// Set locale of String environment
String.locale = i18n.locale;
// Override String.localeString method
String.prototype.toLocaleString = function () {
var localeParts, messageLocation, localePartIndex, value, locale, fallbackIndex;
var localeParts, localePartIndex, value, locale, fallbackIndex,
_locale, message;
value = this.valueOf();
locale = i18n.locale;
@@ -62,24 +62,11 @@
localePartIndex = localeParts.length;
do {
var _locale = localeParts.slice( 0, localePartIndex ).join( '-' );
if ( i18n.options.messageLocationResolver ) {
messageLocation = i18n.options.messageLocationResolver( _locale, value );
if ( messageLocation &&
( !i18n.messageStore.isLoaded( _locale ,messageLocation ) )
) {
i18n.messageStore.load( messageLocation, _locale );
}
}
var message = i18n.messageStore.get( _locale, value );
_locale = localeParts.slice( 0, localePartIndex ).join( '-' );
message = i18n.messageStore.get( _locale, value );
if ( message ) {
return message;
}
localePartIndex--;
} while ( localePartIndex );
@@ -89,7 +76,7 @@
locale = ( $.i18n.fallbacks[i18n.locale] && $.i18n.fallbacks[i18n.locale][fallbackIndex] ) ||
i18n.options.fallbackLocale;
i18n.log( 'Trying fallback locale for ' + i18n.locale + ': ' + locale );
$.i18n.log( 'Trying fallback locale for ' + i18n.locale + ': ' + locale );
fallbackIndex++;
}
@@ -122,17 +109,12 @@
* null/undefined/false,
* all cached messages for the i18n instance will get reset.
*
* @param {String|Object|null} data
* @param {String|Object} source
* @param {String} locale Language tag
* @returns {jQuery.Promise}
*/
load: function ( data, locale ) {
this.messageStore.load( data, locale );
},
log: function ( /* arguments */ ) {
if ( window.console && $.i18n.debug ) {
window.console.log.apply( window.console, arguments );
}
load: function ( source, locale ) {
return this.messageStore.load( source, locale );
},
/**
@@ -204,18 +186,16 @@
var i18n = $.data( document, 'i18n' );
String.locale = i18n.locale;
if ( !i18n ) {
i18n = new I18N( );
i18n = new I18N();
$.data( document, 'i18n', i18n );
}
return this.each( function () {
var $this = $( this );
if ( $this.data( 'i18n' ) ) {
var messageKey = $this.data( 'i18n' ),
message = messageKey.toLocaleString();
if ( message !== '' ) {
$this.text( message );
}
return this.each( function () {
var $this = $( this ),
messageKey = $this.data( 'i18n' );
if ( messageKey ) {
$this.text( i18n.parse( messageKey ) );
} else {
$this.find( '[data-i18n]' ).i18n();
}
@@ -247,19 +227,19 @@
};
$.i18n.debug = false;
$.i18n.log = function ( /* arguments */ ) {
if ( window.console && $.i18n.debug ) {
window.console.log.apply( window.console, arguments );
}
};
/* Static members */
I18N.defaults = {
locale: String.locale,
fallbackLocale: 'en',
parser: $.i18n.parser,
messageStore: $.i18n.messageStore,
/* messageLocationResolver - should be a function taking language code as argument and
* returning absolute or relative path to the localization file
*/
messageLocationResolver: null
messageStore: $.i18n.messageStore
};
// Expose constructor
$.I18N = I18N;
$.i18n.constructor = I18N;
}( jQuery ) );

View File

@@ -1,5 +1,5 @@
/**
* jQuery Internationalization library Message loading , parsing, retrieving utilities
* jQuery Internationalization library - Message Store
*
* Copyright (C) 2012 Santhosh Thottingal
*
@@ -18,44 +18,20 @@
var MessageStore = function () {
this.messages = {};
this.sources = {};
this.locale = String.locale;
};
/**
* See https://github.com/wikimedia/jquery.i18n/wiki/Specification#wiki-Message_File_Loading
*/
MessageStore.prototype = {
/**
* See https://github.com/wikimedia/jquery.i18n/wiki/Specification#wiki-Message_File_Loading
*
* @param locale
*/
init: function ( locale ) {
var messageStore = this;
messageStore.locale = locale;
messageStore.log( 'initializing for ' + locale );
$( 'link' ).each( function ( index, element ) {
var $link = $( element ),
rel = ( $link.attr( 'rel' ) || '' ).toLowerCase().split( /\s+/ );
if ( $.inArray( 'localizations', rel ) !== -1 ) {
// multiple localizations
messageStore.load( $link.attr( 'href' ) );
} else if ( $.inArray( 'localization', rel ) !== -1 ) {
// single localization
messageStore.queue( ( $link.attr( 'hreflang' ) || '' ).toLowerCase(),
$link.attr( 'href' ) );
}
} );
},
/**
* General message loading API This can take a URL string for
* the json formatted messages.
* <code>load('path/to/all_localizations.json');</code>
*
* This can also load a localization file for a locale <code>
* load('path/to/de-messages.json', 'de' );
* load( 'path/to/de-messages.json', 'de' );
* </code>
* A data object containing message key- message translation mappings
* can also be passed Eg:
@@ -65,168 +41,54 @@
* null/undefined/false,
* all cached messages for the i18n instance will get reset.
*
* @param {String|Object|null} data
* @param {String|Object} source
* @param {String} locale Language tag
* @return {jQuery.Promise}
*/
load: function ( data, locale ) {
load: function ( source, locale ) {
var key = null,
messageStore = this,
hasOwn = Object.prototype.hasOwnProperty;
deferred = null,
deferreds = [],
messageStore = this;
if ( !data ) {
// reset all localizations
messageStore.log( 'Resetting for locale ' + locale );
messageStore.messages = {};
return;
}
if ( typeof data === 'string' ) {
if ( typeof source === 'string' ) {
// This is a URL to the messages file.
messageStore.log( 'Loading messages from: ' + data );
$.i18n.log( 'Loading messages from: ' + source );
deferred = jsonMessageLoader( source )
.done( function ( localization ) {
messageStore.set( locale, localization );
} );
messageStore.jsonMessageLoader( data ).done( function ( localization, textStatus ) {
messageStore.load( localization, locale );
messageStore.queue( locale, data );
messageStore.markLoaded( locale, data );
} );
return deferred.promise();
}
if ( locale ) {
// source is an key-value pair of messages for given locale
messageStore.set( locale, source );
return $.Deferred().resolve();
} else {
// Data is either a group of messages for {locale},
// or a group of languages with groups of messages inside.
for ( key in data ) {
if ( hasOwn.call( data, key ) ) {
if ( locale ) {
// Lazy-init the object
if ( !messageStore.messages[locale] ) {
messageStore.messages[locale] = {};
}
// Update message object keys,
// don't overwrite the entire object.
messageStore.messages[locale][key] = data[key];
messageStore.log(
'[' + locale + '][' + key + '] : ' + data[key]
);
// No {locale} given, assume data is a group of languages,
// call this function again for each langauge.
} else {
messageStore.load( data[key], key );
}
// source is a key-value pair of locales and their source
for ( key in source ) {
if ( Object.prototype.hasOwnProperty.call( source, key ) ) {
locale = key;
// No {locale} given, assume data is a group of languages,
// call this function again for each language.
deferreds.push( messageStore.load( source[key], locale ) );
}
}
return $.when.apply( $, deferreds );
}
},
log: function ( /* arguments */ ) {
if ( window.console && $.i18n.debug ) {
window.console.log.apply( window.console, arguments );
}
},
/**
* Mark a message Location for a locale loaded
*
* Set messages
* @param locale
* @param messageLocation
* @param messages
*/
markLoaded: function ( locale, messageLocation ) {
var i,
queue = this.sources[locale];
if ( !queue ) {
this.queue( locale, messageLocation );
queue = this.sources[locale];
}
this.sources[locale] = this.sources[locale] || [];
for ( i = 0; i < queue.length; i++ ) {
if ( queue[i].source.url === messageLocation ) {
queue[i].source.loaded = true;
return;
}
}
},
/**
* Register the message location for a locale, will be loaded when required
*
* @param locale
* @param messageLocation
*/
queue: function ( locale, messageLocation ) {
var i,
queue = this.sources[locale];
this.sources[locale] = this.sources[locale] || [];
if ( queue ) {
for ( i = 0; i < queue.length; i++ ) {
if ( queue[i].source.url === messageLocation ) {
return;
}
}
}
this.log( 'Source for: ' + locale + ' is ' + messageLocation + ' registered' );
this.sources[locale].push( {
source: {
url: messageLocation,
loaded: false
}
} );
},
/**
* Load the messages from the source queue for the locale
*
* @param {String} locale
*/
loadFromQueue: function ( locale ) {
var i,
queue = this.sources[locale];
if ( queue ) {
for ( i = 0; i < queue.length; i++ ) {
if ( !queue[i].source.loaded ) {
this.load( queue[i].source.url, locale );
this.sources[locale][i].source.loaded = true;
}
}
}
},
isLoaded: function ( locale, messageLocation ) {
var i,
sources = this.sources[locale],
result = false;
if ( sources ) {
for ( i = 0; i < sources.length; i++ ) {
if ( sources[i].source.url === messageLocation ) {
result = true;
}
}
}
return result;
},
jsonMessageLoader: function ( url ) {
var messageStore = this;
return $.ajax( {
url: url,
dataType: 'json',
//async: false
// This is unfortunate.
} ).fail( function ( jqxhr, settings, exception ) {
messageStore.log( 'Error in loading messages from ' + url + ' Exception: ' + exception );
} );
set: function( locale, messages ) {
this.messages[locale] = messages;
},
/**
@@ -236,15 +98,16 @@
* @returns {Boolean}
*/
get: function ( locale, messageKey ) {
// load locale if not loaded
if ( !this.messages[locale] ) {
this.loadFromQueue( locale );
}
return this.messages[locale] && this.messages[locale][messageKey];
}
};
function jsonMessageLoader( url ) {
return $.getJSON( url ).fail( function ( jqxhr, settings, exception ) {
$.i18n.log( 'Error in loading messages from ' + url + ' Exception: ' + exception );
} );
}
$.extend( $.i18n.messageStore, new MessageStore() );
}( jQuery, window ) );

View File

@@ -46,7 +46,11 @@
},
ast: function ( message ) {
var pos = 0;
var pipe, colon, backslash, anyCharacter, dollar, digits, regularLiteral,
regularLiteralWithoutBar, regularLiteralWithoutSpace, escapedOrLiteralWithoutBar,
escapedOrRegularLiteral, templateContents, templateName, openTemplate,
closeTemplate, expression, paramExpression, result,
pos = 0;
// Try parsers until one works, if none work return null
function choice ( parserSyntax ) {
@@ -142,15 +146,15 @@
};
}
var pipe = makeStringParser( '|' );
var colon = makeStringParser( ':' );
var backslash = makeStringParser( '\\' );
var anyCharacter = makeRegexParser( /^./ );
var dollar = makeStringParser( '$' );
var digits = makeRegexParser( /^\d+/ );
var regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
var regularLiteralWithoutBar = makeRegexParser( /^[^{}\[\]$\\|]/ );
var regularLiteralWithoutSpace = makeRegexParser( /^[^{}\[\]$\s]/ );
pipe = makeStringParser( '|' );
colon = makeStringParser( ':' );
backslash = makeStringParser( '\\' );
anyCharacter = makeRegexParser( /^./ );
dollar = makeStringParser( '$' );
digits = makeRegexParser( /^\d+/ );
regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
regularLiteralWithoutBar = makeRegexParser( /^[^{}\[\]$\\|]/ );
regularLiteralWithoutSpace = makeRegexParser( /^[^{}\[\]$\s]/ );
// There is a general pattern:
// parse a thing;
@@ -189,8 +193,8 @@
}
choice( [ escapedLiteral, regularLiteralWithoutSpace ] );
var escapedOrLiteralWithoutBar = choice( [ escapedLiteral, regularLiteralWithoutBar ] );
var escapedOrRegularLiteral = choice( [ escapedLiteral, regularLiteral ] );
escapedOrLiteralWithoutBar = choice( [ escapedLiteral, regularLiteralWithoutBar ] );
escapedOrRegularLiteral = choice( [ escapedLiteral, regularLiteral ] );
function replacement () {
var result = sequence( [ dollar, digits ] );
@@ -202,7 +206,7 @@
return [ 'REPLACE', parseInt( result[1], 10 ) - 1 ];
}
var templateName = transform(
templateName = transform(
// see $wgLegalTitleChars
// not allowing : due to the need to catch "PLURAL:$1"
makeRegexParser( /^[ !"$&'()*,.\/0-9;=?@A-Z\^_`a-z~\x80-\xFF+\-]+/ ),
@@ -213,13 +217,14 @@
);
function templateParam () {
var result = sequence( [ pipe, nOrMore( 0, paramExpression ) ] );
var expr,
result = sequence( [ pipe, nOrMore( 0, paramExpression ) ] );
if ( result === null ) {
return null;
}
var expr = result[1];
expr = result[1];
// use a "CONCAT" operator if there are multiple nodes,
// otherwise return the first node, raw.
@@ -238,7 +243,7 @@
return result === null ? null : [ result[0], result[2] ];
}
var templateContents = choice( [
templateContents = choice( [
function () {
var res = sequence( [
// templates can have placeholders for dynamic
@@ -262,8 +267,8 @@
}
] );
var openTemplate = makeStringParser( '{{' );
var closeTemplate = makeStringParser( '}}' );
openTemplate = makeStringParser( '{{' );
closeTemplate = makeStringParser( '}}' );
function template () {
var result = sequence( [ openTemplate, templateContents, closeTemplate ] );
@@ -271,8 +276,8 @@
return result === null ? null : result[1];
}
var expression = choice( [ template, replacement, literal ] );
var paramExpression = choice( [ template, replacement, literalWithoutBar ] );
expression = choice( [ template, replacement, literal ] );
paramExpression = choice( [ template, replacement, literalWithoutBar ] );
function start () {
var result = nOrMore( 0, expression )();
@@ -284,7 +289,7 @@
return [ 'CONCAT' ].concat( result );
}
var result = start();
result = start();
/*
* For success, the pos must have gotten to the end of the input
@@ -301,5 +306,4 @@
};
$.extend( $.i18n.parser, new MessageParser() );
}( jQuery ) );