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