openlp/openlp/core/common/languagemanager.py

211 lines
8.4 KiB
Python
Raw Normal View History

2010-04-16 22:06:28 +00:00
# -*- coding: utf-8 -*-
2012-12-29 09:35:24 +00:00
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
2010-04-16 22:06:28 +00:00
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
2016-12-31 11:01:36 +00:00
# Copyright (c) 2008-2017 OpenLP Developers #
2010-04-16 22:06:28 +00:00
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
2010-06-29 07:07:03 +00:00
"""
2013-02-02 20:18:34 +00:00
The :mod:`languagemanager` module provides all the translation settings and language file loading for OpenLP.
2010-06-29 07:07:03 +00:00
"""
2016-04-03 19:44:09 +00:00
import locale
2010-04-16 22:06:28 +00:00
import logging
2012-05-19 15:10:05 +00:00
import re
2010-04-16 22:06:28 +00:00
2015-11-07 00:49:40 +00:00
from PyQt5 import QtCore, QtWidgets
2010-06-09 17:09:32 +00:00
from openlp.core.common import AppLocation, Settings, translate, is_win, is_macosx
2010-04-19 19:12:34 +00:00
log = logging.getLogger(__name__)
2010-04-16 22:06:28 +00:00
2016-04-05 17:30:20 +00:00
ICU_COLLATOR = None
2016-04-03 19:44:09 +00:00
DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE)
2013-02-02 20:18:34 +00:00
2010-04-16 22:06:28 +00:00
class LanguageManager(object):
"""
2010-06-08 15:38:09 +00:00
Helper for Language selection
2010-04-16 22:06:28 +00:00
"""
__qm_list__ = {}
auto_language = False
2010-04-16 22:06:28 +00:00
@staticmethod
def get_translators(language):
2010-06-29 07:07:03 +00:00
"""
Set up a translator to use in this instance of OpenLP
2014-03-17 19:05:55 +00:00
:param language: The language to load into the translator
2010-06-29 07:07:03 +00:00
"""
if LanguageManager.auto_language:
2010-04-16 22:06:28 +00:00
language = QtCore.QLocale.system().name()
lang_path = AppLocation.get_directory(AppLocation.LanguageDir)
2010-06-29 07:07:03 +00:00
app_translator = QtCore.QTranslator()
2011-04-23 15:15:01 +00:00
app_translator.load(language, lang_path)
# A translator for buttons and other default strings provided by Qt.
if not is_win() and not is_macosx():
2012-12-29 09:35:24 +00:00
lang_path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)
# As of Qt5, the core translations come in 2 files per language
2011-04-23 15:40:07 +00:00
default_translator = QtCore.QTranslator()
2013-08-31 18:17:38 +00:00
default_translator.load('qt_%s' % language, lang_path)
base_translator = QtCore.QTranslator()
base_translator.load('qtbase_%s' % language, lang_path)
return app_translator, default_translator, base_translator
2010-04-16 22:06:28 +00:00
@staticmethod
2010-04-19 19:12:34 +00:00
def find_qm_files():
2010-06-29 07:07:03 +00:00
"""
Find all available language files in this OpenLP install
"""
log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
2012-12-29 09:35:24 +00:00
trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir))
2014-04-03 12:38:39 +00:00
file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt".
file_names = [file_ for file_ in file_names if not file_.startswith('qt')]
2013-08-31 18:17:38 +00:00
return list(map(trans_dir.filePath, file_names))
2010-04-16 22:06:28 +00:00
@staticmethod
2010-06-29 07:07:03 +00:00
def language_name(qm_file):
"""
Load the language name from a language file
2014-03-17 19:05:55 +00:00
:param qm_file: The file to obtain the name from
2010-06-29 07:07:03 +00:00
"""
translator = QtCore.QTranslator()
2010-06-29 07:07:03 +00:00
translator.load(qm_file)
2012-12-29 09:35:24 +00:00
return translator.translate('OpenLP.MainWindow', 'English', 'Please add the name of your language here')
2010-04-16 22:06:28 +00:00
@staticmethod
2010-04-19 19:12:34 +00:00
def get_language():
2010-06-29 07:07:03 +00:00
"""
Retrieve a saved language to use from settings
"""
2013-08-31 18:17:38 +00:00
language = Settings().value('core/language')
2012-05-19 15:10:05 +00:00
language = str(language)
log.info("Language file: '{language}' Loaded from conf file".format(language=language))
2012-05-19 15:10:05 +00:00
if re.match(r'[[].*[]]', language):
LanguageManager.auto_language = True
2012-05-19 15:10:05 +00:00
language = re.sub(r'[\[\]]', '', language)
2010-04-16 22:06:28 +00:00
return language
@staticmethod
2011-02-27 09:53:47 +00:00
def set_language(action, message=True):
2010-06-29 07:07:03 +00:00
"""
Set the language to translate OpenLP into
2014-03-17 19:05:55 +00:00
:param action: The language menu option
:param message: Display the message option
2010-06-29 07:07:03 +00:00
"""
2013-08-31 18:17:38 +00:00
language = 'en'
if action:
2013-08-31 18:17:38 +00:00
action_name = str(action.objectName())
if action_name == 'autoLanguageItem':
LanguageManager.auto_language = True
else:
LanguageManager.auto_language = False
qm_list = LanguageManager.get_qm_list()
2013-08-31 18:17:38 +00:00
language = str(qm_list[action_name])
if LanguageManager.auto_language:
language = '[{language}]'.format(language=language)
2013-08-31 18:17:38 +00:00
Settings().setValue('core/language', language)
log.info("Language file: '{language}' written to conf file".format(language=language))
2011-02-27 09:53:47 +00:00
if message:
2015-11-07 00:49:40 +00:00
QtWidgets.QMessageBox.information(None,
translate('OpenLP.LanguageManager', 'Language'),
translate('OpenLP.LanguageManager',
'Please restart OpenLP to use your new language setting.'))
2010-04-16 22:06:28 +00:00
@staticmethod
2010-04-19 19:12:34 +00:00
def init_qm_list():
2010-06-29 07:07:03 +00:00
"""
Initialise the list of available translations
"""
LanguageManager.__qm_list__ = {}
2010-06-29 07:07:03 +00:00
qm_files = LanguageManager.find_qm_files()
for counter, qmf in enumerate(qm_files):
reg_ex = QtCore.QRegExp("^.*i18n/(.*).qm")
if reg_ex.exactMatch(qmf):
name = '{regex}'.format(regex=reg_ex.cap(1))
# TODO: Test before converting to python3 string format
2013-08-31 18:17:38 +00:00
LanguageManager.__qm_list__['%#2i %s' % (counter + 1, LanguageManager.language_name(qmf))] = name
2010-04-16 22:06:28 +00:00
@staticmethod
2010-04-19 19:12:34 +00:00
def get_qm_list():
2010-06-29 07:07:03 +00:00
"""
Return the list of available translations
"""
if not LanguageManager.__qm_list__:
2010-04-19 19:12:34 +00:00
LanguageManager.init_qm_list()
return LanguageManager.__qm_list__
2016-04-03 19:44:09 +00:00
def format_time(text, local_time):
"""
Workaround for Python built-in time formatting function time.strftime().
time.strftime() accepts only ascii characters. This function accepts
unicode string and passes individual % placeholders to time.strftime().
This ensures only ascii characters are passed to time.strftime().
:param text: The text to be processed.
:param local_time: The time to be used to add to the string. This is a time object
"""
def match_formatting(match):
"""
Format the match
"""
return local_time.strftime(match.group())
2016-07-01 21:17:20 +00:00
return re.sub(r'\%[a-zA-Z]', match_formatting, text)
2016-04-03 19:44:09 +00:00
def get_locale_key(string):
"""
Creates a key for case insensitive, locale aware string sorting.
:param string: The corresponding string.
"""
string = string.lower()
# ICU is the prefered way to handle locale sort key, we fallback to locale.strxfrm which will work in most cases.
global ICU_COLLATOR
try:
if ICU_COLLATOR is None:
import icu
language = LanguageManager.get_language()
icu_locale = icu.Locale(language)
ICU_COLLATOR = icu.Collator.createInstance(icu_locale)
return ICU_COLLATOR.getSortKey(string)
except:
return locale.strxfrm(string).encode()
def get_natural_key(string):
"""
Generate a key for locale aware natural string sorting.
:param string: string to be sorted by
Returns a list of string compare keys and integers.
"""
key = DIGITS_OR_NONDIGITS.findall(string)
key = [int(part) if part.isdigit() else get_locale_key(part) for part in key]
# Python 3 does not support comparison of different types anymore. So make sure, that we do not compare str
# and int.
if string and string[0].isdigit():
return [b''] + key
return key