From 269506ff8ff4f0afdfb0a148097bd4bc11197419 Mon Sep 17 00:00:00 2001 From: bmng-dev Date: Wed, 6 Aug 2014 02:01:01 +0000 Subject: [PATCH] New localization module (l10n) Resolves #691 --- src/bitmessagecurses/__init__.py | 18 +++--- src/bitmessageqt/__init__.py | 99 ++++++++------------------------ src/class_objectProcessor.py | 4 +- src/class_singleWorker.py | 21 +++---- src/l10n.py | 42 ++++++++++++++ 5 files changed, 86 insertions(+), 98 deletions(-) create mode 100644 src/l10n.py diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 91c99df8..1c88d222 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -25,6 +25,7 @@ import shared import ConfigParser from addresses import * from pyelliptic.openssl import OpenSSL +import l10n quit = False menutab = 1 @@ -210,7 +211,7 @@ def drawtab(stdscr): stdscr.addstr(8+i, 18, str(item).ljust(2)) # Uptime and processing data - stdscr.addstr(6, 35, "Since startup on "+unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(startuptime))))) + stdscr.addstr(6, 35, "Since startup on "+l10n.formatTimestamp(startuptime, False)) stdscr.addstr(7, 40, "Processed "+str(shared.numberOfMessagesProcessed).ljust(4)+" person-to-person messages.") stdscr.addstr(8, 40, "Processed "+str(shared.numberOfBroadcastsProcessed).ljust(4)+" broadcast messages.") stdscr.addstr(9, 40, "Processed "+str(shared.numberOfPubkeysProcessed).ljust(4)+" public keys.") @@ -851,8 +852,7 @@ def loadInbox(): # Load into array inbox.append([msgid, tolabel, toaddr, fromlabel, fromaddr, subject, - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(received))), - read]) + l10n.formatTimestamp(received, False), read]) inbox.reverse() def loadSent(): sys.stdout = sys.__stdout__ @@ -902,20 +902,20 @@ def loadSent(): elif status == "msgqueued": statstr = "Message queued" elif status == "msgsent": - t = strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(lastactiontime))) + t = l10n.formatTimestamp(lastactiontime, False) statstr = "Message sent at "+t+".Waiting for acknowledgement." elif status == "msgsentnoackexpected": - t = strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(lastactiontime))) + t = l10n.formatTimestamp(lastactiontime, False) statstr = "Message sent at "+t+"." elif status == "doingmsgpow": statstr = "The proof of work required to send the message has been queued." elif status == "askreceived": - t = strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(lastactiontime))) + t = l10n.formatTimestamp(lastactiontime, False) statstr = "Acknowledgment of the message received at "+t+"." elif status == "broadcastqueued": statstr = "Broadcast queued." elif status == "broadcastsent": - t = strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(lastactiontime))) + t = l10n.formatTimestamp(lastactiontime, False) statstr = "Broadcast sent at "+t+"." elif status == "forcepow": statstr = "Forced difficulty override. Message will start sending soon." @@ -924,12 +924,12 @@ def loadSent(): elif status == "toodifficult": statstr = "Error: The work demanded by the recipient is more difficult than you are willing to do." else: - t = strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(lastactiontime))) + t = l10n.formatTimestamp(lastactiontime, False) statstr = "Unknown status "+status+" at "+t+"." # Load into array sentbox.append([tolabel, toaddr, fromlabel, fromaddr, subject, statstr, ackdata, - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(lastactiontime)))]) + l10n.formatTimestamp(lastactiontime, False)]) sentbox.reverse() def loadAddrBook(): sys.stdout = sys.__stdout__ diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 47870046..e00011a9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1,8 +1,3 @@ -try: - import locale -except: - pass - withMessagingMenu = False try: from gi.repository import MessagingMenu @@ -40,6 +35,7 @@ from debug import logger import subprocess import datetime from helper_sql import * +import l10n try: from PyQt4 import QtCore, QtGui @@ -578,7 +574,7 @@ class MyForm(QtGui.QMainWindow): self.statusbar = self.statusBar() self.statusbar.insertPermanentWidget(0, self.ui.pushButtonStatusIcon) self.ui.labelStartupTime.setText(_translate("MainWindow", "Since startup on %1").arg( - unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))),'utf-8'))) + l10n.formatTimestamp())) self.numberOfMessagesProcessed = 0 self.numberOfBroadcastsProcessed = 0 self.numberOfPubkeysProcessed = 0 @@ -837,34 +833,34 @@ class MyForm(QtGui.QMainWindow): "MainWindow", "Queued.") elif status == 'msgsent': statusText = _translate("MainWindow", "Message sent. Waiting for acknowledgement. Sent at %1").arg( - unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + l10n.formatTimestamp(lastactiontime)) elif status == 'msgsentnoackexpected': statusText = _translate("MainWindow", "Message sent. Sent at %1").arg( - unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + l10n.formatTimestamp(lastactiontime)) elif status == 'doingmsgpow': statusText = _translate( "MainWindow", "Need to do work to send message. Work is queued.") elif status == 'ackreceived': statusText = _translate("MainWindow", "Acknowledgement of the message received %1").arg( - unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + l10n.formatTimestamp(lastactiontime)) elif status == 'broadcastqueued': statusText = _translate( "MainWindow", "Broadcast queued.") elif status == 'broadcastsent': - statusText = _translate("MainWindow", "Broadcast on %1").arg(unicode(strftime( - shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + statusText = _translate("MainWindow", "Broadcast on %1").arg( + l10n.formatTimestamp(lastactiontime)) elif status == 'toodifficult': statusText = _translate("MainWindow", "Problem: The work demanded by the recipient is more difficult than you are willing to do. %1").arg( - unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + l10n.formatTimestamp(lastactiontime)) elif status == 'badkey': statusText = _translate("MainWindow", "Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1").arg( - unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + l10n.formatTimestamp(lastactiontime)) elif status == 'forcepow': statusText = _translate( "MainWindow", "Forced difficulty override. Send should start soon.") else: - statusText = _translate("MainWindow", "Unknown status: %1 %2").arg(status).arg(unicode( - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(lastactiontime)),'utf-8')) + statusText = _translate("MainWindow", "Unknown status: %1 %2").arg(status).arg( + l10n.formatTimestamp(lastactiontime)) newItem = myTableWidgetItem(statusText) newItem.setToolTip(statusText) newItem.setData(Qt.UserRole, QByteArray(ackdata)) @@ -971,10 +967,8 @@ class MyForm(QtGui.QMainWindow): subject_item.setFont(font) self.ui.tableWidgetInbox.setItem(0, 2, subject_item) # time received - time_item = myTableWidgetItem(unicode(strftime(shared.config.get( - 'bitmessagesettings', 'timeformat'), localtime(int(received))), 'utf-8')) - time_item.setToolTip(unicode(strftime(shared.config.get( - 'bitmessagesettings', 'timeformat'), localtime(int(received))), 'utf-8')) + time_item = myTableWidgetItem(l10n.formatTimestamp(received)) + time_item.setToolTip(l10n.formatTimestamp(received)) time_item.setData(Qt.UserRole, QByteArray(msgid)) time_item.setData(33, int(received)) time_item.setFlags( @@ -2062,12 +2056,9 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetSent.setItem(0, 2, newItem) # newItem = QtGui.QTableWidgetItem('Doing work necessary to send # broadcast...'+ - # unicode(strftime(shared.config.get('bitmessagesettings', - # 'timeformat'),localtime(int(time.time()))),'utf-8')) - newItem = myTableWidgetItem(_translate("MainWindow", "Work is queued. %1").arg(unicode(strftime(shared.config.get( - 'bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))) - newItem.setToolTip(_translate("MainWindow", "Work is queued. %1").arg(unicode(strftime(shared.config.get( - 'bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))) + # l10n.formatTimestamp()) + newItem = myTableWidgetItem(_translate("MainWindow", "Work is queued. %1").arg(l10n.formatTimestamp())) + newItem.setToolTip(_translate("MainWindow", "Work is queued. %1").arg(l10n.formatTimestamp())) newItem.setData(Qt.UserRole, QByteArray(ackdata)) newItem.setData(33, int(time.time())) self.ui.tableWidgetSent.setItem(0, 3, newItem) @@ -2134,10 +2125,8 @@ class MyForm(QtGui.QMainWindow): #newItem.setData(Qt.UserRole, unicode(message, 'utf-8)')) # No longer hold the message in the table; we'll use a SQL query to display it as needed. newItem.setFont(font) self.ui.tableWidgetInbox.setItem(0, 2, newItem) - newItem = myTableWidgetItem(unicode(strftime(shared.config.get( - 'bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')) - newItem.setToolTip(unicode(strftime(shared.config.get( - 'bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8')) + newItem = myTableWidgetItem(l10n.formatTimestamp()) + newItem.setToolTip(l10n.formatTimestamp()) newItem.setData(Qt.UserRole, QByteArray(inventoryHash)) newItem.setData(33, int(time.time())) newItem.setFont(font) @@ -3811,52 +3800,12 @@ def run(): app = QtGui.QApplication(sys.argv) translator = QtCore.QTranslator() - try: - locale_countrycode = str(locale.getdefaultlocale()[0]) - except: - # The above is not compatible with all versions of OSX. - locale_countrycode = "en_US" # Default to english. - locale_lang = locale_countrycode[0:2] - user_countrycode = str(shared.config.get('bitmessagesettings', 'userlocale')) - user_lang = user_countrycode[0:2] - try: - translation_path = os.path.join(sys._MEIPASS, "translations/bitmessage_") - except Exception, e: - translation_path = "translations/bitmessage_" - - if shared.config.get('bitmessagesettings', 'userlocale') == 'system': - # try to detect the users locale otherwise fallback to English - try: - # try the users full locale, e.g. 'en_US': - # since we usually only provide languages, not localozations - # this will usually fail - translator.load(translation_path + locale_countrycode) - except: - try: - # try the users locale language, e.g. 'en': - # since we usually only provide languages, not localozations - # this will usually succeed - translator.load(translation_path + locale_lang) - except: - # as English is already the default language, we don't - # need to do anything. No need to translate. - pass - else: - try: - # check if the user input is a valid translation file: - # since user_countrycode will be usually set by the combobox - # it will usually just be a language code - translator.load(translation_path + user_countrycode) - except: - try: - # check if the user lang is a valid translation file: - # this is only needed if the user manually set his 'userlocale' - # in the keys.dat to a countrycode (e.g. 'de_CH') - translator.load(translation_path + user_lang) - except: - # as English is already the default language, we don't - # need to do anything. No need to translate. - pass + translationpath = os.path.join( + getattr(sys, '_MEIPASS', ''), + 'translations', + 'bitmessage_' + l10n.getTranslationLanguage() + ) + translator.load(translationpath) QtGui.QApplication.installTranslator(translator) app.setStyleSheet("QStatusBar::item { border: 0px solid black }") diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index b8a3c949..326ba98a 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -19,6 +19,7 @@ import helper_sent from helper_sql import * import tr from debug import logger +import l10n class objectProcessor(threading.Thread): @@ -421,8 +422,7 @@ class objectProcessor(threading.Thread): del shared.ackdataForWhichImWatching[data[readPosition:]] sqlExecute('UPDATE sent SET status=? WHERE ackdata=?', 'ackreceived', data[readPosition:]) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[readPosition:], tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(unicode( - time.strftime(shared.config.get('bitmessagesettings', 'timeformat'), time.localtime(int(time.time()))), 'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[readPosition:], tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(l10n.formatTimestamp())))) return else: logger.info('This was NOT an acknowledgement bound for me.') diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 5e8f11e8..e5353bda 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -13,6 +13,7 @@ from debug import logger from helper_sql import * import helper_inbox from helper_generic import addDataPadding +import l10n # This thread, of which there is only one, does the heavy lifting: # calculating POWs. @@ -440,8 +441,7 @@ class singleWorker(threading.Thread): shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Broadcast sent on %1").arg(unicode( - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) # Update the status of the message in the 'sent' table to have # a 'broadcastsent' status @@ -616,7 +616,7 @@ class singleWorker(threading.Thread): if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.') - shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(l10n.formatTimestamp())))) # if the human changes their setting and then sends another message or restarts their client, this one will send at that time. continue readPosition += 4 # to bypass the bitfield of behaviors @@ -655,7 +655,7 @@ class singleWorker(threading.Thread): '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', ackdata) shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do.").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( - requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) + requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. with shared.printLock: @@ -666,7 +666,7 @@ class singleWorker(threading.Thread): privEncryptionKeyBase58 = shared.config.get( toaddress, 'privencryptionkey') except Exception as err: - shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) with shared.printLock: sys.stderr.write( 'Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err) @@ -803,7 +803,7 @@ class singleWorker(threading.Thread): encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex')) except: sqlExecute('''UPDATE sent SET status='badkey' WHERE ackdata=?''', ackdata) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) continue encryptedPayload = embeddedTime + encodeVarint(toStreamNumber) + encrypted target = 2**64 / ((len(encryptedPayload)+requiredPayloadLengthExtraBytes+8) * requiredAverageProofOfWorkNonceTrialsPerByte) @@ -828,12 +828,10 @@ class singleWorker(threading.Thread): objectType, toStreamNumber, encryptedPayload, int(time.time()),'') shared.inventorySets[toStreamNumber].add(inventoryHash) if shared.config.has_section(toaddress): - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent on %1").arg(unicode( - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent on %1").arg(l10n.formatTimestamp())))) else: # not sending to a chan or one of my addresses - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(unicode( - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(l10n.formatTimestamp())))) print 'Broadcasting inv for my msg(within sendmsg function):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) @@ -926,8 +924,7 @@ class singleWorker(threading.Thread): shared.UISignalQueue.put(( 'updateStatusBar', tr.translateText("MainWindow",'Broacasting the public key request. This program will auto-retry if they are offline.'))) - shared.UISignalQueue.put(('updateSentItemStatusByHash', (ripe, tr.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(unicode( - strftime(shared.config.get('bitmessagesettings', 'timeformat'), localtime(int(time.time()))), 'utf-8'))))) + shared.UISignalQueue.put(('updateSentItemStatusByHash', (ripe, tr.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) def generateFullAckMessage(self, ackdata, toStreamNumber): embeddedTime = pack('>Q', (int(time.time()) + random.randrange( diff --git a/src/l10n.py b/src/l10n.py new file mode 100644 index 00000000..c04b5cdb --- /dev/null +++ b/src/l10n.py @@ -0,0 +1,42 @@ + +import logging +import time + +import shared + + +#logger = logging.getLogger(__name__) +logger = logging.getLogger('file_only') + +try: + import locale + encoding = locale.getpreferredencoding(False) + language = locale.getlocale()[0] or locale.getdefaultlocale()[0] +except: + logger.exception('Could not determine language or encoding') + if not encoding: + encoding = 'ISO8859-1' + language = 'en_US' + + +time_format = shared.config.get('bitmessagesettings', 'timeformat') + +def formatTimestamp(timestamp = None, as_unicode = True): + if timestamp and isinstance(timestamp, (float, int)): + timestring = time.strftime(time_format, time.localtime(timestamp)) + else: + timestring = time.strftime(time_format) + if as_unicode: + return unicode(timestring, encoding) + return timestring + +def getTranslationLanguage(): + userlocale = None + if shared.config.has_option('bitmessagesettings', 'userlocale'): + userlocale = shared.config.get('bitmessagesettings', 'userlocale') + + if userlocale in [None, '', 'system']: + return language + + return userlocale + -- 2.45.1