silverstripe-framework/javascript/i18n.js
Sam Minnee 3ee8f505b7 MINORE: Remove training whitespace.
The main benefit of this is so that authors who make use of
.editorconfig don't end up with whitespace changes in their PRs.

Spaces vs. tabs has been left alone, although that could do with a
tidy-up in SS4 after the switch to PSR-1/2.

The command used was this:

for match in '*.ss' '*.css' '*.scss' '*.html' '*.yml' '*.php' '*.js' '*.csv' '*.inc' '*.php5'; do
	find . -path ./thirdparty -not -prune -o -path ./admin/thirdparty -not -prune -o -type f -name "$match" -exec sed -E -i '' 's/[[:space:]]+$//' {} \+
	find . -path ./thirdparty -not -prune -o -path ./admin/thirdparty -not -prune -o -type f -name "$match" | xargs perl -pi -e 's/ +$//'
done
2016-01-07 10:15:54 +13:00

256 lines
6.8 KiB
JavaScript

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('html').attr('lang') || 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();
});