diff --git a/app/locale/locale-de-DE.js b/app/locale/de.js similarity index 86% rename from app/locale/locale-de-DE.js rename to app/locale/de.js index c9d75aa6..6819c486 100644 --- a/app/locale/locale-de-DE.js +++ b/app/locale/de.js @@ -1,11 +1,18 @@ +/* + * Translations for de + * + * This file was autotomatically generated from de.po + * DO NOT EDIT! + */ + Language = { + "Connecting...": "Verbunden...", "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ", "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ", - "Must set host and port": "Richten Sie Host und Port ein", - "Disconnect timeout": "Timeout beim trennen", - "Password is required": "Passwort ist erforderlich", - "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht unterstützt", - "Connecting...": "Verbunden...", "Disconnecting...": "Verbindung trennen...", "Disconnected": "Verbindung zum Server getrennt", + "Must set host and port": "Richten Sie Host und Port ein", + "Password is required": "Passwort ist erforderlich", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht unterstützt", + "Disconnect timeout": "Timeout beim trennen", }; diff --git a/app/locale/el.js b/app/locale/el.js new file mode 100644 index 00000000..1af2ee62 --- /dev/null +++ b/app/locale/el.js @@ -0,0 +1,18 @@ +/* + * Translations for el + * + * This file was autotomatically generated from el.po + * DO NOT EDIT! + */ + +Language = { + "Connecting...": "Συνδέεται...", + "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ", + "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ", + "Disconnecting...": "Aποσυνδέεται...", + "Disconnected": "Αποσυνδέθηκε", + "Must set host and port": "Πρέπει να οριστεί το όνομα και η πόρτα του διακομιστή", + "Password is required": "Απαιτείται ο κωδικός", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Εφαρμογή λειτουργίας αποκοπής αφού δεν υποστηρίζονται οι λωρίδες κύλισης σε πλήρη οθόνη στον IE", + "Disconnect timeout": "Παρέλευση χρονικού ορίου αποσύνδεσης", +}; diff --git a/app/locale/locale-el-GR.js b/app/locale/locale-el-GR.js deleted file mode 100644 index a27fe5a1..00000000 --- a/app/locale/locale-el-GR.js +++ /dev/null @@ -1,11 +0,0 @@ -Language = { - "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ", - "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ", - "Must set host and port": "Πρέπει να οριστεί το όνομα και η πόρτα του διακομιστή", - "Disconnect timeout": "Παρέλευση χρονικού ορίου αποσύνδεσης", - "Password is required": "Απαιτείται ο κωδικός", - "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Εφαρμογή λειτουργίας αποκοπής αφού δεν υποστηρίζονται οι λωρίδες κύλισης σε πλήρη οθόνη στον IE", - "Connecting...": "Συνδέεται...", - "Disconnecting...": "Aποσυνδέεται...", - "Disconnected": "Αποσυνδέθηκε", -}; diff --git a/app/locale/locale-en-GB.js b/app/locale/locale-en-GB.js deleted file mode 100644 index 57ce6978..00000000 --- a/app/locale/locale-en-GB.js +++ /dev/null @@ -1,11 +0,0 @@ -Language = { - "Connected (encrypted) to ": "Connected (encrypted) to ", - "Connected (unencrypted) to ": "Connected (unencrypted) to ", - "Must set host and port": "Must set host and port", - "Disconnect timeout": "Disconnect timeout", - "Password is required": "Password is required", - "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen", - "Connecting...": "Connecting...", - "Disconnecting...": "Disconnecting...", - "Disconnected": "Disconnected", -}; diff --git a/app/locale/locale-sv-SE.js b/app/locale/locale-sv-SE.js deleted file mode 100644 index eee7f15e..00000000 --- a/app/locale/locale-sv-SE.js +++ /dev/null @@ -1,11 +0,0 @@ -Language = { - "Connected (encrypted) to ": "Ansluten (krypterat) till ", - "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", - "Must set host and port": "Du måste specifiera en host och port", - "Disconnect timeout": "Det tog för lång tid att koppla ner", - "Password is required": "Lösenord krävs", - "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Tvingar 'Clipping mode' eftersom skrollning inte stödjs av IE i fullskärm", - "Connecting...": "Ansluter...", - "Disconnecting...": "Kopplar ner...", - "Disconnected": "Frånkopplad", -}; diff --git a/app/locale/locale-nl-NL.js b/app/locale/nl.js similarity index 86% rename from app/locale/locale-nl-NL.js rename to app/locale/nl.js index 24ad903e..cacab302 100644 --- a/app/locale/locale-nl-NL.js +++ b/app/locale/nl.js @@ -1,11 +1,18 @@ +/* + * Translations for nl + * + * This file was autotomatically generated from nl.po + * DO NOT EDIT! + */ + Language = { + "Connecting...": "Verbinden...", "Connected (encrypted) to ": "Verbonden (versleuteld) met ", "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", - "Must set host and port": "Host en poort moeten worden ingesteld", - "Disconnect timeout": "Timeout tijdens verbreken van verbinding", - "Password is required": "Wachtwoord is vereist", - "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus in IE niet worden ondersteund", - "Connecting...": "Verbinden...", "Disconnecting...": "Verbinding verbreken...", "Disconnected": "Verbinding verbroken", + "Must set host and port": "Host en poort moeten worden ingesteld", + "Password is required": "Wachtwoord is vereist", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus in IE niet worden ondersteund", + "Disconnect timeout": "Timeout tijdens verbreken van verbinding", }; diff --git a/app/locale/sv.js b/app/locale/sv.js new file mode 100644 index 00000000..b7f4c1fb --- /dev/null +++ b/app/locale/sv.js @@ -0,0 +1,77 @@ +/* + * Translations for sv + * + * This file was autotomatically generated from sv.po + * DO NOT EDIT! + */ + +Language = { + "Connecting...": "Ansluter...", + "Connected (encrypted) to ": "Ansluten (krypterat) till ", + "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", + "Disconnecting...": "Kopplar ner...", + "Disconnected": "Frånkopplad", + "Must set host and port": "Du måste specifiera en host och port", + "Password is required": "Lösenord krävs", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Tvingar 'Clipping mode' eftersom skrollning inte stödjs av IE i fullskärm", + "Disconnect timeout": "Det tog för lång tid att koppla ner", + "noVNC encountered an error:": "noVNC stötte på ett problem:", + "Hide/Show the control bar": "Göm/Visa kontrollbaren", + "Move/Drag Viewport": "Flytta/Dra Vyn", + "viewport drag": "dra vy", + "Active Mouse Button": "Aktiv musknapp", + "No mousebutton": "Ingen musknapp", + "Left mousebutton": "Vänster musknapp", + "Middle mousebutton": "Mitten-musknapp", + "Right mousebutton": "Höger musknapp", + "Keyboard": "Tangentbord", + "Show Keyboard": "Visa Tangentbord", + "Extra keys": "Extraknappar", + "Show Extra Keys": "Visa Extraknappar", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Växla Ctrl", + "Alt": "Alt", + "Toggle Alt": "Växla Alt", + "Send Tab": "Skicka Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Skicka Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del", + "Shutdown/Reboot": "Stäng av/Boota om", + "Shutdown/Reboot...": "Stäng av/Boota om...", + "Power": "Ström", + "Shutdown": "Stäng av", + "Reboot": "Boota om", + "Reset": "Återställ", + "Clipboard": "Urklipp", + "Clear": "Rensa", + "Fullscreen": "Fullskärm", + "Settings": "Inställningar", + "Encrypt": "Kryptera", + "True Color": "Fullfärg", + "Local Cursor": "Lokal Muspekare", + "Clip to Window": "Begränsa till Fönster", + "Shared Mode": "Delat Läge", + "View Only": "Endast Visning", + "Path:": "Sökväg:", + "Scaling Mode:": "Skalningsläge:", + "None": "Ingen", + "Local Scaling": "Lokal Skalning", + "Local Downscaling": "Lokal Nedskalning", + "Remote Resizing": "Ändra Storlek", + "Repeater ID:": "Repeater-ID:", + "Style:": "Stil:", + "default": "standard", + "Logging:": "Loggning:", + "Apply": "Verkställ", + "Connect": "Anslut", + "Disconnect": "Koppla från", + "Connection": "Uppkoppling", + "Host:": "Värd:", + "Port:": "Port:", + "Password:": "Lösenord:", + "Token:": "Token:", + "Send Password": "Skicka Lösenord", + "Canvas not supported.": "Canvas stöds ej", +}; diff --git a/app/ui.js b/app/ui.js index 5a8c1ea8..4bd5f0fb 100644 --- a/app/ui.js +++ b/app/ui.js @@ -40,17 +40,26 @@ var UI; return false; }); + // Set up translations + var LINGUAS = ["de", "el", "nl", "sv"]; + Util.Localisation.setup(LINGUAS); + if (Util.Localisation.language !== "en") { + WebUtil.load_scripts( + {'app': ["locale/" + Util.Localisation.language + ".js"]}); + } + /* [begin skip-as-module] */ // Load supporting scripts WebUtil.load_scripts( - {'core': [WebUtil.getLanguageFileLocation(), "base64.js", "websock.js", - "des.js", "input/keysymdef.js", "input/xtscancodes.js", - "input/util.js", "input/devices.js", "display.js", - "inflator.js", "rfb.js", "input/keysym.js"]}); + {'core': ["base64.js", "websock.js", "des.js", "input/keysymdef.js", + "input/xtscancodes.js", "input/util.js", "input/devices.js", + "display.js", "inflator.js", "rfb.js", "input/keysym.js"]}); window.onscriptsload = function () { UI.load(); }; /* [end skip-as-module] */ + var _ = Util.Localisation.get; + UI = { connected: false, @@ -87,6 +96,9 @@ var UI; UI.initSettings(); + // Translate the DOM + Util.Localisation.translateDOM(); + // Adapt the interface for touch screen devices if (Util.isTouchDevice) { document.documentElement.classList.add("noVNC_touch"); @@ -390,26 +402,26 @@ var UI; switch (state) { case 'connecting': - document.getElementById("noVNC_transition_text").innerHTML = Util.Localisation.get("Connecting..."); + document.getElementById("noVNC_transition_text").innerHTML = _("Connecting..."); document.documentElement.classList.add("noVNC_connecting"); break; case 'connected': UI.connected = true; document.documentElement.classList.add("noVNC_connected"); if (rfb && rfb.get_encrypt()) { - msg = Util.Localisation.get("Connected (encrypted) to ") + UI.desktopName; + msg = _("Connected (encrypted) to ") + UI.desktopName; } else { - msg = Util.Localisation.get("Connected (unencrypted) to ") + UI.desktopName; + msg = _("Connected (unencrypted) to ") + UI.desktopName; } UI.showStatus(msg); break; case 'disconnecting': - document.getElementById("noVNC_transition_text").innerHTML = Util.Localisation.get("Disconnecting..."); + document.getElementById("noVNC_transition_text").innerHTML = _("Disconnecting..."); document.documentElement.classList.add("noVNC_disconnecting"); break; case 'disconnected': UI.connected = false; - UI.showStatus(Util.Localisation.get("Disconnected")); + UI.showStatus(_("Disconnected")); break; default: msg = "Invalid UI state"; @@ -994,7 +1006,7 @@ var UI; } if ((!host) || (!port)) { - var msg = Util.Localisation.get("Must set host and port"); + var msg = _("Must set host and port"); Util.Error(msg); UI.showStatus(msg, 'error'); return; @@ -1047,7 +1059,7 @@ var UI; }, 100); if (typeof msg === 'undefined') { - msg = "Password is required"; + msg = _("Password is required"); } Util.Warn(msg); UI.showStatus(msg, "warning"); @@ -1260,9 +1272,9 @@ var UI; // The browser is IE and we are in fullscreen mode. // - We need to force clipping while in fullscreen since // scrollbars doesn't work. - var msg = Util.Localisation.get("Forcing clipping mode since " + - "scrollbars aren't supported " + - "by IE in fullscreen"); + var msg = _("Forcing clipping mode since " + + "scrollbars aren't supported " + + "by IE in fullscreen"); Util.Debug(msg); UI.showStatus(msg); UI.rememberedClipSetting = UI.getSetting('clip'); diff --git a/app/webutil.js b/app/webutil.js index ceacd953..90a0a530 100644 --- a/app/webutil.js +++ b/app/webutil.js @@ -372,11 +372,6 @@ WebUtil.releaseCapture = function () { }; -// Get language file location -WebUtil.getLanguageFileLocation = function () { - return '../app/locale/locale-'+Util.Localisation.getLanguageCode()+'.js'; -}; - // Dynamically load scripts without using document.write() // Reference: http://unixpapa.com/js/dyna.html // diff --git a/core/rfb.js b/core/rfb.js index b7eed17b..bc1fc613 100644 --- a/core/rfb.js +++ b/core/rfb.js @@ -263,6 +263,8 @@ }; (function() { + var _ = Util.Localisation.get; + RFB.prototype = { // Public methods connect: function (host, port, password, path) { @@ -273,7 +275,7 @@ if (!this._rfb_host || !this._rfb_port) { return this._fail( - Util.Localisation.get("Must set host and port")); + _("Must set host and port")); } this._rfb_init_state = ''; @@ -551,7 +553,7 @@ this._disconnect(); this._disconnTimer = setTimeout(function () { - this._rfb_disconnect_reason = "Disconnect timeout"; + this._rfb_disconnect_reason = _("Disconnect timeout"); this._updateConnectionState('disconnected'); }.bind(this), this._disconnectTimeout * 1000); break; diff --git a/core/util.js b/core/util.js index 1ec8a3c9..5054ee9e 100644 --- a/core/util.js +++ b/core/util.js @@ -368,72 +368,69 @@ Util.Flash = (function () { Util.Localisation = { - defaultLanguage: 'en-GB', + // Currently configured language + language: 'en', - /* - * Not all languages have been translated - * Some countries prefer a certain language - */ - supportedLanguages: { - 'en': 'en-GB', - 'en-GB': 'en-GB', - 'en-US': 'en-GB', - 'nl': 'nl-NL', - 'nl-NL': 'nl-NL', - 'nl-BE': 'nl-NL', - 'de': 'de-DE', - 'de-DE': 'de-DE', - 'sv-SE': 'sv-SE', - 'sv': 'sv-SE', - 'el': 'el-GR', - 'el-GR': 'el-GR' - }, + // Configure suitable language based on user preferences + setup: function (supportedLanguages) { + var userLanguages; - // Get language code from browser and verify it - getLanguageCode: function () { - var languageCode = Util.Localisation.getUserPreferredLanguage(); - for (var index = 0; index < languageCode.length; index++) { - var supportedLanguageCode = Util.Localisation.getSupportedLanguageCode(languageCode[index]); - if (supportedLanguageCode) { - return supportedLanguageCode; - } - } + Util.Localisation.language = 'en'; // Default: US English - return Util.Localisation.defaultLanguage; - }, - - /* - * Retrieve user preferred languages - * Navigator.languages only available in Chrome (32+) and FireFox (32+) - * Fall back to navigator.language for other browsers - */ - getUserPreferredLanguage: function () { + /* + * Navigator.languages only available in Chrome (32+) and FireFox (32+) + * Fall back to navigator.language for other browsers + */ if (typeof window.navigator.languages == 'object') { - return window.navigator.languages; + userLanguages = window.navigator.languages; } else { - var userLang = navigator.language || navigator.userLanguage; - return [userLang]; + userLanguages = [navigator.language || navigator.userLanguage]; } - }, - /* - * Verify if languagecode is supported - * Return the languagecode of the language to use or null if not available - */ - getSupportedLanguageCode: function (languageCode) { - var supportedLanguages = Util.Localisation.supportedLanguages; + for (var i = 0;i < userLanguages.length;i++) { + var userLang = userLanguages[i]; + userLang = userLang.toLowerCase(); + userLang = userLang.replace("_", "-"); + userLang = userLang.split("-"); - for (var key in supportedLanguages) { - if (supportedLanguages.hasOwnProperty(key)) { - if (key === languageCode) { - // Return the supported language or good alternative - return supportedLanguages[key]; - } + // 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; + + Util.Localisation.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; + + Util.Localisation.language = supportedLanguages[j]; + return; } } - - // LanguageCode not supported - return null; }, // Retrieve localised text @@ -443,7 +440,81 @@ Util.Localisation = { } else { return id; } - } + }, + + // Traverses the DOM and translates relevant fields + // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate + translateDOM: function () { + function process(elem, enabled) { + function isAnyOf(searchElement, items) { + return items.indexOf(searchElement) !== -1; + } + + function translateAttribute(elem, attr) { + var str = elem.getAttribute(attr); + str = Util.Localisation.get(str); + elem.setAttribute(attr, str); + } + + function translateTextNode(node) { + var str = node.data.trim(); + str = Util.Localisation.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 in ["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++) { + 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); + }, }; /* [module] export default Util; */ diff --git a/package.json b/package.json index 6fd6a85d..52f76f6d 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "chai": "^3.5.0", "commander": "^2.9.0", "fs-extra": "^1.0.0", + "jsdom": "*", "karma": "^1.3.0", "karma-chai": "^0.1.0", "karma-mocha": "^1.3.0", @@ -46,8 +47,10 @@ "karma-sinon": "^1.0.5", "karma-sinon-chai-latest": "^0.1.0", "mocha": "^3.1.2", + "node-getopt": "*", "open": "^0.0.5", "phantomjs-prebuilt": "^2.1.13", + "po2json": "*", "sinon": "^1.17.6", "sinon-chai": "^2.8.0", "spooky": "^0.2.5", diff --git a/po/Makefile b/po/Makefile new file mode 100644 index 00000000..b64b7638 --- /dev/null +++ b/po/Makefile @@ -0,0 +1,34 @@ +all: +.PHONY: update-po update-js update-pot + +LINGUAS := de el nl sv + +VERSION := $(shell grep '"version"' ../package.json | cut -d '"' -f 4) + +POFILES := $(addsuffix .po,$(LINGUAS)) +JSFILES := $(addprefix ../app/locale/,$(addsuffix .js,$(LINGUAS))) + +update-po: $(POFILES) +update-js: $(JSFILES) + +%.po: noVNC.pot + msgmerge --update --lang=$* $@ $< +../app/locale/%.js: %.po + ./po2js $< $@ + +update-pot: + xgettext --output=noVNC.js.pot \ + --copyright-holder="Various Authors" \ + --package-name="noVNC" \ + --package-version="$(VERSION)" \ + --msgid-bugs-address="novnc@googlegroups.com" \ + --add-comments=TRANSLATORS: \ + --sort-by-file \ + ../app/*.js \ + ../core/*.js \ + ../core/input/*.js + ./xgettext-html --output=noVNC.html.pot \ + ../vnc.html + msgcat --output-file=noVNC.pot \ + --sort-by-file noVNC.js.pot noVNC.html.pot + rm -f noVNC.js.pot noVNC.html.pot diff --git a/po/de.po b/po/de.po new file mode 100644 index 00000000..5f15d57d --- /dev/null +++ b/po/de.po @@ -0,0 +1,58 @@ +# German translations for noVNC package +# German translation for noVNC. +# Copyright (C) 2016 Various Authors +# This file is distributed under the same license as the noVNC package. +# Loek Janssen , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: noVNC 0.6.1\n" +"Report-Msgid-Bugs-To: novnc@googlegroups.com\n" +"POT-Creation-Date: 2016-11-15 08:11+0100\n" +"PO-Revision-Date: 2016-11-15 07:51+0100\n" +"Last-Translator: Loek Janssen \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../app/ui.js:402 +msgid "Connecting..." +msgstr "Verbunden..." + +#: ../app/ui.js:409 +msgid "Connected (encrypted) to " +msgstr "Verbunden mit (verschlüsselt) " + +#: ../app/ui.js:411 +msgid "Connected (unencrypted) to " +msgstr "Verbunden mit (unverschlüsselt) " + +#: ../app/ui.js:416 +msgid "Disconnecting..." +msgstr "Verbindung trennen..." + +#: ../app/ui.js:421 +msgid "Disconnected" +msgstr "Verbindung zum Server getrennt" + +#: ../app/ui.js:1006 ../core/rfb.js:278 +msgid "Must set host and port" +msgstr "Richten Sie Host und Port ein" + +#: ../app/ui.js:1059 +msgid "Password is required" +msgstr "Passwort ist erforderlich" + +#: ../app/ui.js:1272 +msgid "" +"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen" +msgstr "" +"'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht " +"unterstützt" + +#: ../core/rfb.js:556 +msgid "Disconnect timeout" +msgstr "Timeout beim trennen" diff --git a/po/el.po b/po/el.po new file mode 100644 index 00000000..5dfb36b6 --- /dev/null +++ b/po/el.po @@ -0,0 +1,57 @@ +# Greek translations for noVNC package. +# Copyright (C) 2016 Various Authors +# This file is distributed under the same license as the noVNC package. +# Giannis Kosmas , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: noVNC 0.6.1\n" +"Report-Msgid-Bugs-To: novnc@googlegroups.com\n" +"POT-Creation-Date: 2016-11-15 08:11+0100\n" +"PO-Revision-Date: 2016-11-15 07:51+0100\n" +"Last-Translator: Giannis Kosmas \n" +"Language-Team: none\n" +"Language: el\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../app/ui.js:402 +msgid "Connecting..." +msgstr "Συνδέεται..." + +#: ../app/ui.js:409 +msgid "Connected (encrypted) to " +msgstr "Συνδέθηκε (κρυπτογραφημένα) με το " + +#: ../app/ui.js:411 +msgid "Connected (unencrypted) to " +msgstr "Συνδέθηκε (μη κρυπτογραφημένα) με το " + +#: ../app/ui.js:416 +msgid "Disconnecting..." +msgstr "Aποσυνδέεται..." + +#: ../app/ui.js:421 +msgid "Disconnected" +msgstr "Αποσυνδέθηκε" + +#: ../app/ui.js:1006 ../core/rfb.js:278 +msgid "Must set host and port" +msgstr "Πρέπει να οριστεί το όνομα και η πόρτα του διακομιστή" + +#: ../app/ui.js:1059 +msgid "Password is required" +msgstr "Απαιτείται ο κωδικός" + +#: ../app/ui.js:1272 +msgid "" +"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen" +msgstr "" +"Εφαρμογή λειτουργίας αποκοπής αφού δεν υποστηρίζονται οι λωρίδες κύλισης σε " +"πλήρη οθόνη στον IE" + +#: ../core/rfb.js:556 +msgid "Disconnect timeout" +msgstr "Παρέλευση χρονικού ορίου αποσύνδεσης" diff --git a/po/nl.po b/po/nl.po new file mode 100644 index 00000000..8a0bf74c --- /dev/null +++ b/po/nl.po @@ -0,0 +1,58 @@ +# Dutch translations for noVNC package +# Nederlandse vertalingen voor het pakket noVNC. +# Copyright (C) 2016 Various Authors +# This file is distributed under the same license as the noVNC package. +# Loek Janssen , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: noVNC 0.6.1\n" +"Report-Msgid-Bugs-To: novnc@googlegroups.com\n" +"POT-Creation-Date: 2016-11-15 08:11+0100\n" +"PO-Revision-Date: 2016-11-15 07:51+0100\n" +"Last-Translator: Loek Janssen \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../app/ui.js:402 +msgid "Connecting..." +msgstr "Verbinden..." + +#: ../app/ui.js:409 +msgid "Connected (encrypted) to " +msgstr "Verbonden (versleuteld) met " + +#: ../app/ui.js:411 +msgid "Connected (unencrypted) to " +msgstr "Verbonden (onversleuteld) met " + +#: ../app/ui.js:416 +msgid "Disconnecting..." +msgstr "Verbinding verbreken..." + +#: ../app/ui.js:421 +msgid "Disconnected" +msgstr "Verbinding verbroken" + +#: ../app/ui.js:1006 ../core/rfb.js:278 +msgid "Must set host and port" +msgstr "Host en poort moeten worden ingesteld" + +#: ../app/ui.js:1059 +msgid "Password is required" +msgstr "Wachtwoord is vereist" + +#: ../app/ui.js:1272 +msgid "" +"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen" +msgstr "" +"''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus " +"in IE niet worden ondersteund" + +#: ../core/rfb.js:556 +msgid "Disconnect timeout" +msgstr "Timeout tijdens verbreken van verbinding" diff --git a/po/noVNC.pot b/po/noVNC.pot new file mode 100644 index 00000000..160a2d47 --- /dev/null +++ b/po/noVNC.pot @@ -0,0 +1,291 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR Various Authors +# This file is distributed under the same license as the noVNC package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: noVNC 0.6.1\n" +"Report-Msgid-Bugs-To: novnc@googlegroups.com\n" +"POT-Creation-Date: 2016-11-15 19:32+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../app/ui.js:405 +msgid "Connecting..." +msgstr "" + +#: ../app/ui.js:412 +msgid "Connected (encrypted) to " +msgstr "" + +#: ../app/ui.js:414 +msgid "Connected (unencrypted) to " +msgstr "" + +#: ../app/ui.js:419 +msgid "Disconnecting..." +msgstr "" + +#: ../app/ui.js:424 +msgid "Disconnected" +msgstr "" + +#: ../app/ui.js:1009 ../core/rfb.js:278 +msgid "Must set host and port" +msgstr "" + +#: ../app/ui.js:1062 +msgid "Password is required" +msgstr "" + +#: ../app/ui.js:1275 +msgid "" +"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen" +msgstr "" + +#: ../core/rfb.js:556 +msgid "Disconnect timeout" +msgstr "" + +#: ../vnc.html:70 +msgid "noVNC encountered an error:" +msgstr "" + +#: ../vnc.html:78 +msgid "Hide/Show the control bar" +msgstr "" + +#: ../vnc.html:85 +msgid "Move/Drag Viewport" +msgstr "" + +#: ../vnc.html:85 +msgid "viewport drag" +msgstr "" + +#: ../vnc.html:91 ../vnc.html:94 ../vnc.html:97 ../vnc.html:100 +msgid "Active Mouse Button" +msgstr "" + +#: ../vnc.html:91 +msgid "No mousebutton" +msgstr "" + +#: ../vnc.html:94 +msgid "Left mousebutton" +msgstr "" + +#: ../vnc.html:97 +msgid "Middle mousebutton" +msgstr "" + +#: ../vnc.html:100 +msgid "Right mousebutton" +msgstr "" + +#: ../vnc.html:103 +msgid "Keyboard" +msgstr "" + +#: ../vnc.html:103 +msgid "Show Keyboard" +msgstr "" + +#: ../vnc.html:110 +msgid "Extra keys" +msgstr "" + +#: ../vnc.html:110 +msgid "Show Extra Keys" +msgstr "" + +#: ../vnc.html:115 +msgid "Ctrl" +msgstr "" + +#: ../vnc.html:115 +msgid "Toggle Ctrl" +msgstr "" + +#: ../vnc.html:118 +msgid "Alt" +msgstr "" + +#: ../vnc.html:118 +msgid "Toggle Alt" +msgstr "" + +#: ../vnc.html:121 +msgid "Send Tab" +msgstr "" + +#: ../vnc.html:121 +msgid "Tab" +msgstr "" + +#: ../vnc.html:124 +msgid "Esc" +msgstr "" + +#: ../vnc.html:124 +msgid "Send Escape" +msgstr "" + +#: ../vnc.html:127 +msgid "Ctrl+Alt+Del" +msgstr "" + +#: ../vnc.html:127 +msgid "Send Ctrl-Alt-Del" +msgstr "" + +#: ../vnc.html:135 +msgid "Shutdown/Reboot" +msgstr "" + +#: ../vnc.html:135 +msgid "Shutdown/Reboot..." +msgstr "" + +#: ../vnc.html:141 +msgid "Power" +msgstr "" + +#: ../vnc.html:143 +msgid "Shutdown" +msgstr "" + +#: ../vnc.html:144 +msgid "Reboot" +msgstr "" + +#: ../vnc.html:145 +msgid "Reset" +msgstr "" + +#: ../vnc.html:150 ../vnc.html:156 +msgid "Clipboard" +msgstr "" + +#: ../vnc.html:160 +msgid "Clear" +msgstr "" + +#: ../vnc.html:166 +msgid "Fullscreen" +msgstr "" + +#: ../vnc.html:171 ../vnc.html:178 +msgid "Settings" +msgstr "" + +#: ../vnc.html:181 +msgid "Encrypt" +msgstr "" + +#: ../vnc.html:184 +msgid "True Color" +msgstr "" + +#: ../vnc.html:187 +msgid "Local Cursor" +msgstr "" + +#: ../vnc.html:190 +msgid "Clip to Window" +msgstr "" + +#: ../vnc.html:193 +msgid "Shared Mode" +msgstr "" + +#: ../vnc.html:196 +msgid "View Only" +msgstr "" + +#: ../vnc.html:200 +msgid "Path:" +msgstr "" + +#: ../vnc.html:204 +msgid "Scaling Mode:" +msgstr "" + +#: ../vnc.html:206 +msgid "None" +msgstr "" + +#: ../vnc.html:207 +msgid "Local Scaling" +msgstr "" + +#: ../vnc.html:208 +msgid "Local Downscaling" +msgstr "" + +#: ../vnc.html:209 +msgid "Remote Resizing" +msgstr "" + +#: ../vnc.html:213 +msgid "Repeater ID:" +msgstr "" + +#: ../vnc.html:219 +msgid "Style:" +msgstr "" + +#: ../vnc.html:221 +msgid "default" +msgstr "" + +#: ../vnc.html:227 +msgid "Logging:" +msgstr "" + +#: ../vnc.html:234 +msgid "Apply" +msgstr "" + +#: ../vnc.html:241 ../vnc.html:271 +msgid "Connect" +msgstr "" + +#: ../vnc.html:244 +msgid "Disconnect" +msgstr "" + +#: ../vnc.html:251 +msgid "Connection" +msgstr "" + +#: ../vnc.html:254 +msgid "Host:" +msgstr "" + +#: ../vnc.html:258 +msgid "Port:" +msgstr "" + +#: ../vnc.html:262 ../vnc.html:290 +msgid "Password:" +msgstr "" + +#: ../vnc.html:266 +msgid "Token:" +msgstr "" + +#: ../vnc.html:294 +msgid "Send Password" +msgstr "" + +#: ../vnc.html:319 +msgid "Canvas not supported." +msgstr "" diff --git a/po/po2js b/po/po2js new file mode 100755 index 00000000..972f0b2c --- /dev/null +++ b/po/po2js @@ -0,0 +1,56 @@ +#!/usr/bin/env node +/* + * ps2js: gettext .po to noVNC .js converter + * Copyright (C) 2016 Pierre Ossman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +var getopt = require('node-getopt'); +var fs = require('fs'); +var po2json = require("po2json"); + +opt = getopt.create([ + ['h' , 'help' , 'display this help'], +]).bindHelp().parseSystem(); + +if (opt.argv.length != 2) { + console.error("Incorrect number of arguments given"); + process.exit(1); +} + +var data = po2json.parseFileSync(opt.argv[0]); + +var output = +"/*\n" + +" * Translations for " + data[""]["language"] + "\n" + +" *\n" + +" * This file was autotomatically generated from " + opt.argv[0] + "\n" + +" * DO NOT EDIT!\n" + +" */\n" + +"\n" + +"Language = {\n"; + +for (msgid in data) { + if (msgid === "") + continue; + + msgstr = data[msgid][1]; + output += " " + JSON.stringify(msgid) + ": " + + JSON.stringify(msgstr) + ",\n"; +} + +output += "};\n"; + +fs.writeFileSync(opt.argv[1], output); diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 00000000..9df5ad5e --- /dev/null +++ b/po/sv.po @@ -0,0 +1,293 @@ +# Swedish translations for noVNC package +# Svenska översättningar för paket noVNC. +# Copyright (C) 2016 Various Authors +# This file is distributed under the same license as the noVNC package. +# Samuel Mannehed , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: noVNC 0.6.1\n" +"Report-Msgid-Bugs-To: novnc@googlegroups.com\n" +"POT-Creation-Date: 2016-11-15 19:32+0100\n" +"PO-Revision-Date: 2016-11-15 07:51+0100\n" +"Last-Translator: Pierre Ossman \n" +"Language-Team: none\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../app/ui.js:405 +msgid "Connecting..." +msgstr "Ansluter..." + +#: ../app/ui.js:412 +msgid "Connected (encrypted) to " +msgstr "Ansluten (krypterat) till " + +#: ../app/ui.js:414 +msgid "Connected (unencrypted) to " +msgstr "Ansluten (okrypterat) till " + +#: ../app/ui.js:419 +msgid "Disconnecting..." +msgstr "Kopplar ner..." + +#: ../app/ui.js:424 +msgid "Disconnected" +msgstr "Frånkopplad" + +#: ../app/ui.js:1009 ../core/rfb.js:278 +msgid "Must set host and port" +msgstr "Du måste specifiera en host och port" + +#: ../app/ui.js:1062 +msgid "Password is required" +msgstr "Lösenord krävs" + +#: ../app/ui.js:1275 +msgid "" +"Forcing clipping mode since scrollbars aren't supported by IE in fullscreen" +msgstr "" +"Tvingar 'Clipping mode' eftersom skrollning inte stödjs av IE i fullskärm" + +#: ../core/rfb.js:556 +msgid "Disconnect timeout" +msgstr "Det tog för lång tid att koppla ner" + +#: ../vnc.html:70 +msgid "noVNC encountered an error:" +msgstr "noVNC stötte på ett problem:" + +#: ../vnc.html:78 +msgid "Hide/Show the control bar" +msgstr "Göm/Visa kontrollbaren" + +#: ../vnc.html:85 +msgid "Move/Drag Viewport" +msgstr "Flytta/Dra Vyn" + +#: ../vnc.html:85 +msgid "viewport drag" +msgstr "dra vy" + +#: ../vnc.html:91 ../vnc.html:94 ../vnc.html:97 ../vnc.html:100 +msgid "Active Mouse Button" +msgstr "Aktiv musknapp" + +#: ../vnc.html:91 +msgid "No mousebutton" +msgstr "Ingen musknapp" + +#: ../vnc.html:94 +msgid "Left mousebutton" +msgstr "Vänster musknapp" + +#: ../vnc.html:97 +msgid "Middle mousebutton" +msgstr "Mitten-musknapp" + +#: ../vnc.html:100 +msgid "Right mousebutton" +msgstr "Höger musknapp" + +#: ../vnc.html:103 +msgid "Keyboard" +msgstr "Tangentbord" + +#: ../vnc.html:103 +msgid "Show Keyboard" +msgstr "Visa Tangentbord" + +#: ../vnc.html:110 +msgid "Extra keys" +msgstr "Extraknappar" + +#: ../vnc.html:110 +msgid "Show Extra Keys" +msgstr "Visa Extraknappar" + +#: ../vnc.html:115 +msgid "Ctrl" +msgstr "Ctrl" + +#: ../vnc.html:115 +msgid "Toggle Ctrl" +msgstr "Växla Ctrl" + +#: ../vnc.html:118 +msgid "Alt" +msgstr "Alt" + +#: ../vnc.html:118 +msgid "Toggle Alt" +msgstr "Växla Alt" + +#: ../vnc.html:121 +msgid "Send Tab" +msgstr "Skicka Tab" + +#: ../vnc.html:121 +msgid "Tab" +msgstr "Tab" + +#: ../vnc.html:124 +msgid "Esc" +msgstr "Esc" + +#: ../vnc.html:124 +msgid "Send Escape" +msgstr "Skicka Escape" + +#: ../vnc.html:127 +msgid "Ctrl+Alt+Del" +msgstr "Ctrl+Alt+Del" + +#: ../vnc.html:127 +msgid "Send Ctrl-Alt-Del" +msgstr "Skicka Ctrl-Alt-Del" + +#: ../vnc.html:135 +msgid "Shutdown/Reboot" +msgstr "Stäng av/Boota om" + +#: ../vnc.html:135 +msgid "Shutdown/Reboot..." +msgstr "Stäng av/Boota om..." + +#: ../vnc.html:141 +msgid "Power" +msgstr "Ström" + +#: ../vnc.html:143 +msgid "Shutdown" +msgstr "Stäng av" + +#: ../vnc.html:144 +msgid "Reboot" +msgstr "Boota om" + +#: ../vnc.html:145 +msgid "Reset" +msgstr "Återställ" + +#: ../vnc.html:150 ../vnc.html:156 +msgid "Clipboard" +msgstr "Urklipp" + +#: ../vnc.html:160 +msgid "Clear" +msgstr "Rensa" + +#: ../vnc.html:166 +msgid "Fullscreen" +msgstr "Fullskärm" + +#: ../vnc.html:171 ../vnc.html:178 +msgid "Settings" +msgstr "Inställningar" + +#: ../vnc.html:181 +msgid "Encrypt" +msgstr "Kryptera" + +#: ../vnc.html:184 +msgid "True Color" +msgstr "Fullfärg" + +#: ../vnc.html:187 +msgid "Local Cursor" +msgstr "Lokal Muspekare" + +#: ../vnc.html:190 +msgid "Clip to Window" +msgstr "Begränsa till Fönster" + +#: ../vnc.html:193 +msgid "Shared Mode" +msgstr "Delat Läge" + +#: ../vnc.html:196 +msgid "View Only" +msgstr "Endast Visning" + +#: ../vnc.html:200 +msgid "Path:" +msgstr "Sökväg:" + +#: ../vnc.html:204 +msgid "Scaling Mode:" +msgstr "Skalningsläge:" + +#: ../vnc.html:206 +msgid "None" +msgstr "Ingen" + +#: ../vnc.html:207 +msgid "Local Scaling" +msgstr "Lokal Skalning" + +#: ../vnc.html:208 +msgid "Local Downscaling" +msgstr "Lokal Nedskalning" + +#: ../vnc.html:209 +msgid "Remote Resizing" +msgstr "Ändra Storlek" + +#: ../vnc.html:213 +msgid "Repeater ID:" +msgstr "Repeater-ID:" + +#: ../vnc.html:219 +msgid "Style:" +msgstr "Stil:" + +#: ../vnc.html:221 +msgid "default" +msgstr "standard" + +#: ../vnc.html:227 +msgid "Logging:" +msgstr "Loggning:" + +#: ../vnc.html:234 +msgid "Apply" +msgstr "Verkställ" + +#: ../vnc.html:241 ../vnc.html:271 +msgid "Connect" +msgstr "Anslut" + +#: ../vnc.html:244 +msgid "Disconnect" +msgstr "Koppla från" + +#: ../vnc.html:251 +msgid "Connection" +msgstr "Uppkoppling" + +#: ../vnc.html:254 +msgid "Host:" +msgstr "Värd:" + +#: ../vnc.html:258 +msgid "Port:" +msgstr "Port:" + +#: ../vnc.html:262 ../vnc.html:290 +msgid "Password:" +msgstr "Lösenord:" + +#: ../vnc.html:266 +msgid "Token:" +msgstr "Token:" + +#: ../vnc.html:294 +msgid "Send Password" +msgstr "Skicka Lösenord" + +#: ../vnc.html:319 +msgid "Canvas not supported." +msgstr "Canvas stöds ej" diff --git a/po/xgettext-html b/po/xgettext-html new file mode 100755 index 00000000..d71822c4 --- /dev/null +++ b/po/xgettext-html @@ -0,0 +1,117 @@ +#!/usr/bin/env node +/* + * xgettext-html: HTML gettext parser + * Copyright (C) 2016 Pierre Ossman + * Licensed under MPL 2.0 (see LICENSE.txt) + */ + +var getopt = require('node-getopt'); + +var jsdom = require("jsdom"); +var fs = require("fs"); + +opt = getopt.create([ + ['o' , 'output=FILE' , 'write output to specified file'], + ['h' , 'help' , 'display this help'], +]).bindHelp().parseSystem(); + +var strings = {}; + +function addString(str, location) { + if (str.length == 0) { + return; + } + + if (strings[str] === undefined) { + strings[str] = {} + } + strings[str][location] = null; +} + +// See https://html.spec.whatwg.org/multipage/dom.html#attr-translate +function process(elem, locator, enabled) { + function isAnyOf(searchElement, items) { + return items.indexOf(searchElement) !== -1; + } + + 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") { + addString(elem.getAttribute("abbr"), locator(elem)); + } + if (elem.hasAttribute("alt") && + isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) { + addString(elem.getAttribute("alt"), locator(elem)); + } + if (elem.hasAttribute("download") && + isAnyOf(elem.tagName, ["A", "AREA"])) { + addString(elem.getAttribute("download"), locator(elem)); + } + if (elem.hasAttribute("label") && + isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP", + "OPTION", "TRACK"])) { + addString(elem.getAttribute("label"), locator(elem)); + } + if (elem.hasAttribute("placeholder") && + isAnyOf(elem.tagName in ["INPUT", "TEXTAREA"])) { + addString(elem.getAttribute("placeholder"), locator(elem)); + } + if (elem.hasAttribute("title")) { + addString(elem.getAttribute("title"), locator(elem)); + } + if (elem.hasAttribute("value") && + elem.tagName === "INPUT" && + isAnyOf(elem.getAttribute("type"), ["reset", "button"])) { + addString(elem.getAttribute("value"), locator(elem)); + } + } + + for (var i = 0;i < elem.childNodes.length;i++) { + node = elem.childNodes[i]; + if (node.nodeType === node.ELEMENT_NODE) { + process(node, locator, enabled); + } else if (node.nodeType === node.TEXT_NODE && enabled) { + addString(node.data.trim(), locator(node)); + } + } +} + +for (var i = 0;i < opt.argv.length;i++) { + var file; + + fn = opt.argv[i]; + file = fs.readFileSync(fn, "utf8"); + doc = jsdom.jsdom(file); + + locator = function (elem) { + offset = jsdom.nodeLocation(elem).start; + line = file.slice(0, offset).split("\n").length; + return fn + ":" + line; + }; + + process(doc.body, locator, true); +} + +var output = ""; + +for (str in strings) { + output += "#:"; + for (location in strings[str]) { + output += " " + location; + } + output += "\n"; + + output += "msgid " + JSON.stringify(str) + "\n"; + output += "msgstr \"\"\n"; + output += "\n"; +} + +fs.writeFileSync(opt.options.output, output); diff --git a/tests/test.util.js b/tests/test.util.js index c903c745..fbce2ef8 100644 --- a/tests/test.util.js +++ b/tests/test.util.js @@ -56,6 +56,47 @@ describe('Utils', function() { }); }); + describe('language selection', function () { + it('should use English by default', function() { + expect(Util.Localisation.language).to.equal('en'); + }); + it('should use English if no user language matches', function() { + window.navigator.languages = ["nl", "de"]; + Util.Localisation.setup(["es", "fr"]); + expect(Util.Localisation.language).to.equal('en'); + }); + it('should use the most preferred user language', function() { + window.navigator.languages = ["nl", "de", "fr"]; + Util.Localisation.setup(["es", "fr", "de"]); + expect(Util.Localisation.language).to.equal('de'); + }); + it('should prefer sub-languages languages', function() { + window.navigator.languages = ["pt-BR"]; + Util.Localisation.setup(["pt", "pt-BR"]); + expect(Util.Localisation.language).to.equal('pt-BR'); + }); + it('should fall back to language "parents"', function() { + window.navigator.languages = ["pt-BR"]; + Util.Localisation.setup(["fr", "pt", "de"]); + expect(Util.Localisation.language).to.equal('pt'); + }); + it('should not use specific language when user asks for a generic language', function() { + window.navigator.languages = ["pt", "de"]; + Util.Localisation.setup(["fr", "pt-BR", "de"]); + expect(Util.Localisation.language).to.equal('de'); + }); + it('should handle underscore as a separator', function() { + window.navigator.languages = ["pt-BR"]; + Util.Localisation.setup(["pt_BR"]); + expect(Util.Localisation.language).to.equal('pt_BR'); + }); + it('should handle difference in case', function() { + window.navigator.languages = ["pt-br"]; + Util.Localisation.setup(["pt-BR"]); + expect(Util.Localisation.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) diff --git a/vnc.html b/vnc.html index ef880d20..85e4ab13 100644 --- a/vnc.html +++ b/vnc.html @@ -79,7 +79,7 @@
-

no
VNC

+

no
VNC

-

no
VNC

+

no
VNC

diff --git a/vnc_auto.html b/vnc_auto.html index ea1ca7b1..e86ae5d2 100644 --- a/vnc_auto.html +++ b/vnc_auto.html @@ -81,8 +81,7 @@ WebUtil.load_scripts({ 'core': ["base64.js", "websock.js", "des.js", "input/keysymdef.js", "input/xtscancodes.js", "input/util.js", "input/devices.js", - "display.js", "inflator.js", "rfb.js", "input/keysym.js"], - 'app': [WebUtil.getLanguageFileLocation(), "webutil.js"]}); + "display.js", "inflator.js", "rfb.js", "input/keysym.js"]}); var rfb; var resizeTimeout; @@ -153,24 +152,22 @@ var cad = document.getElementById('sendCtrlAltDelButton'); switch (state) { case 'connecting': - status(Util.Localisation.get("Connecting"), "normal"); + status("Connecting", "normal"); break; case 'connected': if (rfb && rfb.get_encrypt()) { - status(Util.Localisation. - get("Connected (encrypted) to ") + + status("Connected (encrypted) to " + desktopName, "normal"); } else { - status(Util.Localisation. - get("Connected (unencrypted) to ") + + status("Connected (unencrypted) to " + desktopName, "normal"); } break; case 'disconnecting': - status(Util.Localisation.get("Disconnecting"), "normal"); + status("Disconnecting", "normal"); break; case 'disconnected': - status(Util.Localisation.get("Disconnected"), "normal"); + status("Disconnected", "normal"); break; default: status(state, "warn");