From f347ebff1507ee20febc441f1ee93d8fb23ce46f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Wed, 22 Apr 2015 12:57:36 +0200 Subject: [PATCH 01/12] Add support for language selection in preferences --- spyderlib/baseconfig.py | 97 +++++++++++++++++++++++++++++-- spyderlib/config.py | 3 +- spyderlib/plugins/configdialog.py | 65 +++++++++++++++++++-- spyderlib/utils/iofuncs.py | 3 +- 4 files changed, 155 insertions(+), 13 deletions(-) diff --git a/spyderlib/baseconfig.py b/spyderlib/baseconfig.py index 7a53974e25c..483119aeebf 100644 --- a/spyderlib/baseconfig.py +++ b/spyderlib/baseconfig.py @@ -14,6 +14,7 @@ from __future__ import print_function +import locale import os.path as osp import os import sys @@ -204,18 +205,102 @@ def get_image_path(name, default="not_found.png"): #============================================================================== # Translations #============================================================================== +LANG_FILE = osp.join(get_conf_path(), '.langconfig') +DEFAULT_LANGUAGE = 'en' + +# This needs to be updated every time a new language is added to spyder. +LANGUAGE_CODES = {'en': u'English', + 'fr': u'Français', + 'es': u'Español', + 'pt_BR': u'Português (brasileiro)' + } + + +def get_available_translations(): + """ + List available translations for spyder based on the folders found in the + locale folder. + """ + locale_path = get_module_data_path("spyderlib", relpath="locale", + attr_name='LOCALEPATH') + listdir = os.listdir(locale_path) + langs = [d for d in listdir if osp.isdir(osp.join(locale_path, d))] + langs = [DEFAULT_LANGUAGE] + langs + + # Check that there is a language code available in case a new translation + # is added, to ensure LANGUAGE_CODES is updated. + for lang in langs: + if lang not in LANGUAGE_CODES: + error = _('Update LANGUAGE_CODES if a new translation has been ' + 'added to Spyder') + raise Exception(error) + return langs + + +def get_interface_language(): + """ + If Spyder has a translation available for the locale language, it will + return the version provided by Spyder adjusted for language subdifferences, + otherwise it will return DEFAULT_LANGUAGE. + + Example: + 1.) Spyder provides ('en', 'fr', 'es' and 'pt_BR'), if the locale is + either 'en_US' or 'en' or 'en_UK', this function will return 'en' + + 2.) Spyder provides ('en', 'fr', 'es' and 'pt_BR'), if the locale is + either 'pt' or 'pt_BR', this function will return 'pt_BR' + """ + locale_language = locale.getdefaultlocale()[0] + + if locale_language is None: + language = DEFAULT_LANGUAGE + else: + spyder_languages = get_available_translations() + for spyder_language in spyder_languages: + if locale_language == spyder_language: + language = locale_language + break + elif locale_language.startswith(spyder_language) or\ + spyder_language.startswith(locale_language): + language = spyder_language + break + + return language + + +def save_lang_conf(value): + """Save language setting to language config file""" + with open(LANG_FILE, 'w') as f: + f.write(value) + + +def load_lang_conf(): + """ + Load language setting from language config file if it exists, otherwise + try to use the local settings if Spyder provides a translation, or + return the default if no translation provided. + """ + if osp.isfile(LANG_FILE): + with open(LANG_FILE, 'r') as f: + lang = f.read() + else: + lang = get_interface_language() + save_lang_conf(lang) + return lang + + def get_translation(modname, dirname=None): """Return translation callback for module *modname*""" if dirname is None: dirname = modname locale_path = get_module_data_path(dirname, relpath="locale", attr_name='LOCALEPATH') - # fixup environment var LANG in case it's unknown - if "LANG" not in os.environ: - import locale - lang = locale.getdefaultlocale()[0] - if lang is not None: - os.environ["LANG"] = lang + + # fixup environment var LANG, LANGUAGE + language = load_lang_conf() + os.environ["LANG"] = language # Works in windows + os.environ["LANGUAGE"] = language # Works in ubuntu + import gettext try: _trans = gettext.translation(modname, locale_path, codeset="utf-8") diff --git a/spyderlib/config.py b/spyderlib/config.py index 88228f779a5..18413fe9ca3 100644 --- a/spyderlib/config.py +++ b/spyderlib/config.py @@ -18,7 +18,7 @@ # Local import from spyderlib.userconfig import UserConfig from spyderlib.baseconfig import (CHECK_ALL, EXCLUDED_NAMES, SUBFOLDER, - get_home_dir, _) + get_home_dir, _, load_lang_conf) from spyderlib.utils import iofuncs, codeanalysis @@ -169,6 +169,7 @@ def is_ubuntu(): 'animated_docks': True, 'prompt_on_exit': False, 'panes_locked': True, + 'interface_language': load_lang_conf(), 'window/size': (1260, 740), 'window/position': (10, 10), 'window/is_maximized': True, diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index 4dc33d9ebec..99e80e916e5 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -21,7 +21,8 @@ from spyderlib.qt.compat import (to_qvariant, from_qvariant, getexistingdirectory, getopenfilename) -from spyderlib.baseconfig import _, running_in_mac_app +from spyderlib.baseconfig import (_, running_in_mac_app, LANGUAGE_CODES, + get_available_translations, save_lang_conf) from spyderlib.config import CONF from spyderlib.guiconfig import (CUSTOM_COLOR_SCHEME_NAME, set_default_color_scheme) @@ -90,6 +91,12 @@ def apply_changes(self): self.save_to_conf() if self.apply_callback is not None: self.apply_callback() + # Since the language cannot be retrieved by CONF and the language + # is needed before loading CONF, this is an extra method needed to + # ensure when changes are applied, they are copied to a specific + # file storing the language value. + if getattr(self, 'save_lang', False): + self.save_lang() self.set_modified(False) def load_from_conf(self): @@ -192,6 +199,7 @@ def current_page_changed(self, index): self.apply_btn.setEnabled(widget.is_modified) def add_page(self, widget): + setattr(widget, 'parent_config_dialog', self) self.check_settings.connect(widget.check_settings) widget.show_this_page.connect(lambda row=self.contents_widget.count(): self.contents_widget.setCurrentRow(row)) @@ -238,6 +246,7 @@ def __init__(self, parent): self.coloredits = {} self.scedits = {} self.changed_options = set() + self.options_restart = set() self.default_button_group = None def apply_settings(self, options): @@ -301,6 +310,9 @@ def load_from_conf(self): combobox.setCurrentIndex(index) combobox.currentIndexChanged.connect(lambda _foo, opt=option: self.has_been_modified(opt)) + if combobox.restart_required: + self.options_restart.add(option) + for (fontbox, sizebox), option in list(self.fontboxes.items()): font = self.get_font(option) fontbox.setCurrentFont(font) @@ -344,7 +356,7 @@ def load_from_conf(self): else: cb_italic.clicked.connect(lambda opt=option: self.has_been_modified(opt)) - + def save_to_conf(self): """Save settings to configuration file""" for checkbox, (option, _default) in list(self.checkboxes.items()): @@ -374,7 +386,11 @@ def save_to_conf(self): def has_been_modified(self, option): self.set_modified(True) self.changed_options.add(option) - + + # If the option requires restart, prompt the user + if option in self.options_restart: + self.prompt_restart_required(option) + def create_checkbox(self, text, option, default=NoDefault, tip=None, msg_warning=None, msg_info=None, msg_if_enabled=False): @@ -579,7 +595,7 @@ def create_scedit(self, text, option, default=NoDefault, tip=None, return widget def create_combobox(self, text, choices, option, default=NoDefault, - tip=None): + tip=None, restart=False): """choices: couples (name, key)""" label = QLabel(text) combobox = QComboBox() @@ -595,6 +611,7 @@ def create_combobox(self, text, choices, option, default=NoDefault, layout.setContentsMargins(0, 0, 0, 0) widget = QWidget(self) widget.setLayout(layout) + combobox.restart_required = restart return widget def create_fontgroup(self, option=None, text=None, @@ -661,13 +678,27 @@ def get_icon(self): def apply_settings(self, options): raise NotImplementedError + def apply_restart_actions(self, option): + """Actions to be applied if the user accepts restarting right away.""" + raise NotImplementedError + + def prompt_restart_required(self, option): + """Prompt the user with a request to restart.""" + answer = QMessageBox.information(self, _("Information"), + _("To change this setting Spyder " + "needs to restart.\n\n" + "Do you wish to restart now?\n"), + QMessageBox.Yes | QMessageBox.No) + if answer == QMessageBox.Yes: + self.apply_restart_actions(option) + class MainConfigPage(GeneralConfigPage): CONF_SECTION = "main" NAME = _("General") ICON = "genprefs.png" - + def setup_page(self): newcb = self.create_checkbox @@ -704,6 +735,13 @@ def setup_page(self): margins_layout.addWidget(margin_spin) prompt_box = newcb(_("Prompt when exiting"), 'prompt_on_exit') + # Language chooser + langs = get_available_translations() + choices = list(zip([LANGUAGE_CODES[key] for key in langs], langs)) + language_combo = self.create_combobox(_('Language'), choices, + 'interface_language', + restart=True) + # Decide if it's possible to activate or not singie instance mode if running_in_mac_app(): self.set_option("single_instance", True) @@ -711,6 +749,7 @@ def setup_page(self): interface_layout = QVBoxLayout() interface_layout.addWidget(style_combo) + interface_layout.addWidget(language_combo) interface_layout.addWidget(single_instance_box) interface_layout.addWidget(vertdock_box) interface_layout.addWidget(verttabs_box) @@ -777,6 +816,22 @@ def setup_page(self): def apply_settings(self, options): self.main.apply_settings() + def apply_restart_actions(self, option): + self.apply_changes() + if option == 'interface_language': + self.save_lang() + self.main.restart() + + def save_lang(self): + """Get selected language setting and save to '.langconfig file'.""" + for combobox, (option, _default) in list(self.comboboxes.items()): + if option == 'interface_language': + data = combobox.itemData(combobox.currentIndex()) + value = from_qvariant(data, to_text_string) + break + save_lang_conf(value) + self.set_option('interface_language', value) + class ColorSchemeConfigPage(GeneralConfigPage): CONF_SECTION = "color_schemes" diff --git a/spyderlib/utils/iofuncs.py b/spyderlib/utils/iofuncs.py index e148bb068a4..defc671a31a 100644 --- a/spyderlib/utils/iofuncs.py +++ b/spyderlib/utils/iofuncs.py @@ -362,7 +362,8 @@ def load_dictionary(filename): 'spyder.ini', 'temp.py', 'temp.spydata', 'template.py', 'history.py', 'history_internal.py', 'workingdir', '.projects', '.spyderproject', '.ropeproject', - 'monitor.log', 'monitor_debug.log', 'rope.log') + 'monitor.log', 'monitor_debug.log', 'rope.log', + '.langconfig') def reset_session(): """Remove all config files""" From bdac181c1a77b26ad02d9e68c4665c166946aecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 26 Apr 2015 12:37:50 +0200 Subject: [PATCH 02/12] Rename LANGCONF file. Minor language display fix. --- spyderlib/baseconfig.py | 8 ++++---- spyderlib/utils/iofuncs.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spyderlib/baseconfig.py b/spyderlib/baseconfig.py index 483119aeebf..d3808f3513b 100644 --- a/spyderlib/baseconfig.py +++ b/spyderlib/baseconfig.py @@ -205,14 +205,14 @@ def get_image_path(name, default="not_found.png"): #============================================================================== # Translations #============================================================================== -LANG_FILE = osp.join(get_conf_path(), '.langconfig') +LANG_FILE = osp.join(get_conf_path(), 'langconfig') DEFAULT_LANGUAGE = 'en' # This needs to be updated every time a new language is added to spyder. LANGUAGE_CODES = {'en': u'English', 'fr': u'Français', 'es': u'Español', - 'pt_BR': u'Português (brasileiro)' + 'pt_BR': u'Português' } @@ -231,8 +231,8 @@ def get_available_translations(): # is added, to ensure LANGUAGE_CODES is updated. for lang in langs: if lang not in LANGUAGE_CODES: - error = _('Update LANGUAGE_CODES if a new translation has been ' - 'added to Spyder') + error = _('Update LANGUAGE_CODES (inside baseconfig.py) if a new ' + 'translation has been added to Spyder') raise Exception(error) return langs diff --git a/spyderlib/utils/iofuncs.py b/spyderlib/utils/iofuncs.py index defc671a31a..51965d591ef 100644 --- a/spyderlib/utils/iofuncs.py +++ b/spyderlib/utils/iofuncs.py @@ -363,7 +363,7 @@ def load_dictionary(filename): 'history.py', 'history_internal.py', 'workingdir', '.projects', '.spyderproject', '.ropeproject', 'monitor.log', 'monitor_debug.log', 'rope.log', - '.langconfig') + 'langconfig') def reset_session(): """Remove all config files""" From 3c49cb2a57b1a0e0ee63c0b1fd2c68991bca21aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 26 Apr 2015 13:37:14 +0200 Subject: [PATCH 03/12] Remove undeed code in preferences manager --- spyderlib/plugins/configdialog.py | 1 - 1 file changed, 1 deletion(-) diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index 99e80e916e5..a5a8b9c0ac9 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -199,7 +199,6 @@ def current_page_changed(self, index): self.apply_btn.setEnabled(widget.is_modified) def add_page(self, widget): - setattr(widget, 'parent_config_dialog', self) self.check_settings.connect(widget.check_settings) widget.show_this_page.connect(lambda row=self.contents_widget.count(): self.contents_widget.setCurrentRow(row)) From 5d8e05b75c72a1ea90dd47dfa21e8a8912443358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 12:20:55 +0200 Subject: [PATCH 04/12] Ask for restart when clicking Apply or Ok only --- spyderlib/plugins/configdialog.py | 58 +++++++++++++++++++------------ 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index a5a8b9c0ac9..bf0c8d3e459 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -93,10 +93,14 @@ def apply_changes(self): self.apply_callback() # Since the language cannot be retrieved by CONF and the language # is needed before loading CONF, this is an extra method needed to - # ensure when changes are applied, they are copied to a specific - # file storing the language value. + # ensure that when changes are applied, they are copied to a + # specific file storing the language value. if getattr(self, 'save_lang', False): self.save_lang() + + if self.options_restart: + self.prompt_restart_required() + self.set_modified(False) def load_from_conf(self): @@ -245,7 +249,7 @@ def __init__(self, parent): self.coloredits = {} self.scedits = {} self.changed_options = set() - self.options_restart = set() + self.options_restart = dict() # Dict to store name and localized text self.default_button_group = None def apply_settings(self, options): @@ -310,8 +314,8 @@ def load_from_conf(self): combobox.currentIndexChanged.connect(lambda _foo, opt=option: self.has_been_modified(opt)) if combobox.restart_required: - self.options_restart.add(option) - + self.options_restart[option] = combobox.label_text + for (fontbox, sizebox), option in list(self.fontboxes.items()): font = self.get_font(option) fontbox.setCurrentFont(font) @@ -387,8 +391,8 @@ def has_been_modified(self, option): self.changed_options.add(option) # If the option requires restart, prompt the user - if option in self.options_restart: - self.prompt_restart_required(option) +# if option in self.options_restart: +# self.prompt_restart_required(option) def create_checkbox(self, text, option, default=NoDefault, tip=None, msg_warning=None, msg_info=None, @@ -611,6 +615,7 @@ def create_combobox(self, text, choices, option, default=NoDefault, widget = QWidget(self) widget.setLayout(layout) combobox.restart_required = restart + combobox.label_text = text return widget def create_fontgroup(self, option=None, text=None, @@ -677,19 +682,32 @@ def get_icon(self): def apply_settings(self, options): raise NotImplementedError - def apply_restart_actions(self, option): - """Actions to be applied if the user accepts restarting right away.""" - raise NotImplementedError - - def prompt_restart_required(self, option): + def prompt_restart_required(self): """Prompt the user with a request to restart.""" - answer = QMessageBox.information(self, _("Information"), - _("To change this setting Spyder " - "needs to restart.\n\n" - "Do you wish to restart now?\n"), + options = self.options_restart + + if len(options) == 1: + msg_start = _("Spyder needs to restart to change the following " + "setting:") + else: + msg_start = _("Spyder needs to restart to change the following " + "settings:") + msg_end = _("Do you wish to restart now?") + + msg_options = "" + for option, localized_option in options.items(): + msg_options += "
  • {0}
  • ".format(localized_option) + + msg_title = _("Information") + msg = "{0}
      {1}

    {2}".format(msg_start, msg_options, msg_end) + answer = QMessageBox.information(self, msg_title, msg, QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: - self.apply_restart_actions(option) + self.restart() + + def restart(self): + """Restart Spyder.""" + self.main.restart() class MainConfigPage(GeneralConfigPage): @@ -815,12 +833,6 @@ def setup_page(self): def apply_settings(self, options): self.main.apply_settings() - def apply_restart_actions(self, option): - self.apply_changes() - if option == 'interface_language': - self.save_lang() - self.main.restart() - def save_lang(self): """Get selected language setting and save to '.langconfig file'.""" for combobox, (option, _default) in list(self.comboboxes.items()): From 2c7a6a78d01c8a1abe0db75b192cf033f87ddd36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 13:00:31 +0200 Subject: [PATCH 05/12] Ask for restart only if an option that requires it, is changed --- spyderlib/plugins/configdialog.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index bf0c8d3e459..ef3dc2aef92 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -98,8 +98,10 @@ def apply_changes(self): if getattr(self, 'save_lang', False): self.save_lang() - if self.options_restart: - self.prompt_restart_required() + for restart_option in self.restart_options: + if restart_option in self.changed_options: + self.prompt_restart_required() + break self.set_modified(False) @@ -249,7 +251,7 @@ def __init__(self, parent): self.coloredits = {} self.scedits = {} self.changed_options = set() - self.options_restart = dict() # Dict to store name and localized text + self.restart_options = dict() # Dict to store name and localized text self.default_button_group = None def apply_settings(self, options): @@ -314,7 +316,7 @@ def load_from_conf(self): combobox.currentIndexChanged.connect(lambda _foo, opt=option: self.has_been_modified(opt)) if combobox.restart_required: - self.options_restart[option] = combobox.label_text + self.restart_options[option] = combobox.label_text for (fontbox, sizebox), option in list(self.fontboxes.items()): font = self.get_font(option) @@ -390,10 +392,6 @@ def has_been_modified(self, option): self.set_modified(True) self.changed_options.add(option) - # If the option requires restart, prompt the user -# if option in self.options_restart: -# self.prompt_restart_required(option) - def create_checkbox(self, text, option, default=NoDefault, tip=None, msg_warning=None, msg_info=None, msg_if_enabled=False): @@ -684,7 +682,9 @@ def apply_settings(self, options): def prompt_restart_required(self): """Prompt the user with a request to restart.""" - options = self.options_restart + restart_opt = self.restart_options + changed_opt = self.changed_options + options = [restart_opt[o] for o in changed_opt if o in restart_opt] if len(options) == 1: msg_start = _("Spyder needs to restart to change the following " @@ -695,8 +695,8 @@ def prompt_restart_required(self): msg_end = _("Do you wish to restart now?") msg_options = "" - for option, localized_option in options.items(): - msg_options += "
  • {0}
  • ".format(localized_option) + for option in options: + msg_options += "
  • {0}
  • ".format(option) msg_title = _("Information") msg = "{0}
      {1}

    {2}".format(msg_start, msg_options, msg_end) From 90c2b936efba94d8088bdcb0a1dd256b85136279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 13:05:19 +0200 Subject: [PATCH 06/12] Fix docstring --- spyderlib/plugins/configdialog.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index ef3dc2aef92..895f6072eca 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -834,7 +834,9 @@ def apply_settings(self, options): self.main.apply_settings() def save_lang(self): - """Get selected language setting and save to '.langconfig file'.""" + """ + Get selected language setting and save to language configuration file. + """ for combobox, (option, _default) in list(self.comboboxes.items()): if option == 'interface_language': data = combobox.itemData(combobox.currentIndex()) From b79ff924c2475f92967214887410b19ccff6ba63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 17:09:07 +0200 Subject: [PATCH 07/12] Rename variables for clarity, minor fixes --- spyderlib/baseconfig.py | 14 +++++++------- spyderlib/plugins/configdialog.py | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/spyderlib/baseconfig.py b/spyderlib/baseconfig.py index d3808f3513b..db5cd3fd815 100644 --- a/spyderlib/baseconfig.py +++ b/spyderlib/baseconfig.py @@ -256,13 +256,13 @@ def get_interface_language(): language = DEFAULT_LANGUAGE else: spyder_languages = get_available_translations() - for spyder_language in spyder_languages: - if locale_language == spyder_language: + for lang in spyder_languages: + if locale_language == lang: language = locale_language break - elif locale_language.startswith(spyder_language) or\ - spyder_language.startswith(locale_language): - language = spyder_language + elif locale_language.startswith(lang) or \ + lang.startswith(locale_language): + language = lang break return language @@ -298,8 +298,8 @@ def get_translation(modname, dirname=None): # fixup environment var LANG, LANGUAGE language = load_lang_conf() - os.environ["LANG"] = language # Works in windows - os.environ["LANGUAGE"] = language # Works in ubuntu + os.environ["LANG"] = language # Works on Windows + os.environ["LANGUAGE"] = language # Works on Linux import gettext try: diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index 895f6072eca..1dcf19cd61b 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -91,6 +91,8 @@ def apply_changes(self): self.save_to_conf() if self.apply_callback is not None: self.apply_callback() + self.set_modified(False) + # Since the language cannot be retrieved by CONF and the language # is needed before loading CONF, this is an extra method needed to # ensure that when changes are applied, they are copied to a @@ -101,10 +103,8 @@ def apply_changes(self): for restart_option in self.restart_options: if restart_option in self.changed_options: self.prompt_restart_required() - break + break # Ensure a single popup is displayed - self.set_modified(False) - def load_from_conf(self): """Load settings from configuration file""" raise NotImplementedError @@ -682,9 +682,9 @@ def apply_settings(self, options): def prompt_restart_required(self): """Prompt the user with a request to restart.""" - restart_opt = self.restart_options - changed_opt = self.changed_options - options = [restart_opt[o] for o in changed_opt if o in restart_opt] + restart_opts = self.restart_options + changed_opts = self.changed_options + options = [restart_opts[o] for o in changed_opts if o in restart_opts] if len(options) == 1: msg_start = _("Spyder needs to restart to change the following " From f8ce02805f805ff00d2e6fdfa71ad74aefd1aeb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 18:18:38 +0200 Subject: [PATCH 08/12] Minor fixes, added extra comments, simplify code --- spyderlib/baseconfig.py | 9 ++++++--- spyderlib/plugins/configdialog.py | 7 +++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/spyderlib/baseconfig.py b/spyderlib/baseconfig.py index db5cd3fd815..1881e8b3bb7 100644 --- a/spyderlib/baseconfig.py +++ b/spyderlib/baseconfig.py @@ -205,10 +205,11 @@ def get_image_path(name, default="not_found.png"): #============================================================================== # Translations #============================================================================== -LANG_FILE = osp.join(get_conf_path(), 'langconfig') +LANG_FILE = get_conf_path('langconfig') DEFAULT_LANGUAGE = 'en' -# This needs to be updated every time a new language is added to spyder. +# This needs to be updated every time a new language is added to spyder, and is +# used by the Preferences configuration to populate the Language QComboBox LANGUAGE_CODES = {'en': u'English', 'fr': u'Français', 'es': u'Español', @@ -219,7 +220,9 @@ def get_image_path(name, default="not_found.png"): def get_available_translations(): """ List available translations for spyder based on the folders found in the - locale folder. + locale folder. This function checks if LANGUAGE_CODES contain the same + information that is found in the 'locale' folder to ensure that when a new + language is added, LANGUAGE_CODES is updated. """ locale_path = get_module_data_path("spyderlib", relpath="locale", attr_name='LOCALEPATH') diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index 1dcf19cd61b..05616d6f83d 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -22,7 +22,7 @@ getexistingdirectory, getopenfilename) from spyderlib.baseconfig import (_, running_in_mac_app, LANGUAGE_CODES, - get_available_translations, save_lang_conf) + save_lang_conf) from spyderlib.config import CONF from spyderlib.guiconfig import (CUSTOM_COLOR_SCHEME_NAME, set_default_color_scheme) @@ -91,7 +91,6 @@ def apply_changes(self): self.save_to_conf() if self.apply_callback is not None: self.apply_callback() - self.set_modified(False) # Since the language cannot be retrieved by CONF and the language # is needed before loading CONF, this is an extra method needed to @@ -104,6 +103,7 @@ def apply_changes(self): if restart_option in self.changed_options: self.prompt_restart_required() break # Ensure a single popup is displayed + self.set_modified(False) def load_from_conf(self): """Load settings from configuration file""" @@ -753,8 +753,7 @@ def setup_page(self): prompt_box = newcb(_("Prompt when exiting"), 'prompt_on_exit') # Language chooser - langs = get_available_translations() - choices = list(zip([LANGUAGE_CODES[key] for key in langs], langs)) + choices = sorted([(val, key) for key, val in LANGUAGE_CODES.items()]) language_combo = self.create_combobox(_('Language'), choices, 'interface_language', restart=True) From 5bae10be0773ab2a3b3a2a943606ab49e4d69d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Sun, 3 May 2015 20:30:34 +0200 Subject: [PATCH 09/12] Add environment variable on unix os to set default encoding --- spyderlib/spyder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spyderlib/spyder.py b/spyderlib/spyder.py index dcf4774eaca..d394dee807c 100644 --- a/spyderlib/spyder.py +++ b/spyderlib/spyder.py @@ -2743,6 +2743,9 @@ def restart(self): startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW shell = False else: + # This environment variable is needed so that the new python + # process spawned with Popen sets this as the default encoding + env['PYTHONIOENCODING'] = 'utf-8' startupinfo = None shell = True From ea40c03238f17a253c17c3099f10be542f34c097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Thu, 7 May 2015 20:23:31 +0200 Subject: [PATCH 10/12] Fix debug_print encoding errors --- spyderlib/baseconfig.py | 12 ++++++++++-- spyderlib/spyder.py | 3 --- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/spyderlib/baseconfig.py b/spyderlib/baseconfig.py index 1881e8b3bb7..471dab1e61c 100644 --- a/spyderlib/baseconfig.py +++ b/spyderlib/baseconfig.py @@ -14,6 +14,7 @@ from __future__ import print_function +import codecs import locale import os.path as osp import os @@ -40,7 +41,8 @@ #============================================================================== # Debug helpers #============================================================================== -STDOUT = sys.stdout +# This is needed after restarting and using debug_print +STDOUT = sys.stdout if PY3 else codecs.getwriter('utf-8')(sys.stdout) STDERR = sys.stderr def _get_debug_env(): debug_env = os.environ.get('SPYDER_DEBUG', '') @@ -53,7 +55,13 @@ def debug_print(*message): """Output debug messages to stdout""" if DEBUG: ss = STDOUT - print(*message, file=ss) + if PY3: + # This is needed after restarting and using debug_print + for m in message: + ss.buffer.write(str(m).encode('utf-8')) + print('', file=ss) + else: + print(*message, file=ss) #============================================================================== # Configuration paths diff --git a/spyderlib/spyder.py b/spyderlib/spyder.py index d394dee807c..dcf4774eaca 100644 --- a/spyderlib/spyder.py +++ b/spyderlib/spyder.py @@ -2743,9 +2743,6 @@ def restart(self): startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW shell = False else: - # This environment variable is needed so that the new python - # process spawned with Popen sets this as the default encoding - env['PYTHONIOENCODING'] = 'utf-8' startupinfo = None shell = True From 8285af5c82963c510689a50e381070deeaba4338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Wed, 27 May 2015 15:23:08 +0200 Subject: [PATCH 11/12] Create language conf entry on first run --- spyderlib/config.py | 4 +++- spyderlib/plugins/configdialog.py | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/spyderlib/config.py b/spyderlib/config.py index 18413fe9ca3..ca371d39c4a 100644 --- a/spyderlib/config.py +++ b/spyderlib/config.py @@ -169,7 +169,6 @@ def is_ubuntu(): 'animated_docks': True, 'prompt_on_exit': False, 'panes_locked': True, - 'interface_language': load_lang_conf(), 'window/size': (1260, 740), 'window/position': (10, 10), 'window/is_maximized': True, @@ -725,6 +724,9 @@ def is_ubuntu(): CONF = UserConfig('spyder', defaults=DEFAULTS, load=True, version=CONF_VERSION, subfolder=SUBFOLDER, backup=True, raw_mode=True) +# Ensures that the config is present on spyder first run +CONF.set('main', 'interface_language', load_lang_conf()) + # Removing old .spyder.ini location: old_location = osp.join(get_home_dir(), '.spyder.ini') if osp.isfile(old_location): diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index 05616d6f83d..cfd8be496e9 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -95,9 +95,10 @@ def apply_changes(self): # Since the language cannot be retrieved by CONF and the language # is needed before loading CONF, this is an extra method needed to # ensure that when changes are applied, they are copied to a - # specific file storing the language value. - if getattr(self, 'save_lang', False): - self.save_lang() + # specific file storing the language value. This only applies to + # the main section config. + if self.CONF_SECTION == u'main': + self._save_lang() for restart_option in self.restart_options: if restart_option in self.changed_options: @@ -832,7 +833,7 @@ def setup_page(self): def apply_settings(self, options): self.main.apply_settings() - def save_lang(self): + def _save_lang(self): """ Get selected language setting and save to language configuration file. """ From 8a3d66482e36e1301615b3920222453896bd2b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Pe=C3=B1a?= Date: Fri, 29 May 2015 19:20:46 +0200 Subject: [PATCH 12/12] Add lang loading for first spyder run in preferences config dialog --- spyderlib/config.py | 5 +---- spyderlib/plugins/configdialog.py | 5 ++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spyderlib/config.py b/spyderlib/config.py index ca371d39c4a..88228f779a5 100644 --- a/spyderlib/config.py +++ b/spyderlib/config.py @@ -18,7 +18,7 @@ # Local import from spyderlib.userconfig import UserConfig from spyderlib.baseconfig import (CHECK_ALL, EXCLUDED_NAMES, SUBFOLDER, - get_home_dir, _, load_lang_conf) + get_home_dir, _) from spyderlib.utils import iofuncs, codeanalysis @@ -724,9 +724,6 @@ def is_ubuntu(): CONF = UserConfig('spyder', defaults=DEFAULTS, load=True, version=CONF_VERSION, subfolder=SUBFOLDER, backup=True, raw_mode=True) -# Ensures that the config is present on spyder first run -CONF.set('main', 'interface_language', load_lang_conf()) - # Removing old .spyder.ini location: old_location = osp.join(get_home_dir(), '.spyder.ini') if osp.isfile(old_location): diff --git a/spyderlib/plugins/configdialog.py b/spyderlib/plugins/configdialog.py index cfd8be496e9..1c89799fdc9 100644 --- a/spyderlib/plugins/configdialog.py +++ b/spyderlib/plugins/configdialog.py @@ -22,7 +22,7 @@ getexistingdirectory, getopenfilename) from spyderlib.baseconfig import (_, running_in_mac_app, LANGUAGE_CODES, - save_lang_conf) + save_lang_conf, load_lang_conf) from spyderlib.config import CONF from spyderlib.guiconfig import (CUSTOM_COLOR_SCHEME_NAME, set_default_color_scheme) @@ -165,6 +165,9 @@ def __init__(self, parent=None): self.setWindowTitle(_("Preferences")) self.setWindowIcon(get_icon("configure.png")) + + # Ensures that the config is present on spyder first run + CONF.set('main', 'interface_language', load_lang_conf()) def get_current_index(self): """Return current page index"""