diff --git a/deluge/ui/baseargparser.py b/deluge/argparserbase.py similarity index 97% rename from deluge/ui/baseargparser.py rename to deluge/argparserbase.py index 6024e99d5..3952e1ef3 100644 --- a/deluge/ui/baseargparser.py +++ b/deluge/argparserbase.py @@ -86,7 +86,7 @@ argparse.ArgumentParser.find_subcommand = find_subcommand argparse.ArgumentParser.set_default_subparser = set_default_subparser -def get_version(): +def _get_version_detail(): version_str = '%s\n' % (common.get_version()) try: from deluge._libtorrent import LT_VERSION @@ -151,7 +151,7 @@ class HelpAction(argparse._HelpAction): parser.exit() -class BaseArgParser(argparse.ArgumentParser): +class ArgParserBase(argparse.ArgumentParser): def __init__(self, *args, **kwargs): if 'formatter_class' not in kwargs: kwargs['formatter_class'] = lambda prog: DelugeTextHelpFormatter( @@ -165,7 +165,7 @@ class BaseArgParser(argparse.ArgumentParser): self.log_stream = kwargs['log_stream'] del kwargs['log_stream'] - super(BaseArgParser, self).__init__(*args, **kwargs) + super(ArgParserBase, self).__init__(*args, **kwargs) self.common_setup = False self.process_arg_group = False @@ -178,13 +178,13 @@ class BaseArgParser(argparse.ArgumentParser): '-V', '--version', action='version', - version='%(prog)s ' + get_version(), + version='%(prog)s ' + _get_version_detail(), help=_('Print version information'), ) self.group.add_argument( '-v', action='version', - version='%(prog)s ' + get_version(), + version='%(prog)s ' + _get_version_detail(), help=argparse.SUPPRESS, ) # Deprecated arg self.group.add_argument( @@ -246,7 +246,7 @@ class BaseArgParser(argparse.ArgumentParser): argparse.Namespace: The parsed arguments. """ - options = super(BaseArgParser, self).parse_args(args=args) + options = super(ArgParserBase, self).parse_args(args=args) return self._handle_ui_options(options) def parse_known_ui_args(self, args, withhold=None): @@ -262,7 +262,7 @@ class BaseArgParser(argparse.ArgumentParser): """ if withhold: args = [a for a in args if a not in withhold] - options, remaining = super(BaseArgParser, self).parse_known_args(args=args) + options, remaining = super(ArgParserBase, self).parse_known_args(args=args) options.remaining = remaining # Hanlde common and process group options return self._handle_ui_options(options) diff --git a/deluge/core/daemon_entry.py b/deluge/core/daemon_entry.py index d62245c36..0a2261a08 100644 --- a/deluge/core/daemon_entry.py +++ b/deluge/core/daemon_entry.py @@ -15,10 +15,10 @@ from logging import DEBUG, FileHandler, getLogger from twisted.internet.error import CannotListenError +from deluge.argparserbase import ArgParserBase from deluge.common import run_profiled from deluge.configmanager import get_config_dir -from deluge.ui.baseargparser import BaseArgParser -from deluge.ui.translations_util import set_dummy_trans +from deluge.i18n import setup_mock_translation def add_daemon_options(parser): @@ -78,10 +78,10 @@ def start_daemon(skip_start=False): deluge.core.daemon.Daemon: A new daemon object """ - set_dummy_trans(warn_msg=True) + setup_mock_translation(warn_msg=True) # Setup the argument parser - parser = BaseArgParser() + parser = ArgParserBase() add_daemon_options(parser) options = parser.parse_args() diff --git a/deluge/i18n/__init__.py b/deluge/i18n/__init__.py new file mode 100644 index 000000000..701d2afa6 --- /dev/null +++ b/deluge/i18n/__init__.py @@ -0,0 +1,15 @@ +from .util import ( + I18N_DOMAIN, + get_languages, + set_language, + setup_mock_translation, + setup_translation, +) + +__all__ = [ + 'I18N_DOMAIN', + 'set_language', + 'get_languages', + 'setup_translation', + 'setup_mock_translation', +] diff --git a/deluge/ui/languages.py b/deluge/i18n/languages.py similarity index 97% rename from deluge/ui/languages.py rename to deluge/i18n/languages.py index ab2df02e7..49dc53026 100644 --- a/deluge/ui/languages.py +++ b/deluge/i18n/languages.py @@ -9,6 +9,12 @@ from __future__ import unicode_literals # http://www.i18nguy.com/unicode/language-identifiers.html LANGUAGE_CODE = 'en-us' + +# Deferred translation +def _(message): + return message + + # Languages we provide translations for, out of the box. LANGUAGES = { 'af': _('Afrikaans'), @@ -107,3 +113,5 @@ LANGUAGES = { 'zh-hant': _('Traditional Chinese'), 'zh_TW': _('Chinese (Taiwan)'), } + +del _ diff --git a/deluge/ui/translations_util.py b/deluge/i18n/util.py similarity index 89% rename from deluge/ui/translations_util.py rename to deluge/i18n/util.py index cf64c994f..a2f287645 100644 --- a/deluge/ui/translations_util.py +++ b/deluge/i18n/util.py @@ -20,35 +20,19 @@ from six.moves import builtins import deluge.common +from .languages import LANGUAGES + log = logging.getLogger(__name__) -log.addHandler( - logging.NullHandler() -) # Silence: No handlers could be found for logger "deluge.util.lang" I18N_DOMAIN = 'deluge' -def set_dummy_trans(warn_msg=None): - def _func(*txt): - if warn_msg: - log.warning( - '"%s" has been marked for translation, but translation is unavailable.', - txt[0], - ) - return txt[0] - - builtins.__dict__['_'] = _func - builtins.__dict__['ngettext'] = builtins.__dict__['_n'] = _func - - def get_translations_path(): """Get the absolute path to the directory containing translation files""" return deluge.common.resource_filename('deluge', 'i18n') def get_languages(): - from deluge.ui import languages # Import here so that gettext has been setup first - lang = [] translations_path = get_translations_path() @@ -61,9 +45,9 @@ def get_languages(): for i, lang_code in enumerate(lang_dirs): name = '%s (Language name missing)' % lang_code - if lang_code in languages.LANGUAGES: - name = languages.LANGUAGES[lang_code] - lang.append([lang_code, name]) + if lang_code in LANGUAGES: + name = LANGUAGES[lang_code] + lang.append([lang_code, _(name)]) lang = sorted(lang, key=lambda l: l[1]) return lang @@ -93,8 +77,21 @@ def set_language(lang): log.warning('IOError when loading translations: %s', ex) +def setup_mock_translation(warn_msg=None): + def _func(*txt): + if warn_msg: + log.warning( + '"%s" has been marked for translation, but translation is unavailable.', + txt[0], + ) + return txt[0] + + builtins.__dict__['_'] = _func + builtins.__dict__['ngettext'] = builtins.__dict__['_n'] = _func + + # Initialize gettext -def setup_translations(): +def setup_translation(): translations_path = get_translations_path() log.info('Setting up translations from %s', translations_path) @@ -131,6 +128,6 @@ def setup_translations(): except Exception as ex: log.error('Unable to initialize gettext/locale!') log.exception(ex) - set_dummy_trans() + setup_mock_translation() deluge.common.translate_size_units() diff --git a/deluge/tests/common.py b/deluge/tests/common.py index 4ca34d400..0fb8d5002 100644 --- a/deluge/tests/common.py +++ b/deluge/tests/common.py @@ -23,7 +23,7 @@ import deluge.configmanager import deluge.core.preferencesmanager import deluge.log from deluge.error import DelugeError -from deluge.ui.translations_util import setup_translations +from deluge.i18n import setup_translation # This sets log level to critical, so use log.critical() to debug while running unit tests deluge.log.setup_logger('none') @@ -75,7 +75,7 @@ def add_watchdog(deferred, timeout=0.05, message=None): # Initialize gettext -setup_translations() +setup_translation() class ReactorOverride(object): diff --git a/deluge/tests/test_common.py b/deluge/tests/test_common.py index 7e90cbc91..3cecb6467 100644 --- a/deluge/tests/test_common.py +++ b/deluge/tests/test_common.py @@ -30,7 +30,7 @@ from deluge.common import ( is_url, windows_check, ) -from deluge.ui.translations_util import setup_translations +from deluge.i18n import setup_translation from .common import get_test_data_file, set_tmp_config_dir @@ -38,7 +38,7 @@ from .common import get_test_data_file, set_tmp_config_dir class CommonTestCase(unittest.TestCase): def setUp(self): # NOQA self.config_dir = set_tmp_config_dir() - setup_translations() + setup_translation() def tearDown(self): # NOQA pass diff --git a/deluge/tests/test_files_tab.py b/deluge/tests/test_files_tab.py index 5625010ea..23865d78f 100644 --- a/deluge/tests/test_files_tab.py +++ b/deluge/tests/test_files_tab.py @@ -13,7 +13,7 @@ from twisted.trial import unittest import deluge.component as component from deluge.common import windows_check from deluge.configmanager import ConfigManager -from deluge.ui.translations_util import setup_translations +from deluge.i18n import setup_translation from . import common from .basetest import BaseTestCase @@ -27,7 +27,7 @@ try: except ImportError: libs_available = False -setup_translations() +setup_translation() @pytest.mark.gtkui diff --git a/deluge/tests/test_torrentview.py b/deluge/tests/test_torrentview.py index 6c4350a48..590760d1e 100644 --- a/deluge/tests/test_torrentview.py +++ b/deluge/tests/test_torrentview.py @@ -15,7 +15,7 @@ from twisted.trial import unittest import deluge.component as component from deluge.configmanager import ConfigManager -from deluge.ui.translations_util import setup_translations +from deluge.i18n import setup_translation from . import common from .basetest import BaseTestCase @@ -36,7 +36,7 @@ except (ImportError, ValueError): else: libs_available = True -setup_translations() +setup_translation() @pytest.mark.gtkui diff --git a/deluge/ui/console/console.py b/deluge/ui/console/console.py index 99d6ea72c..58d31d514 100644 --- a/deluge/ui/console/console.py +++ b/deluge/ui/console/console.py @@ -15,7 +15,7 @@ import os import sys import deluge.common -from deluge.ui.baseargparser import BaseArgParser, DelugeTextHelpFormatter +from deluge.argparserbase import ArgParserBase, DelugeTextHelpFormatter from deluge.ui.ui import UI log = logging.getLogger(__name__) @@ -143,7 +143,7 @@ class Console(UI): def start(self): if self.ui_args is None: # Started directly by deluge-console script so must find the UI args manually - options, remaining = BaseArgParser(common_help=False).parse_known_args() + options, remaining = ArgParserBase(common_help=False).parse_known_args() self.ui_args = remaining i = self.console_parser.find_subcommand(args=self.ui_args) diff --git a/deluge/ui/console/modes/preferences/preference_panes.py b/deluge/ui/console/modes/preferences/preference_panes.py index 2bdf5a932..62029a6a9 100644 --- a/deluge/ui/console/modes/preferences/preference_panes.py +++ b/deluge/ui/console/modes/preferences/preference_panes.py @@ -13,6 +13,7 @@ import logging from deluge.common import is_ip from deluge.decorators import overrides +from deluge.i18n import get_languages from deluge.ui.client import client from deluge.ui.common import DISK_CACHE_KEYS from deluge.ui.console.widgets import BaseInputPane, BaseWindow @@ -192,7 +193,6 @@ class InterfacePane(BasePreferencePane): _('Move selection when moving torrents in the queue'), console_config['torrentview']['move_selection'], ) - from deluge.ui.translations_util import get_languages langs = get_languages() langs.insert(0, ('', 'System Default')) diff --git a/deluge/ui/console/utils/column.py b/deluge/ui/console/utils/column.py index 47b0b2433..d93215957 100644 --- a/deluge/ui/console/utils/column.py +++ b/deluge/ui/console/utils/column.py @@ -13,11 +13,11 @@ import copy import logging import deluge.common +from deluge.i18n import setup_translation from deluge.ui.common import TORRENT_DATA_FIELD from deluge.ui.console.utils import format_utils -from deluge.ui.translations_util import setup_translations -setup_translations() +setup_translation() log = logging.getLogger(__name__) diff --git a/deluge/ui/gtk3/gtkui.py b/deluge/ui/gtk3/gtkui.py index c30561ecb..8feed0e5c 100644 --- a/deluge/ui/gtk3/gtkui.py +++ b/deluge/ui/gtk3/gtkui.py @@ -47,11 +47,11 @@ from deluge.common import ( ) from deluge.configmanager import ConfigManager, get_config_dir from deluge.error import DaemonRunningError +from deluge.i18n import I18N_DOMAIN, set_language, setup_translation from deluge.ui.client import client from deluge.ui.hostlist import LOCALHOST from deluge.ui.sessionproxy import SessionProxy from deluge.ui.tracker_icons import TrackerIcons -from deluge.ui.translations_util import I18N_DOMAIN, set_language, setup_translations # isort:imports-localfolder from .addtorrentdialog import AddTorrentDialog @@ -146,7 +146,7 @@ def windowing(like): class GtkUI(object): def __init__(self, args): # Setup gtkbuilder/glade translation - setup_translations() + setup_translation() Builder().set_translation_domain(I18N_DOMAIN) # Setup signals diff --git a/deluge/ui/gtk3/preferences.py b/deluge/ui/gtk3/preferences.py index c91e7f2ed..b19612891 100644 --- a/deluge/ui/gtk3/preferences.py +++ b/deluge/ui/gtk3/preferences.py @@ -22,9 +22,9 @@ import deluge.common import deluge.component as component from deluge.configmanager import ConfigManager, get_config_dir from deluge.error import AuthManagerError, NotAuthorizedError +from deluge.i18n import get_languages from deluge.ui.client import client from deluge.ui.common import DISK_CACHE_KEYS, PREFS_CATOG_TRANS -from deluge.ui.translations_util import get_languages from .common import associate_magnet_links, get_clipboard_text, get_deluge_icon from .dialogs import AccountDialog, ErrorDialog, InformationDialog, YesNoDialog diff --git a/deluge/ui/ui.py b/deluge/ui/ui.py index 6b149f72d..0986ec777 100644 --- a/deluge/ui/ui.py +++ b/deluge/ui/ui.py @@ -14,8 +14,8 @@ import logging import deluge.common import deluge.configmanager import deluge.log -from deluge.ui.baseargparser import BaseArgParser -from deluge.ui.translations_util import setup_translations +from deluge.argparserbase import ArgParserBase +from deluge.i18n import setup_translation log = logging.getLogger(__name__) @@ -38,8 +38,8 @@ class UI(object): def __init__(self, name, **kwargs): self.__name = name self.ui_args = kwargs.pop('ui_args', None) - setup_translations() - self.__parser = BaseArgParser(**kwargs) + setup_translation() + self.__parser = ArgParserBase(**kwargs) def parse_args(self, parser, args=None): options = parser.parse_args(args) diff --git a/deluge/ui/ui_entry.py b/deluge/ui/ui_entry.py index cefce0db5..71ce83783 100644 --- a/deluge/ui/ui_entry.py +++ b/deluge/ui/ui_entry.py @@ -23,8 +23,8 @@ import pkg_resources import deluge.common import deluge.configmanager -from deluge.ui.baseargparser import BaseArgParser -from deluge.ui.translations_util import setup_translations +from deluge.argparserbase import ArgParserBase +from deluge.i18n import setup_translation DEFAULT_PREFS = {'default_ui': 'gtk'} @@ -33,7 +33,7 @@ AMBIGUOUS_CMD_ARGS = ('-h', '--help', '-v', '-V', '--version') def start_ui(): """Entry point for ui script""" - setup_translations() + setup_translation() # Get the registered UI entry points ui_entrypoints = {} @@ -59,7 +59,7 @@ def start_ui(): return _parser # Setup parser with Common Options and add UI Options group. - parser = add_ui_options_group(BaseArgParser()) + parser = add_ui_options_group(ArgParserBase()) # Parse and handle common/process group options options = parser.parse_known_ui_args(sys.argv, withhold=AMBIGUOUS_CMD_ARGS) @@ -81,7 +81,7 @@ def start_ui(): # We have parsed and got the config dir needed to get the default UI # Now create a parser for choosing the UI. We reuse the ui option group for # parsing to succeed and the text displayed to user, but result is not used. - parser = add_ui_options_group(BaseArgParser(common_help=True)) + parser = add_ui_options_group(ArgParserBase(common_help=True)) # Create subparser for each registered UI. Empty title is used to remove unwanted positional text. subparsers = parser.add_subparsers( diff --git a/deluge/ui/web/json_api.py b/deluge/ui/web/json_api.py index d06ce1ef6..d760845e6 100644 --- a/deluge/ui/web/json_api.py +++ b/deluge/ui/web/json_api.py @@ -26,12 +26,12 @@ from deluge import component, httpdownloader from deluge.common import AUTH_LEVEL_DEFAULT, get_magnet_info, is_magnet from deluge.configmanager import get_config_dir from deluge.error import NotAuthorizedError +from deluge.i18n import get_languages from deluge.ui.client import Client, client from deluge.ui.common import FileTree2, TorrentInfo from deluge.ui.coreconfig import CoreConfig from deluge.ui.hostlist import HostList from deluge.ui.sessionproxy import SessionProxy -from deluge.ui.translations_util import get_languages from deluge.ui.web.common import _ log = logging.getLogger(__name__) diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py index ebb92151a..c8f901a5a 100644 --- a/deluge/ui/web/server.py +++ b/deluge/ui/web/server.py @@ -25,8 +25,8 @@ from deluge import common, component, configmanager from deluge.common import is_ipv6 from deluge.core.rpcserver import check_ssl_keys from deluge.crypto_utils import get_context_factory +from deluge.i18n import set_language, setup_translation from deluge.ui.tracker_icons import TrackerIcons -from deluge.ui.translations_util import set_language, setup_translations from deluge.ui.web.auth import Auth from deluge.ui.web.common import Template from deluge.ui.web.json_api import JSON, WebApi, WebUtils @@ -687,7 +687,7 @@ class DelugeWeb(component.Component): # Strip away slashes and serve on the base path as well as root path self.top_level.putChild(self.base.strip('/'), self.top_level) - setup_translations() + setup_translation() # Remove twisted version number from 'server' http-header for security reasons server.version = 'TwistedWeb'