/* * noVNC: HTML5 VNC client * Copyright (C) 2012 Joel Martin * Licensed under MPL 2.0 (see LICENSE.txt) * * See README.md for usage and integration instructions. */ /* * Localization Utilities */ export function Localizer() { // Currently configured language this.language = 'en'; // Current dictionary of translations this.dictionary = undefined; } Localizer.prototype = { // Configure suitable language based on user preferences setup: function (supportedLanguages) { var userLanguages; this.language = 'en'; // Default: US English /* * Navigator.languages only available in Chrome (32+) and FireFox (32+) * Fall back to navigator.language for other browsers */ if (typeof window.navigator.languages == 'object') { userLanguages = window.navigator.languages; } else { userLanguages = [navigator.language || navigator.userLanguage]; } for (var i = 0;i < userLanguages.length;i++) { var userLang = userLanguages[i]; userLang = userLang.toLowerCase(); userLang = userLang.replace("_", "-"); userLang = userLang.split("-"); // Built-in default? if ((userLang[0] === 'en') && ((userLang[1] === undefined) || (userLang[1] === 'us'))) { return; } // First pass: perfect match for (var j = 0;j < supportedLanguages.length;j++) { var supLang = supportedLanguages[j]; supLang = supLang.toLowerCase(); supLang = supLang.replace("_", "-"); supLang = supLang.split("-"); if (userLang[0] !== supLang[0]) continue; if (userLang[1] !== supLang[1]) continue; this.language = supportedLanguages[j]; return; } // Second pass: fallback for (var j = 0;j < supportedLanguages.length;j++) { supLang = supportedLanguages[j]; supLang = supLang.toLowerCase(); supLang = supLang.replace("_", "-"); supLang = supLang.split("-"); if (userLang[0] !== supLang[0]) continue; if (supLang[1] !== undefined) continue; this.language = supportedLanguages[j]; return; } } }, // Retrieve localised text get: function (id) { if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) { return this.dictionary[id]; } else { return id; } }, // Traverses the DOM and translates relevant fields // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate translateDOM: function () { var self = this; function process(elem, enabled) { function isAnyOf(searchElement, items) { return items.indexOf(searchElement) !== -1; } function translateAttribute(elem, attr) { var str = elem.getAttribute(attr); str = self.get(str); elem.setAttribute(attr, str); } function translateTextNode(node) { var str = node.data.trim(); str = self.get(str); node.data = str; } if (elem.hasAttribute("translate")) { if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) { enabled = true; } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) { enabled = false; } } if (enabled) { if (elem.hasAttribute("abbr") && elem.tagName === "TH") { translateAttribute(elem, "abbr"); } if (elem.hasAttribute("alt") && isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) { translateAttribute(elem, "alt"); } if (elem.hasAttribute("download") && isAnyOf(elem.tagName, ["A", "AREA"])) { translateAttribute(elem, "download"); } if (elem.hasAttribute("label") && isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP", "OPTION", "TRACK"])) { translateAttribute(elem, "label"); } // FIXME: Should update "lang" if (elem.hasAttribute("placeholder") && isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) { translateAttribute(elem, "placeholder"); } if (elem.hasAttribute("title")) { translateAttribute(elem, "title"); } if (elem.hasAttribute("value") && elem.tagName === "INPUT" && isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) { translateAttribute(elem, "value"); } } for (var i = 0;i < elem.childNodes.length;i++) { var node = elem.childNodes[i]; if (node.nodeType === node.ELEMENT_NODE) { process(node, enabled); } else if (node.nodeType === node.TEXT_NODE && enabled) { translateTextNode(node); } } } process(document.body, true); }, }; export var l10n = new Localizer(); export default l10n.get.bind(l10n);