2019-10-22 16:22:56 +02:00
|
|
|
"""
|
|
|
|
Localization
|
|
|
|
"""
|
2014-08-06 04:01:01 +02:00
|
|
|
import logging
|
2016-12-13 11:54:01 +01:00
|
|
|
import os
|
2014-08-06 04:01:01 +02:00
|
|
|
import time
|
|
|
|
|
2017-02-22 09:34:54 +01:00
|
|
|
from bmconfigparser import BMConfigParser
|
2014-08-06 04:01:01 +02:00
|
|
|
|
|
|
|
|
2019-10-17 22:37:56 +02:00
|
|
|
logger = logging.getLogger('default')
|
2014-08-06 04:01:01 +02:00
|
|
|
|
2014-08-08 03:34:57 +02:00
|
|
|
|
|
|
|
DEFAULT_ENCODING = 'ISO8859-1'
|
|
|
|
DEFAULT_LANGUAGE = 'en_US'
|
2014-08-08 06:38:23 +02:00
|
|
|
DEFAULT_TIME_FORMAT = '%Y-%m-%d %H:%M:%S'
|
2014-08-08 03:34:57 +02:00
|
|
|
|
|
|
|
encoding = DEFAULT_ENCODING
|
|
|
|
language = DEFAULT_LANGUAGE
|
|
|
|
|
2016-04-27 12:15:30 +02:00
|
|
|
windowsLanguageMap = {
|
|
|
|
"ar": "arabic",
|
|
|
|
"cs": "czech",
|
|
|
|
"da": "danish",
|
|
|
|
"de": "german",
|
|
|
|
"en": "english",
|
|
|
|
"eo": "esperanto",
|
|
|
|
"fr": "french",
|
|
|
|
"it": "italian",
|
|
|
|
"ja": "japanese",
|
|
|
|
"nl": "dutch",
|
|
|
|
"no": "norwegian",
|
|
|
|
"pl": "polish",
|
|
|
|
"pt": "portuguese",
|
|
|
|
"ru": "russian",
|
|
|
|
"sk": "slovak",
|
|
|
|
"zh": "chinese",
|
|
|
|
"zh_CN": "chinese-simplified",
|
|
|
|
"zh_HK": "chinese-traditional",
|
|
|
|
"zh_SG": "chinese-simplified",
|
|
|
|
"zh_TW": "chinese-traditional"
|
|
|
|
}
|
|
|
|
|
2014-08-06 04:01:01 +02:00
|
|
|
try:
|
|
|
|
import locale
|
2014-08-28 13:39:40 +02:00
|
|
|
encoding = locale.getpreferredencoding(True) or DEFAULT_ENCODING
|
2014-08-08 03:34:57 +02:00
|
|
|
language = locale.getlocale()[0] or locale.getdefaultlocale()[0] or DEFAULT_LANGUAGE
|
2014-08-06 04:01:01 +02:00
|
|
|
except:
|
|
|
|
logger.exception('Could not determine language or encoding')
|
|
|
|
|
|
|
|
|
2017-01-11 14:27:19 +01:00
|
|
|
if BMConfigParser().has_option('bitmessagesettings', 'timeformat'):
|
|
|
|
time_format = BMConfigParser().get('bitmessagesettings', 'timeformat')
|
2019-10-22 16:22:56 +02:00
|
|
|
# Test the format string
|
2014-08-08 06:38:23 +02:00
|
|
|
try:
|
|
|
|
time.strftime(time_format)
|
|
|
|
except:
|
2014-08-16 06:23:30 +02:00
|
|
|
logger.exception('Could not format timestamp')
|
2014-08-08 06:38:23 +02:00
|
|
|
time_format = DEFAULT_TIME_FORMAT
|
|
|
|
else:
|
|
|
|
time_format = DEFAULT_TIME_FORMAT
|
|
|
|
|
2019-10-22 16:22:56 +02:00
|
|
|
# It seems some systems lie about the encoding they use so we perform
|
|
|
|
# comprehensive decoding tests
|
2014-08-16 06:23:30 +02:00
|
|
|
if time_format != DEFAULT_TIME_FORMAT:
|
|
|
|
try:
|
2019-12-30 13:10:02 +01:00
|
|
|
# Check day names
|
2019-12-23 12:18:37 +01:00
|
|
|
new_time_format = time_format
|
2019-09-26 16:08:19 +02:00
|
|
|
import sys
|
|
|
|
if sys.version_info >= (3, 0, 0) and time_format == '%%c':
|
|
|
|
time_format = '%c'
|
|
|
|
for i in range(7):
|
2019-12-30 13:10:02 +01:00
|
|
|
# this work for python2.7
|
2019-09-26 16:08:19 +02:00
|
|
|
# unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, i, 0, 0)), encoding)
|
2019-12-30 13:10:02 +01:00
|
|
|
# this code for the python3
|
2019-09-26 16:08:19 +02:00
|
|
|
(time.strftime(time_format, (0, 0, 0, 0, 0, 0, i, 0, 0))).encode()
|
2019-12-30 13:10:02 +01:00
|
|
|
# Check month names
|
2019-09-26 16:08:19 +02:00
|
|
|
for i in range(1, 13):
|
|
|
|
# unicode(time.strftime(time_format, (0, i, 0, 0, 0, 0, 0, 0, 0)), encoding)
|
|
|
|
(time.strftime(time_format, (0, i, 0, 0, 0, 0, 0, 0, 0))).encode()
|
|
|
|
|
2019-12-30 13:10:02 +01:00
|
|
|
# Check AM/PM
|
2019-09-26 16:08:19 +02:00
|
|
|
(time.strftime(time_format, (0, 0, 0, 11, 0, 0, 0, 0, 0))).encode()
|
|
|
|
(time.strftime(time_format, (0, 0, 0, 13, 0, 0, 0, 0, 0))).encode()
|
2019-12-30 13:10:02 +01:00
|
|
|
# Check DST
|
2019-09-26 16:08:19 +02:00
|
|
|
(time.strftime(time_format, (0, 0, 0, 0, 0, 0, 0, 0, 1))).encode()
|
2019-12-23 12:18:37 +01:00
|
|
|
|
2014-08-16 06:23:30 +02:00
|
|
|
except:
|
|
|
|
logger.exception('Could not decode locale formatted timestamp')
|
|
|
|
time_format = DEFAULT_TIME_FORMAT
|
|
|
|
encoding = DEFAULT_ENCODING
|
2019-09-26 16:08:19 +02:00
|
|
|
time_format = new_time_format
|
2014-08-16 06:23:30 +02:00
|
|
|
|
2019-10-22 16:22:56 +02:00
|
|
|
|
2016-12-13 11:54:01 +01:00
|
|
|
def setlocale(category, newlocale):
|
2019-10-22 16:22:56 +02:00
|
|
|
"""Set the locale"""
|
2016-12-13 11:54:01 +01:00
|
|
|
locale.setlocale(category, newlocale)
|
|
|
|
# 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
|
2014-08-06 04:01:01 +02:00
|
|
|
|
2019-10-22 16:22:56 +02:00
|
|
|
|
|
|
|
def formatTimestamp(timestamp=None, as_unicode=True):
|
|
|
|
"""Return a formatted timestamp"""
|
|
|
|
# For some reason some timestamps are strings so we need to sanitize.
|
2014-08-08 06:38:23 +02:00
|
|
|
if timestamp is not None and not isinstance(timestamp, int):
|
|
|
|
try:
|
|
|
|
timestamp = int(timestamp)
|
|
|
|
except:
|
|
|
|
timestamp = None
|
|
|
|
|
2019-10-22 16:22:56 +02:00
|
|
|
# timestamp can't be less than 0.
|
2014-08-08 06:38:23 +02:00
|
|
|
if timestamp is not None and timestamp < 0:
|
|
|
|
timestamp = None
|
|
|
|
|
|
|
|
if timestamp is None:
|
2014-08-06 04:01:01 +02:00
|
|
|
timestring = time.strftime(time_format)
|
2014-08-08 06:38:23 +02:00
|
|
|
else:
|
2019-10-22 16:22:56 +02:00
|
|
|
# In case timestamp is too far in the future
|
2014-08-08 06:38:23 +02:00
|
|
|
try:
|
|
|
|
timestring = time.strftime(time_format, time.localtime(timestamp))
|
|
|
|
except ValueError:
|
|
|
|
timestring = time.strftime(time_format)
|
|
|
|
|
2014-08-06 04:01:01 +02:00
|
|
|
if as_unicode:
|
|
|
|
return unicode(timestring, encoding)
|
|
|
|
return timestring
|
|
|
|
|
2019-10-22 16:22:56 +02:00
|
|
|
|
2014-08-06 04:01:01 +02:00
|
|
|
def getTranslationLanguage():
|
2019-10-22 16:22:56 +02:00
|
|
|
"""Return the user's language choice"""
|
|
|
|
userlocale = BMConfigParser().safeGet(
|
|
|
|
'bitmessagesettings', 'userlocale', 'system')
|
|
|
|
return userlocale if userlocale and userlocale != 'system' else language
|
2014-08-06 04:01:01 +02:00
|
|
|
|
|
|
|
|
2016-04-27 12:15:30 +02:00
|
|
|
def getWindowsLocale(posixLocale):
|
2019-10-22 16:22:56 +02:00
|
|
|
"""
|
|
|
|
Get the Windows locale
|
|
|
|
Technically this converts the locale string from UNIX to Windows format,
|
|
|
|
because they use different ones in their
|
|
|
|
libraries. E.g. "en_EN.UTF-8" to "english".
|
|
|
|
"""
|
2016-04-27 12:15:30 +02:00
|
|
|
if posixLocale in windowsLanguageMap:
|
|
|
|
return windowsLanguageMap[posixLocale]
|
|
|
|
if "." in posixLocale:
|
|
|
|
loc = posixLocale.split(".", 1)
|
|
|
|
if loc[0] in windowsLanguageMap:
|
|
|
|
return windowsLanguageMap[loc[0]]
|
|
|
|
if "_" in posixLocale:
|
|
|
|
loc = posixLocale.split("_", 1)
|
|
|
|
if loc[0] in windowsLanguageMap:
|
|
|
|
return windowsLanguageMap[loc[0]]
|
|
|
|
if posixLocale != DEFAULT_LANGUAGE:
|
|
|
|
return getWindowsLocale(DEFAULT_LANGUAGE)
|
|
|
|
return None
|