Completed
Push — master ( be0721...cced22 )
by Matthew
02:48
created

web/static/js/vendor/jquery.i18n/jquery.i18n.js   B

Complexity

Total Complexity 41
Complexity/F 3.15

Size

Lines of Code 285
Function Count 13

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
wmc 41
nc 55296
mnd 3
bc 39
fnc 13
dl 0
loc 285
rs 8.2769
bpm 3
cpm 3.1538
noi 5
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like web/static/js/vendor/jquery.i18n/jquery.i18n.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
 * jQuery Internationalization library
3
 *
4
 * Copyright (C) 2012 Santhosh Thottingal
5
 *
6
 * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do
7
 * anything special to choose one license or the other and you don't have to
8
 * notify anyone which license you are using. You are free to use
9
 * UniversalLanguageSelector in commercial projects as long as the copyright
10
 * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
11
 *
12
 * @licence GNU General Public Licence 2.0 or later
13
 * @licence MIT License
14
 */
15
16
( function ( $ ) {
17
	'use strict';
18
19
	var nav, I18N,
20
		slice = Array.prototype.slice;
21
	/**
22
	 * @constructor
23
	 * @param {Object} options
24
	 */
25
	I18N = function ( options ) {
26
		// Load defaults
27
		this.options = $.extend( {}, I18N.defaults, options );
28
29
		this.parser = this.options.parser;
30
		this.locale = this.options.locale;
31
		this.messageStore = this.options.messageStore;
32
		this.languages = {};
33
34
		this.init();
35
	};
36
37
	I18N.prototype = {
38
		/**
39
		 * Initialize by loading locales and setting up
40
		 * String.prototype.toLocaleString and String.locale.
41
		 */
42
		init: function () {
43
			var i18n = this;
44
45
			// Set locale of String environment
46
			String.locale = i18n.locale;
47
48
			// Override String.localeString method
49
			String.prototype.toLocaleString = function () {
50
				var localeParts, localePartIndex, value, locale, fallbackIndex,
51
					tryingLocale, message;
52
53
				value = this.valueOf();
54
				locale = i18n.locale;
55
				fallbackIndex = 0;
56
57
				while ( locale ) {
58
					// Iterate through locales starting at most-specific until
59
					// localization is found. As in fi-Latn-FI, fi-Latn and fi.
60
					localeParts = locale.split( '-' );
61
					localePartIndex = localeParts.length;
62
63
					do {
64
						tryingLocale = localeParts.slice( 0, localePartIndex ).join( '-' );
65
						message = i18n.messageStore.get( tryingLocale, value );
66
67
						if ( message ) {
68
							return message;
69
						}
70
71
						localePartIndex--;
72
					} while ( localePartIndex );
73
74
					if ( locale === 'en' ) {
75
						break;
76
					}
77
78
					locale = ( $.i18n.fallbacks[ i18n.locale ] && $.i18n.fallbacks[ i18n.locale ][ fallbackIndex ] ) ||
79
						i18n.options.fallbackLocale;
80
					$.i18n.log( 'Trying fallback locale for ' + i18n.locale + ': ' + locale );
81
82
					fallbackIndex++;
83
				}
84
85
				// key not found
86
				return '';
87
			};
88
		},
89
90
		/*
91
		 * Destroy the i18n instance.
92
		 */
93
		destroy: function () {
94
			$.removeData( document, 'i18n' );
95
		},
96
97
		/**
98
		 * General message loading API This can take a URL string for
99
		 * the json formatted messages. Example:
100
		 * <code>load('path/to/all_localizations.json');</code>
101
		 *
102
		 * To load a localization file for a locale:
103
		 * <code>
104
		 * load('path/to/de-messages.json', 'de' );
105
		 * </code>
106
		 *
107
		 * To load a localization file from a directory:
108
		 * <code>
109
		 * load('path/to/i18n/directory', 'de' );
110
		 * </code>
111
		 * The above method has the advantage of fallback resolution.
112
		 * ie, it will automatically load the fallback locales for de.
113
		 * For most usecases, this is the recommended method.
114
		 * It is optional to have trailing slash at end.
115
		 *
116
		 * A data object containing message key- message translation mappings
117
		 * can also be passed. Example:
118
		 * <code>
119
		 * load( { 'hello' : 'Hello' }, optionalLocale );
120
		 * </code>
121
		 *
122
		 * A source map containing key-value pair of languagename and locations
123
		 * can also be passed. Example:
124
		 * <code>
125
		 * load( {
126
		 * bn: 'i18n/bn.json',
127
		 * he: 'i18n/he.json',
128
		 * en: 'i18n/en.json'
129
		 * } )
130
		 * </code>
131
		 *
132
		 * If the data argument is null/undefined/false,
133
		 * all cached messages for the i18n instance will get reset.
134
		 *
135
		 * @param {string|Object} source
136
		 * @param {string} locale Language tag
137
		 * @return {jQuery.Promise}
138
		 */
139
		load: function ( source, locale ) {
140
			var fallbackLocales, locIndex, fallbackLocale, sourceMap = {};
141
			if ( !source && !locale ) {
142
				source = 'i18n/' + $.i18n().locale + '.json';
143
				locale = $.i18n().locale;
144
			}
145
			if ( typeof source === 'string' &&
146
				source.split( '.' ).pop() !== 'json'
147
			) {
148
				// Load specified locale then check for fallbacks when directory is specified in load()
149
				sourceMap[ locale ] = source + '/' + locale + '.json';
150
				fallbackLocales = ( $.i18n.fallbacks[ locale ] || [] )
151
					.concat( this.options.fallbackLocale );
152
				for ( locIndex in fallbackLocales ) {
153
					fallbackLocale = fallbackLocales[ locIndex ];
154
					sourceMap[ fallbackLocale ] = source + '/' + fallbackLocale + '.json';
155
				}
156
				return this.load( sourceMap );
157
			} else {
158
				return this.messageStore.load( source, locale );
159
			}
160
161
		},
162
163
		/**
164
		 * Does parameter and magic word substitution.
165
		 *
166
		 * @param {string} key Message key
167
		 * @param {Array} parameters Message parameters
168
		 * @return {string}
169
		 */
170
		parse: function ( key, parameters ) {
171
			var message = key.toLocaleString();
172
			// FIXME: This changes the state of the I18N object,
173
			// should probably not change the 'this.parser' but just
174
			// pass it to the parser.
175
			this.parser.language = $.i18n.languages[ $.i18n().locale ] || $.i18n.languages[ 'default' ];
176
			if ( message === '' ) {
177
				message = key;
178
			}
179
			return this.parser.parse( message, parameters );
180
		}
181
	};
182
183
	/**
184
	 * Process a message from the $.I18N instance
185
	 * for the current document, stored in jQuery.data(document).
186
	 *
187
	 * @param {string} key Key of the message.
188
	 * @param {string} param1 [param...] Variadic list of parameters for {key}.
189
	 * @return {string|$.I18N} Parsed message, or if no key was given
190
	 * the instance of $.I18N is returned.
191
	 */
192
	$.i18n = function ( key, param1 ) {
193
		var parameters,
194
			i18n = $.data( document, 'i18n' ),
195
			options = typeof key === 'object' && key;
196
197
		// If the locale option for this call is different then the setup so far,
198
		// update it automatically. This doesn't just change the context for this
199
		// call but for all future call as well.
200
		// If there is no i18n setup yet, don't do this. It will be taken care of
201
		// by the `new I18N` construction below.
202
		// NOTE: It should only change language for this one call.
203
		// Then cache instances of I18N somewhere.
204
		if ( options && options.locale && i18n && i18n.locale !== options.locale ) {
205
			String.locale = i18n.locale = options.locale;
206
		}
207
208
		if ( !i18n ) {
209
			i18n = new I18N( options );
210
			$.data( document, 'i18n', i18n );
211
		}
212
213
		if ( typeof key === 'string' ) {
214
			if ( param1 !== undefined ) {
215
				parameters = slice.call( arguments, 1 );
216
			} else {
217
				parameters = [];
218
			}
219
220
			return i18n.parse( key, parameters );
221
		} else {
222
			// FIXME: remove this feature/bug.
223
			return i18n;
224
		}
225
	};
226
227
	$.fn.i18n = function () {
228
		var i18n = $.data( document, 'i18n' );
229
230
		if ( !i18n ) {
231
			i18n = new I18N();
232
			$.data( document, 'i18n', i18n );
233
		}
234
		String.locale = i18n.locale;
235
		return this.each( function () {
236
			var $this = $( this ),
237
				messageKey = $this.data( 'i18n' ),
238
				lBracket, rBracket, type, key;
239
240
			if ( messageKey ) {
241
				lBracket = messageKey.indexOf( '[' );
242
				rBracket = messageKey.indexOf( ']' );
243
				if ( lBracket !== -1 && rBracket !== -1 && lBracket < rBracket ) {
244
					type = messageKey.slice( lBracket + 1, rBracket );
245
					key = messageKey.slice( rBracket + 1 );
246
					if ( type === 'html' ) {
247
						$this.html( i18n.parse( key ) );
248
					} else {
249
						$this.attr( type, i18n.parse( key ) );
250
					}
251
				} else {
252
					$this.text( i18n.parse( messageKey ) );
253
				}
254
			} else {
255
				$this.find( '[data-i18n]' ).i18n();
256
			}
257
		} );
258
	};
259
260
	String.locale = String.locale || $( 'html' ).attr( 'lang' );
261
262
	if ( !String.locale ) {
263
		if ( typeof window.navigator !== undefined ) {
264
			nav = window.navigator;
265
			String.locale = nav.language || nav.userLanguage || '';
266
		} else {
267
			String.locale = '';
268
		}
269
	}
270
271
	$.i18n.languages = {};
272
	$.i18n.messageStore = $.i18n.messageStore || {};
273
	$.i18n.parser = {
274
		// The default parser only handles variable substitution
275
		parse: function ( message, parameters ) {
276
			return message.replace( /\$(\d+)/g, function ( str, match ) {
277
				var index = parseInt( match, 10 ) - 1;
278
				return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match;
279
			} );
280
		},
281
		emitter: {}
282
	};
283
	$.i18n.fallbacks = {};
284
	$.i18n.debug = false;
285
	$.i18n.log = function ( /* arguments */ ) {
286
		if ( window.console && $.i18n.debug ) {
287
			window.console.log.apply( window.console, arguments );
288
		}
289
	};
290
	/* Static members */
291
	I18N.defaults = {
292
		locale: String.locale,
293
		fallbackLocale: 'en',
294
		parser: $.i18n.parser,
295
		messageStore: $.i18n.messageStore
296
	};
297
298
	// Expose constructor
299
	$.i18n.constructor = I18N;
300
}( jQuery ) );
301