diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 7c2ed733..14ba6651 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -274,7 +274,8 @@ def drawtab(stdscr): stdscr.addstr(8 + i, 18, str(item).ljust(2)) # Uptime and processing data - stdscr.addstr(6, 35, "Since startup on " + l10n.formatTimestamp(startuptime, False)) + stdscr.addstr( + 6, 35, "Since startup on " + l10n.formatTimestamp(startuptime)) stdscr.addstr(7, 40, "Processed " + str( state.numberOfMessagesProcessed).ljust(4) + " person-to-person messages.") stdscr.addstr(8, 40, "Processed " + str( @@ -1027,8 +1028,9 @@ def loadInbox(): fromlabel = shared.fixPotentiallyInvalidUTF8Data(fromlabel) # Load into array - inbox.append([msgid, tolabel, toaddr, fromlabel, fromaddr, subject, l10n.formatTimestamp( - received, False), read]) + inbox.append([ + msgid, tolabel, toaddr, fromlabel, fromaddr, subject, + l10n.formatTimestamp(received), read]) inbox.reverse() @@ -1080,20 +1082,20 @@ def loadSent(): elif status == "msgqueued": statstr = "Message queued" elif status == "msgsent": - t = l10n.formatTimestamp(lastactiontime, False) + t = l10n.formatTimestamp(lastactiontime) statstr = "Message sent at " + t + ".Waiting for acknowledgement." elif status == "msgsentnoackexpected": - t = l10n.formatTimestamp(lastactiontime, False) + t = l10n.formatTimestamp(lastactiontime) statstr = "Message sent at " + t + "." elif status == "doingmsgpow": statstr = "The proof of work required to send the message has been queued." elif status == "ackreceived": - t = l10n.formatTimestamp(lastactiontime, False) + t = l10n.formatTimestamp(lastactiontime) statstr = "Acknowledgment of the message received at " + t + "." elif status == "broadcastqueued": statstr = "Broadcast queued." elif status == "broadcastsent": - t = l10n.formatTimestamp(lastactiontime, False) + t = l10n.formatTimestamp(lastactiontime) statstr = "Broadcast sent at " + t + "." elif status == "forcepow": statstr = "Forced difficulty override. Message will start sending soon." @@ -1102,7 +1104,7 @@ def loadSent(): elif status == "toodifficult": statstr = "Error: The work demanded by the recipient is more difficult than you are willing to do." else: - t = l10n.formatTimestamp(lastactiontime, False) + t = l10n.formatTimestamp(lastactiontime) statstr = "Unknown status " + status + " at " + t + "." # Load into array @@ -1114,7 +1116,7 @@ def loadSent(): subject, statstr, ackdata, - l10n.formatTimestamp(lastactiontime, False)]) + l10n.formatTimestamp(lastactiontime)]) sentbox.reverse() diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index eb140fb9..6a692f38 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -125,6 +125,8 @@ class MyForm(settingsmixin.SMainWindow): self.qsystranslator.load(translationpath) QtGui.QApplication.installTranslator(self.qsystranslator) + # TODO: move this block into l10n + # FIXME: shouldn't newlocale be used here? lang = locale.normalize(l10n.getTranslationLanguage()) langs = [ lang.split(".")[0] + "." + l10n.encoding, @@ -135,7 +137,7 @@ class MyForm(settingsmixin.SMainWindow): langs = [l10n.getWindowsLocale(lang)] for lang in langs: try: - l10n.setlocale(locale.LC_ALL, lang) + l10n.setlocale(lang) if 'win32' not in sys.platform and 'win64' not in sys.platform: l10n.encoding = locale.nl_langinfo(locale.CODESET) else: diff --git a/src/l10n.py b/src/l10n.py index 7a78525b..406e3221 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -1,21 +1,31 @@ -""" -Localization -""" +"""Localization helpers""" + import logging import os +import re +import sys import time from bmconfigparser import BMConfigParser logger = logging.getLogger('default') - DEFAULT_ENCODING = 'ISO8859-1' DEFAULT_LANGUAGE = 'en_US' DEFAULT_TIME_FORMAT = '%Y-%m-%d %H:%M:%S' -encoding = DEFAULT_ENCODING -language = DEFAULT_LANGUAGE +try: + import locale + encoding = locale.getpreferredencoding(True) or DEFAULT_ENCODING + language = ( + locale.getlocale()[0] or locale.getdefaultlocale()[0] + or DEFAULT_LANGUAGE) +except (ImportError, AttributeError): # FIXME: it never happens + logger.exception('Could not determine language or encoding') + locale = None + encoding = DEFAULT_ENCODING + language = DEFAULT_LANGUAGE + windowsLanguageMap = { "ar": "arabic", @@ -40,55 +50,51 @@ windowsLanguageMap = { "zh_TW": "chinese-traditional" } -try: - import locale - encoding = locale.getpreferredencoding(True) or DEFAULT_ENCODING - language = locale.getlocale()[0] or locale.getdefaultlocale()[0] or DEFAULT_LANGUAGE -except: - logger.exception('Could not determine language or encoding') +time_format = BMConfigParser().safeGet( + 'bitmessagesettings', 'timeformat', DEFAULT_TIME_FORMAT) -if BMConfigParser().has_option('bitmessagesettings', 'timeformat'): - time_format = BMConfigParser().get('bitmessagesettings', 'timeformat') - # Test the format string - try: - time.strftime(time_format) - except: - logger.exception('Could not format timestamp') - time_format = DEFAULT_TIME_FORMAT -else: +if not re.search(r'\d', time.strftime(time_format)): time_format = DEFAULT_TIME_FORMAT -# It seems some systems lie about the encoding they use so we perform -# comprehensive decoding tests -if time_format != DEFAULT_TIME_FORMAT: +# It seems some systems lie about the encoding they use +# so we perform comprehensive decoding tests +elif sys.version_info[0] == 2: try: # Check day names - for i in xrange(7): - unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, i, 0, 0)), encoding) + for i in range(7): + time.strftime( + time_format, (0, 0, 0, 0, 0, 0, i, 0, 0)).decode(encoding) # Check month names - for i in xrange(1, 13): - unicode(time.strftime(time_format, (0, i, 0, 0, 0, 0, 0, 0, 0)), encoding) + for i in range(1, 13): + time.strftime( + time_format, (0, i, 0, 0, 0, 0, 0, 0, 0)).decode(encoding) # Check AM/PM - unicode(time.strftime(time_format, (0, 0, 0, 11, 0, 0, 0, 0, 0)), encoding) - unicode(time.strftime(time_format, (0, 0, 0, 13, 0, 0, 0, 0, 0)), encoding) + time.strftime( + time_format, (0, 0, 0, 11, 0, 0, 0, 0, 0)).decode(encoding) + time.strftime( + time_format, (0, 0, 0, 13, 0, 0, 0, 0, 0)).decode(encoding) # Check DST - unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, 0, 0, 1)), encoding) - except: + time.strftime( + time_format, (0, 0, 0, 0, 0, 0, 0, 0, 1)).decode(encoding) + except Exception: # TODO: write tests and determine exception types logger.exception('Could not decode locale formatted timestamp') - time_format = DEFAULT_TIME_FORMAT + # time_format = DEFAULT_TIME_FORMAT encoding = DEFAULT_ENCODING -def setlocale(category, newlocale): +def setlocale(newlocale): """Set the locale""" - locale.setlocale(category, newlocale) + try: + locale.setlocale(locale.LC_ALL, newlocale) + except AttributeError: # locale is None + pass # it looks like some stuff isn't initialised yet when this is called the # first time and its init gets the locale settings from the environment os.environ["LC_ALL"] = newlocale -def formatTimestamp(timestamp=None, as_unicode=True): +def formatTimestamp(timestamp=None): """Return a formatted timestamp""" # For some reason some timestamps are strings so we need to sanitize. if timestamp is not None and not isinstance(timestamp, int): @@ -110,8 +116,8 @@ def formatTimestamp(timestamp=None, as_unicode=True): except ValueError: timestring = time.strftime(time_format) - if as_unicode: - return unicode(timestring, encoding) + if sys.version_info[0] == 2: + return timestring.decode(encoding) return timestring