This commit is contained in:
Enrico Turri 2019-08-29 15:38:43 +02:00
commit a8f7bb54a5
4 changed files with 190 additions and 145 deletions

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -138,6 +138,7 @@ msgstr ""
#: src/slic3r/GUI/BedShapeDialog.cpp:91 src/slic3r/GUI/ConfigWizard.cpp:123 #: 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/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/GUI_ObjectManipulation.cpp:390
#: src/slic3r/GUI/WipeTowerDialog.cpp:84 src/slic3r/GUI/wxExtensions.cpp:509 #: src/slic3r/GUI/WipeTowerDialog.cpp:84 src/slic3r/GUI/wxExtensions.cpp:509
#: src/libslic3r/PrintConfig.cpp:70 src/libslic3r/PrintConfig.cpp:77 #: src/libslic3r/PrintConfig.cpp:70 src/libslic3r/PrintConfig.cpp:77
@ -398,7 +399,7 @@ msgstr ""
msgid "Welcome" msgid "Welcome"
msgstr "" 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 #, possible-c-format
msgid "Run %s" msgid "Run %s"
msgstr "" msgstr ""
@ -645,6 +646,7 @@ msgid "%s doesn't support percentage"
msgstr "" msgstr ""
#: src/slic3r/GUI/Field.cpp:174 src/slic3r/GUI/Field.cpp:197 #: src/slic3r/GUI/Field.cpp:174 src/slic3r/GUI/Field.cpp:197
#: src/slic3r/GUI/GUI_ObjectLayers.cpp:337
msgid "Invalid numeric input." msgid "Invalid numeric input."
msgstr "" msgstr ""
@ -1203,7 +1205,7 @@ msgstr ""
msgid "Notice" msgid "Notice"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:132 #: src/slic3r/GUI/GUI_App.cpp:133
#, possible-c-format #, possible-c-format
msgid "" msgid ""
"%s has encountered an error. It was likely caused by running out of memory. " "%s has encountered an error. It was likely caused by running out of memory. "
@ -1213,96 +1215,96 @@ msgid ""
"The application will now terminate." "The application will now terminate."
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:135 #: src/slic3r/GUI/GUI_App.cpp:136
msgid "Fatal error" msgid "Fatal error"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:301 #: src/slic3r/GUI/GUI_App.cpp:299
#, possible-c-format #, possible-c-format
msgid "" msgid ""
"PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" "PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n"
"while OpenGL version %s, render %s, vendor %s was detected." "while OpenGL version %s, render %s, vendor %s was detected."
msgstr "" 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." msgid "You may need to update your graphics card driver."
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:307 #: src/slic3r/GUI/GUI_App.cpp:305
msgid "" msgid ""
"As a workaround, you may run PrusaSlicer with a software rendered 3D " "As a workaround, you may run PrusaSlicer with a software rendered 3D "
"graphics by running prusa-slicer.exe with the --sw_renderer parameter." "graphics by running prusa-slicer.exe with the --sw_renderer parameter."
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:309 #: src/slic3r/GUI/GUI_App.cpp:307
msgid "Unsupported OpenGL version" msgid "Unsupported OpenGL version"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:460 #: src/slic3r/GUI/GUI_App.cpp:458
msgid "Changing of an application language" msgid "Changing of an application language"
msgstr "" 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" msgid "Recreating"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:481 #: src/slic3r/GUI/GUI_App.cpp:479
msgid "Loading of current presets" msgid "Loading of current presets"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:489 #: src/slic3r/GUI/GUI_App.cpp:487
msgid "Loading of a mode view" msgid "Loading of a mode view"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:569 #: src/slic3r/GUI/GUI_App.cpp:567
msgid "Choose one file (3MF/AMF):" msgid "Choose one file (3MF/AMF):"
msgstr "" 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):" msgid "Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:617 #: src/slic3r/GUI/GUI_App.cpp:641
msgid "Select the language" msgid "Select the language"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:617 #: src/slic3r/GUI/GUI_App.cpp:641
msgid "Language" msgid "Language"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:776 #: src/slic3r/GUI/GUI_App.cpp:786
msgid "&Configuration Snapshots" msgid "&Configuration Snapshots"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:776 #: src/slic3r/GUI/GUI_App.cpp:786
msgid "Inspect / activate configuration snapshots" msgid "Inspect / activate configuration snapshots"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:777 #: src/slic3r/GUI/GUI_App.cpp:787
msgid "Take Configuration &Snapshot" msgid "Take Configuration &Snapshot"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:777 #: src/slic3r/GUI/GUI_App.cpp:787
msgid "Capture a configuration snapshot" msgid "Capture a configuration snapshot"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:780 #: src/slic3r/GUI/GUI_App.cpp:790
msgid "&Preferences" msgid "&Preferences"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:786 #: src/slic3r/GUI/GUI_App.cpp:796
msgid "Application preferences" msgid "Application preferences"
msgstr "" 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" msgid "Simple"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:789 #: src/slic3r/GUI/GUI_App.cpp:799
msgid "Simple View Mode" msgid "Simple View Mode"
msgstr "" 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/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:1073 src/slic3r/GUI/Tab.cpp:1171
#: src/slic3r/GUI/Tab.cpp:1174 src/slic3r/GUI/Tab.cpp:1682 #: src/slic3r/GUI/Tab.cpp:1174 src/slic3r/GUI/Tab.cpp:1682
@ -1313,77 +1315,98 @@ msgstr ""
msgid "Advanced" msgid "Advanced"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:790 #: src/slic3r/GUI/GUI_App.cpp:800
msgid "Advanced View Mode" msgid "Advanced View Mode"
msgstr "" 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" msgid "Expert"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:791 #: src/slic3r/GUI/GUI_App.cpp:801
msgid "Expert View Mode" msgid "Expert View Mode"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:796 #: src/slic3r/GUI/GUI_App.cpp:806
msgid "Mode" msgid "Mode"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:796 #: src/slic3r/GUI/GUI_App.cpp:806
#, possible-c-format #, possible-c-format
msgid "%s View Mode" msgid "%s View Mode"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:798 #: src/slic3r/GUI/GUI_App.cpp:808
msgid "Change Application &Language" msgid "Change Application &Language"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:800 #: src/slic3r/GUI/GUI_App.cpp:810
msgid "Flash printer &firmware" msgid "Flash printer &firmware"
msgstr "" 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" msgid "Upload a firmware image into an Arduino based printer"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:812 #: src/slic3r/GUI/GUI_App.cpp:822
msgid "Taking configuration snapshot" msgid "Taking configuration snapshot"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:812 #: src/slic3r/GUI/GUI_App.cpp:822
msgid "Snapshot name" msgid "Snapshot name"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:855 #: src/slic3r/GUI/GUI_App.cpp:865
msgid "" msgid ""
"Switching the language will trigger application restart.\n" "Switching the language will trigger application restart.\n"
"You will lose content of the plater." "You will lose content of the plater."
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:857 #: src/slic3r/GUI/GUI_App.cpp:867
msgid "Do you want to proceed?" msgid "Do you want to proceed?"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:858 #: src/slic3r/GUI/GUI_App.cpp:868
msgid "Language selection" msgid "Language selection"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:881 #: src/slic3r/GUI/GUI_App.cpp:891
msgid "&Configuration" msgid "&Configuration"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:903 #: src/slic3r/GUI/GUI_App.cpp:913
msgid "The presets on the following tabs were modified" msgid "The presets on the following tabs were modified"
msgstr "" 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?" msgid "Discard changes and continue anyway?"
msgstr "" msgstr ""
#: src/slic3r/GUI/GUI_App.cpp:906 #: src/slic3r/GUI/GUI_App.cpp:916
msgid "Unsaved Presets" msgid "Unsaved Presets"
msgstr "" 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:34 src/slic3r/GUI/GUI_ObjectList.cpp:88
#: src/slic3r/GUI/GUI_ObjectList.cpp:611 src/libslic3r/PrintConfig.cpp:67 #: src/slic3r/GUI/GUI_ObjectList.cpp:611 src/libslic3r/PrintConfig.cpp:67
#: src/libslic3r/PrintConfig.cpp:160 src/libslic3r/PrintConfig.cpp:392 #: src/libslic3r/PrintConfig.cpp:160 src/libslic3r/PrintConfig.cpp:392
@ -4050,10 +4073,6 @@ msgstr ""
msgid "Layers and perimeters" msgid "Layers and perimeters"
msgstr "" msgstr ""
#: src/slic3r/GUI/Tab.cpp:1030 src/libslic3r/PrintConfig.cpp:66
msgid "Layer height"
msgstr ""
#: src/slic3r/GUI/Tab.cpp:1034 #: src/slic3r/GUI/Tab.cpp:1034
msgid "Vertical shells" msgid "Vertical shells"
msgstr "" msgstr ""

View file

@ -18,6 +18,7 @@ src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
src/slic3r/GUI/Gizmos/GLGizmosManager.cpp src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
src/slic3r/GUI/GUI.cpp src/slic3r/GUI/GUI.cpp
src/slic3r/GUI/GUI_App.cpp src/slic3r/GUI/GUI_App.cpp
src/slic3r/GUI/GUI_ObjectLayers.cpp
src/slic3r/GUI/GUI_ObjectList.cpp src/slic3r/GUI/GUI_ObjectList.cpp
src/slic3r/GUI/GUI_ObjectManipulation.cpp src/slic3r/GUI/GUI_ObjectManipulation.cpp
src/slic3r/GUI/GUI_ObjectSettings.cpp src/slic3r/GUI/GUI_ObjectSettings.cpp

View file

@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <exception> #include <exception>
#include <cstdlib>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
@ -229,11 +230,8 @@ bool GUI_App::on_init_inner()
init_label_colours(); init_label_colours();
init_fonts(); init_fonts();
wxString language = wxEmptyString;
if (app_config->has("translation_language"))
language = app_config->get("translation_language");
// If load_language() fails, the application closes. // If load_language() fails, the application closes.
load_language(language); load_language(wxString(), true);
// Suppress the '- default -' presets. // Suppress the '- default -' presets.
preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1"); preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1");
@ -600,132 +598,156 @@ bool GUI_App::switch_language()
// select language from the list of installed languages // select language from the list of installed languages
bool GUI_App::select_language() bool GUI_App::select_language()
{ {
const std::vector<const wxLanguageInfo*> langs = get_installed_languages(); wxArrayString translations = wxTranslations::Get()->GetAvailableTranslations(SLIC3R_APP_KEY);
std::vector<const wxLanguageInfo*> 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; wxArrayString names;
names.Alloc(langs.size()); names.Alloc(language_infos.size());
// Some valid language should be selected since the application start up. // Some valid language should be selected since the application start up.
assert(m_wxLocale != nullptr); const wxLanguage current_language = wxLanguage(m_wxLocale->GetLanguage());
const auto current_language = m_wxLocale->GetLanguage(); int init_selection = -1;
int init_selection = 0; int init_selection_alt = -1;
for (size_t i = 0; i < langs.size(); ++ i) { int init_selection_default = -1;
if (langs[i]->Language == current_language) 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; 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. // 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)) {
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. // Save language at application config.
app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data()); app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data());
app_config->save(); app_config->save();
return true; return true;
} }
return false;
} }
// Get the language code before underscore, if there is underscore. return false;
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, // Load gettext translation files and activate them at the start of the application,
// based on the "translation_language" key stored in the application config. // 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()) { if (initial) {
int lang = wxLocale::GetSystemLanguage(); // There is a static list of lookup path prefixes in wxWidgets. Add ours.
if (lang != wxLANGUAGE_UNKNOWN) { wxFileTranslationsLoader::AddCatalogLookupPathPrefix(from_u8(localization_dir()));
const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); // Get the active language from PrusaSlicer.ini, or empty string if the key does not exist.
if (info != nullptr) language = app_config->get("translation_language");
language = info->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;
// 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())
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()) if (language.IsEmpty())
language = "en_US"; 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. // Alternate language code.
wxString language_code_alt = language_code_short(language); wxLanguage language_dict = wxLanguage(language_info->Language);
if (language_code_alt == "sk") if (language.BeforeFirst('_') == "sk")
// Slovaks understand Czech well. Give them the Czech translation. // Slovaks understand Czech well. Give them the Czech translation.
language_code_alt = "cz"; language_dict = wxLANGUAGE_CZECH;
const wxLanguageInfo *info = nullptr; if (! wxLocale::IsAvailable(language_info->Language)) {
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)) {
// Loading the language dictionary failed. // 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__) #if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux system // likely some linux system
"\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n"; message += "\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n";
#endif #endif
delete new_locale; if (initial)
if (m_wxLocale == nullptr)
message + "\n\nApplication will close."; message + "\n\nApplication will close.";
wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR); wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR);
if (m_wxLocale == nullptr) if (initial)
std::terminate(); std::exit(EXIT_FAILURE);
else else
return false; return false;
} }
wxLocale *old_locale = m_wxLocale;
m_wxLocale = new_locale; // Release the old locales, create new locales.
m_wxLocale->AddCatalogLookupPathPrefix(from_u8(localization_dir())); //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<wxLocale>();
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_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. //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
wxSetlocale(LC_NUMERIC, "C"); wxSetlocale(LC_NUMERIC, "C");
Preset::update_suffix_modified(); Preset::update_suffix_modified();
//FIXME Why the following line crashes?
// delete old_locale;
return true; return true;
} }
// Get a list of installed languages (languages for which we have dictionaries).
std::vector<const wxLanguageInfo*> GUI_App::get_installed_languages()
{
wxDir dir(from_u8(localization_dir()));
wxString filename;
std::vector<const wxLanguageInfo*> 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) Tab* GUI_App::get_tab(Preset::Type type)
{ {
for (Tab* tab: tabs_list) for (Tab* tab: tabs_list)
@ -1019,7 +1041,7 @@ wxString GUI_App::current_language_code_safe() const
{ "uk", "uk_UA", }, { "uk", "uk_UA", },
{ "zh", "zh_CN", }, { "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); auto it = mapping.find(language_code);
if (it != mapping.end()) if (it != mapping.end())
language_code = it->second; language_code = it->second;

View file

@ -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 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 // 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<wxLocale> 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<ImGuiWrapper> m_imgui; std::unique_ptr<ImGuiWrapper> m_imgui;
std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue; std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue;
@ -132,7 +136,7 @@ public:
void update_ui_from_settings(); void update_ui_from_settings();
bool switch_language(); bool switch_language();
bool load_language(wxString language); bool load_language(wxString language, bool initial);
Tab* get_tab(Preset::Type type); Tab* get_tab(Preset::Type type);
ConfigOptionMode get_mode(); ConfigOptionMode get_mode();
@ -144,7 +148,7 @@ public:
bool checked_tab(Tab* tab); bool checked_tab(Tab* tab);
void load_current_presets(); 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". // Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
wxString current_language_code_safe() const; wxString current_language_code_safe() const;
@ -187,7 +191,6 @@ private:
void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false); void window_pos_restore(wxTopLevelWindow* window, const std::string &name, bool default_maximized = false);
void window_pos_sanitize(wxTopLevelWindow* window); void window_pos_sanitize(wxTopLevelWindow* window);
bool select_language(); bool select_language();
std::vector<const wxLanguageInfo*> get_installed_languages();
#ifdef __WXMSW__ #ifdef __WXMSW__
void associate_3mf_files(); void associate_3mf_files();
#endif // __WXMSW__ #endif // __WXMSW__