]> git.proxmox.com Git - mirror_novnc.git/blobdiff - app/localization.js
Move localization.js to app
[mirror_novnc.git] / app / localization.js
diff --git a/app/localization.js b/app/localization.js
new file mode 100644 (file)
index 0000000..39c91f6
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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"])) {
+                    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);