diff --git a/deluge/common.py b/deluge/common.py index 3d75f9da1..1f068f97c 100644 --- a/deluge/common.py +++ b/deluge/common.py @@ -115,6 +115,7 @@ FILE_PRIORITY = { "Highest Priority": 7 } + def get_version(): """ Returns the program version from the egg metadata @@ -125,9 +126,11 @@ def get_version(): """ return pkg_resources.require("Deluge")[0].version + def get_default_config_dir(filename=None): """ - :param filename: if None, only the config path is returned, if provided, a path including the filename will be returned + :param filename: if None, only the config path is returned, if provided, + a path including the filename will be returned :type filename: string :returns: a file path to the config directory and optional filename :rtype: string @@ -139,7 +142,8 @@ def get_default_config_dir(filename=None): appDataPath = os.environ.get("APPDATA") if not appDataPath: import _winreg - hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") + hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders") appDataReg = _winreg.QueryValueEx(hkey, "AppData") appDataPath = appDataReg[0] _winreg.CloseKey(hkey) @@ -154,6 +158,7 @@ def get_default_config_dir(filename=None): log.error("Unable to use default config directory, exiting... (%s)", e) sys.exit(1) + def get_default_download_dir(): """ :returns: the default download directory @@ -168,8 +173,7 @@ def get_default_download_dir(): try: for line in open(userdir_file, 'r'): if not line.startswith('#') and 'XDG_DOWNLOAD_DIR' in line: - download_dir = os.path.expandvars(\ - line.partition("=")[2].rstrip().strip('"')) + download_dir = os.path.expandvars(line.partition("=")[2].rstrip().strip('"')) if os.path.isdir(download_dir): return download_dir except IOError: @@ -177,6 +181,7 @@ def get_default_download_dir(): return os.environ.get("HOME") + def windows_check(): """ Checks if the current platform is Windows @@ -187,6 +192,7 @@ def windows_check(): """ return platform.system() in ('Windows', 'Microsoft') + def vista_check(): """ Checks if the current platform is Windows Vista @@ -197,6 +203,7 @@ def vista_check(): """ return platform.release() == "Vista" + def osx_check(): """ Checks if the current platform is Mac OS X @@ -207,6 +214,7 @@ def osx_check(): """ return platform.system() == "Darwin" + def get_pixmap(fname): """ Provides easy access to files in the deluge/ui/data/pixmaps folder within the Deluge egg @@ -219,6 +227,7 @@ def get_pixmap(fname): """ return resource_filename("deluge", os.path.join("ui", "data", "pixmaps", fname)) + def resource_filename(module, path): # While developing, if there's a second deluge package, installed globally # and another in develop mode somewhere else, while pkg_resources.require("Deluge") @@ -230,6 +239,7 @@ def resource_filename(module, path): pkg_resources._manager, os.path.join(*(module.split('.')+[path])) ) + def open_file(path): """ Opens a file or folder using the system configured program @@ -245,6 +255,7 @@ def open_file(path): else: subprocess.Popen(["xdg-open", "%s" % path]) + def open_url_in_browser(url): """ Opens a url in the desktop's default browser @@ -263,12 +274,14 @@ kib_txt = "KiB" mib_txt = "MiB" gib_txt = "GiB" + def translate_strings(): byte_txt = _("Bytes") kib_txt = _("KiB") mib_txt = _("MiB") gib_txt = _("GiB") + def fsize(fsize_b): """ Formats the bytes value into a string with KiB, MiB or GiB units @@ -296,6 +309,7 @@ def fsize(fsize_b): else: return "%d %s" % (fsize_b, byte_txt) + def fsize_short(fsize_b): """ Formats the bytes value into a string with K, M or G units @@ -320,6 +334,7 @@ def fsize_short(fsize_b): fsize_gb = fsize_mb / 1024.0 return "%.1f %s" % (fsize_gb, _("G")) + def fpcnt(dec): """ Formats a string to display a percentage with two decimal places @@ -337,6 +352,7 @@ def fpcnt(dec): """ return '%.2f%%' % (dec * 100) + def fspeed(bps): """ Formats a string to display a transfer speed utilizing :func:`fsize` @@ -361,6 +377,7 @@ def fspeed(bps): fspeed_gb = fspeed_mb / 1024.0 return "%.1f %s" % (fspeed_gb, _("GiB/s")) + def fpeer(num_peers, total_peers): """ Formats a string to show 'num_peers' ('total_peers') @@ -385,6 +402,7 @@ def fpeer(num_peers, total_peers): else: return "%d" % num_peers + def ftime(seconds): """ Formats a string to show time in a human readable form @@ -424,6 +442,7 @@ def ftime(seconds): weeks = weeks % 52 return '%dy %dw' % (years, weeks) + def fdate(seconds): """ Formats a date time string in the locale's date representation based on the systems timezone @@ -438,6 +457,7 @@ def fdate(seconds): return "" return time.strftime("%x %X", time.localtime(seconds)) + def is_url(url): """ A simple test to check if the URL is valid @@ -455,6 +475,7 @@ def is_url(url): """ return url.partition('://')[0] in ("http", "https", "ftp", "udp") + def is_magnet(uri): """ A check to determine if a uri is a valid bittorrent magnet uri @@ -476,6 +497,7 @@ def is_magnet(uri): return True return False + def create_magnet_uri(infohash, name=None, trackers=[]): """ Creates a magnet uri @@ -501,6 +523,7 @@ def create_magnet_uri(infohash, name=None, trackers=[]): return uri + def get_path_size(path): """ Gets the size in bytes of 'path' @@ -524,6 +547,7 @@ def get_path_size(path): dir_size += os.path.getsize(filename) return dir_size + def free_space(path): """ Gets the free space available at 'path' @@ -547,6 +571,7 @@ def free_space(path): block_size = disk_data.f_frsize return disk_data.f_bavail * block_size + def is_ip(ip): """ A simple test to see if 'ip' is valid @@ -585,6 +610,7 @@ def is_ip(ip): except socket.error: return False + def path_join(*parts): """ An implementation of os.path.join that always uses / for the separator @@ -611,6 +637,7 @@ XML_ESCAPES = ( ("'", ''') ) + def xml_decode(string): """ Unescape a string that was previously encoded for use within xml. @@ -624,6 +651,7 @@ def xml_decode(string): string = string.replace(escape, char) return string + def xml_encode(string): """ Escape a string for use within an xml element or attribute. @@ -637,6 +665,7 @@ def xml_encode(string): string = string.replace(char, escape) return string + def decode_string(s, encoding="utf8"): """ Decodes a string and return unicode. If it cannot decode using @@ -672,6 +701,7 @@ def decode_string(s, encoding="utf8"): pass return u'' + def utf8_encoded(s, encoding="utf8"): """ Returns a utf8 encoded string of s @@ -690,6 +720,7 @@ def utf8_encoded(s, encoding="utf8"): s = s.encode("utf8") return s + class VersionSplit(object): """ Used for comparing version numbers. @@ -715,8 +746,8 @@ class VersionSplit(object): # Check for PEP 386 compliant version match = re.search(VERSION_RE, ver) if match: - group = [(x if x is not None else '') for x in match.group(1,2,3,4,8)] - vs = [''.join(group[0:2]),''.join(group[2:4]), group[4].lstrip('.')] + group = [(x if x is not None else '') for x in match.group(1, 2, 3, 4, 8)] + vs = [''.join(group[0:2]), ''.join(group[2:4]), group[4].lstrip('.')] else: ver = ver.lower() vs = ver.replace("_", "-").split("-") @@ -759,8 +790,10 @@ AUTH_LEVEL_NORMAL = 5 AUTH_LEVEL_ADMIN = 10 AUTH_LEVEL_DEFAULT = AUTH_LEVEL_NORMAL + def create_auth_file(): - import stat, configmanager + import stat + import configmanager auth_file = configmanager.get_config_dir("auth") # Check for auth file and create if necessary if not os.path.exists(auth_file): @@ -771,8 +804,10 @@ def create_auth_file(): # Change the permissions on the file so only this user can read/write it os.chmod(auth_file, stat.S_IREAD | stat.S_IWRITE) + def create_localclient_account(append=False): - import configmanager, random + import configmanager + import random auth_file = configmanager.get_config_dir("auth") if not os.path.exists(auth_file): create_auth_file() @@ -792,31 +827,137 @@ def create_localclient_account(append=False): fd.close() +def get_translations_path(): + """Get the absolute path to the directory containing translation files""" + return resource_filename("deluge", "i18n") + + +def set_env_variable(name, value): + ''' + :param name: environment variable name + :param value: environment variable value + + This function ensures that changes to an environment variable are applied + to each copy of the environment variables used by a process. Starting from + Python 2.4, os.environ changes only apply to the copy Python keeps (os.environ) + and are no longer automatically applied to the other copies for the process. + + On Microsoft Windows, each process has multiple copies of the environment + variables, one managed by the OS and one managed by the C library. We also + need to take care of the fact that the C library used by Python is not + necessarily the same as the C library used by pygtk and friends. This because + the latest releases of pygtk and friends are built with mingw32 and are thus + linked against msvcrt.dll. The official gtk+ binaries have always been built + in this way. + + Basen on _putenv in TransUtils.py from sourceforge project gramps + http://sourceforge.net/p/gramps/code/HEAD/tree/branches/maintenance/gramps32/src/TransUtils.py + ''' + # Update Python's copy of the environment variables + os.environ[name] = value + + if windows_check(): + from ctypes import windll + from ctypes import cdll + from ctypes.util import find_msvcrt + + # Update the copy maintained by Windows (so SysInternals Process Explorer sees it) + try: + result = windll.kernel32.SetEnvironmentVariableW(name, value) + if result == 0: + raise Warning + except Exception: + log.warning('Failed to set Env Var \'%s\' (\'kernel32.SetEnvironmentVariableW\')' % name) + else: + log.debug('Set Env Var \'%s\' to \'%s\' (\'kernel32.SetEnvironmentVariableW\')' % (name, value)) + + # Update the copy maintained by msvcrt (used by gtk+ runtime) + try: + result = cdll.msvcrt._putenv('%s=%s' % (name, value)) + if result != 0: + raise Warning + except Exception: + log.warning('Failed to set Env Var \'%s\' (\'msvcrt._putenv\')' % name) + else: + log.debug('Set Env Var \'%s\' to \'%s\' (\'msvcrt._putenv\')' % (name, value)) + + # Update the copy maintained by whatever c runtime is used by Python + try: + msvcrt = find_msvcrt() + msvcrtname = str(msvcrt).split('.')[0] if '.' in msvcrt else str(msvcrt) + result = cdll.LoadLibrary(msvcrt)._putenv('%s=%s' % (name, value)) + if result != 0: + raise Warning + except Exception: + log.warning('Failed to set Env Var \'%s\' (\'%s._putenv\')' % (name, msvcrtname)) + else: + log.debug('Set Env Var \'%s\' to \'%s\' (\'%s._putenv\')' % (name, value, msvcrtname)) + + +def set_language(lang): + """ + Set the language to use. + + gettext and GtkBuilder will load the translations from the specified + language. + + :param lang: the language, e.g. "en", "de" or "en_GB" + :type lang: str + """ + lang = str(lang) + # Necessary to set there environment variables for GtkBuilder + set_env_variable('LANGUAGE', lang) # Windows/Linux + set_env_variable('LANG', lang) # For OSX + + translations_path = get_translations_path() + ro = gettext.translation("deluge", localedir=translations_path, languages=[lang]) + ro.install() + + # Initialize gettext -def setup_translations(setup_pygtk=False): - translations_path = resource_filename("deluge", "i18n") +def setup_translations(setup_gettext=True, setup_pygtk=False): + translations_path = get_translations_path() + domain = "deluge" log.info("Setting up translations from %s", translations_path) - try: - if hasattr(locale, "bindtextdomain"): - locale.bindtextdomain("deluge", translations_path) - if hasattr(locale, "textdomain"): - locale.textdomain("deluge") - gettext.install("deluge", translations_path, unicode=True) - if setup_pygtk: - # Even though we're not using glade anymore, let's set it up so that - # plugins still using it get properly translated. + if setup_pygtk: + try: log.info("Setting up GTK translations from %s", translations_path) + + if windows_check(): + import ctypes + libintl = ctypes.cdll.intl + libintl.bindtextdomain(domain, translations_path.encode(sys.getfilesystemencoding())) + libintl.textdomain(domain) + libintl.bind_textdomain_codeset(domain, "UTF-8") + libintl.gettext.restype = ctypes.c_char_p + + # Use glade for plugins that still uses it import gtk import gtk.glade - gtk.glade.bindtextdomain("deluge", translations_path) - gtk.glade.textdomain("deluge") + gtk.glade.bindtextdomain(domain, translations_path) + gtk.glade.textdomain(domain) + except Exception, e: + log.error("Unable to initialize glade translation!") + log.exception(e) + if setup_gettext: + try: + if hasattr(locale, "bindtextdomain"): + locale.bindtextdomain(domain, translations_path) + if hasattr(locale, "textdomain"): + locale.textdomain(domain) + + gettext.bindtextdomain(domain, translations_path) + gettext.bind_textdomain_codeset(domain, 'UTF-8') + gettext.textdomain(domain) + gettext.install(domain, translations_path, unicode=True) + except Exception, e: + log.error("Unable to initialize gettext/locale!") + log.exception(e) + import __builtin__ + __builtin__.__dict__["_"] = lambda x: x translate_strings() - except Exception, e: - log.error("Unable to initialize gettext/locale!") - log.exception(e) - import __builtin__ - __builtin__.__dict__["_"] = lambda x: x + def unicode_argv(): """ Gets sys.argv as list of unicode objects on any platform.""" diff --git a/deluge/main.py b/deluge/main.py index 05d3827de..2a747e97f 100644 --- a/deluge/main.py +++ b/deluge/main.py @@ -64,8 +64,6 @@ def version_callback(option, opt_str, value, parser): def start_ui(): """Entry point for ui script""" - deluge.common.setup_translations() - # Setup the argument parser parser = OptionParser(usage="%prog [options] [actions]") parser.add_option("-v", "--version", action="callback", callback=version_callback, diff --git a/deluge/ui/gtkui/glade/preferences_dialog.ui b/deluge/ui/gtkui/glade/preferences_dialog.ui index a774e29a0..86b8cc8ba 100644 --- a/deluge/ui/gtkui/glade/preferences_dialog.ui +++ b/deluge/ui/gtkui/glade/preferences_dialog.ui @@ -320,6 +320,14 @@ + + + + + + + + False 5 @@ -344,7 +352,6 @@ gtk-cancel - False True True True @@ -360,7 +367,6 @@ gtk-apply - False True True True @@ -376,7 +382,6 @@ gtk-ok - False True True True @@ -492,7 +497,6 @@ Standalone - False True True False @@ -509,7 +513,6 @@ Thin Client - False True True False @@ -566,7 +569,6 @@ Show session speed in titlebar - False True True False @@ -581,7 +583,6 @@ Focus window when adding torrent - False True True False @@ -594,35 +595,6 @@ 1 - - - False - True - True - False - Besides being experimental, using the pieces bar -will increase the bandwidth used between client -and daemon(does not apply in classic mode). -Use at your own risk if you wish to help us debug -this new feature. - True - - - - True - False - Show a pieces bar in the torrent's -status tab (<b>EXPERIMENTAL!!!</b>) - True - - - - - True - True - 2 - - True @@ -652,7 +624,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) - False True True True @@ -663,7 +634,7 @@ status tab (<b>EXPERIMENTAL!!!</b>) 1 2 - + @@ -681,7 +652,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) - False True True True @@ -694,7 +664,7 @@ status tab (<b>EXPERIMENTAL!!!</b>) 2 1 2 - + @@ -712,7 +682,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) - False True True True @@ -725,7 +694,7 @@ status tab (<b>EXPERIMENTAL!!!</b>) 2 2 3 - + @@ -743,7 +712,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) - False True True True @@ -756,13 +724,12 @@ status tab (<b>EXPERIMENTAL!!!</b>) 2 3 4 - + gtk-revert-to-saved - False True False True @@ -775,13 +742,12 @@ status tab (<b>EXPERIMENTAL!!!</b>) 2 3 - + gtk-revert-to-saved - False True False True @@ -796,13 +762,12 @@ status tab (<b>EXPERIMENTAL!!!</b>) 3 1 2 - + gtk-revert-to-saved - False True False True @@ -817,13 +782,12 @@ status tab (<b>EXPERIMENTAL!!!</b>) 3 2 3 - + gtk-revert-to-saved - False True False True @@ -838,7 +802,7 @@ status tab (<b>EXPERIMENTAL!!!</b>) 3 3 4 - + @@ -859,6 +823,34 @@ status tab (<b>EXPERIMENTAL!!!</b>) 2 + + + True + True + False + Besides being experimental, using the pieces bar +will increase the bandwidth used between client +and daemon(does not apply in classic mode). +Use at your own risk if you wish to help us debug +this new feature. + True + + + + True + False + Show a pieces bar in the torrent's +status tab (<b>EXPERIMENTAL!!!</b>) + True + + + + + True + True + 2 + + @@ -901,7 +893,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Always show - False True True False @@ -921,7 +912,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Bring the dialog to focus - False True True False @@ -977,7 +967,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Enable system tray icon - False True False False @@ -999,7 +988,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Minimize to tray on close - False True False False @@ -1023,7 +1011,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Start in tray - False True False False @@ -1047,7 +1034,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Enable Application Indicator - False True False False @@ -1072,7 +1058,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Password protect system tray - False True False True @@ -1164,6 +1149,74 @@ status tab (<b>EXPERIMENTAL!!!</b>) 5 + + + True + False + 0 + none + + + True + False + 12 + + + True + False + + + System Default + True + True + False + True + + + + True + True + 0 + + + + + True + False + liststore8 + 0 + + + + 1 + + + + + True + True + 1 + + + + + + + + + True + False + <b>Languge</b> + True + + + + + False + True + 6 + + @@ -1249,7 +1302,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Move completed to: - False True True False @@ -1265,7 +1317,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Copy of .torrent files to: - False True True False @@ -1281,7 +1332,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Delete copy of torrent file on remove - False True True False @@ -1407,7 +1457,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Use Full Allocation - False True True False @@ -1425,7 +1474,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Use Compact Allocation - False True True False @@ -1482,7 +1530,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Prioritize first and last pieces of torrent - False True True False @@ -1498,7 +1545,6 @@ status tab (<b>EXPERIMENTAL!!!</b>) Sequential download - False True True False @@ -1519,7 +1565,6 @@ used sparingly. Add torrents in Paused state - False True True False @@ -1763,7 +1808,6 @@ used sparingly. Random - False True True False @@ -1838,7 +1882,6 @@ used sparingly. Test Active Port - False True True True @@ -1990,7 +2033,6 @@ used sparingly. Random - False True True False @@ -2213,7 +2255,6 @@ used sparingly. UPnP - False True True False @@ -2229,7 +2270,6 @@ used sparingly. NAT-PMP - False True True False @@ -2247,7 +2287,6 @@ used sparingly. Peer Exchange - False True True False @@ -2264,7 +2303,6 @@ used sparingly. Tracker Exchange - False True True False @@ -2283,7 +2321,6 @@ used sparingly. LSD - False True True False @@ -2299,7 +2336,6 @@ used sparingly. DHT - False True True False @@ -2709,7 +2745,6 @@ Requires a Hex value. Ignore limits on local network - False True True False @@ -2732,7 +2767,6 @@ Requires a Hex value. Rate limit IP overhead - False True True False @@ -3045,7 +3079,6 @@ Requires a Hex value. Be alerted about new releases - False True True False @@ -3121,7 +3154,6 @@ Requires a Hex value. Yes, please send anonymous statistics - False True True False @@ -3255,7 +3287,6 @@ Requires a Hex value. start - False True True True @@ -3468,7 +3499,6 @@ Requires a Hex value. Allow Remote Connections - False True True False @@ -3510,7 +3540,6 @@ Requires a Hex value. Periodically check the website for new releases - False True True False @@ -3573,7 +3602,6 @@ Requires a Hex value. gtk-add - False True True True @@ -3589,7 +3617,6 @@ Requires a Hex value. gtk-edit - False True False True @@ -3606,7 +3633,6 @@ Requires a Hex value. gtk-delete - False True False True @@ -3743,7 +3769,6 @@ Requires a Hex value. Queue new torrents to top - False True True False @@ -3816,7 +3841,7 @@ Requires a Hex value. 1 2 - + @@ -3837,7 +3862,7 @@ Requires a Hex value. 2 2 3 - + @@ -3882,7 +3907,7 @@ Requires a Hex value. 2 1 2 - + @@ -3908,7 +3933,6 @@ Requires a Hex value. Do not count slow torrents - False True True False @@ -3923,7 +3947,6 @@ Requires a Hex value. Prefer Seeding over Downloading - False True True False @@ -4033,7 +4056,7 @@ Requires a Hex value. 1 2 - + @@ -4054,7 +4077,7 @@ Requires a Hex value. 2 1 2 - + @@ -4074,7 +4097,7 @@ Requires a Hex value. 2 2 3 - + @@ -4092,7 +4115,6 @@ Requires a Hex value. Stop seeding when share ratio reaches: - False True True False @@ -4140,7 +4162,6 @@ Requires a Hex value. Remove torrent when share ratio reached - False True False True @@ -4412,7 +4433,7 @@ Requires a Hex value. 1 2 GTK_FILL - + @@ -4424,7 +4445,7 @@ Requires a Hex value. GTK_FILL - + @@ -4617,7 +4638,7 @@ Requires a Hex value. 1 2 GTK_FILL - + @@ -4629,7 +4650,7 @@ Requires a Hex value. GTK_FILL - + @@ -4822,7 +4843,7 @@ Requires a Hex value. 1 2 GTK_FILL - + @@ -4834,7 +4855,7 @@ Requires a Hex value. GTK_FILL - + @@ -4901,7 +4922,7 @@ Requires a Hex value. 2 3 GTK_FILL - + @@ -4934,7 +4955,7 @@ Requires a Hex value. 3 4 GTK_FILL - + @@ -4965,7 +4986,7 @@ Requires a Hex value. 4 5 GTK_FILL - + @@ -5030,7 +5051,7 @@ Requires a Hex value. 1 2 GTK_FILL - + @@ -5042,7 +5063,7 @@ Requires a Hex value. GTK_FILL - + @@ -5056,7 +5077,7 @@ Requires a Hex value. 1 2 GTK_FILL - + @@ -5219,7 +5240,7 @@ Requires a Hex value. 1 2 - + @@ -5241,7 +5262,7 @@ Requires a Hex value. 2 1 2 - + @@ -5349,7 +5370,7 @@ Requires a Hex value. 1 2 - + @@ -5363,7 +5384,7 @@ Requires a Hex value. 2 1 2 - + @@ -5377,7 +5398,7 @@ Requires a Hex value. 2 2 3 - + @@ -5468,7 +5489,7 @@ Requires a Hex value. 1 2 - + @@ -5482,7 +5503,7 @@ Requires a Hex value. 2 1 2 - + @@ -5496,7 +5517,7 @@ Requires a Hex value. 2 3 4 - + @@ -5524,7 +5545,7 @@ Requires a Hex value. 2 2 3 - + @@ -5600,7 +5621,7 @@ Requires a Hex value. 1 2 - + @@ -5614,7 +5635,7 @@ Requires a Hex value. 2 1 2 - + @@ -5646,7 +5667,6 @@ Requires a Hex value. gtk-refresh - False True True True @@ -5820,7 +5840,7 @@ Requires a Hex value. 2 4 5 - + @@ -5834,7 +5854,7 @@ Requires a Hex value. 2 1 2 - + @@ -5846,7 +5866,7 @@ Requires a Hex value. 1 2 - + @@ -5875,7 +5895,7 @@ Requires a Hex value. 1 2 GTK_FILL - + @@ -5887,7 +5907,7 @@ Requires a Hex value. GTK_FILL - + @@ -5929,7 +5949,7 @@ Requires a Hex value. 2 3 4 - + @@ -5943,7 +5963,7 @@ Requires a Hex value. 2 2 3 - + @@ -5984,7 +6004,6 @@ Requires a Hex value. center - False True True True @@ -6031,7 +6050,6 @@ Requires a Hex value. - False True True True @@ -6089,7 +6107,6 @@ Requires a Hex value. False - False True True True diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py index f4ed2be9f..86f08612f 100644 --- a/deluge/ui/gtkui/gtkui.py +++ b/deluge/ui/gtkui/gtkui.py @@ -114,8 +114,8 @@ DEFAULT_PREFS = { "pref_dialog_width": None, "pref_dialog_height": None, "window_pane_position": -1, - "tray_download_speed_list" : [5.0, 10.0, 30.0, 80.0, 300.0], - "tray_upload_speed_list" : [5.0, 10.0, 30.0, 80.0, 300.0], + "tray_download_speed_list": [5.0, 10.0, 30.0, 80.0, 300.0], + "tray_upload_speed_list": [5.0, 10.0, 30.0, 80.0, 300.0], "connection_limit_list": [50, 100, 200, 300, 500], "enabled_plugins": [], "show_connection_manager_on_start": True, @@ -151,18 +151,23 @@ DEFAULT_PREFS = { "pieces_color_downloading": [65535, 55255, 0], "pieces_color_completed": [4883, 26985, 56540], "focus_main_window_on_add": True, + "language": None, } class GtkUI(object): def __init__(self, args): - self.daemon_bps = (0,0,0) + self.daemon_bps = (0, 0, 0) + # Setup btkbuilder/glade translation + deluge.common.setup_translations(setup_gettext=False, setup_pygtk=True) + # Setup signals try: import gnome.ui import gnome self.gnome_prog = gnome.init("Deluge", deluge.common.get_version()) self.gnome_client = gnome.ui.master_client() + def on_die(*args): reactor.stop() self.gnome_client.connect("die", on_die) @@ -174,6 +179,7 @@ class GtkUI(object): from win32api import SetConsoleCtrlHandler from win32con import CTRL_CLOSE_EVENT from win32con import CTRL_SHUTDOWN_EVENT + def win_handler(ctrl_type): log.debug("ctrl_type: %s", ctrl_type) if ctrl_type in (CTRL_CLOSE_EVENT, CTRL_SHUTDOWN_EVENT): @@ -184,11 +190,11 @@ class GtkUI(object): if deluge.common.osx_check() and gtk.gdk.WINDOWING == "quartz": import gtkosx_application self.osxapp = gtkosx_application.gtkosx_application_get() + def on_die(*args): reactor.stop() self.osxapp.connect("NSApplicationWillTerminate", on_die) - # Set process name again to fix gtk issue setproctitle(getproctitle()) @@ -207,6 +213,10 @@ class GtkUI(object): # shutdown the daemon. self.started_in_classic = self.config["classic_mode"] + # Set language + if not self.config["language"] is None: + deluge.common.set_language(self.config["language"]) + # Start the IPC Interface before anything else.. Just in case we are # already running. self.queuedtorrents = QueuedTorrents() @@ -215,7 +225,6 @@ class GtkUI(object): # Initialize gdk threading gtk.gdk.threads_init() - # We make sure that the UI components start once we get a core URI client.set_disconnect_callback(self.__on_disconnect) @@ -327,8 +336,8 @@ You will either need to stop the daemon or turn off Classic Mode to continue.")) except ImportError, e: if "No module named libtorrent" in e.message: d = dialogs.YesNoDialog( - _("Enable Thin Client Mode?"), - _("Thin client mode is only available because libtorrent is not installed.\n\n\ + _("Enable Thin Client Mode?"), + _("Thin client mode is only available because libtorrent is not installed.\n\n\ To use Deluge standalone (Classic mode) please install libtorrent.")).run() self.started_in_classic = False d.addCallback(on_dialog_response) @@ -344,10 +353,12 @@ To use Deluge standalone (Classic mode) please install libtorrent.")).run() _("Error Starting Core"), _("There was an error starting the core component which is required to run Deluge in Classic Mode.\n\n\ Please see the details below for more information."), details=traceback.format_exc(tb[2])).run() + def on_ed_response(response): d = dialogs.YesNoDialog( _("Turn off Classic Mode?"), - _("Since there was an error starting in Classic Mode would you like to continue by turning it off?")).run() + _("Since there was an error starting in Classic Mode would you like to continue by turning it off?") + ).run() self.started_in_classic = False d.addCallback(on_dialog_response) ed.addCallback(on_ed_response) @@ -406,6 +417,7 @@ Please see the details below for more information."), details=traceback.format_e dialog = dialogs.AuthenticationDialog( reason.value.message, reason.value.username ) + def dialog_finished(response_id, host, port): if response_id == gtk.RESPONSE_OK: reactor.callLater( @@ -446,7 +458,6 @@ Please see the details below for more information."), details=traceback.format_e reactor.simulate() self.connectionmanager.show() - def __on_disconnect(self): """ Called when disconnected from the daemon. We basically just stop all diff --git a/deluge/ui/gtkui/menubar_osx.py b/deluge/ui/gtkui/menubar_osx.py index 43f290c4e..4cf0b3584 100644 --- a/deluge/ui/gtkui/menubar_osx.py +++ b/deluge/ui/gtkui/menubar_osx.py @@ -17,9 +17,9 @@ # # You should have received a copy of the GNU General Public License # along with deluge. If not, write to: -# The Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor -# Boston, MA 02110-1301, USA. +# The Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor +# Boston, MA 02110-1301, USA. # # In addition, as a special exception, the copyright holders give # permission to link the code of portions of this program with the OpenSSL @@ -32,66 +32,69 @@ # statement from all source files in the program, then also delete it here. # # -import gtk, gtk.glade +import gtk from deluge.configmanager import ConfigManager + def accel_swap(item, group, skey, smod, dkey, dmod): - item.remove_accelerator(group, ord(skey), smod) - item.add_accelerator("activate", group, ord(dkey), dmod, gtk.ACCEL_VISIBLE) + item.remove_accelerator(group, ord(skey), smod) + item.add_accelerator("activate", group, ord(dkey), dmod, gtk.ACCEL_VISIBLE) + def accel_meta(item, group, key): - accel_swap(item, group, key, gtk.gdk.CONTROL_MASK, key, gtk.gdk.META_MASK) + accel_swap(item, group, key, gtk.gdk.CONTROL_MASK, key, gtk.gdk.META_MASK) + def menubar_osx(gtkui, osxapp): - window = gtkui.mainwindow - glade = window.main_glade - menubar = glade.get_widget("menubar") - group = gtk.accel_groups_from_object(window.window)[0] + window = gtkui.mainwindow + main_builder = window.get_builder() + menubar = main_builder.get_object("menubar") + group = gtk.accel_groups_from_object(window.window)[0] - config = ConfigManager("gtkui.conf") + config = ConfigManager("gtkui.conf") - # NOTE: accel maps doesn't work with glade file format - # because of libglade not setting MenuItem accel groups - # That's why we remove / set accelerators by hand... (dirty) - # Clean solution: migrate glades files to gtkbuilder format - file_menu = glade.get_widget("menu_file").get_submenu() - file_items = file_menu.get_children() - accel_meta(file_items[0], group, 'o') - accel_meta(file_items[1], group, 'n') - quit_all_item = file_items[3] - accel_swap(quit_all_item, group, 'q', gtk.gdk.SHIFT_MASK | gtk.gdk.CONTROL_MASK, - 'q', gtk.gdk.SHIFT_MASK | gtk.gdk.META_MASK) - for item in range(2, len(file_items)): # remove quits - file_menu.remove(file_items[item]) + # NOTE: accel maps doesn't work with glade file format + # because of libglade not setting MenuItem accel groups + # That's why we remove / set accelerators by hand... (dirty) + # Clean solution: migrate glades files to gtkbuilder format + file_menu = main_builder.get_object("menu_file").get_submenu() + file_items = file_menu.get_children() + accel_meta(file_items[0], group, 'o') + accel_meta(file_items[1], group, 'n') + quit_all_item = file_items[3] + accel_swap(quit_all_item, group, 'q', gtk.gdk.SHIFT_MASK | gtk.gdk.CONTROL_MASK, + 'q', gtk.gdk.SHIFT_MASK | gtk.gdk.META_MASK) + for item in range(2, len(file_items)): # remove quits + file_menu.remove(file_items[item]) - menu_widget = glade.get_widget("menu_edit") - edit_menu = menu_widget.get_submenu() - edit_items = edit_menu.get_children() - pref_item = edit_items[0] - accel_swap(pref_item, group, 'p', gtk.gdk.CONTROL_MASK, ',', gtk.gdk.META_MASK) - edit_menu.remove(pref_item) + menu_widget = main_builder.get_object("menu_edit") + edit_menu = menu_widget.get_submenu() + edit_items = edit_menu.get_children() + pref_item = edit_items[0] + accel_swap(pref_item, group, 'p', gtk.gdk.CONTROL_MASK, ',', gtk.gdk.META_MASK) + edit_menu.remove(pref_item) - conn_item = edit_items[1] - accel_meta(conn_item, group, 'm') - edit_menu.remove(conn_item) + conn_item = edit_items[1] + accel_meta(conn_item, group, 'm') + edit_menu.remove(conn_item) - menubar.remove(menu_widget) + menubar.remove(menu_widget) - help_menu = glade.get_widget("menu_help").get_submenu() - help_items = help_menu.get_children() - about_item = help_items[4] - help_menu.remove(about_item) - help_menu.remove(help_items[3]) # separator + help_menu = main_builder.get_object("menu_help").get_submenu() + help_items = help_menu.get_children() + about_item = help_items[4] + help_menu.remove(about_item) + help_menu.remove(help_items[3]) # separator - menubar.hide() - osxapp.set_menu_bar(menubar) - # populate app menu - osxapp.insert_app_menu_item(about_item, 0) - osxapp.insert_app_menu_item(gtk.SeparatorMenuItem(), 1) - osxapp.insert_app_menu_item(pref_item, 2) - if not config["classic_mode"]: - osxapp.insert_app_menu_item(conn_item, 3) - if quit_all_item.get_visible(): - osxapp.insert_app_menu_item(gtk.SeparatorMenuItem(), 4) - osxapp.insert_app_menu_item(quit_all_item, 5) + menubar.hide() + osxapp.set_menu_bar(menubar) + # populate app menu + osxapp.insert_app_menu_item(about_item, 0) + osxapp.insert_app_menu_item(gtk.SeparatorMenuItem(), 1) + osxapp.insert_app_menu_item(pref_item, 2) + if not config["classic_mode"]: + osxapp.insert_app_menu_item(conn_item, 3) + if quit_all_item.get_visible(): + osxapp.insert_app_menu_item(gtk.SeparatorMenuItem(), 4) + osxapp.insert_app_menu_item(quit_all_item, 5) diff --git a/deluge/ui/gtkui/preferences.py b/deluge/ui/gtkui/preferences.py index b546b6fc3..1fa83fc57 100644 --- a/deluge/ui/gtkui/preferences.py +++ b/deluge/ui/gtkui/preferences.py @@ -62,6 +62,7 @@ COLOR_STATES = { "completed": COLOR_COMPLETED } + class Preferences(component.Component): def __init__(self): component.Component.__init__(self, "Preferences") @@ -180,6 +181,7 @@ class Preferences(component.Component): "on_missing_color_set": self._on_missing_color_set, "on_revert_color_missing_clicked": self._on_revert_color_missing_clicked, "on_pref_dialog_configure_event": self.on_pref_dialog_configure_event, + "on_checkbutton_language_toggled": self._on_checkbutton_language_toggled, }) from deluge.ui.gtkui.gtkui import DEFAULT_PREFS @@ -193,6 +195,7 @@ class Preferences(component.Component): self.enabled_plugins = [] self.setup_path_choosers() + self.load_languages() def setup_path_choosers(self): self.download_location_hbox = self.builder.get_object("hbox_download_to_path_chooser") @@ -210,6 +213,31 @@ class Preferences(component.Component): self.copy_torrents_to_hbox.add(self.copy_torrent_files_path_chooser) self.copy_torrents_to_hbox.show_all() + def load_languages(self): + from deluge.ui import languages # Import here so that gettext has been setup first + translations_path = deluge.common.get_translations_path() + for root, dirs, files in os.walk(translations_path): + # Get the dirs + break + self.language_combo = self.builder.get_object("combobox_language") + self.language_checkbox = self.builder.get_object("checkbutton_language") + lang_model = self.language_combo.get_model() + + index = -1 + for i, lang_code in enumerate(sorted(dirs)): + name = "%s (Language name missing)" % lang_code + if lang_code in languages.LANGUAGES: + name = languages.LANGUAGES[lang_code] + lang_model.append([lang_code, name]) + if self.gtkui_config["language"] == lang_code: + index = i + + if self.gtkui_config["language"] is None: + self.language_checkbox.set_active(True) + self.language_combo.set_sensitive(False) + elif index != -1: + self.language_combo.set_active(index) + def __del__(self): del self.gtkui_config @@ -260,9 +288,9 @@ class Preferences(component.Component): self.liststore.foreach(check_row, name) # Remove the page and row - if self.page_num_to_remove != None: + if self.page_num_to_remove is not None: self.notebook.remove_page(self.page_num_to_remove) - if self.iter_to_remove != None: + if self.iter_to_remove is not None: self.liststore.remove(self.iter_to_remove) # We need to re-adjust the index values for the remaining pages @@ -273,7 +301,7 @@ class Preferences(component.Component): """Page should be the string in the left list.. ie, 'Network' or 'Bandwidth'""" self.window_open = True - if page != None: + if page is not None: for (index, string) in self.liststore: if page == string: self.treeview.get_selection().select_path(index) @@ -321,7 +349,7 @@ class Preferences(component.Component): self._show() def _show(self): - self.is_connected = self.core_config != {} and self.core_config != None + self.is_connected = self.core_config != {} and self.core_config is not None core_widgets = { "chk_move_completed": ("active", "move_completed"), "chk_copy_torrent_file": ("active", "copy_torrent_file"), @@ -430,7 +458,7 @@ class Preferences(component.Component): elif type(value) is str: value = self.core_config[value] elif modifier: - value = {"active": False, "not_active": False, "value": 0, "text": "", "path_chooser": "" }[modifier] + value = {"active": False, "not_active": False, "value": 0, "text": "", "path_chooser": ""}[modifier] if modifier == "active": widget.set_active(value) @@ -644,8 +672,7 @@ class Preferences(component.Component): self.builder.get_object("chk_enable_appindicator").get_active() new_gtkui_config["lock_tray"] = \ self.builder.get_object("chk_lock_tray").get_active() - passhex = sha_hash(\ - self.builder.get_object("txt_tray_password").get_text()).hexdigest() + passhex = sha_hash(self.builder.get_object("txt_tray_password").get_text()).hexdigest() if passhex != "c07eb5a8c0dc7bb81c217b67f11c3b7a5e95ffd7": new_gtkui_config["tray_password"] = passhex @@ -723,6 +750,29 @@ class Preferences(component.Component): # Run plugin hook to apply preferences component.get("PluginManager").run_on_apply_prefs() + # Lanuage + if self.language_checkbox.get_active(): + new_gtkui_config["language"] = None + else: + active = self.language_combo.get_active() + if active == -1: + dialog = dialogs.InformationDialog( + _("Attention"), + _("You must choose a language") + ) + dialog.run() + return + else: + model = self.language_combo.get_model() + new_gtkui_config["language"] = model.get(model.get_iter(active), 0)[0] + + if new_gtkui_config["language"] != self.gtkui_config["language"]: + dialog = dialogs.InformationDialog( + _("Attention"), + _("You must now restart the deluge UI for the changes to take effect.") + ) + dialog.run() + # GtkUI for key in new_gtkui_config.keys(): # The values do not match so this needs to be updated @@ -751,7 +801,7 @@ class Preferences(component.Component): # Re-show the dialog to make sure everything has been updated self.show() - if classic_mode_was_set == True and new_gtkui_in_classic_mode == False: + if classic_mode_was_set and not new_gtkui_in_classic_mode: def on_response(response): if response == gtk.RESPONSE_NO: # Set each changed config value in the core @@ -766,7 +816,7 @@ class Preferences(component.Component): _("Your current session will be stopped. Continue?") ) dialog.run().addCallback(on_response) - elif classic_mode_was_set == False and new_gtkui_in_classic_mode == True: + elif not classic_mode_was_set and new_gtkui_in_classic_mode: dialog = dialogs.InformationDialog( _("Attention"), _("You must now restart the deluge UI") @@ -807,7 +857,7 @@ class Preferences(component.Component): def load_pref_dialog_state(self): w = self.gtkui_config["pref_dialog_width"] h = self.gtkui_config["pref_dialog_height"] - if w != None and h != None: + if w is not None and h is not None: self.pref_dialog.resize(w, h) def on_pref_dialog_configure_event(self, widget, event): @@ -827,25 +877,25 @@ class Preferences(component.Component): } dependents = { - "chk_show_dialog": {"chk_focus_dialog": True}, - "chk_random_port": {"spin_port_min": False, - "spin_port_max": False}, - "chk_random_outgoing_ports": {"spin_outgoing_port_min": False, - "spin_outgoing_port_max": False}, - "chk_use_tray": {"chk_min_on_close": True, - "chk_start_in_tray": True, - "chk_enable_appindicator": True, - "chk_lock_tray": True}, - "chk_lock_tray": {"txt_tray_password": True, - "password_label": True}, - "radio_open_folder_custom": {"combo_file_manager": False, - "txt_open_folder_location": True}, - "chk_move_completed" : {"move_completed_path_chooser" : True}, - "chk_copy_torrent_file" : {"torrentfiles_location_path_chooser" : True, - "chk_del_copy_torrent_file" : True}, - "chk_seed_ratio" : {"spin_share_ratio": True, - "chk_remove_ratio" : True} - } + "chk_show_dialog": {"chk_focus_dialog": True}, + "chk_random_port": {"spin_port_min": False, + "spin_port_max": False}, + "chk_random_outgoing_ports": {"spin_outgoing_port_min": False, + "spin_outgoing_port_max": False}, + "chk_use_tray": {"chk_min_on_close": True, + "chk_start_in_tray": True, + "chk_enable_appindicator": True, + "chk_lock_tray": True}, + "chk_lock_tray": {"txt_tray_password": True, + "password_label": True}, + "radio_open_folder_custom": {"combo_file_manager": False, + "txt_open_folder_location": True}, + "chk_move_completed": {"move_completed_path_chooser": True}, + "chk_copy_torrent_file": {"torrentfiles_location_path_chooser": True, + "chk_del_copy_torrent_file": True}, + "chk_seed_ratio": {"spin_share_ratio": True, + "chk_remove_ratio": True} + } def update_dependent_widgets(name, value): dependency = dependents[name] @@ -935,11 +985,13 @@ class Preferences(component.Component): def _on_button_plugin_install_clicked(self, widget): log.debug("_on_button_plugin_install_clicked") - chooser = gtk.FileChooserDialog(_("Select the Plugin"), + chooser = gtk.FileChooserDialog( + _("Select the Plugin"), self.pref_dialog, gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, - gtk.RESPONSE_OK)) + gtk.RESPONSE_OK) + ) chooser.set_transient_for(self.pref_dialog) chooser.set_select_multiple(False) @@ -1029,7 +1081,6 @@ class Preferences(component.Component): def _on_button_associate_magnet_clicked(self, widget): common.associate_magnet_links(True) - def _get_accounts_tab_data(self): def on_ok(accounts): self.accounts_frame.show() @@ -1151,7 +1202,7 @@ class Preferences(component.Component): dialogs.ErrorDialog( _("Error Updating Account"), _("An error ocurred while updating account"), - parent=self.pref_dialog, details=failure.getErrorMessage() + parent=self.pref_dialog, details=failure.getErrorMessage() ).run() if response_id == gtk.RESPONSE_OK: @@ -1207,6 +1258,9 @@ class Preferences(component.Component): colors_widget = self.builder.get_object("piecebar_colors_expander") colors_widget.set_visible(widget.get_active()) + def _on_checkbutton_language_toggled(self, widget): + self.language_combo.set_sensitive(not self.language_checkbox.get_active()) + def _on_completed_color_set(self, widget): self.__set_color("completed") diff --git a/deluge/ui/languages.py b/deluge/ui/languages.py new file mode 100644 index 000000000..5e4a1d116 --- /dev/null +++ b/deluge/ui/languages.py @@ -0,0 +1,105 @@ +# +# languages.py +# +# This file is public domain. +# + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'en-us' + +# Languages we provide translations for, out of the box. +LANGUAGES = { + 'af': _('Afrikaans'), + 'ar': _('Arabic'), + 'ast': _('Asturian'), + 'az': _('Azerbaijani'), + 'bg': _('Bulgarian'), + 'be': _('Belarusian'), + 'bn': _('Bengali'), + 'br': _('Breton'), + 'bs': _('Bosnian'), + 'ca': _('Catalan'), + 'cs': _('Czech'), + 'cy': _('Welsh'), + 'da': _('Danish'), + 'de': _('German'), + 'el': _('Greek'), + 'en': _('English'), + 'en_AU': _('English (Australia)'), + 'en_CA': _('English (Canada)'), + 'en_GB': _('English (United Kingdom)'), + 'eo': _('Esperanto'), + 'es': _('Spanish'), + 'es-ar': _('Argentinian Spanish'), + 'es-mx': _('Mexican Spanish'), + 'es-ni': _('Nicaraguan Spanish'), + 'es-ve': _('Venezuelan Spanish'), + 'et': _('Estonian'), + 'eu': _('Basque'), + 'fa': _('Persian'), + 'fi': _('Finnish'), + 'fr': _('French'), + 'fy': _('Frisian'), + 'ga': _('Irish'), + 'gl': _('Galician'), + 'he': _('Hebrew'), + 'hi': _('Hindi'), + 'hr': _('Croatian'), + 'hu': _('Hungarian'), + 'ia': _('Interlingua'), + 'id': _('Indonesian'), + 'is': _('Icelandic'), + 'it': _('Italian'), + 'ja': _('Japanese'), + 'ka': _('Georgian'), + 'kk': _('Kazakh'), + 'km': _('Khmer'), + 'kn': _('Kannada'), + 'ko': _('Korean'), + 'la': _('Latin'), + 'lb': _('Luxembourgish'), + 'lt': _('Lithuanian'), + 'lv': _('Latvian'), + 'mk': _('Macedonian'), + 'ml': _('Malayalam'), + 'mn': _('Mongolian'), + 'ms': _('Mayaly'), + 'my': _('Burmese'), + 'nb': _('Norwegian Bokmal'), + 'ne': _('Nepali'), + 'nds': _('Low German'), + 'nl': _('Dutch'), + 'nn': _('Norwegian Nynorsk'), + 'os': _('Ossetic'), + 'pa': _('Punjabi'), + 'pl': _('Polish'), + 'pms': _('Piedmontese'), + 'pt': _('Portuguese'), + 'pt_BR': _('Brazilian Portuguese'), + 'ro': _('Romanian'), + 'ru': _('Russian'), + 'sk': _('Slovak'), + 'sl': _('Slovenian'), + 'sq': _('Albanian'), + 'sr': _('Serbian'), + 'sr-latn': _('Serbian Latin'), + 'sv': _('Swedish'), + 'sw': _('Swahili'), + 'ta': _('Tamil'), + 'te': _('Telugu'), + 'th': _('Thai'), + 'tl': _('Tagalog'), + 'tlh': _('Klingon'), + 'tr': _('Turkish'), + 'tt': _('Tatar'), + 'udm': _('Udmurt'), + 'uk': _('Ukrainian'), + 'ur': _('Urdu'), + 'vi': _('Vietnamese'), + 'zh_CN': _('Chinese (Simplified)'), + 'zh_HK': _('Chinese (Hong Kong)'), + 'zh-hans': _('Simplified Chinese'), + 'zh-hant': _('Traditional Chinese'), + 'zh_TW': _('Chinese (Taiwan)'), +} diff --git a/deluge/ui/ui.py b/deluge/ui/ui.py index 46a597a5f..1cedc3dae 100644 --- a/deluge/ui/ui.py +++ b/deluge/ui/ui.py @@ -47,6 +47,7 @@ try: except ImportError: setproctitle = lambda t: None + def version_callback(option, opt_str, value, parser): print os.path.basename(sys.argv[0]) + ": " + deluge.common.get_version() try: @@ -64,20 +65,16 @@ if 'dev' not in deluge.common.get_version(): import warnings warnings.filterwarnings('ignore', category=DeprecationWarning, module='twisted') + class _UI(object): def __init__(self, name="gtk"): self.__name = name - if name == "gtk": - deluge.common.setup_translations(setup_pygtk=True) - else: - deluge.common.setup_translations() - self.__parser = OptionParser(usage="%prog [options] [actions]") self.__parser.add_option("-v", "--version", action="callback", callback=version_callback, help="Show program's version number and exit") - group = OptionGroup(self.__parser, _("Common Options")) + group = OptionGroup(self.__parser, "Common Options") group.add_option("-c", "--config", dest="config", help="Set the config folder location", action="store", type="str") group.add_option("-l", "--logfile", dest="logfile", @@ -133,6 +130,9 @@ class _UI(object): log.error("There was an error setting the config dir! Exiting..") sys.exit(1) + # Setup gettext + deluge.common.setup_translations() + setproctitle("deluge-%s" % self.__name) log.info("Deluge ui %s", deluge.common.get_version()) @@ -140,12 +140,16 @@ class _UI(object): log.debug("args: %s", self.__args) log.info("Starting %s ui..", self.__name) + class UI: def __init__(self, options, args, ui_args): import logging log = logging.getLogger(__name__) log.debug("UI init..") + # Setup gettext + deluge.common.setup_translations() + # Set the config directory deluge.configmanager.set_config_dir(options.config) @@ -181,7 +185,8 @@ class UI: stack = traceback.extract_tb(tb) last_frame = stack[-1] if last_frame[0] == __file__: - log.error("Unable to find the requested UI: %s. Please select a different UI with the '-u' option or alternatively use the '-s' option to select a different default UI.", selected_ui) + log.error("Unable to find the requested UI: %s. Please select a different UI with the '-u' option \ + or alternatively use the '-s' option to select a different default UI.", selected_ui) else: log.exception(e) log.error("There was an error whilst launching the request UI: %s", selected_ui)