mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-22 08:26:16 -04:00
Allow 'placeholder' to be a localizable attribute on HTML elements (#3257)
This commit is contained in:
parent
67439545a6
commit
0e1414dcca
1 changed files with 44 additions and 43 deletions
|
@ -21,7 +21,7 @@
|
||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
window.html10n = (function(window, document, undefined) {
|
window.html10n = (function(window, document, undefined) {
|
||||||
|
|
||||||
// fix console
|
// fix console
|
||||||
(function() {
|
(function() {
|
||||||
var noop = function() {};
|
var noop = function() {};
|
||||||
|
@ -80,7 +80,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MicroEvent - to make any js object an event emitter (server or browser)
|
* MicroEvent - to make any js object an event emitter (server or browser)
|
||||||
*/
|
*/
|
||||||
|
@ -116,7 +116,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
destObject[props[i]] = MicroEvent.prototype[props[i]];
|
destObject[props[i]] = MicroEvent.prototype[props[i]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader
|
* Loader
|
||||||
* The loader is responsible for loading
|
* The loader is responsible for loading
|
||||||
|
@ -127,7 +127,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
this.cache = {} // file => contents
|
this.cache = {} // file => contents
|
||||||
this.langs = {} // lang => strings
|
this.langs = {} // lang => strings
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader.prototype.load = function(lang, cb) {
|
Loader.prototype.load = function(lang, cb) {
|
||||||
if(this.langs[lang]) return cb()
|
if(this.langs[lang]) return cb()
|
||||||
|
|
||||||
|
@ -137,22 +137,22 @@ window.html10n = (function(window, document, undefined) {
|
||||||
this.fetch(this.resources[i], lang, function(e) {
|
this.fetch(this.resources[i], lang, function(e) {
|
||||||
reqs++;
|
reqs++;
|
||||||
if(e) console.warn(e)
|
if(e) console.warn(e)
|
||||||
|
|
||||||
if (reqs < n) return;// Call back once all reqs are completed
|
if (reqs < n) return;// Call back once all reqs are completed
|
||||||
cb && cb()
|
cb && cb()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader.prototype.fetch = function(href, lang, cb) {
|
Loader.prototype.fetch = function(href, lang, cb) {
|
||||||
var that = this
|
var that = this
|
||||||
|
|
||||||
if (this.cache[href]) {
|
if (this.cache[href]) {
|
||||||
this.parse(lang, href, this.cache[href], cb)
|
this.parse(lang, href, this.cache[href], cb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest()
|
var xhr = new XMLHttpRequest()
|
||||||
xhr.open('GET', href, /*async: */true)
|
xhr.open('GET', href, /*async: */true)
|
||||||
if (xhr.overrideMimeType) {
|
if (xhr.overrideMimeType) {
|
||||||
|
@ -172,7 +172,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
};
|
};
|
||||||
xhr.send(null);
|
xhr.send(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader.prototype.parse = function(lang, currHref, data, cb) {
|
Loader.prototype.parse = function(lang, currHref, data, cb) {
|
||||||
if ('object' != typeof data) {
|
if ('object' != typeof data) {
|
||||||
cb(new Error('A file couldn\'t be parsed as json.'))
|
cb(new Error('A file couldn\'t be parsed as json.'))
|
||||||
|
@ -192,7 +192,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
}
|
}
|
||||||
if(lang != l) return cb(new Error(msg))
|
if(lang != l) return cb(new Error(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('string' == typeof data[lang]) {
|
if ('string' == typeof data[lang]) {
|
||||||
// Import rule
|
// Import rule
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
var importUrl = data[lang]
|
var importUrl = data[lang]
|
||||||
|
|
||||||
// relative path
|
// relative path
|
||||||
if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) {
|
if(data[lang].indexOf("http") != 0 && data[lang].indexOf("/") != 0) {
|
||||||
importUrl = currHref+"/../"+data[lang]
|
importUrl = currHref+"/../"+data[lang]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +217,20 @@ window.html10n = (function(window, document, undefined) {
|
||||||
// TODO: Also store accompanying langs
|
// TODO: Also store accompanying langs
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The html10n object
|
* The html10n object
|
||||||
*/
|
*/
|
||||||
var html10n =
|
var html10n =
|
||||||
{ language : null
|
{ language : null
|
||||||
}
|
}
|
||||||
MicroEvent.mixin(html10n)
|
MicroEvent.mixin(html10n)
|
||||||
|
|
||||||
html10n.macros = {}
|
html10n.macros = {}
|
||||||
|
|
||||||
html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"]
|
html10n.rtl = ["ar","dv","fa","ha","he","ks","ku","ps","ur","yi"]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get rules for plural forms (shared with JetPack), see:
|
* Get rules for plural forms (shared with JetPack), see:
|
||||||
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
||||||
|
@ -668,7 +668,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Localize a document
|
* Localize a document
|
||||||
* @param langs An array of lang codes defining fallbacks
|
* @param langs An array of lang codes defining fallbacks
|
||||||
|
@ -710,7 +710,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
// translate element itself if necessary
|
// translate element itself if necessary
|
||||||
this.translateNode(translations, element)
|
this.translateNode(translations, element)
|
||||||
}
|
}
|
||||||
|
|
||||||
function asyncForEach(list, iterator, cb) {
|
function asyncForEach(list, iterator, cb) {
|
||||||
var i = 0
|
var i = 0
|
||||||
, n = list.length
|
, n = list.length
|
||||||
|
@ -721,7 +721,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
cb()
|
cb()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTranslatableChildren(element) {
|
function getTranslatableChildren(element) {
|
||||||
if(!document.querySelectorAll) {
|
if(!document.querySelectorAll) {
|
||||||
if (!element) return []
|
if (!element) return []
|
||||||
|
@ -735,29 +735,29 @@ window.html10n = (function(window, document, undefined) {
|
||||||
}
|
}
|
||||||
return element.querySelectorAll('*[data-l10n-id]')
|
return element.querySelectorAll('*[data-l10n-id]')
|
||||||
}
|
}
|
||||||
|
|
||||||
html10n.get = function(id, args) {
|
html10n.get = function(id, args) {
|
||||||
var translations = html10n.translations
|
var translations = html10n.translations
|
||||||
if(!translations) return console.warn('No translations available (yet)')
|
if(!translations) return console.warn('No translations available (yet)')
|
||||||
if(!translations[id]) return console.warn('Could not find string '+id)
|
if(!translations[id]) return console.warn('Could not find string '+id)
|
||||||
|
|
||||||
// apply macros
|
// apply macros
|
||||||
var str = translations[id]
|
var str = translations[id]
|
||||||
|
|
||||||
str = substMacros(id, str, args)
|
str = substMacros(id, str, args)
|
||||||
|
|
||||||
// apply args
|
// apply args
|
||||||
str = substArguments(str, args)
|
str = substArguments(str, args)
|
||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace {{arguments}} with their values or the
|
// replace {{arguments}} with their values or the
|
||||||
// associated translation string (based on its key)
|
// associated translation string (based on its key)
|
||||||
function substArguments(str, args) {
|
function substArguments(str, args) {
|
||||||
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/
|
var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/
|
||||||
, match
|
, match
|
||||||
|
|
||||||
while (match = reArgs.exec(str)) {
|
while (match = reArgs.exec(str)) {
|
||||||
if (!match || match.length < 2)
|
if (!match || match.length < 2)
|
||||||
return str // argument key not found
|
return str // argument key not found
|
||||||
|
@ -775,15 +775,15 @@ window.html10n = (function(window, document, undefined) {
|
||||||
|
|
||||||
str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length)
|
str = str.substring(0, match.index) + sub + str.substr(match.index + match[0].length)
|
||||||
}
|
}
|
||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace {[macros]} with their values
|
// replace {[macros]} with their values
|
||||||
function substMacros(key, str, args) {
|
function substMacros(key, str, args) {
|
||||||
var regex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/ //.exec('{[ plural(n) other: are {{n}}, one: is ]}')
|
var regex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/ //.exec('{[ plural(n) other: are {{n}}, one: is ]}')
|
||||||
, match
|
, match
|
||||||
|
|
||||||
while(match = regex.exec(str)) {
|
while(match = regex.exec(str)) {
|
||||||
// a macro has been found
|
// a macro has been found
|
||||||
// Note: at the moment, only one parameter is supported
|
// Note: at the moment, only one parameter is supported
|
||||||
|
@ -791,9 +791,9 @@ window.html10n = (function(window, document, undefined) {
|
||||||
, paramName = match[2]
|
, paramName = match[2]
|
||||||
, optv = match[3]
|
, optv = match[3]
|
||||||
, opts = {}
|
, opts = {}
|
||||||
|
|
||||||
if (!(macroName in html10n.macros)) continue
|
if (!(macroName in html10n.macros)) continue
|
||||||
|
|
||||||
if(optv) {
|
if(optv) {
|
||||||
optv.match(/(?=\s*)([a-zA-Z]+)\: ?([ a-zA-Z{}]+)(?=,?)/g).forEach(function(arg) {
|
optv.match(/(?=\s*)([a-zA-Z]+)\: ?([ a-zA-Z{}]+)(?=,?)/g).forEach(function(arg) {
|
||||||
var parts = arg.split(':')
|
var parts = arg.split(':')
|
||||||
|
@ -802,7 +802,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
opts[name] = value
|
opts[name] = value
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var param
|
var param
|
||||||
if (args && paramName in args) {
|
if (args && paramName in args) {
|
||||||
param = args[paramName]
|
param = args[paramName]
|
||||||
|
@ -814,10 +814,10 @@ window.html10n = (function(window, document, undefined) {
|
||||||
var macro = html10n.macros[macroName]
|
var macro = html10n.macros[macroName]
|
||||||
str = str.substr(0, match.index) + macro(key, param, opts) + str.substr(match.index+match[0].length)
|
str = str.substr(0, match.index) + macro(key, param, opts) + str.substr(match.index+match[0].length)
|
||||||
}
|
}
|
||||||
|
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies translations to a DOM node (recursive)
|
* Applies translations to a DOM node (recursive)
|
||||||
*/
|
*/
|
||||||
|
@ -840,9 +840,9 @@ window.html10n = (function(window, document, undefined) {
|
||||||
console.warn('Couldn\'t parse args for '+str.id)
|
console.warn('Couldn\'t parse args for '+str.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
str.str = html10n.get(str.id, str.args)
|
str.str = html10n.get(str.id, str.args)
|
||||||
|
|
||||||
// get attribute name to apply str to
|
// get attribute name to apply str to
|
||||||
var prop
|
var prop
|
||||||
, index = str.id.lastIndexOf('.')
|
, index = str.id.lastIndexOf('.')
|
||||||
|
@ -852,6 +852,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
, "alt": 1
|
, "alt": 1
|
||||||
, "textContent": 1
|
, "textContent": 1
|
||||||
, "value": 1
|
, "value": 1
|
||||||
|
, "placeholder": 1
|
||||||
}
|
}
|
||||||
if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified
|
if (index > 0 && str.id.substr(index + 1) in attrList) { // an attribute has been specified
|
||||||
prop = str.id.substr(index + 1)
|
prop = str.id.substr(index + 1)
|
||||||
|
@ -883,7 +884,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a translation object from a list of langs (loads the necessary translations)
|
* Builds a translation object from a list of langs (loads the necessary translations)
|
||||||
* @param langs Array - a list of langs sorted by priority (default langs should go last)
|
* @param langs Array - a list of langs sorted by priority (default langs should go last)
|
||||||
|
@ -898,11 +899,11 @@ window.html10n = (function(window, document, undefined) {
|
||||||
}, function() {
|
}, function() {
|
||||||
var lang
|
var lang
|
||||||
langs.reverse()
|
langs.reverse()
|
||||||
|
|
||||||
// loop through the priority array...
|
// loop through the priority array...
|
||||||
for (var i=0, n=langs.length; i < n; i++) {
|
for (var i=0, n=langs.length; i < n; i++) {
|
||||||
lang = langs[i]
|
lang = langs[i]
|
||||||
|
|
||||||
if(!lang) continue;
|
if(!lang) continue;
|
||||||
if(!(lang in that.loader.langs)) {// uh, we don't have this lang availbable..
|
if(!(lang in that.loader.langs)) {// uh, we don't have this lang availbable..
|
||||||
// then check for related langs
|
// then check for related langs
|
||||||
|
@ -915,13 +916,13 @@ window.html10n = (function(window, document, undefined) {
|
||||||
}
|
}
|
||||||
if(lang != l) continue;
|
if(lang != l) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... and apply all strings of the current lang in the list
|
// ... and apply all strings of the current lang in the list
|
||||||
// to our build object
|
// to our build object
|
||||||
for (var string in that.loader.langs[lang]) {
|
for (var string in that.loader.langs[lang]) {
|
||||||
build[string] = that.loader.langs[lang][string]
|
build[string] = that.loader.langs[lang][string]
|
||||||
}
|
}
|
||||||
|
|
||||||
// the last applied lang will be exposed as the
|
// the last applied lang will be exposed as the
|
||||||
// lang the page was translated to
|
// lang the page was translated to
|
||||||
that.language = lang
|
that.language = lang
|
||||||
|
@ -929,7 +930,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
cb(null, build)
|
cb(null, build)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the language that was last applied to the translations hash
|
* Returns the language that was last applied to the translations hash
|
||||||
* thus overriding most of the formerly applied langs
|
* thus overriding most of the formerly applied langs
|
||||||
|
@ -962,7 +963,7 @@ window.html10n = (function(window, document, undefined) {
|
||||||
this.loader = new Loader(resources)
|
this.loader = new Loader(resources)
|
||||||
this.trigger('indexed')
|
this.trigger('indexed')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.addEventListener) // modern browsers and IE9+
|
if (document.addEventListener) // modern browsers and IE9+
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
html10n.index()
|
html10n.index()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue