Skip to content

Commit 7e371ee

Browse files
authored
switch languages without an app restart (#1555)
switch languages without an app restart
2 parents 23d50ca + ea1aaf7 commit 7e371ee

File tree

11 files changed

+189
-119
lines changed

11 files changed

+189
-119
lines changed

locales/en/messages.json

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,75 +69,81 @@
6969
"analyticsOptOut": {
7070
"message": "Opt out of the anonymised collection of statistics data"
7171
},
72-
"userLanguageSelect": {
73-
"message": "Language (need to restart the application for the changes to take effect)"
72+
"language_changed": {
73+
"message": "Language change saved"
74+
},
75+
"language_choice_message": {
76+
"message": "Change language:",
77+
"description": "Try and be brief"
7478
},
7579
"language_default": {
76-
"message": "Default"
80+
"message": "System Default"
81+
},
82+
"language_default_pretty": {
83+
"message": "System Default ($t(detectedLanguage))"
7784
},
7885
"language_ca": {
79-
"message": "Catal\u00e0 (ca)",
86+
"message": "Catal\u00e0",
8087
"description": "Don't translate!!!"
8188
},
8289
"language_de": {
83-
"message": "Deutsch (de)",
90+
"message": "Deutsch",
8491
"description": "Don't translate!!!"
8592
},
8693
"language_en": {
87-
"message": "English (en)",
94+
"message": "English",
8895
"description": "Don't translate!!!"
8996
},
9097
"language_es": {
91-
"message": "Espa\u00f1ol (es)",
98+
"message": "Espa\u00f1ol",
9299
"description": "Don't translate!!!"
93100
},
94101
"language_fr": {
95-
"message": "Fran\u00e7ais (fr)",
102+
"message": "Fran\u00e7ais",
96103
"description": "Don't translate!!!"
97104
},
98105
"language_gl": {
99-
"message": "Galego (gl)",
106+
"message": "Galego",
100107
"description": "Don't translate!!!"
101108
},
102109
"language_hr": {
103-
"message": "Hrvatski (hr)",
110+
"message": "Hrvatski",
104111
"description": "Don't translate!!!"
105112
},
106-
107113
"language_id": {
108-
"message": "Bahasa Indonesia (id)",
114+
"message": "Bahasa Indonesia",
109115
"description": "Don't translate!!!"
110116
},
111117
"language_it": {
112-
"message": "Italiano (it)",
118+
"message": "Italiano",
113119
"description": "Don't translate!!!"
114120
},
115121
"language_ja": {
116-
"message": "\u65E5\u672C\u8A9E (ja)",
122+
"message": "\u65E5\u672C\u8A9E",
117123
"description": "Don't translate!!!"
118124
},
119125
"language_ko": {
120-
"message": "\ud55c\uad6d\uc5b4 (ko)",
126+
"message": "\ud55c\uad6d\uc5b4",
121127
"description": "Don't translate!!!"
122128
},
123129
"language_lv": {
124-
"message": "Latvie\u0161u (lv)",
130+
"message": "Latvie\u0161u",
125131
"description": "Don't translate!!!"
126132
},
127133
"language_pt": {
128-
"message": "Portugu\u00EAs (pt)",
134+
"message": "Portugu\u00EAs",
129135
"description": "Don't translate!!!"
130136
},
131137
"language_ru": {
132-
"message": "\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u044F\u0437\u044B\u043A (ru)",
138+
"message": "\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u044F\u0437\u044B\u043A",
133139
"description": "Don't translate!!!"
134140
},
135141
"language_sv": {
136-
"message": "Svenska (sv)",
142+
"message": "Svenska",
137143
"description": "Don't translate!!!"
138144
},
139145
"language_zh_CN": {
140-
"message": "\u7b80\u4f53\u4e2d\u6587 (zh_CN)",
146+
"message": "\u7b80\u4f53\u4e2d\u6587",
141147
"description": "Don't translate!!!"
142148
},
143149

@@ -231,6 +237,12 @@
231237
"tabLanding": {
232238
"message": "Welcome"
233239
},
240+
"tabChangelog": {
241+
"message": "Changelog"
242+
},
243+
"tabPrivacyPolicy": {
244+
"message": "Privacy Policy"
245+
},
234246
"tabHelp": {
235247
"message": "Documentation & Support"
236248
},
@@ -573,15 +585,9 @@
573585
"defaultFacebookText": {
574586
"message": "We also have a <a href=\"https://www.facebook.com/groups/betaflightgroup/\" target=\"_blank\">Facebook Group</a>.<br />Join us to get a place to talk about Betaflight, ask configuration questions, or just hang out with fellow pilots."
575587
},
576-
"defaultChangelogAction": {
577-
"message": "Changelog"
578-
},
579588
"defaultChangelogHead": {
580589
"message": "Configurator - Changelog"
581590
},
582-
"defaultPrivacyPolicyAction": {
583-
"message": "Privacy Policy"
584-
},
585591
"defaultButtonFirmwareFlasher": {
586592
"message": "Firmware Flasher"
587593
},

src/css/main.css

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ body {
4040
a {
4141
text-decoration: none;
4242
color: var(--defaultText);
43-
font-family: 'open_sanssemibold', Arial;
43+
font-weight: bold;
4444
}
4545

4646
a:hover {
@@ -513,7 +513,7 @@ input[type="number"]::-webkit-inner-spin-button {
513513
}
514514

515515
#log a {
516-
font-weight: regular;
516+
font-weight: normal;
517517
color: #ffbb00;
518518
}
519519

@@ -590,6 +590,7 @@ input[type="number"]::-webkit-inner-spin-button {
590590

591591
#tabs li a {
592592
font-family: 'open_sansregular', Arial;
593+
font-weight: normal;
593594
padding-left: 33px;
594595
padding-top: 5px;
595596
padding-bottom: 3px;
@@ -1654,6 +1655,7 @@ dialog {
16541655
color: #fff;
16551656
font-size: 12px;
16561657
font-family: 'open_sansregular', Arial;
1658+
font-weight: normal;
16571659
text-shadow: 0px 1px rgba(0, 0, 0, 0.25);
16581660
margin-top: -1px;
16591661
}
@@ -1666,6 +1668,7 @@ dialog {
16661668
color: #fff;
16671669
font-size: 12px;
16681670
font-family: 'open_sansregular', Arial;
1671+
font-weight: normal;
16691672
text-shadow: 0px 1px rgba(0, 0, 0, 0.25);
16701673
margin-top: -1px;
16711674
}

src/css/tabs/landing.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,22 @@
180180
display: block;
181181
float: left;
182182
}
183+
184+
.tab-landing .languageSwitcher .selected_language {
185+
font-weight: bold;
186+
}
187+
.tab-landing .languageSwitcher {
188+
margin-left: auto;
189+
margin-right: auto;
190+
text-align: center;
191+
color: silver;
192+
}
193+
.tab-landing .languageSwitcher a {
194+
color: silver;
195+
font-weight: normal;
196+
white-space: nowrap;
197+
}
198+
.tab-landing .languageSwitcher a:not(:last-child):after {
199+
content: ", ";
200+
font-weight: normal;
201+
}

src/js/localization.js

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,30 @@ i18n.init = function(cb) {
3030
console.error('Error loading i18n ' + err);
3131
} else {
3232
console.log('i18n system loaded');
33+
var detectedLanguage = i18n.getMessage('language_' + getValidLocale("DEFAULT"));
34+
i18n.addResources({"detectedLanguage": detectedLanguage });
3335
}
3436
if (cb !== undefined) {
3537
cb();
3638
}
3739
});
3840
});
41+
// This function should do the same things that the i18n.localizePage function below does.
42+
i18next.on('languageChanged', function (newLang) {
43+
var translate = function(messageID) {
44+
return i18n.getMessage(messageID);
45+
};
46+
i18n.localizePage(true);
47+
updateStatusBarVersion();
48+
});
3949
}
4050

51+
i18n.changeLanguage = function(languageSelected) {
52+
ConfigStorage.set({'userLanguageSelect': languageSelected});
53+
i18next.changeLanguage(getValidLocale(languageSelected));
54+
i18n.selectedLanguage = languageSelected;
55+
GUI.log(i18n.getMessage('language_changed'));
56+
}
4157
i18n.getMessage = function(messageID, parameters) {
4258

4359
var translatedString;
@@ -79,44 +95,58 @@ i18n.existsMessage = function(key) {
7995
* Helper functions, don't depend of the i18n framework
8096
*/
8197

82-
i18n.localizePage = function() {
98+
i18n.localizePage = function(forceReTranslate) {
8399

84100
var localized = 0;
85101

86102
var translate = function(messageID) {
87103
localized++;
88-
89104
return i18n.getMessage(messageID);
90105
};
91106

92-
$('[i18n]:not(.i18n-replaced)').each(function() {
93-
var element = $(this);
94-
95-
element.html(translate(element.attr('i18n')));
96-
element.addClass('i18n-replaced');
97-
});
98-
99-
$('[i18n_title]:not(.i18n_title-replaced)').each(function() {
100-
var element = $(this);
101-
102-
element.attr('title', translate(element.attr('i18n_title')));
103-
element.addClass('i18n_title-replaced');
104-
});
105-
106-
$('[i18n_value]:not(.i18n_value-replaced)').each(function() {
107-
var element = $(this);
107+
if (forceReTranslate) {
108+
$('[i18n]').each(function() {
109+
var element = $(this);
110+
element.html(translate(element.attr('i18n')));
111+
});
112+
$('[i18n_title]').each(function() {
113+
var element = $(this);
114+
element.attr('title', translate(element.attr('i18n_title')));
115+
});
116+
$('[i18n_value]').each(function() {
117+
var element = $(this);
118+
element.val(translate(element.attr('i18n_value')));
119+
});
120+
$('[i18n_placeholder]').each(function() {
121+
var element = $(this);
122+
element.attr('placeholder', translate(element.attr('i18n_placeholder')));
123+
});
124+
} else {
108125

109-
element.val(translate(element.attr('i18n_value')));
110-
element.addClass('i18n_value-replaced');
111-
});
126+
$('[i18n]:not(.i18n-replaced)').each(function() {
127+
var element = $(this);
128+
element.html(translate(element.attr('i18n')));
129+
element.addClass('i18n-replaced');
130+
});
112131

113-
$('[i18n_placeholder]:not(.i18n_placeholder-replaced)').each(function() {
114-
var element = $(this);
132+
$('[i18n_title]:not(.i18n_title-replaced)').each(function() {
133+
var element = $(this);
134+
element.attr('title', translate(element.attr('i18n_title')));
135+
element.addClass('i18n_title-replaced');
136+
});
115137

116-
element.attr('placeholder', translate(element.attr('i18n_placeholder')));
117-
element.addClass('i18n_placeholder-replaced');
118-
});
138+
$('[i18n_value]:not(.i18n_value-replaced)').each(function() {
139+
var element = $(this);
140+
element.val(translate(element.attr('i18n_value')));
141+
element.addClass('i18n_value-replaced');
142+
});
119143

144+
$('[i18n_placeholder]:not(.i18n_placeholder-replaced)').each(function() {
145+
var element = $(this);
146+
element.attr('placeholder', translate(element.attr('i18n_placeholder')));
147+
element.addClass('i18n_placeholder-replaced');
148+
});
149+
}
120150
return localized;
121151
}
122152

@@ -129,7 +159,8 @@ function getStoredUserLocale(cb) {
129159
var userLanguage = 'DEFAULT';
130160
if (result.userLanguageSelect) {
131161
userLanguage = result.userLanguageSelect
132-
}
162+
}
163+
i18n.selectedLanguage = userLanguage;
133164

134165
userLanguage = getValidLocale(userLanguage);
135166

src/js/main.js

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,6 @@ function startProcess() {
121121
checkForConfiguratorUpdates();
122122
}
123123

124-
ConfigStorage.get('logopen', function (result) {
125-
if (result.logopen) {
126-
$("#showlog").trigger('click');
127-
}
128-
});
129-
130124
// log webgl capability
131125
// it would seem the webgl "enabling" through advanced settings will be ignored in the future
132126
// and webgl will be supported if gpu supports it by default (canary 40.0.2175.0), keep an eye on this one
@@ -385,29 +379,6 @@ function startProcess() {
385379
DarkTheme.setConfig(checked);
386380
}).change();
387381

388-
ConfigStorage.get('userLanguageSelect', function (result) {
389-
390-
var userLanguage_e = $('div.userLanguage select');
391-
var languagesAvailables = i18n.getLanguagesAvailables();
392-
userLanguage_e.append('<option value="DEFAULT">' + i18n.getMessage('language_default') + '</option>');
393-
userLanguage_e.append('<option disabled>------</option>');
394-
languagesAvailables.forEach(function(element) {
395-
var languageName = i18n.getMessage('language_' + element);
396-
userLanguage_e.append('<option value="' + element + '">' + languageName + '</option>');
397-
});
398-
399-
if (result.userLanguageSelect) {
400-
userLanguage_e.val(result.userLanguageSelect);
401-
}
402-
403-
userLanguage_e.change(function () {
404-
var languageSelected = $(this).val();
405-
406-
// Select the new language, a restart is required
407-
ConfigStorage.set({'userLanguageSelect': languageSelected});
408-
});
409-
});
410-
411382
function close_and_cleanup(e) {
412383
if (e.type == 'click' && !$.contains($('div#options-window')[0], e.target) || e.type == 'keyup' && e.keyCode == 27) {
413384
$(document).unbind('click keyup', close_and_cleanup);
@@ -529,6 +500,12 @@ function startProcess() {
529500
$(this).data('state', state);
530501
});
531502

503+
ConfigStorage.get('logopen', function (result) {
504+
if (result.logopen) {
505+
$("#showlog").trigger('click');
506+
}
507+
});
508+
532509
ConfigStorage.get('permanentExpertMode', function (result) {
533510
if (result.permanentExpertMode) {
534511
$('input[name="expertModeCheckbox"]').prop('checked', true);

src/js/port_handler.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ PortHandler.update_port_select = function (ports) {
174174
$('div#port-picker #port').append($("<option/>", {value: ports[i], text: ports[i], data: {isManual: false}}));
175175
}
176176

177-
$('div#port-picker #port').append($("<option/>", {value: 'manual', text: i18n.getMessage('portsSelectManual'), data: {isManual: true}}));
177+
$('div#port-picker #port').append($("<option/>", {value: 'manual', i18n: 'portsSelectManual', data: {isManual: true}}));
178+
i18n.localizePage();
179+
178180
};
179181

180182
PortHandler.port_detected = function(name, code, timeout, ignore_timeout) {

0 commit comments

Comments
 (0)