mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUAC-1053: Pull language from preferences when configuring the translate service. Fallback to US English if there is no such translation file.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -23,21 +23,25 @@
|
|||||||
/**
|
/**
|
||||||
* The configuration block for setting up everything having to do with i18n.
|
* The configuration block for setting up everything having to do with i18n.
|
||||||
*/
|
*/
|
||||||
angular.module('index').config(['$translateProvider', function($translateProvider) {
|
angular.module('index').config(['$injector', function($injector) {
|
||||||
|
|
||||||
// TODONT: Use US English by default (this should come from preferences)
|
// Required providers
|
||||||
$translateProvider.preferredLanguage('en_US');
|
var $translateProvider = $injector.get('$translateProvider');
|
||||||
|
var preferenceServiceProvider = $injector.get('preferenceServiceProvider');
|
||||||
|
|
||||||
// Use US English for any undefined strings
|
// Fallback to US English
|
||||||
$translateProvider.fallbackLanguage('en_US');
|
var fallbackLanguages = ['en_US'];
|
||||||
|
|
||||||
// Load translations from static JSON files
|
// Prefer chosen language, use fallback languages if necessary
|
||||||
$translateProvider.useStaticFilesLoader({
|
$translateProvider.fallbackLanguage(fallbackLanguages);
|
||||||
prefix: 'translations/',
|
$translateProvider.preferredLanguage(preferenceServiceProvider.preferences.language);
|
||||||
suffix: '.json'
|
|
||||||
|
// Load translations via translationLoader service
|
||||||
|
$translateProvider.useLoader('translationLoader', {
|
||||||
|
fallbackLanguages : fallbackLanguages
|
||||||
});
|
});
|
||||||
|
|
||||||
// Provide pluralization, etc. via messageformat.js
|
// Provide pluralization, etc. via messageformat.js
|
||||||
$translateProvider.useMessageFormatInterpolation();
|
$translateProvider.useMessageFormatInterpolation();
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for loading translation definition files, conforming to the
|
||||||
|
* angular-translate documentation for custom translation loaders:
|
||||||
|
*
|
||||||
|
* https://github.com/angular-translate/angular-translate/wiki/Asynchronous-loading#using-custom-loader-service
|
||||||
|
*/
|
||||||
|
angular.module('locale').factory('translationLoader', ['$injector', function translationLoader($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $http = $injector.get('$http');
|
||||||
|
var $q = $injector.get('$q');
|
||||||
|
var cacheService = $injector.get('cacheService');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Satisfies a translation request for the given key by searching for the
|
||||||
|
* translation files for each key in the given array, in order. The request
|
||||||
|
* fails only if none of the files can be found.
|
||||||
|
*
|
||||||
|
* @param {Deferred} deferred
|
||||||
|
* The Deferred object to resolve or reject depending on whether at
|
||||||
|
* least one translation file can be successfully loaded.
|
||||||
|
*
|
||||||
|
* @param {String} requestedKey
|
||||||
|
* The originally-requested language key.
|
||||||
|
*
|
||||||
|
* @param {String[]} remainingKeys
|
||||||
|
* The keys of the languages to attempt to load, in order, where the
|
||||||
|
* first key in this array is the language to try within this function
|
||||||
|
* call. The first key in the array is not necessarily the originally-
|
||||||
|
* requested language key.
|
||||||
|
*/
|
||||||
|
var satisfyTranslation = function satisfyTranslation(deferred, requestedKey, remainingKeys) {
|
||||||
|
|
||||||
|
// Get current language key
|
||||||
|
var currentKey = remainingKeys.shift();
|
||||||
|
|
||||||
|
// If no languages to try, just fail
|
||||||
|
if (!currentKey) {
|
||||||
|
deferred.reject(requestedKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to retrieve language
|
||||||
|
$http({
|
||||||
|
cache : cacheService.languages,
|
||||||
|
method : 'GET',
|
||||||
|
url : 'translations/' + encodeURIComponent(currentKey) + '.json'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Resolve promise if translation retrieved successfully
|
||||||
|
.success(function translationFileRetrieved(translation) {
|
||||||
|
deferred.resolve(translation);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Retry with remaining languages if translation file could not be retrieved
|
||||||
|
.error(function translationFileUnretrievable() {
|
||||||
|
satisfyTranslation(deferred, requestedKey, remainingKeys);
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom loader function for angular-translate which loads the desired
|
||||||
|
* language file dynamically via HTTP. If the language file cannot be
|
||||||
|
* found, the fallback language is used instead.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* Arbitrary options, containing at least a "key" property which
|
||||||
|
* contains the requested language key.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Object>}
|
||||||
|
* A promise which resolves to the requested translation string object.
|
||||||
|
*/
|
||||||
|
return function loadTranslationFile(options) {
|
||||||
|
|
||||||
|
var translation = $q.defer();
|
||||||
|
|
||||||
|
// Get requested language from options
|
||||||
|
var requestedKey = options.key;
|
||||||
|
|
||||||
|
// Append fallback languages to requested language
|
||||||
|
var keys = [requestedKey].concat(options.fallbackLanguages);
|
||||||
|
|
||||||
|
// Satisfy the translation request
|
||||||
|
satisfyTranslation(translation, requestedKey, keys);
|
||||||
|
|
||||||
|
// Return promise which is resolved only after the translation file is loaded
|
||||||
|
return translation.promise;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
@@ -24,16 +24,20 @@
|
|||||||
* A service for setting and retrieving browser-local preferences. Preferences
|
* A service for setting and retrieving browser-local preferences. Preferences
|
||||||
* may be any JSON-serializable type.
|
* may be any JSON-serializable type.
|
||||||
*/
|
*/
|
||||||
angular.module('settings').factory('preferenceService', ['$injector',
|
angular.module('settings').provider('preferenceService', function preferenceServiceProvider() {
|
||||||
function preferenceService($injector) {
|
|
||||||
|
|
||||||
// Required services
|
/**
|
||||||
var $rootScope = $injector.get('$rootScope');
|
* Reference to the provider itself.
|
||||||
var $window = $injector.get('$window');
|
*
|
||||||
|
* @type preferenceServiceProvider
|
||||||
|
*/
|
||||||
|
var provider = this;
|
||||||
|
|
||||||
var service = {};
|
/**
|
||||||
|
* The storage key of Guacamole preferences within local storage.
|
||||||
// The parameter name for getting the history from local storage
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
var GUAC_PREFERENCES_STORAGE_KEY = "GUAC_PREFERENCES";
|
var GUAC_PREFERENCES_STORAGE_KEY = "GUAC_PREFERENCES";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,7 +45,7 @@ angular.module('settings').factory('preferenceService', ['$injector',
|
|||||||
*
|
*
|
||||||
* @type Object.<String, String>
|
* @type Object.<String, String>
|
||||||
*/
|
*/
|
||||||
service.inputMethods = {
|
var inputMethods = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No input method is used. Keyboard events are generated from a
|
* No input method is used. Keyboard events are generated from a
|
||||||
@@ -97,7 +101,7 @@ angular.module('settings').factory('preferenceService', ['$injector',
|
|||||||
*
|
*
|
||||||
* @type Object.<String, Object>
|
* @type Object.<String, Object>
|
||||||
*/
|
*/
|
||||||
service.preferences = {
|
this.preferences = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether translation of touch to mouse events should emulate an
|
* Whether translation of touch to mouse events should emulate an
|
||||||
@@ -113,7 +117,7 @@ angular.module('settings').factory('preferenceService', ['$injector',
|
|||||||
*
|
*
|
||||||
* @type String
|
* @type String
|
||||||
*/
|
*/
|
||||||
inputMethod : service.inputMethods.NONE,
|
inputMethod : inputMethods.NONE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The key of the desired display language.
|
* The key of the desired display language.
|
||||||
@@ -124,45 +128,71 @@ angular.module('settings').factory('preferenceService', ['$injector',
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Persists the current values of all preferences, if possible.
|
|
||||||
*/
|
|
||||||
service.save = function save() {
|
|
||||||
|
|
||||||
// Save updated preferences, ignore inability to use localStorage
|
|
||||||
try {
|
|
||||||
if (localStorage)
|
|
||||||
localStorage.setItem(GUAC_PREFERENCES_STORAGE_KEY, JSON.stringify(service.preferences));
|
|
||||||
}
|
|
||||||
catch (ignore) {}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get stored preferences, ignore inability to use localStorage
|
// Get stored preferences, ignore inability to use localStorage
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (localStorage) {
|
if (localStorage) {
|
||||||
var preferencesJSON = localStorage.getItem(GUAC_PREFERENCES_STORAGE_KEY);
|
var preferencesJSON = localStorage.getItem(GUAC_PREFERENCES_STORAGE_KEY);
|
||||||
if (preferencesJSON)
|
if (preferencesJSON)
|
||||||
angular.extend(service.preferences, JSON.parse(preferencesJSON));
|
angular.extend(provider.preferences, JSON.parse(preferencesJSON));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (ignore) {}
|
catch (ignore) {}
|
||||||
|
|
||||||
// Persist settings when window is unloaded
|
// Factory method required by provider
|
||||||
$window.addEventListener('unload', service.save);
|
this.$get = ['$injector', function preferenceServiceFactory($injector) {
|
||||||
|
|
||||||
// Persist settings upon navigation
|
// Required services
|
||||||
$rootScope.$on('$routeChangeSuccess', function handleNavigate() {
|
var $rootScope = $injector.get('$rootScope');
|
||||||
service.save();
|
var $window = $injector.get('$window');
|
||||||
});
|
|
||||||
|
|
||||||
// Persist settings upon logout
|
var service = {};
|
||||||
$rootScope.$on('guacLogout', function handleLogout() {
|
|
||||||
service.save();
|
|
||||||
});
|
|
||||||
|
|
||||||
return service;
|
/**
|
||||||
|
* All valid input method type names.
|
||||||
|
*
|
||||||
|
* @type Object.<String, String>
|
||||||
|
*/
|
||||||
|
service.inputMethods = inputMethods;
|
||||||
|
|
||||||
}]);
|
/**
|
||||||
|
* All currently-set preferences, as name/value pairs. Each property name
|
||||||
|
* corresponds to the name of a preference.
|
||||||
|
*
|
||||||
|
* @type Object.<String, Object>
|
||||||
|
*/
|
||||||
|
service.preferences = provider.preferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the current values of all preferences, if possible.
|
||||||
|
*/
|
||||||
|
service.save = function save() {
|
||||||
|
|
||||||
|
// Save updated preferences, ignore inability to use localStorage
|
||||||
|
try {
|
||||||
|
if (localStorage)
|
||||||
|
localStorage.setItem(GUAC_PREFERENCES_STORAGE_KEY, JSON.stringify(service.preferences));
|
||||||
|
}
|
||||||
|
catch (ignore) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Persist settings when window is unloaded
|
||||||
|
$window.addEventListener('unload', service.save);
|
||||||
|
|
||||||
|
// Persist settings upon navigation
|
||||||
|
$rootScope.$on('$routeChangeSuccess', function handleNavigate() {
|
||||||
|
service.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Persist settings upon logout
|
||||||
|
$rootScope.$on('guacLogout', function handleLogout() {
|
||||||
|
service.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user