if(typeof(ss) == 'undefined') ss = {}; /* * Lightweight clientside i18n implementation. * Caution: Only available after DOM loaded because we need to detect the language * * For non-i18n stub implementation, see framework/javascript/i18nx.js * * Based on jQuery i18n plugin: 1.0.0 Feb-10-2008 * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Based on 'javascript i18n that almost doesn't suck' by markos * http://markos.gaivo.net/blog/?p=100 */ ss.i18n = { currentLocale: null, defaultLocale: 'en_US', lang: {}, inited: false, init: function() { if(this.inited) return; this.currentLocale = this.detectLocale(); this.inited = true; }, /** * set_locale() * Set locale in long format, e.g. "de_AT" for Austrian German. * @param string locale */ setLocale: function(locale) { this.currentLocale = locale; }, /** * getLocale() * Get locale in long format. Falls back to i18n.defaut_locale. * @return string */ getLocale: function() { return (this.currentLocale) ? this.currentLocale : this.defaultLocale; }, /** * _() * The actual translation function. Looks the given string up in the * dictionary and returns the translation if one exists. If a translation * is not found, returns the original word * * @param string entity A "long" locale format, e.g. "de_DE" (Required) * @param string fallbackString (Required) * @param int priority (not used) * @param string context Give translators context for the string * @return string : Translated word * */ _t: function (entity, fallbackString, priority, context) { this.init(); var langName = this.getLocale().replace(/_[\w]+/i, ''); var defaultlangName = this.defaultLocale.replace(/_[\w]+/i, ''); if (this.lang && this.lang[this.getLocale()] && this.lang[this.getLocale()][entity]) { return this.lang[this.getLocale()][entity]; } else if (this.lang && this.lang[langName] && this.lang[langName][entity]) { return this.lang[langName][entity]; } else if (this.lang && this.lang[this.defaultLocale] && this.lang[this.defaultLocale][entity]) { return this.lang[this.defaultLocale][entity]; } else if (this.lang && this.lang[defaultlangName] && this.lang[defaultlangName][entity]) { return this.lang[defaultlangName][entity]; } else if(fallbackString) { return fallbackString; } else { return ''; } }, /** * Add entities to a dictionary. If a dictionary doesn't * exist for this locale, its automatically created. * Existing entities are overwritten. * * @param string locale * @param Object dict */ addDictionary: function(locale, dict) { if(!this.lang[locale]) this.lang[locale] = {}; for(entity in dict) { this.lang[locale][entity] = dict[entity]; } }, /** * Get dictionary for a specific locale. * * @param string locale */ getDictionary: function(locale) { return this.lang[locale]; }, /** * stripStr() * * @param string str : The string to strip * @return string result : Stripped string * */ stripStr: function(str) { return str.replace(/^\s*/, "").replace(/\s*$/, ""); }, /** * stripStrML() * * @param string str : The multi-line string to strip * @return string result : Stripped string * */ stripStrML: function(str) { // Split because m flag doesn't exist before JS1.5 and we need to // strip newlines anyway var parts = str.split('\n'); for (var i=0; i<parts.length; i++) parts[i] = stripStr(parts[i]); // Don't join with empty strings, because it "concats" words // And strip again return stripStr(parts.join(" ")); }, /** * Substitutes %s with parameters * given in list. %%s is used to escape %s. * * @param string S : The string to perform the substitutions on. * @return string The new string with substitutions made */ sprintf: function(S) { if (arguments.length == 1) return S; var args = [], len = arguments.length, index = 0, regx = new RegExp('(.?)(%s)', 'g'), result; for (var i=1; i<len; ++i) { args.push(arguments[i]); }; result = S.replace(regx, function(match, subMatch1, subMatch2, offset, string){ if (subMatch1 == '%') return match; // skip %%s return subMatch1 + args[index++]; }); return result; }, /** * Substitutes variables with a list of injections. * * @param string S : The string to perform the substitutions on. * @param object map : An object with the substitions map e.g. {var: value} * @return string The new string with substitutions made */ inject: function(S, map) { var regx = new RegExp("\{([A-Za-z0-9_]*)\}", "g"), result; result = S.replace(regx, function(match, key, offset, string){ return (map[key]) ? map[key] : match; }); return result; }, /** * Detect document language settings by looking at <meta> tags. * If no match is found, returns this.defaultLocale. * * @todo get by <html lang=''> - needs modification of SSViewer * * @return string Locale in mixed lowercase/uppercase format suitable * for usage in ss.i18n.lang arrays (e.g. 'en_US'). */ detectLocale: function() { var rawLocale; var detectedLocale; // get by container tag rawLocale = jQuery('body').attr('lang'); // get by meta if(!rawLocale) { var metas = document.getElementsByTagName('meta'); for(var i=0; i<metas.length; i++) { if(metas[i].attributes['http-equiv'] && metas[i].attributes['http-equiv'].nodeValue.toLowerCase() == 'content-language') { rawLocale = metas[i].attributes['content'].nodeValue; } } } // fallback to default locale if(!rawLocale) rawLocale = this.defaultLocale; var rawLocaleParts = rawLocale.match(/([^-|_]*)[-|_](.*)/); // get locale (e.g. 'en_US') from common name (e.g. 'en') // by looking at ss.i18n.lang tables if(rawLocale.length == 2) { for(compareLocale in ss.i18n.lang) { if(compareLocale.substr(0,2).toLowerCase() == rawLocale.toLowerCase()) { detectedLocale = compareLocale; break; } } } else if(rawLocaleParts) { detectedLocale = rawLocaleParts[1].toLowerCase() + '_' + rawLocaleParts[2].toUpperCase(); } return detectedLocale; }, /** * Attach an event listener to the given object. * Modeled after behaviour.js, but externalized * to keep the i18n library standalone for now. */ addEvent: function(obj, evType, fn, useCapture){ if (obj.addEventListener){ obj.addEventListener(evType, fn, useCapture); return true; } else if (obj.attachEvent){ var r = obj.attachEvent("on"+evType, fn); return r; } else { alert("Handler could not be attached"); } } }; ss.i18n.addEvent(window, "load", function() { ss.i18n.init(); });