mirror of https://github.com/portainer/portainer
feat(i18n): add the ability to change the application language
parent
f9308406af
commit
1a2ed3a6a4
|
@ -125,6 +125,7 @@ func initSettings(settingsService portainer.SettingsService, flags *portainer.CL
|
||||||
portainer.LDAPSearchSettings{},
|
portainer.LDAPSearchSettings{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Language: "en",
|
||||||
}
|
}
|
||||||
|
|
||||||
if *flags.Templates != "" {
|
if *flags.Templates != "" {
|
||||||
|
|
|
@ -57,6 +57,7 @@ type (
|
||||||
DisplayExternalContributors bool `valid:""`
|
DisplayExternalContributors bool `valid:""`
|
||||||
AuthenticationMethod int `valid:"required"`
|
AuthenticationMethod int `valid:"required"`
|
||||||
LDAPSettings portainer.LDAPSettings `valid:""`
|
LDAPSettings portainer.LDAPSettings `valid:""`
|
||||||
|
Language string `valid:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
putSettingsLDAPCheckRequest struct {
|
putSettingsLDAPCheckRequest struct {
|
||||||
|
@ -114,6 +115,7 @@ func (handler *SettingsHandler) handlePutSettings(w http.ResponseWriter, r *http
|
||||||
BlackListedLabels: req.BlackListedLabels,
|
BlackListedLabels: req.BlackListedLabels,
|
||||||
DisplayExternalContributors: req.DisplayExternalContributors,
|
DisplayExternalContributors: req.DisplayExternalContributors,
|
||||||
LDAPSettings: req.LDAPSettings,
|
LDAPSettings: req.LDAPSettings,
|
||||||
|
Language: req.Language,
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.AuthenticationMethod == 1 {
|
if req.AuthenticationMethod == 1 {
|
||||||
|
|
|
@ -75,6 +75,7 @@ type (
|
||||||
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
DisplayExternalContributors bool `json:"DisplayExternalContributors"`
|
||||||
AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"`
|
AuthenticationMethod AuthenticationMethod `json:"AuthenticationMethod"`
|
||||||
LDAPSettings LDAPSettings `json:"LDAPSettings"`
|
LDAPSettings LDAPSettings `json:"LDAPSettings"`
|
||||||
|
Language string `json:"Language"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// User represents a user account.
|
// User represents a user account.
|
||||||
|
|
|
@ -8,24 +8,24 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12 col-md-12 col-xs-12" ng-if="applicationState.endpoint.mode.provider !== 'DOCKER_SWARM'">
|
<div class="col-lg-12 col-md-12 col-xs-12" ng-if="applicationState.endpoint.mode.provider !== 'DOCKER_SWARM'">
|
||||||
<rd-widget>
|
<rd-widget>
|
||||||
<rd-widget-header icon="fa-tachometer" title="Node info"></rd-widget-header>
|
<rd-widget-header icon="fa-tachometer" title="DASHBOARD.WIDGET_NODE.TITLE"></rd-widget-header>
|
||||||
<rd-widget-body classes="no-padding">
|
<rd-widget-body classes="no-padding">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ 'DASHBOARD.NODE_NAME' | translate }}</td>
|
<td translate>DASHBOARD.WIDGET_NODE.NODE_NAME</td>
|
||||||
<td>{{ infoData.Name }}</td>
|
<td>{{ infoData.Name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Docker version</td>
|
<td translate>DASHBOARD.WIDGET_NODE.DOCKER_VERSION</td>
|
||||||
<td>{{ infoData.ServerVersion }}</td>
|
<td>{{ infoData.ServerVersion }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>CPU</td>
|
<td translate>DASHBOARD.WIDGET_NODE.CPU</td>
|
||||||
<td>{{ infoData.NCPU }}</td>
|
<td>{{ infoData.NCPU }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Memory</td>
|
<td translate>DASHBOARD.WIDGET_NODE.MEMORY</td>
|
||||||
<td>{{ infoData.MemTotal|humansize }}</td>
|
<td>{{ infoData.MemTotal|humansize }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
@ -11,6 +11,20 @@
|
||||||
<rd-widget-header icon="fa-cogs" title="Application settings"></rd-widget-header>
|
<rd-widget-header icon="fa-cogs" title="Application settings"></rd-widget-header>
|
||||||
<rd-widget-body>
|
<rd-widget-body>
|
||||||
<form class="form-horizontal">
|
<form class="form-horizontal">
|
||||||
|
<!-- language -->
|
||||||
|
<div class="col-sm-12 form-section-title">
|
||||||
|
Language
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="lang" class="col-sm-2 col-lg-1 control-label text-left">Language</label>
|
||||||
|
<div class="col-sm-10 col-lg-11">
|
||||||
|
<select class="form-control" id="lang" ng-model="settings.Language">
|
||||||
|
<option value="en">English</option>
|
||||||
|
<option value="fr">Français</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- !language -->
|
||||||
<!-- logo -->
|
<!-- logo -->
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
Logo
|
Logo
|
||||||
|
|
|
@ -55,6 +55,7 @@ function ($scope, $state, Notifications, SettingsService, StateManager, DEFAULT_
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
Notifications.success('Settings updated');
|
Notifications.success('Settings updated');
|
||||||
StateManager.updateLogo(settings.LogoURL);
|
StateManager.updateLogo(settings.LogoURL);
|
||||||
|
StateManager.updateLang(settings.Language);
|
||||||
StateManager.updateExternalContributions(settings.DisplayExternalContributors);
|
StateManager.updateExternalContributions(settings.DisplayExternalContributors);
|
||||||
if (resetForm) {
|
if (resetForm) {
|
||||||
resetFormValues();
|
resetFormValues();
|
||||||
|
|
|
@ -9,7 +9,7 @@ angular
|
||||||
classes: '@?'
|
classes: '@?'
|
||||||
},
|
},
|
||||||
transclude: true,
|
transclude: true,
|
||||||
template: '<div class="widget-header"><div class="row"><span ng-class="classes" class="pull-left"><i class="fa" ng-class="icon"></i> {{title}} </span><span ng-class="classes" class="pull-right" ng-transclude></span></div></div>',
|
template: '<div class="widget-header"><div class="row"><span ng-class="classes" class="pull-left" translate><i class="fa" ng-class="icon"></i> {{title}} </span><span ng-class="classes" class="pull-right" ng-transclude></span></div></div>',
|
||||||
restrict: 'E'
|
restrict: 'E'
|
||||||
};
|
};
|
||||||
return directive;
|
return directive;
|
||||||
|
|
|
@ -5,4 +5,5 @@ function SettingsViewModel(data) {
|
||||||
this.DisplayExternalContributors = data.DisplayExternalContributors;
|
this.DisplayExternalContributors = data.DisplayExternalContributors;
|
||||||
this.AuthenticationMethod = data.AuthenticationMethod;
|
this.AuthenticationMethod = data.AuthenticationMethod;
|
||||||
this.LDAPSettings = data.LDAPSettings;
|
this.LDAPSettings = data.LDAPSettings;
|
||||||
|
this.Language = data.Language;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
angular.module('portainer.services')
|
angular.module('portainer.services')
|
||||||
.factory('StateManager', ['$q', 'SystemService', 'InfoHelper', 'LocalStorage', 'SettingsService', 'StatusService', function StateManagerFactory($q, SystemService, InfoHelper, LocalStorage, SettingsService, StatusService) {
|
.factory('StateManager', ['$q', 'TranslationService', 'SystemService', 'InfoHelper', 'LocalStorage', 'SettingsService', 'StatusService', function StateManagerFactory($q, TranslationService, SystemService, InfoHelper, LocalStorage, SettingsService, StatusService) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var manager = {};
|
var manager = {};
|
||||||
|
@ -24,6 +24,12 @@ angular.module('portainer.services')
|
||||||
LocalStorage.storeApplicationState(state.application);
|
LocalStorage.storeApplicationState(state.application);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
manager.updateLang = function(lang) {
|
||||||
|
state.application.lang = lang;
|
||||||
|
LocalStorage.storeApplicationState(state.application);
|
||||||
|
TranslationService.setLang(state.application.lang);
|
||||||
|
};
|
||||||
|
|
||||||
manager.updateExternalContributions = function(displayExternalContributors) {
|
manager.updateExternalContributions = function(displayExternalContributors) {
|
||||||
state.application.displayExternalContributors = displayExternalContributors;
|
state.application.displayExternalContributors = displayExternalContributors;
|
||||||
LocalStorage.storeApplicationState(state.application);
|
LocalStorage.storeApplicationState(state.application);
|
||||||
|
@ -41,6 +47,7 @@ angular.module('portainer.services')
|
||||||
if (applicationState) {
|
if (applicationState) {
|
||||||
state.application = applicationState;
|
state.application = applicationState;
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
|
TranslationService.setLang(state.application.lang);
|
||||||
deferred.resolve(state);
|
deferred.resolve(state);
|
||||||
} else {
|
} else {
|
||||||
$q.all({
|
$q.all({
|
||||||
|
@ -55,8 +62,10 @@ angular.module('portainer.services')
|
||||||
state.application.endpointManagement = status.EndpointManagement;
|
state.application.endpointManagement = status.EndpointManagement;
|
||||||
state.application.version = status.Version;
|
state.application.version = status.Version;
|
||||||
state.application.logo = settings.LogoURL;
|
state.application.logo = settings.LogoURL;
|
||||||
|
state.application.lang = settings.Language;
|
||||||
state.application.displayExternalContributors = settings.DisplayExternalContributors;
|
state.application.displayExternalContributors = settings.DisplayExternalContributors;
|
||||||
LocalStorage.storeApplicationState(state.application);
|
LocalStorage.storeApplicationState(state.application);
|
||||||
|
TranslationService.setLang(state.application.lang);
|
||||||
deferred.resolve(state);
|
deferred.resolve(state);
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
angular.module('portainer.services')
|
||||||
|
.factory('TranslationService', ['$translate', function TranslationServiceFactory($translate) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var service = {};
|
||||||
|
|
||||||
|
service.setLang = function(lang) {
|
||||||
|
$translate.use(lang);
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}]);
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"DASHBOARD": {
|
"DASHBOARD": {
|
||||||
"NODE_NAME": "Name"
|
"WIDGET_NODE": {
|
||||||
|
"TITLE": "Node info",
|
||||||
|
"NODE_NAME": "Name",
|
||||||
|
"DOCKER_VERSION": "Docker version",
|
||||||
|
"CPU": "CPU",
|
||||||
|
"MEMORY": "Memory"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
{
|
{
|
||||||
"DASHBOARD": {
|
"DASHBOARD": {
|
||||||
"NODE_NAME": "Nom"
|
"WIDGET_NODE": {
|
||||||
|
"TITLE": "Informations à propos de l'hôte",
|
||||||
|
"NODE_NAME": "Nom",
|
||||||
|
"DOCKER_VERSION": "Version de Docker",
|
||||||
|
"CPU": "Processeurs",
|
||||||
|
"MEMORY": "Mémoire"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue