--- /dev/null
+/*
+ * 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);
/* global window, document.getElementById, Util, WebUtil, RFB, Display */
import * as Log from '../core/util/logging.js';
-import _, { l10n } from '../core/util/localization.js';
+import _, { l10n } from './localization.js';
import { isTouchDevice } from '../core/util/browsers.js';
import { setCapture, getPointerEvent } from '../core/util/events.js';
import KeyTable from "../core/input/keysym.js";
+++ /dev/null
-/*
- * 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);
files: [
{ pattern: 'vendor/sinon.js', included: false },
{ pattern: 'node_modules/sinon-chai/lib/sinon-chai.js', included: false },
+ { pattern: 'app/localization.js', included: false },
{ pattern: 'core/**/*.js', included: false },
{ pattern: 'vendor/pako/**/*.js', included: false },
{ pattern: 'tests/test.*.js', included: false },
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
+ 'app/localization.js': ['babel'],
'core/**/*.js': ['babel'],
'tests/test.*.js': ['babel'],
'tests/fake.*.js': ['babel'],
--- /dev/null
+/* jshint expr: true */
+
+var assert = chai.assert;
+var expect = chai.expect;
+
+import l10nGet, { l10n } from '../app/localization.js';
+
+describe('Localization', function() {
+ "use strict";
+
+ describe('language selection', function () {
+ var origNavigator;
+ beforeEach(function () {
+ // window.navigator is a protected read-only property in many
+ // environments, so we need to redefine it whilst running these
+ // tests.
+ origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
+ if (origNavigator === undefined) {
+ // Object.getOwnPropertyDescriptor() doesn't work
+ // properly in any version of IE
+ this.skip();
+ }
+
+ Object.defineProperty(window, "navigator", {value: {}});
+ if (window.navigator.languages !== undefined) {
+ // Object.defineProperty() doesn't work properly in old
+ // versions of Chrome
+ this.skip();
+ }
+
+ window.navigator.languages = [];
+ });
+ afterEach(function () {
+ Object.defineProperty(window, "navigator", origNavigator);
+ });
+
+ it('should use English by default', function() {
+ expect(l10n.language).to.equal('en');
+ });
+ it('should use English if no user language matches', function() {
+ window.navigator.languages = ["nl", "de"];
+ l10n.setup(["es", "fr"]);
+ expect(l10n.language).to.equal('en');
+ });
+ it('should use the most preferred user language', function() {
+ window.navigator.languages = ["nl", "de", "fr"];
+ l10n.setup(["es", "fr", "de"]);
+ expect(l10n.language).to.equal('de');
+ });
+ it('should prefer sub-languages languages', function() {
+ window.navigator.languages = ["pt-BR"];
+ l10n.setup(["pt", "pt-BR"]);
+ expect(l10n.language).to.equal('pt-BR');
+ });
+ it('should fall back to language "parents"', function() {
+ window.navigator.languages = ["pt-BR"];
+ l10n.setup(["fr", "pt", "de"]);
+ expect(l10n.language).to.equal('pt');
+ });
+ it('should not use specific language when user asks for a generic language', function() {
+ window.navigator.languages = ["pt", "de"];
+ l10n.setup(["fr", "pt-BR", "de"]);
+ expect(l10n.language).to.equal('de');
+ });
+ it('should handle underscore as a separator', function() {
+ window.navigator.languages = ["pt-BR"];
+ l10n.setup(["pt_BR"]);
+ expect(l10n.language).to.equal('pt_BR');
+ });
+ it('should handle difference in case', function() {
+ window.navigator.languages = ["pt-br"];
+ l10n.setup(["pt-BR"]);
+ expect(l10n.language).to.equal('pt-BR');
+ });
+ });
+});
var expect = chai.expect;
import * as Log from '../core/util/logging.js';
-import l10nGet, { l10n } from '../core/util/localization.js';
import sinon from '../vendor/sinon.js';
});
});
- describe('language selection', function () {
- var origNavigator;
- beforeEach(function () {
- // window.navigator is a protected read-only property in many
- // environments, so we need to redefine it whilst running these
- // tests.
- origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
- if (origNavigator === undefined) {
- // Object.getOwnPropertyDescriptor() doesn't work
- // properly in any version of IE
- this.skip();
- }
-
- Object.defineProperty(window, "navigator", {value: {}});
- if (window.navigator.languages !== undefined) {
- // Object.defineProperty() doesn't work properly in old
- // versions of Chrome
- this.skip();
- }
-
- window.navigator.languages = [];
- });
- afterEach(function () {
- Object.defineProperty(window, "navigator", origNavigator);
- });
-
- it('should use English by default', function() {
- expect(l10n.language).to.equal('en');
- });
- it('should use English if no user language matches', function() {
- window.navigator.languages = ["nl", "de"];
- l10n.setup(["es", "fr"]);
- expect(l10n.language).to.equal('en');
- });
- it('should use the most preferred user language', function() {
- window.navigator.languages = ["nl", "de", "fr"];
- l10n.setup(["es", "fr", "de"]);
- expect(l10n.language).to.equal('de');
- });
- it('should prefer sub-languages languages', function() {
- window.navigator.languages = ["pt-BR"];
- l10n.setup(["pt", "pt-BR"]);
- expect(l10n.language).to.equal('pt-BR');
- });
- it('should fall back to language "parents"', function() {
- window.navigator.languages = ["pt-BR"];
- l10n.setup(["fr", "pt", "de"]);
- expect(l10n.language).to.equal('pt');
- });
- it('should not use specific language when user asks for a generic language', function() {
- window.navigator.languages = ["pt", "de"];
- l10n.setup(["fr", "pt-BR", "de"]);
- expect(l10n.language).to.equal('de');
- });
- it('should handle underscore as a separator', function() {
- window.navigator.languages = ["pt-BR"];
- l10n.setup(["pt_BR"]);
- expect(l10n.language).to.equal('pt_BR');
- });
- it('should handle difference in case', function() {
- window.navigator.languages = ["pt-br"];
- l10n.setup(["pt-BR"]);
- expect(l10n.language).to.equal('pt-BR');
- });
- });
-
// TODO(directxman12): test the conf_default and conf_defaults methods
// TODO(directxman12): test decodeUTF8
// TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent)