From 468abfefbc6ef2b25271deb012f3109d191eb226 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 29 Aug 2019 14:07:45 +0200 Subject: [PATCH 1/4] Reworked selection of locales and translation dictionaries. Slicer now tries to heed user's locales, also it tries to switch to the language recommended by the operating system (Windows & OSX specific). --- src/slic3r/GUI/GUI_App.cpp | 192 +++++++++++++++++++------------------ src/slic3r/GUI/GUI_App.hpp | 7 +- 2 files changed, 104 insertions(+), 95 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index ccda72f5c..80df9c542 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -229,11 +230,8 @@ bool GUI_App::on_init_inner() init_label_colours(); init_fonts(); - wxString language = wxEmptyString; - if (app_config->has("translation_language")) - language = app_config->get("translation_language"); // If load_language() fails, the application closes. - load_language(language); + load_language(wxString(), true); // Suppress the '- default -' presets. preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1"); @@ -600,23 +598,49 @@ bool GUI_App::switch_language() // select language from the list of installed languages bool GUI_App::select_language() { - const std::vector langs = get_installed_languages(); + wxArrayString translations = wxTranslations::Get()->GetAvailableTranslations(SLIC3R_APP_KEY); + std::vector language_infos; + language_infos.emplace_back(wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH)); + for (size_t i = 0; i < translations.GetCount(); ++ i) { + const wxLanguageInfo *langinfo = wxLocale::FindLanguageInfo(translations[i]); + if (langinfo != nullptr) + language_infos.emplace_back(langinfo); + } + sort_remove_duplicates(language_infos); + std::sort(language_infos.begin(), language_infos.end(), [](const wxLanguageInfo* l, const wxLanguageInfo* r) { return l->Description < r->Description; }); + wxArrayString names; - names.Alloc(langs.size()); + names.Alloc(language_infos.size()); // Some valid language should be selected since the application start up. - assert(m_wxLocale != nullptr); - const auto current_language = m_wxLocale->GetLanguage(); - int init_selection = 0; - for (size_t i = 0; i < langs.size(); ++ i) { - if (langs[i]->Language == current_language) + const wxLanguage current_language = wxLanguage(m_wxLocale->GetLanguage()); + int init_selection = -1; + int init_selection_alt = -1; + int init_selection_default = -1; + for (size_t i = 0; i < language_infos.size(); ++ i) { + if (wxLanguage(language_infos[i]->Language) == current_language) + // The dictionary matches the active language and country. init_selection = i; - names.Add(langs[i]->Description); + else if ((language_infos[i]->CanonicalName.BeforeFirst('_') == m_wxLocale->GetCanonicalName().BeforeFirst('_')) || + // if the active language is Slovak, mark the Czech language as active. + (language_infos[i]->CanonicalName.BeforeFirst('_') == "cs" && m_wxLocale->GetCanonicalName().BeforeFirst('_') == "sk")) + // The dictionary matches the active language, it does not necessarily match the country. + init_selection_alt = i; + if (language_infos[i]->CanonicalName.BeforeFirst('_') == "en") + // This will be the default selection if the active language does not match any dictionary. + init_selection_default = i; + names.Add(language_infos[i]->Description); } + if (init_selection == -1) + // This is the dictionary matching the active language. + init_selection = init_selection_alt; + if (init_selection != -1) + // This is the language to highlight in the choice dialog initially. + init_selection_default = init_selection; - const long index = wxGetSingleChoiceIndex(_(L("Select the language")), _(L("Language")), names, init_selection); + const long index = wxGetSingleChoiceIndex(_(L("Select the language")), _(L("Language")), names, init_selection_default); // Try to load a new language. - if (index != -1 && langs[index]->Language != current_language && this->load_language(langs[index]->CanonicalName)) { + if (index != -1 && (init_selection == -1 || init_selection != index) && this->load_language(language_infos[index]->CanonicalName, false)) { // Save language at application config. app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data()); app_config->save(); @@ -626,106 +650,92 @@ bool GUI_App::select_language() return false; } -// Get the language code before underscore, if there is underscore. -static wxString language_code_short(const wxString &language_code) -{ - size_t idx_underscore = language_code.find('_'); - return (idx_underscore != wxString::npos) ? language_code.substr(0, idx_underscore) : language_code; -} - // Load gettext translation files and activate them at the start of the application, // based on the "translation_language" key stored in the application config. -bool GUI_App::load_language(wxString language) +bool GUI_App::load_language(wxString language, bool initial) { - if (language.IsEmpty()) { - int lang = wxLocale::GetSystemLanguage(); - if (lang != wxLANGUAGE_UNKNOWN) { - const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); - if (info != nullptr) - language = info->CanonicalName; - } + if (initial) { + // There is a static list of lookup path prefixes in wxWidgets. Add ours. + wxFileTranslationsLoader::AddCatalogLookupPathPrefix(from_u8(localization_dir())); + // Get the active language from PrusaSlicer.ini, or empty string if the key does not exist. + language = app_config->get("translation_language"); } - if (language.IsEmpty()) - language = "en_US"; + const wxLanguageInfo *language_info = wxLocale::FindLanguageInfo(language); + if (language_info == nullptr) + language.clear(); + + if (language.IsEmpty()) { + const wxLanguage lang_system = wxLanguage(wxLocale::GetSystemLanguage()); + const wxLanguageInfo *lang_info_system = nullptr; + if (lang_system != wxLANGUAGE_UNKNOWN) { + lang_info_system = wxLocale::GetLanguageInfo(lang_system); + if (lang_info_system != nullptr) + language = lang_info_system->CanonicalName; + } + { + // Allocating a temporary locale will switch the default wxTranslations to its internal wxTranslations instance. + wxLocale temp_locale; + // Set the current translation's language to default, otherwise GetBestTranslation() may not work (see the wxWidgets source code). + wxTranslations::Get()->SetLanguage(wxLANGUAGE_DEFAULT); + // Let the wxFileTranslationsLoader enumerate all translation dictionaries for PrusaSlicer + // and try to match them with the system specific "preferred languages". + // There seems to be a support for that on Windows and OSX, while on Linuxes the code just returns wxLocale::GetSystemLanguage(). + // The last parameter gets added to the list of detected dictionaries. This is a workaround + // for not having the English dictionary. Let's hope wxWidgets of various versions process this call the same way. + wxString best_language = wxTranslations::Get()->GetBestTranslation(SLIC3R_APP_KEY, wxLANGUAGE_ENGLISH); + if (! best_language.IsEmpty()) + language = best_language; + } + if (language.IsEmpty()) + language = "en_US"; + } + + language_info = wxLocale::FindLanguageInfo(language); + if (language_info == nullptr || language_info->LayoutDirection == wxLayout_RightToLeft) { + // We don't support right-to-left rendering (Hebrew, Arabic ...), therefore we switch to English. + language = "en_US"; + language_info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US); + } // Alternate language code. - wxString language_code_alt = language_code_short(language); - if (language_code_alt == "sk") + wxLanguage language_dict = wxLanguage(language_info->Language); + if (language.BeforeFirst('_') == "sk") // Slovaks understand Czech well. Give them the Czech translation. - language_code_alt = "cz"; + language_dict = wxLANGUAGE_CZECH; - const wxLanguageInfo *info = nullptr; - for (const wxLanguageInfo *this_info : get_installed_languages()) { - if (this_info->CanonicalName == language) { - // The language matches exactly, including the country suffix. Use it. - info = this_info; - break; - } - if (language_code_short(this_info->CanonicalName) == language_code_alt) - // Alternatively try to match just the language without the country suffix. - info = this_info; - } - - wxString canonical_name; - if (info == nullptr) { - // Fallback for user languages, for which we do not have dictionaries. - canonical_name = "en_EN"; - info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US); - } else - canonical_name = info->CanonicalName; - - wxLocale *new_locale = new wxLocale; - if (info == nullptr || ! new_locale->Init(info->Language)) { + if (! wxLocale::IsAvailable(language_info->Language)) { // Loading the language dictionary failed. - wxString message = "Switching PrusaSlicer to language " + canonical_name + " failed."; + wxString message = "Switching PrusaSlicer to language " + language_info->CanonicalName + " failed."; #if !defined(_WIN32) && !defined(__APPLE__) - // likely some linux system - "\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n"; + // likely some linux system + message += "\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n"; #endif - delete new_locale; - if (m_wxLocale == nullptr) + if (initial) message + "\n\nApplication will close."; wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR); - if (m_wxLocale == nullptr) - std::terminate(); + if (initial) + std::exit(EXIT_FAILURE); else return false; } - wxLocale *old_locale = m_wxLocale; - m_wxLocale = new_locale; - m_wxLocale->AddCatalogLookupPathPrefix(from_u8(localization_dir())); + + // Release the old locales, create new locales. + + m_wxLocale.release(); + m_wxLocale = std::make_unique(); + m_wxLocale->Init(language_info->Language); + // Override language at the active wxTranslations class (which is stored in the active m_wxLocale) + // to load possibly different dictionary, for example, load Czech dictionary for Slovak language. + wxTranslations::Get()->SetLanguage(language_dict); m_wxLocale->AddCatalog(SLIC3R_APP_KEY); - m_imgui->set_language(into_u8(info->CanonicalName)); + m_imgui->set_language(into_u8(language_info->CanonicalName)); //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); - //FIXME Why the following line crashes? - // delete old_locale; return true; } -// Get a list of installed languages (languages for which we have dictionaries). -std::vector GUI_App::get_installed_languages() -{ - wxDir dir(from_u8(localization_dir())); - wxString filename; - std::vector res; - res.emplace_back(wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US)); - for (bool cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_DIRS); cont; cont = dir.GetNext(&filename)) { - const wxLanguageInfo *langinfo = wxLocale::FindLanguageInfo(filename); - if (langinfo != nullptr) { - auto full_file_name = dir.GetName() + wxFileName::GetPathSeparator() + - filename + wxFileName::GetPathSeparator() + SLIC3R_APP_KEY + wxT(".mo"); - if (wxFileExists(full_file_name)) - res.push_back(langinfo); - } - } - // Remove duplicated "en_EN" and possible others. - sort_remove_duplicates(res); - return res; -} - Tab* GUI_App::get_tab(Preset::Type type) { for (Tab* tab: tabs_list) @@ -1019,7 +1029,7 @@ wxString GUI_App::current_language_code_safe() const { "uk", "uk_UA", }, { "zh", "zh_CN", }, }; - wxString language_code = language_code_short(this->current_language_code()); + wxString language_code = this->current_language_code().BeforeFirst('_'); auto it = mapping.find(language_code); if (it != mapping.end()) language_code = it->second; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 52c2a7a26..83017f176 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -88,7 +88,7 @@ class GUI_App : public wxApp size_t m_em_unit; // width of a "m"-symbol in pixels for current system font // Note: for 100% Scale m_em_unit = 10 -> it's a good enough coefficient for a size setting of controls - wxLocale* m_wxLocale{ nullptr }; + std::unique_ptr m_wxLocale; std::unique_ptr m_imgui; std::unique_ptr m_printhost_job_queue; @@ -132,7 +132,7 @@ public: void update_ui_from_settings(); bool switch_language(); - bool load_language(wxString language); + bool load_language(wxString language, bool initial); Tab* get_tab(Preset::Type type); ConfigOptionMode get_mode(); @@ -144,7 +144,7 @@ public: bool checked_tab(Tab* tab); void load_current_presets(); - wxString current_language_code() const { assert(m_wxLocale != nullptr); return m_wxLocale->GetCanonicalName(); } + wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); } // Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US". wxString current_language_code_safe() const; @@ -187,7 +187,6 @@ private: void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false); void window_pos_sanitize(wxTopLevelWindow* window); bool select_language(); - std::vector get_installed_languages(); #ifdef __WXMSW__ void associate_3mf_files(); #endif // __WXMSW__ From ab361fc0e707c7682d5a0628b218581d3b297d3e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 29 Aug 2019 14:10:10 +0200 Subject: [PATCH 2/4] Refreshed dictionaries with keys from GUI_ObjectLayers.cpp --- resources/localization/PrusaSlicer.pot | 111 +++++++++++++++---------- resources/localization/list.txt | 1 + 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/resources/localization/PrusaSlicer.pot b/resources/localization/PrusaSlicer.pot index 87a7fe3c0..b0c5a3051 100644 --- a/resources/localization/PrusaSlicer.pot +++ b/resources/localization/PrusaSlicer.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-08-29 11:15+0200\n" +"POT-Creation-Date: 2019-08-29 14:09+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -138,6 +138,7 @@ msgstr "" #: src/slic3r/GUI/BedShapeDialog.cpp:91 src/slic3r/GUI/ConfigWizard.cpp:123 #: src/slic3r/GUI/ConfigWizard.cpp:576 src/slic3r/GUI/ConfigWizard.cpp:590 +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:135 #: src/slic3r/GUI/GUI_ObjectManipulation.cpp:390 #: src/slic3r/GUI/WipeTowerDialog.cpp:84 src/slic3r/GUI/wxExtensions.cpp:509 #: src/libslic3r/PrintConfig.cpp:70 src/libslic3r/PrintConfig.cpp:77 @@ -398,7 +399,7 @@ msgstr "" msgid "Welcome" msgstr "" -#: src/slic3r/GUI/ConfigWizard.cpp:309 src/slic3r/GUI/GUI_App.cpp:773 +#: src/slic3r/GUI/ConfigWizard.cpp:309 src/slic3r/GUI/GUI_App.cpp:783 #, possible-c-format msgid "Run %s" msgstr "" @@ -645,6 +646,7 @@ msgid "%s doesn't support percentage" msgstr "" #: src/slic3r/GUI/Field.cpp:174 src/slic3r/GUI/Field.cpp:197 +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:337 msgid "Invalid numeric input." msgstr "" @@ -1203,7 +1205,7 @@ msgstr "" msgid "Notice" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:132 +#: src/slic3r/GUI/GUI_App.cpp:133 #, possible-c-format msgid "" "%s has encountered an error. It was likely caused by running out of memory. " @@ -1213,96 +1215,96 @@ msgid "" "The application will now terminate." msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:135 +#: src/slic3r/GUI/GUI_App.cpp:136 msgid "Fatal error" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:301 +#: src/slic3r/GUI/GUI_App.cpp:299 #, possible-c-format msgid "" "PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" "while OpenGL version %s, render %s, vendor %s was detected." msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:304 +#: src/slic3r/GUI/GUI_App.cpp:302 msgid "You may need to update your graphics card driver." msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:307 +#: src/slic3r/GUI/GUI_App.cpp:305 msgid "" "As a workaround, you may run PrusaSlicer with a software rendered 3D " "graphics by running prusa-slicer.exe with the --sw_renderer parameter." msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:309 +#: src/slic3r/GUI/GUI_App.cpp:307 msgid "Unsupported OpenGL version" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:460 +#: src/slic3r/GUI/GUI_App.cpp:458 msgid "Changing of an application language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:468 src/slic3r/GUI/GUI_App.cpp:477 +#: src/slic3r/GUI/GUI_App.cpp:466 src/slic3r/GUI/GUI_App.cpp:475 msgid "Recreating" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:481 +#: src/slic3r/GUI/GUI_App.cpp:479 msgid "Loading of current presets" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:489 +#: src/slic3r/GUI/GUI_App.cpp:487 msgid "Loading of a mode view" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:569 +#: src/slic3r/GUI/GUI_App.cpp:567 msgid "Choose one file (3MF/AMF):" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:581 +#: src/slic3r/GUI/GUI_App.cpp:579 msgid "Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:617 +#: src/slic3r/GUI/GUI_App.cpp:641 msgid "Select the language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:617 +#: src/slic3r/GUI/GUI_App.cpp:641 msgid "Language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:776 +#: src/slic3r/GUI/GUI_App.cpp:786 msgid "&Configuration Snapshots" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:776 +#: src/slic3r/GUI/GUI_App.cpp:786 msgid "Inspect / activate configuration snapshots" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:777 +#: src/slic3r/GUI/GUI_App.cpp:787 msgid "Take Configuration &Snapshot" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:777 +#: src/slic3r/GUI/GUI_App.cpp:787 msgid "Capture a configuration snapshot" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:780 +#: src/slic3r/GUI/GUI_App.cpp:790 msgid "&Preferences" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:786 +#: src/slic3r/GUI/GUI_App.cpp:796 msgid "Application preferences" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:789 src/slic3r/GUI/wxExtensions.cpp:3041 +#: src/slic3r/GUI/GUI_App.cpp:799 src/slic3r/GUI/wxExtensions.cpp:3041 msgid "Simple" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:789 +#: src/slic3r/GUI/GUI_App.cpp:799 msgid "Simple View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:790 src/slic3r/GUI/GUI_ObjectList.cpp:97 +#: src/slic3r/GUI/GUI_App.cpp:800 src/slic3r/GUI/GUI_ObjectList.cpp:97 #: src/slic3r/GUI/GUI_ObjectList.cpp:620 src/slic3r/GUI/Tab.cpp:1058 #: src/slic3r/GUI/Tab.cpp:1073 src/slic3r/GUI/Tab.cpp:1171 #: src/slic3r/GUI/Tab.cpp:1174 src/slic3r/GUI/Tab.cpp:1682 @@ -1313,77 +1315,98 @@ msgstr "" msgid "Advanced" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:790 +#: src/slic3r/GUI/GUI_App.cpp:800 msgid "Advanced View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:791 src/slic3r/GUI/wxExtensions.cpp:3043 +#: src/slic3r/GUI/GUI_App.cpp:801 src/slic3r/GUI/wxExtensions.cpp:3043 msgid "Expert" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:791 +#: src/slic3r/GUI/GUI_App.cpp:801 msgid "Expert View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:796 +#: src/slic3r/GUI/GUI_App.cpp:806 msgid "Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:796 +#: src/slic3r/GUI/GUI_App.cpp:806 #, possible-c-format msgid "%s View Mode" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:798 +#: src/slic3r/GUI/GUI_App.cpp:808 msgid "Change Application &Language" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:800 +#: src/slic3r/GUI/GUI_App.cpp:810 msgid "Flash printer &firmware" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:800 +#: src/slic3r/GUI/GUI_App.cpp:810 msgid "Upload a firmware image into an Arduino based printer" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:812 +#: src/slic3r/GUI/GUI_App.cpp:822 msgid "Taking configuration snapshot" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:812 +#: src/slic3r/GUI/GUI_App.cpp:822 msgid "Snapshot name" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:855 +#: src/slic3r/GUI/GUI_App.cpp:865 msgid "" "Switching the language will trigger application restart.\n" "You will lose content of the plater." msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:857 +#: src/slic3r/GUI/GUI_App.cpp:867 msgid "Do you want to proceed?" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:858 +#: src/slic3r/GUI/GUI_App.cpp:868 msgid "Language selection" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:881 +#: src/slic3r/GUI/GUI_App.cpp:891 msgid "&Configuration" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:903 +#: src/slic3r/GUI/GUI_App.cpp:913 msgid "The presets on the following tabs were modified" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:903 src/slic3r/GUI/Tab.cpp:3130 +#: src/slic3r/GUI/GUI_App.cpp:913 src/slic3r/GUI/Tab.cpp:3130 msgid "Discard changes and continue anyway?" msgstr "" -#: src/slic3r/GUI/GUI_App.cpp:906 +#: src/slic3r/GUI/GUI_App.cpp:916 msgid "Unsaved Presets" msgstr "" +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:27 +msgid "Start at height" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:27 +msgid "Stop at height" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:27 src/slic3r/GUI/Tab.cpp:1030 +#: src/libslic3r/PrintConfig.cpp:66 +msgid "Layer height" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:153 +msgid "Remove layer range" +msgstr "" + +#: src/slic3r/GUI/GUI_ObjectLayers.cpp:162 +msgid "Add layer range" +msgstr "" + #: src/slic3r/GUI/GUI_ObjectList.cpp:34 src/slic3r/GUI/GUI_ObjectList.cpp:88 #: src/slic3r/GUI/GUI_ObjectList.cpp:611 src/libslic3r/PrintConfig.cpp:67 #: src/libslic3r/PrintConfig.cpp:160 src/libslic3r/PrintConfig.cpp:392 @@ -4050,10 +4073,6 @@ msgstr "" msgid "Layers and perimeters" msgstr "" -#: src/slic3r/GUI/Tab.cpp:1030 src/libslic3r/PrintConfig.cpp:66 -msgid "Layer height" -msgstr "" - #: src/slic3r/GUI/Tab.cpp:1034 msgid "Vertical shells" msgstr "" diff --git a/resources/localization/list.txt b/resources/localization/list.txt index a553e775a..440f0ee4c 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -18,6 +18,7 @@ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp src/slic3r/GUI/Gizmos/GLGizmosManager.cpp src/slic3r/GUI/GUI.cpp src/slic3r/GUI/GUI_App.cpp +src/slic3r/GUI/GUI_ObjectLayers.cpp src/slic3r/GUI/GUI_ObjectList.cpp src/slic3r/GUI/GUI_ObjectManipulation.cpp src/slic3r/GUI/GUI_ObjectSettings.cpp From ace275af7f539fd623834cd3731ad7b96ac87e6f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 29 Aug 2019 14:51:24 +0200 Subject: [PATCH 3/4] std::make_unique is not supported by our build servers. use Slic3r::make_unique instead --- src/slic3r/GUI/GUI_App.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 80df9c542..a01d885ec 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -723,7 +723,7 @@ bool GUI_App::load_language(wxString language, bool initial) // Release the old locales, create new locales. m_wxLocale.release(); - m_wxLocale = std::make_unique(); + m_wxLocale = Slic3r::make_unique(); m_wxLocale->Init(language_info->Language); // Override language at the active wxTranslations class (which is stored in the active m_wxLocale) // to load possibly different dictionary, for example, load Czech dictionary for Slovak language. From 78697b2acfd3a4fbbb0b49b955f6a2b12df72326 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 29 Aug 2019 15:35:28 +0200 Subject: [PATCH 4/4] Improvement of selection of language / dictionaries. When switching the languages, if the newly selected dictionary is "compatible" with the system best language or user's locale, then the system best language locale or user's locale is activated, not the locale connected to the dictionary. --- src/slic3r/GUI/GUI_App.cpp | 54 +++++++++++++++++++++++--------------- src/slic3r/GUI/GUI_App.hpp | 6 ++++- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index a01d885ec..0f1040d42 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -640,11 +640,20 @@ bool GUI_App::select_language() const long index = wxGetSingleChoiceIndex(_(L("Select the language")), _(L("Language")), names, init_selection_default); // Try to load a new language. - if (index != -1 && (init_selection == -1 || init_selection != index) && this->load_language(language_infos[index]->CanonicalName, false)) { - // Save language at application config. - app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data()); - app_config->save(); - return true; + if (index != -1 && (init_selection == -1 || init_selection != index)) { + const wxLanguageInfo *new_language_info = language_infos[index]; + if (new_language_info == m_language_info_best || new_language_info == m_language_info_system) { + // The newly selected profile matches user's default profile exactly. That's great. + } else if (m_language_info_best != nullptr && new_language_info->CanonicalName.BeforeFirst('_') == m_language_info_best->CanonicalName.BeforeFirst('_')) + new_language_info = m_language_info_best; + else if (m_language_info_system != nullptr && new_language_info->CanonicalName.BeforeFirst('_') == m_language_info_system->CanonicalName.BeforeFirst('_')) + new_language_info = m_language_info_system; + if (this->load_language(new_language_info->CanonicalName, false)) { + // Save language at application config. + app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data()); + app_config->save(); + return true; + } } return false; @@ -659,20 +668,12 @@ bool GUI_App::load_language(wxString language, bool initial) wxFileTranslationsLoader::AddCatalogLookupPathPrefix(from_u8(localization_dir())); // Get the active language from PrusaSlicer.ini, or empty string if the key does not exist. language = app_config->get("translation_language"); - } - - const wxLanguageInfo *language_info = wxLocale::FindLanguageInfo(language); - if (language_info == nullptr) - language.clear(); - - if (language.IsEmpty()) { - const wxLanguage lang_system = wxLanguage(wxLocale::GetSystemLanguage()); - const wxLanguageInfo *lang_info_system = nullptr; - if (lang_system != wxLANGUAGE_UNKNOWN) { - lang_info_system = wxLocale::GetLanguageInfo(lang_system); - if (lang_info_system != nullptr) - language = lang_info_system->CanonicalName; - } + // Get the system language. + { + const wxLanguage lang_system = wxLanguage(wxLocale::GetSystemLanguage()); + if (lang_system != wxLANGUAGE_UNKNOWN) + m_language_info_system = wxLocale::GetLanguageInfo(lang_system); + } { // Allocating a temporary locale will switch the default wxTranslations to its internal wxTranslations instance. wxLocale temp_locale; @@ -685,8 +686,19 @@ bool GUI_App::load_language(wxString language, bool initial) // for not having the English dictionary. Let's hope wxWidgets of various versions process this call the same way. wxString best_language = wxTranslations::Get()->GetBestTranslation(SLIC3R_APP_KEY, wxLANGUAGE_ENGLISH); if (! best_language.IsEmpty()) - language = best_language; + m_language_info_best = wxLocale::FindLanguageInfo(best_language); } + } + + const wxLanguageInfo *language_info = wxLocale::FindLanguageInfo(language); + if (language_info == nullptr) + language.clear(); + + if (language.IsEmpty()) { + if (m_language_info_system != nullptr && m_language_info_system->LayoutDirection != wxLayout_RightToLeft) + language = m_language_info_system->CanonicalName; + if (m_language_info_best != nullptr && m_language_info_best->LayoutDirection != wxLayout_RightToLeft) + language = m_language_info_best->CanonicalName; if (language.IsEmpty()) language = "en_US"; } @@ -721,7 +733,7 @@ bool GUI_App::load_language(wxString language, bool initial) } // Release the old locales, create new locales. - + //FIXME wxWidgets cause havoc if the current locale is deleted. We just forget it causing memory leaks for now. m_wxLocale.release(); m_wxLocale = Slic3r::make_unique(); m_wxLocale->Init(language_info->Language); diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 83017f176..a8043e991 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -88,7 +88,11 @@ class GUI_App : public wxApp size_t m_em_unit; // width of a "m"-symbol in pixels for current system font // Note: for 100% Scale m_em_unit = 10 -> it's a good enough coefficient for a size setting of controls - std::unique_ptr m_wxLocale; + std::unique_ptr m_wxLocale; + // System language, from locales, owned by wxWidgets. + const wxLanguageInfo *m_language_info_system = nullptr; + // Best translation language, provided by Windows or OSX, owned by wxWidgets. + const wxLanguageInfo *m_language_info_best = nullptr; std::unique_ptr m_imgui; std::unique_ptr m_printhost_job_queue;