diff --git a/include/locale/locale-de-DE.js b/include/locale/locale-de-DE.js new file mode 100644 index 00000000..65bdf14f --- /dev/null +++ b/include/locale/locale-de-DE.js @@ -0,0 +1,20 @@ +Language = { + connectedUnencrypted: 'Verbunden mit (unverschlüsselt)', + connectedEncrypted: 'Verbunden mit (verschlüsselt)', + errorHostPort: 'Richten Sie Host und Port ein', + ready: 'NoVNC bereit: Native WebSockets', + readyEmulation: 'NoVNC bereit: Emulierte WebSockets', + authentication: 'Authentifizierung', + errorFatal: 'Schwerwiegender Fehler. Die Verbindung kann nicht hergestellt werden.', + errorTimeout: 'Timeout. Verbindung unterbrochen', + errorConnected: 'Fehler beim Verbinden', + errorInitializing: 'Fehler beim Initialisieren', + startingVNC: 'Starte VNC Authentifizierung', + errorDisconnected: 'Verbindung zum Server getrennt', + errorConnection: 'Verbindung zum Server konnte nicht hergestellt werden', + errorProtocolVerion: 'Unvollständige Protokollversion', + errorServerVersion: 'Ungültige Serverversion', + errorSecurity: 'Sicherheitsfehler', + errorAuthFailure: 'Authentifizierungsfehler', + errorAuthAttempts: 'Zu viele Authentifizierungsversuche' +}; \ No newline at end of file diff --git a/include/locale/locale-en-GB.js b/include/locale/locale-en-GB.js new file mode 100644 index 00000000..009c3903 --- /dev/null +++ b/include/locale/locale-en-GB.js @@ -0,0 +1,20 @@ +Language = { + connectedUnencrypted: 'Connected to (unencrypted)', + connectedEncrypted: 'Connected to (encrypted)', + errorHostPort: 'Must set host and port', + ready: 'noVNC ready: native WebSockets', + readyEmulation: 'noVNC ready: WebSockets emulation', + authentication: 'Authentication', + errorFatal: 'Fatal error, cannot continue', + errorTimeout: 'Disconnect timeout', + errorConnected: 'Error while connected', + errorInitializing: 'Error while initializing', + startingVNC: 'Starting VNC handshake', + errorDisconnected: 'Server disconnected', + errorConnection: 'Failed to connect to server', + errorProtocolVerion: 'Incomplete protocol version', + errorServerVersion: 'Invalid server version', + errorSecurity: 'Security failure', + errorAuthFailure: 'Authentication failure', + errorAuthAttempts: 'Too many authentication attempts' +}; \ No newline at end of file diff --git a/include/locale/locale-nl-NL.js b/include/locale/locale-nl-NL.js new file mode 100644 index 00000000..2d1df251 --- /dev/null +++ b/include/locale/locale-nl-NL.js @@ -0,0 +1,20 @@ +Language = { + connectedUnencrypted: 'Verbonden met (onversleuteld)', + connectedEncrypted: 'Verbonden met (versleuteld)', + errorHostPort: 'Stel host en poort in', + ready: 'NoVNC gereed: geïntegreerde WebSockets', + readyEmulation: 'NoVNC gereed: geëmuleerde WebSocktets', + authentication: 'Authenticatie', + errorFatal: 'Onherstelbare fout', + errorTimeout: 'Timeout tijdens verbreken van verbinding', + errorConnected: 'Fout tijdens verbinding', + errorInitializing: 'Fout tijdens initializatie', + startingVNC: 'Starten van VNC handshake', + errorDisconnected: 'Verbindng met server verbroken', + errorConnection: 'Kon geen verbinding met de server maken', + errorProtocolVerion: 'Protocol versie is incompleet', + errorServerVersion: 'Ongeldige server versie', + errorSecurity: 'Beveiligingsfout', + errorAuthFailure: 'Authenticatie fout', + errorAuthAttempts: 'Te veel Authenticatie pogingen' +}; \ No newline at end of file diff --git a/include/rfb.js b/include/rfb.js index dfd9269c..998b00e3 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -183,7 +183,7 @@ var RFB; this._sock.on('message', this._handle_message.bind(this)); this._sock.on('open', function () { if (this._rfb_state === 'connect') { - this._updateState('ProtocolVersion', "Starting VNC handshake"); + this._updateState('ProtocolVersion', Util.Localisation.get('startingVNC')); } else { this._fail("Got unexpected WebSocket connection"); } @@ -201,11 +201,11 @@ var RFB; if (this._rfb_state === 'disconnect') { this._updateState('disconnected', 'VNC disconnected' + msg); } else if (this._rfb_state === 'ProtocolVersion') { - this._fail('Failed to connect to server' + msg); + this._fail(Util.Localisation.get('errorConnection') + msg); } else if (this._rfb_state in {'failed': 1, 'disconnected': 1}) { Util.Error("Received onclose while disconnected" + msg); } else { - this._fail("Server disconnected" + msg); + this._fail(Util.Localisation.get('errorDisconnected') + msg); } this._sock.off('close'); }.bind(this)); @@ -218,7 +218,7 @@ var RFB; var rmode = this._display.get_render_mode(); if (Websock_native) { Util.Info("Using native WebSockets"); - this._updateState('loaded', 'noVNC ready: native WebSockets, ' + rmode); + this._updateState('loaded', Util.Localisation.get('ready')+', ' + rmode); } else { this._cleanupSocket('fatal'); throw new Error("WebSocket support is required to use noVNC"); @@ -236,7 +236,7 @@ var RFB; this._rfb_path = (path !== undefined) ? path : ""; if (!this._rfb_host || !this._rfb_port) { - return this._fail("Must set host and port"); + return this._fail(Util.Localisation.get('errorHostPort')); } this._updateState('connect'); @@ -251,7 +251,7 @@ var RFB; sendPassword: function (passwd) { this._rfb_password = passwd; - this._rfb_state = 'Authentication'; + this._rfb_state = Util.Localisation.get('authentication'); setTimeout(this._init_msg.bind(this), 1); }, @@ -501,7 +501,7 @@ var RFB; case 'disconnect': this._disconnTimer = setTimeout(function () { - this._fail("Disconnect timeout"); + this._fail(Util.Localisation.get('errorTimeout')); }.bind(this), this._disconnectTimeout * 1000); this._print_stats(); @@ -513,9 +513,9 @@ var RFB; if (oldstate === 'disconnected') { Util.Error("Invalid transition from 'disconnected' to 'failed'"); } else if (oldstate === 'normal') { - Util.Error("Error while connected."); + Util.Error(Util.Localisation.get('errorConnected')); } else if (oldstate === 'init') { - Util.Error("Error while initializing."); + Util.Error(Util.Localisation.get('errorInitializing')); } // Make sure we transition to disconnected @@ -626,7 +626,7 @@ var RFB; _negotiate_protocol_version: function () { if (this._sock.rQlen() < 12) { - return this._fail("Incomplete protocol version"); + return this._fail(Util.Localisation.get('errorProtocolVerion')); } var sversion = this._sock.rQshiftStr(12).substr(4, 7); @@ -650,7 +650,7 @@ var RFB; this._rfb_version = 3.8; break; default: - return this._fail("Invalid server version " + sversion); + return this._fail(Util.Localisation.get('errorServerVerion') + ' ' + sversion); } if (is_repeater) { @@ -685,7 +685,7 @@ var RFB; if (num_types === 0) { var strlen = this._sock.rQshift32(); var reason = this._sock.rQshiftStr(strlen); - return this._fail("Security failure: " + reason); + return this._fail(Util.Localisation.get('errorSecurity') + ': ' + reason); } this._rfb_auth_scheme = 0; @@ -836,7 +836,7 @@ var RFB; if (this._sock.rQwait("auth reason", 4)) { return false; } var strlen = this._sock.rQshift32(); var reason = this._sock.rQshiftStr(strlen); - return this._fail("Auth failure: " + reason); + return this._fail(Util.Localisation.get('errorAuthFailure') + ': ' + reason); case 1: // no auth if (this._rfb_version >= 3.8) { @@ -873,11 +873,11 @@ var RFB; var reason = this._sock.rQshiftStr(length); return this._fail(reason); } else { - return this._fail("Authentication failure"); + return this._fail(Util.Localisation.get('errorAuthFailure')); } return false; case 2: - return this._fail("Too many auth attempts"); + return this._fail(Util.Localisation.get('errorAuthAttempts')); } }, @@ -992,9 +992,9 @@ var RFB; this._sock.flush(); if (this._encrypt) { - this._updateState('normal', 'Connected (encrypted) to: ' + this._fb_name); + this._updateState('normal', Util.Localisation.get('connectedEncrypted') + ': ' + this._fb_name); } else { - this._updateState('normal', 'Connected (unencrypted) to: ' + this._fb_name); + this._updateState('normal', Util.Localisation.get('connectedUnencrypted') + ': ' + this._fb_name); } }, @@ -2110,4 +2110,4 @@ var RFB; Util.Error("Server sent compress level pseudo-encoding"); } }; -})(); +})(); \ No newline at end of file diff --git a/include/ui.js b/include/ui.js index cb5717cb..dbce8825 100644 --- a/include/ui.js +++ b/include/ui.js @@ -17,7 +17,8 @@ var UI; // Load supporting scripts window.onscriptsload = function () { UI.load(); }; - Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", + Util.load_scripts([Util.Localisation.getLanguageFileLocation(), + "webutil.js", "base64.js", "websock.js", "des.js", "keysymdef.js", "keyboard.js", "input.js", "display.js", "rfb.js", "keysym.js", "inflator.js"]); diff --git a/include/util.js b/include/util.js index ed0e3cde..c26378b3 100644 --- a/include/util.js +++ b/include/util.js @@ -11,6 +11,7 @@ // Globals defined here var Util = {}; +var Language = {}; /* @@ -620,3 +621,83 @@ Util.Flash = (function () { version = v.match(/\d+/g); return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; }()); + +Util.Localisation = { + defaultLanguage: 'en-GB', + + /* + * 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' + }, + + // Get language file location + getLanguageFileLocation: function () { + return 'locale/locale-'+Util.Localisation.getLanguageCode()+'.js'; + }, + + // 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; + } + } + + 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 () { + if (typeof window.navigator.languages == 'object') { + return window.navigator.languages; + } else { + var userLang = navigator.language || navigator.userLanguage; + return [userLang]; + } + }, + + /* + * 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 key in supportedLanguages) { + if (supportedLanguages.hasOwnProperty(key)) { + if (key === languageCode) { + // Return the supported language or good alternative + return supportedLanguages[key]; + } + } + } + + // LanguageCode not supported + return null; + }, + + // Retrieve localised text + get: function (id) { + if (Language[id]) { + return Language[id]; + } else { + return '{'+id+'}'; + } + } +}; \ No newline at end of file