1 /**	When called as a function, acts as an alias of {@link puredom.i18n.localize}.
  2  *	@namespace Internationalization extension for puredom.
  3  *	@function
  4  */
  5 puredom.i18n = (function() {
  6 	/**	@exports i18n as puredom.i18n */
  7 	var langs = {},
  8 		i18n;
  9 	
 10 	/**	@ignore */
 11 	i18n = function() {
 12 		return i18n.localize.apply(this,arguments);
 13 	};
 14 	
 15 	/**	Get the locale definition corresponding to the given language code.
 16 	 *	@param {String} langCode		A language code to retrieve the definition for.
 17 	 *	@returns {Object} locale, or <code>false</code> on error.
 18 	 */
 19 	i18n.getLang = function(langCode) {
 20 		langCode = langCode.toLowerCase().replace(/[^a-z0-9]/gim,'');
 21 		for (var x in langs) {
 22 			if (langs.hasOwnProperty(x) && (x+'').toLowerCase().replace(/[^a-z0-9]/gim,'')===langCode) {
 23 				return langs[x];
 24 			}
 25 		}
 26 		return false;
 27 	};
 28 	
 29 	/**	Check if a locale definition is registered for the given language code.
 30 	 *	@param {String} langCode		A language code to check for.
 31 	 *	@returns {Boolean} exists
 32 	 */
 33 	i18n.hasLang = function(langCode) {
 34 		return !!i18n.getLang(langCode);
 35 	};
 36 	
 37 	/**	Set the global locale.
 38 	 *	@param {String} langCode		The new language code to apply globally.
 39 	 *	@returns {this}
 40 	 */
 41 	i18n.setLang = function(langCode) {
 42 		if (i18n.hasLang(langCode)) {
 43 			i18n.locale = i18n.lang = langCode;
 44 		}
 45 		return this;
 46 	};
 47 	
 48 	/**	Apply the global locale definition to a selection ({@link puredom.NodeSelection}).<br />
 49 	 *	Looks for <code>data-i18n-id</code> attributes, and updates their owner nodes' contents with the corresponding String from the global locale definition.
 50 	 *	@param {puredom.NodeSelection} selection		A selection to apply the global locale definition to.
 51 	 */
 52 	i18n.localizeDOM = function(nodeSelection) {
 53 		nodeSelection.query('[data-i18n-id]').each(function(node) {
 54 			var key = (node.attr('data-i18n-id') || '') + '',
 55 				type = node.nodeName(),
 56 				current,
 57 				localized;
 58 			if (key && key.length>0) {
 59 				localized = i18n.localize(key, null, '');
 60 				if (localized && localized!==key && localized!=='') {
 61 					switch (type) {
 62 						case "select":
 63 						case "input":
 64 						case "textarea":
 65 							current = node.value();
 66 							if (current!==localized) {
 67 								node.value(localized);
 68 							}
 69 							break;
 70 						
 71 						default:
 72 							current = node.html();
 73 							if (current!==localized) {
 74 								node.html(localized);
 75 							}
 76 							break;
 77 					}
 78 				}
 79 			}
 80 		});
 81 	};
 82 	
 83 	/**	Localize a variable.
 84 	 *	@param {Any} value						A value to localize.  Ex: a Date, Number or String
 85 	 *	@param {String} [langCode=i18n.locale]	An alternative language code to use.
 86 	 *	@param {String} [defaultValue]			A fallback value to use if no localized value can be generated.
 87 	 *	@param {Object} [options]				Configuration object.
 88 	 */
 89 	i18n.localize = function(value, lang, defaultValue, options) {
 90 		var type = puredom.typeOf(value),
 91 			originalValue = value,
 92 			dateFormat, def, localizedValue, t, i;
 93 		options = options || {};
 94 		lang = (lang || i18n.lang || i18n.locale || 'en').toUpperCase();
 95 		if (langs.hasOwnProperty(lang)) {
 96 			def = langs[lang];
 97 		}
 98 		else if (lang.indexOf('-')>-1) {
 99 			lang = lang.substring(0, lang.indexOf('-'));
100 			if (langs.hasOwnProperty(lang)) {
101 				def = langs[lang];
102 			}
103 		}
104 		
105 		if (def && value!==null && value!==undefined) {
106 			if (type==='string') {
107 				value = value.replace(/\{([^{}]+)\}/gim,'$1');
108 			}
109 			def = {
110 				labels : def.labels || {},
111 				formats : def.formats || {}
112 			};
113 			if (type==='string' && !value.match(/^(labels|formats)\./gim)) {
114 				value = 'labels.' + value;
115 			}
116 			if (type==='date' || value.constructor===Date) {
117 				dateFormat = def.formats[options.datetype || 'date'];
118 				//console.log(options.datetype, dateFormat);
119 				localizedValue = dateFormat && puredom.date.format(value, dateFormat) || value.toLocaleString();
120 			}
121 			else if (type==='number') {
122 				if (def.formats.thousands_separator) {
123 					localizedValue = '';
124 					t = value+'';
125 					while (t.length > 0) {
126 						localizedValue = t.substring(Math.max(0,t.length-3)) + localizedValue;
127 						if (t.length>3) {
128 							localizedValue = def.formats.thousands_separator + localizedValue;
129 						}
130 						t = t.substring(0, Math.max(0,t.length-3));
131 					}
132 				}
133 			}
134 			else if (type==='boolean') {
135 				localizedValue = (value===true ? def.formats.booleanTrue : def.formats.booleanFalse) || (value+'');
136 			}
137 			else {
138 				localizedValue = puredom.delve(def, value+'');
139 			}
140 		}
141 		
142 		if (localizedValue) {
143 			return localizedValue;
144 		}
145 		else if (defaultValue!==null && defaultValue!==undefined) {
146 			return defaultValue;
147 		}
148 		return originalValue;
149 	};
150 	
151 	/**	Add a locale definition.
152 	 *	@param {String} langCode		A language code
153 	 *	@param {Object} definition		A key-value JSON object that defines labels and formats
154 	 *	@returns {this}
155 	 */
156 	i18n.addLang = function(langCode, definition) {
157 		langCode = (langCode+'').toUpperCase();
158 		// if the JSON object is just a list, it is treated as a static label lookup:
159 		if (!definition.labels) {
160 			definition = {
161 				labels : definition
162 			};
163 		}
164 		langs[langCode] = definition;
165 		return this;
166 	};
167 	
168 	// Register this as a plugin for nodeselections
169 	/**	Localize the selection.
170 	 *	@name puredom.NodeSelection#localize
171 	 *	@function
172 	 */
173 	puredom.addNodeSelectionPlugin('localize', function() {
174 		i18n.localizeDOM(this);
175 		return this;
176 	});
177 	
178 	return i18n;
179 }());
180