Allow 'placeholder' to be a localizable attribute on HTML elements (#3257)

This commit is contained in:
Luiza Pagliari 2017-09-21 17:49:33 -03:00 committed by GitHub
parent 67439545a6
commit 0e1414dcca

View file

@ -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()