diff --git a/locales/en/messages.json b/locales/en/messages.json index a0bf2d16..732acc8e 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -69,75 +69,81 @@ "analyticsOptOut": { "message": "Opt out of the anonymised collection of statistics data" }, - "userLanguageSelect": { - "message": "Language (need to restart the application for the changes to take effect)" + "language_changed": { + "message": "Language change saved" + }, + "language_choice_message": { + "message": "Change language:", + "description": "Try and be brief" }, "language_default": { - "message": "Default" + "message": "System Default" + }, + "language_default_pretty": { + "message": "System Default ($t(detectedLanguage))" }, "language_ca": { - "message": "Catal\u00e0 (ca)", + "message": "Catal\u00e0", "description": "Don't translate!!!" }, "language_de": { - "message": "Deutsch (de)", + "message": "Deutsch", "description": "Don't translate!!!" }, "language_en": { - "message": "English (en)", + "message": "English", "description": "Don't translate!!!" }, "language_es": { - "message": "Espa\u00f1ol (es)", + "message": "Espa\u00f1ol", "description": "Don't translate!!!" }, "language_fr": { - "message": "Fran\u00e7ais (fr)", + "message": "Fran\u00e7ais", "description": "Don't translate!!!" }, "language_gl": { - "message": "Galego (gl)", + "message": "Galego", "description": "Don't translate!!!" }, "language_hr": { - "message": "Hrvatski (hr)", + "message": "Hrvatski", "description": "Don't translate!!!" }, - "language_id": { - "message": "Bahasa Indonesia (id)", + "message": "Bahasa Indonesia", "description": "Don't translate!!!" }, "language_it": { - "message": "Italiano (it)", + "message": "Italiano", "description": "Don't translate!!!" }, "language_ja": { - "message": "\u65E5\u672C\u8A9E (ja)", + "message": "\u65E5\u672C\u8A9E", "description": "Don't translate!!!" }, "language_ko": { - "message": "\ud55c\uad6d\uc5b4 (ko)", + "message": "\ud55c\uad6d\uc5b4", "description": "Don't translate!!!" }, "language_lv": { - "message": "Latvie\u0161u (lv)", + "message": "Latvie\u0161u", "description": "Don't translate!!!" }, "language_pt": { - "message": "Portugu\u00EAs (pt)", + "message": "Portugu\u00EAs", "description": "Don't translate!!!" }, "language_ru": { - "message": "\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u044F\u0437\u044B\u043A (ru)", + "message": "\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u044F\u0437\u044B\u043A", "description": "Don't translate!!!" }, "language_sv": { - "message": "Svenska (sv)", + "message": "Svenska", "description": "Don't translate!!!" }, "language_zh_CN": { - "message": "\u7b80\u4f53\u4e2d\u6587 (zh_CN)", + "message": "\u7b80\u4f53\u4e2d\u6587", "description": "Don't translate!!!" }, @@ -231,6 +237,12 @@ "tabLanding": { "message": "Welcome" }, + "tabChangelog": { + "message": "Changelog" + }, + "tabPrivacyPolicy": { + "message": "Privacy Policy" + }, "tabHelp": { "message": "Documentation & Support" }, @@ -573,15 +585,9 @@ "defaultFacebookText": { "message": "We also have a Facebook Group.
Join us to get a place to talk about Betaflight, ask configuration questions, or just hang out with fellow pilots." }, - "defaultChangelogAction": { - "message": "Changelog" - }, "defaultChangelogHead": { "message": "Configurator - Changelog" }, - "defaultPrivacyPolicyAction": { - "message": "Privacy Policy" - }, "defaultButtonFirmwareFlasher": { "message": "Firmware Flasher" }, diff --git a/src/css/main.css b/src/css/main.css index cc0dd048..139faad4 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -40,7 +40,7 @@ body { a { text-decoration: none; color: var(--defaultText); - font-family: 'open_sanssemibold', Arial; + font-weight: bold; } a:hover { @@ -513,7 +513,7 @@ input[type="number"]::-webkit-inner-spin-button { } #log a { - font-weight: regular; + font-weight: normal; color: #ffbb00; } @@ -590,6 +590,7 @@ input[type="number"]::-webkit-inner-spin-button { #tabs li a { font-family: 'open_sansregular', Arial; + font-weight: normal; padding-left: 33px; padding-top: 5px; padding-bottom: 3px; @@ -1654,6 +1655,7 @@ dialog { color: #fff; font-size: 12px; font-family: 'open_sansregular', Arial; + font-weight: normal; text-shadow: 0px 1px rgba(0, 0, 0, 0.25); margin-top: -1px; } @@ -1666,6 +1668,7 @@ dialog { color: #fff; font-size: 12px; font-family: 'open_sansregular', Arial; + font-weight: normal; text-shadow: 0px 1px rgba(0, 0, 0, 0.25); margin-top: -1px; } diff --git a/src/css/tabs/landing.css b/src/css/tabs/landing.css index 2dccedfb..6692cbc3 100644 --- a/src/css/tabs/landing.css +++ b/src/css/tabs/landing.css @@ -180,3 +180,22 @@ display: block; float: left; } + +.tab-landing .languageSwitcher .selected_language { + font-weight: bold; +} +.tab-landing .languageSwitcher { + margin-left: auto; + margin-right: auto; + text-align: center; + color: silver; +} +.tab-landing .languageSwitcher a { + color: silver; + font-weight: normal; + white-space: nowrap; +} +.tab-landing .languageSwitcher a:not(:last-child):after { + content: ", "; + font-weight: normal; +} diff --git a/src/js/localization.js b/src/js/localization.js index 0c50c7e3..f2e74d17 100644 --- a/src/js/localization.js +++ b/src/js/localization.js @@ -30,14 +30,30 @@ i18n.init = function(cb) { console.error('Error loading i18n ' + err); } else { console.log('i18n system loaded'); + var detectedLanguage = i18n.getMessage('language_' + getValidLocale("DEFAULT")); + i18n.addResources({"detectedLanguage": detectedLanguage }); } if (cb !== undefined) { cb(); } }); }); + // This function should do the same things that the i18n.localizePage function below does. + i18next.on('languageChanged', function (newLang) { + var translate = function(messageID) { + return i18n.getMessage(messageID); + }; + i18n.localizePage(true); + updateStatusBarVersion(); + }); } +i18n.changeLanguage = function(languageSelected) { + ConfigStorage.set({'userLanguageSelect': languageSelected}); + i18next.changeLanguage(getValidLocale(languageSelected)); + i18n.selectedLanguage = languageSelected; + GUI.log(i18n.getMessage('language_changed')); +} i18n.getMessage = function(messageID, parameters) { var translatedString; @@ -79,44 +95,58 @@ i18n.existsMessage = function(key) { * Helper functions, don't depend of the i18n framework */ -i18n.localizePage = function() { +i18n.localizePage = function(forceReTranslate) { var localized = 0; var translate = function(messageID) { localized++; - return i18n.getMessage(messageID); }; - $('[i18n]:not(.i18n-replaced)').each(function() { - var element = $(this); + if (forceReTranslate) { + $('[i18n]').each(function() { + var element = $(this); + element.html(translate(element.attr('i18n'))); + }); + $('[i18n_title]').each(function() { + var element = $(this); + element.attr('title', translate(element.attr('i18n_title'))); + }); + $('[i18n_value]').each(function() { + var element = $(this); + element.val(translate(element.attr('i18n_value'))); + }); + $('[i18n_placeholder]').each(function() { + var element = $(this); + element.attr('placeholder', translate(element.attr('i18n_placeholder'))); + }); + } else { - element.html(translate(element.attr('i18n'))); - element.addClass('i18n-replaced'); - }); + $('[i18n]:not(.i18n-replaced)').each(function() { + var element = $(this); + element.html(translate(element.attr('i18n'))); + element.addClass('i18n-replaced'); + }); - $('[i18n_title]:not(.i18n_title-replaced)').each(function() { - var element = $(this); + $('[i18n_title]:not(.i18n_title-replaced)').each(function() { + var element = $(this); + element.attr('title', translate(element.attr('i18n_title'))); + element.addClass('i18n_title-replaced'); + }); - element.attr('title', translate(element.attr('i18n_title'))); - element.addClass('i18n_title-replaced'); - }); - - $('[i18n_value]:not(.i18n_value-replaced)').each(function() { - var element = $(this); - - element.val(translate(element.attr('i18n_value'))); - element.addClass('i18n_value-replaced'); - }); - - $('[i18n_placeholder]:not(.i18n_placeholder-replaced)').each(function() { - var element = $(this); - - element.attr('placeholder', translate(element.attr('i18n_placeholder'))); - element.addClass('i18n_placeholder-replaced'); - }); + $('[i18n_value]:not(.i18n_value-replaced)').each(function() { + var element = $(this); + element.val(translate(element.attr('i18n_value'))); + element.addClass('i18n_value-replaced'); + }); + $('[i18n_placeholder]:not(.i18n_placeholder-replaced)').each(function() { + var element = $(this); + element.attr('placeholder', translate(element.attr('i18n_placeholder'))); + element.addClass('i18n_placeholder-replaced'); + }); + } return localized; } @@ -129,7 +159,8 @@ function getStoredUserLocale(cb) { var userLanguage = 'DEFAULT'; if (result.userLanguageSelect) { userLanguage = result.userLanguageSelect - } + } + i18n.selectedLanguage = userLanguage; userLanguage = getValidLocale(userLanguage); diff --git a/src/js/main.js b/src/js/main.js index 579f72ba..9050d6f5 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -134,12 +134,6 @@ function startProcess() { checkForConfiguratorUpdates(); } - ConfigStorage.get('logopen', function (result) { - if (result.logopen) { - $("#showlog").trigger('click'); - } - }); - // log webgl capability // it would seem the webgl "enabling" through advanced settings will be ignored in the future // and webgl will be supported if gpu supports it by default (canary 40.0.2175.0), keep an eye on this one @@ -398,29 +392,6 @@ function startProcess() { DarkTheme.setConfig(checked); }).change(); - ConfigStorage.get('userLanguageSelect', function (result) { - - var userLanguage_e = $('div.userLanguage select'); - var languagesAvailables = i18n.getLanguagesAvailables(); - userLanguage_e.append(''); - userLanguage_e.append(''); - languagesAvailables.forEach(function(element) { - var languageName = i18n.getMessage('language_' + element); - userLanguage_e.append(''); - }); - - if (result.userLanguageSelect) { - userLanguage_e.val(result.userLanguageSelect); - } - - userLanguage_e.change(function () { - var languageSelected = $(this).val(); - - // Select the new language, a restart is required - ConfigStorage.set({'userLanguageSelect': languageSelected}); - }); - }); - function close_and_cleanup(e) { if (e.type == 'click' && !$.contains($('div#options-window')[0], e.target) || e.type == 'keyup' && e.keyCode == 27) { $(document).unbind('click keyup', close_and_cleanup); @@ -542,6 +513,12 @@ function startProcess() { $(this).data('state', state); }); + ConfigStorage.get('logopen', function (result) { + if (result.logopen) { + $("#showlog").trigger('click'); + } + }); + ConfigStorage.get('permanentExpertMode', function (result) { if (result.permanentExpertMode) { $('input[name="expertModeCheckbox"]').prop('checked', true); diff --git a/src/js/port_handler.js b/src/js/port_handler.js index ea7181d6..91997761 100644 --- a/src/js/port_handler.js +++ b/src/js/port_handler.js @@ -174,7 +174,9 @@ PortHandler.update_port_select = function (ports) { $('div#port-picker #port').append($("".format(index, build.tag ? i18n.getMessage(build.tag) : build.title))) + buildType_e.append($("".format(index,build.tag ? 'i18n="' + build.tag + '" ' : '', build.tag ? i18n.getMessage(build.tag) : build.title))) }); $('select[name="build_type"]').val($('select[name="build_type"] option:first').val()); } @@ -300,16 +300,17 @@ TABS.firmware_flasher.initialize = function (callback) { var build_type = $(this).val(); $('select[name="board"]').empty() - .append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectBoard')))); + .append($("")); $('select[name="firmware_version"]').empty() - .append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); + .append($("")); if (!GUI.connect_lock) { buildTypesToShow[build_type].loader(); } chrome.storage.local.set({'selected_build_type': build_type}); + i18n.localizePage(); }); $('select[name="board"]').change(function() { @@ -317,7 +318,7 @@ TABS.firmware_flasher.initialize = function (callback) { var target = $(this).val(); if (!GUI.connect_lock) { - self.flashingMessage(i18n.getMessage('firmwareFlasherLoadFirmwareFile'), self.FLASH_MESSAGE_TYPES.NEUTRAL) + self.flashingMessage('firmwareFlasherLoadFirmwareFile', self.FLASH_MESSAGE_TYPES.NEUTRAL) .flashProgress(0); $('div.git_info').slideUp(); @@ -401,7 +402,7 @@ TABS.firmware_flasher.initialize = function (callback) { self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL); } else { - self.flashingMessage(i18n.getMessage('firmwareFlasherHexCorrupted'), self.FLASH_MESSAGE_TYPES.INVALID); + self.flashingMessage('firmwareFlasherHexCorrupted', self.FLASH_MESSAGE_TYPES.INVALID); } }); } @@ -454,9 +455,10 @@ TABS.firmware_flasher.initialize = function (callback) { } function failed_to_load() { - $('span.progressLabel').text(i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware')); + $('span.progressLabel').attr('i18n','firmwareFlasherFailedToLoadOnlineFirmware').removeClass('i18n-replaced'); $("a.load_remote_file").removeClass('disabled'); $("a.load_remote_file").text(i18n.getMessage('firmwareFlasherButtonLoadOnline')); + i18n.localizePage(); } var summary = $('select[name="firmware_version"] option:selected').data('summary'); @@ -466,7 +468,8 @@ TABS.firmware_flasher.initialize = function (callback) { $("a.load_remote_file").addClass('disabled'); $.get(summary.url, onLoadSuccess).fail(failed_to_load); } else { - $('span.progressLabel').text(i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware')); + $('span.progressLabel').attr('i18n','firmwareFlasherFailedToLoadOnlineFirmware').removeClass('i18n-replaced'); + i18n.localizePage(); } }); @@ -512,7 +515,8 @@ TABS.firmware_flasher.initialize = function (callback) { STM32DFU.connect(usbDevices, parsed_hex, options); } } else { - $('span.progressLabel').text(i18n.getMessage('firmwareFlasherFirmwareNotLoaded')); + $('span.progressLabel').attr('i18n','firmwareFlasherFirmwareNotLoaded').removeClass('i18n-replaced'); + i18n.localizePage(); } } } @@ -740,7 +744,13 @@ TABS.firmware_flasher.flashingMessage = function(message, type) { break; } if (message != null) { - progressLabel_e.html(message); + if (i18next.exists(message)) { + progressLabel_e.attr('i18n',message).removeClass('i18n-replaced'); + i18n.localizePage(); + } else { + progressLabel_e.removeAttr('i18n'); + progressLabel_e.html(message); + } } return self; diff --git a/src/js/tabs/landing.js b/src/js/tabs/landing.js index dd6928ee..9034af6b 100644 --- a/src/js/tabs/landing.js +++ b/src/js/tabs/landing.js @@ -2,18 +2,51 @@ TABS.landing = {}; TABS.landing.initialize = function (callback) { - var self = this; + var self = this; - if (GUI.active_tab != 'landing') { - GUI.active_tab = 'landing'; + if (GUI.active_tab != 'landing') { + GUI.active_tab = 'landing'; + } + + $('#content').load("./tabs/landing.html", function () { + function showLang(newLang) { + var bottomSection = $('.languageSwitcher'); + bottomSection.find('a').each(function(index) { + var element = $(this); + var languageSelected = element.attr('lang'); + if (newLang == languageSelected) { + element.removeClass('selected_language'); + element.addClass('selected_language'); + } else { + element.removeClass('selected_language'); + } + }); } - - $('#content').load("./tabs/landing.html", function () { - // translate to user-selected language - i18n.localizePage(); - - GUI.content_ready(callback); + var bottomSection = $('.languageSwitcher'); + bottomSection.html(' '); + bottomSection.append(' '); + var languagesAvailables = i18n.getLanguagesAvailables(); + languagesAvailables.forEach(function(element) { + bottomSection.append(' '); }); + bottomSection.find('a').each(function(index) { + var element = $(this); + element.click(function(){ + var element = $(this); + var languageSelected = element.attr('lang'); + if (!languageSelected) { return; } + if (i18n.selectedLanguage != languageSelected) { + i18n.changeLanguage(languageSelected); + showLang(languageSelected); + } + }); + }); + showLang(i18n.selectedLanguage); + // translate to user-selected language + i18n.localizePage(); + + GUI.content_ready(callback); + }); }; diff --git a/src/main.html b/src/main.html index 4e27c536..24420676 100644 --- a/src/main.html +++ b/src/main.html @@ -292,8 +292,8 @@