← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~raoul-snyman/openlp/fix-translations into lp:openlp

 

Raoul Snyman has proposed merging lp:~raoul-snyman/openlp/fix-translations into lp:openlp.

Commit message:
Fix a problem with loading Qt's translation files, bug #1676163

Requested reviews:
  OpenLP Core (openlp-core)
Related bugs:
  Bug #1676163 in OpenLP: "Missing Qt 5 translations (OLP 2.3 >)"
  https://bugs.launchpad.net/openlp/+bug/1676163

For more details, see:
https://code.launchpad.net/~raoul-snyman/openlp/fix-translations/+merge/321132

Fix a problem with loading Qt's translation files, bug #1676163

Add this to your merge proposal:
--------------------------------
lp:~raoul-snyman/openlp/fix-translations (revision 2729)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1944/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1855/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1796/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1522/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/1112/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/1180/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/1048/
[SUCCESS] https://ci.openlp.io/job/Branch-05c-Code_Analysis2/182/
-- 
Your team OpenLP Core is requested to review the proposed merge of lp:~raoul-snyman/openlp/fix-translations into lp:openlp.
=== modified file 'CHANGELOG.rst'
--- CHANGELOG.rst	2017-03-23 05:08:14 +0000
+++ CHANGELOG.rst	2017-03-28 01:20:30 +0000
@@ -9,3 +9,4 @@
 * Fix a problem with the new QMediaPlayer not controlling the playlist anymore
 * Added importing of author types to the OpenLP 2 song importer
 * Refactored the merge script and gave it some options
+* Fix a problem with loading Qt's translation files, bug #1676163

=== modified file 'openlp/core/__init__.py'
--- openlp/core/__init__.py	2017-03-10 05:42:38 +0000
+++ openlp/core/__init__.py	2017-03-28 01:20:30 +0000
@@ -428,13 +428,12 @@
             sys.exit()
     # i18n Set Language
     language = LanguageManager.get_language()
-    application_translator, default_translator = LanguageManager.get_translator(language)
-    if not application_translator.isEmpty():
-        application.installTranslator(application_translator)
-    if not default_translator.isEmpty():
-        application.installTranslator(default_translator)
-    else:
-        log.debug('Could not find default_translator.')
+    translators = LanguageManager.get_translators(language)
+    for translator in translators:
+        if not translator.isEmpty():
+            application.installTranslator(translator)
+    if not translators:
+        log.debug('Could not find translators.')
     if args and not args.no_error_form:
         sys.excepthook = application.hook_exception
     sys.exit(application.run(qt_args))

=== modified file 'openlp/core/common/languagemanager.py'
--- openlp/core/common/languagemanager.py	2016-12-31 11:01:36 +0000
+++ openlp/core/common/languagemanager.py	2017-03-28 01:20:30 +0000
@@ -45,7 +45,7 @@
     auto_language = False
 
     @staticmethod
-    def get_translator(language):
+    def get_translators(language):
         """
         Set up a translator to use in this instance of OpenLP
 
@@ -59,9 +59,12 @@
         # A translator for buttons and other default strings provided by Qt.
         if not is_win() and not is_macosx():
             lang_path = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)
+        # As of Qt5, the core translations come in 2 files per language
         default_translator = QtCore.QTranslator()
         default_translator.load('qt_%s' % language, lang_path)
-        return app_translator, default_translator
+        base_translator = QtCore.QTranslator()
+        base_translator.load('qtbase_%s' % language, lang_path)
+        return app_translator, default_translator, base_translator
 
     @staticmethod
     def find_qm_files():
@@ -71,8 +74,8 @@
         log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
         trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir))
         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_')]
+        # Remove qm files from the list which start with "qt".
+        file_names = [file_ for file_ in file_names if not file_.startswith('qt')]
         return list(map(trans_dir.filePath, file_names))
 
     @staticmethod

=== modified file 'openlp/plugins/songs/forms/songmaintenanceform.py'
--- openlp/plugins/songs/forms/songmaintenanceform.py	2016-12-31 11:01:36 +0000
+++ openlp/plugins/songs/forms/songmaintenanceform.py	2017-03-28 01:20:30 +0000
@@ -20,7 +20,6 @@
 # Temple Place, Suite 330, Boston, MA 02111-1307 USA                          #
 ###############################################################################
 import logging
-import os
 
 from PyQt5 import QtCore, QtWidgets
 from sqlalchemy.sql import and_
@@ -184,7 +183,7 @@
                 Author.display_name == new_author.display_name
             )
         )
-        return self.__check_object_exists(authors, new_author, edit)
+        return self._check_object_exists(authors, new_author, edit)
 
     def check_topic_exists(self, new_topic, edit=False):
         """
@@ -194,7 +193,7 @@
         :param edit: Are we editing the song?
         """
         topics = self.manager.get_all_objects(Topic, Topic.name == new_topic.name)
-        return self.__check_object_exists(topics, new_topic, edit)
+        return self._check_object_exists(topics, new_topic, edit)
 
     def check_song_book_exists(self, new_book, edit=False):
         """
@@ -205,9 +204,9 @@
         """
         books = self.manager.get_all_objects(
             Book, and_(Book.name == new_book.name, Book.publisher == new_book.publisher))
-        return self.__check_object_exists(books, new_book, edit)
+        return self._check_object_exists(books, new_book, edit)
 
-    def __check_object_exists(self, existing_objects, new_object, edit):
+    def _check_object_exists(self, existing_objects, new_object, edit):
         """
         Utility method to check for an existing object.
 

=== modified file 'tests/interfaces/openlp_plugins/songs/forms/test_songmaintenanceform.py'
--- tests/interfaces/openlp_plugins/songs/forms/test_songmaintenanceform.py	2017-03-23 04:43:13 +0000
+++ tests/interfaces/openlp_plugins/songs/forms/test_songmaintenanceform.py	2017-03-28 01:20:30 +0000
@@ -25,7 +25,7 @@
 from unittest import TestCase
 from unittest.mock import MagicMock, patch, call
 
-from PyQt5 import QtCore, QtTest, QtWidgets
+from PyQt5 import QtCore, QtWidgets
 
 from openlp.core.common import Registry, UiStrings
 from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
@@ -89,6 +89,7 @@
         mocked_reset_song_books.assert_called_once_with()
         mocked_type_list_widget.setFocus.assert_called_once_with()
         mocked_exec.assert_called_once_with(self.form)
+        assert result is True
 
     def test_get_current_item_id_no_item(self):
         """
@@ -290,3 +291,131 @@
         MockedQListWidgetItem.assert_called_once_with('Hymnal (Hymns and Psalms, Inc.)')
         mocked_song_book_item.setData.assert_called_once_with(QtCore.Qt.UserRole, 1)
         mocked_song_book_list_widget.addItem.assert_called_once_with(mocked_song_book_item)
+
+    @patch('openlp.plugins.songs.forms.songmaintenanceform.and_')
+    @patch('openlp.plugins.songs.forms.songmaintenanceform.Author')
+    def test_check_author_exists(self, MockedAuthor, mocked_and):
+        """
+        Test the check_author_exists() method
+        """
+        # GIVEN: A bunch of mocked out stuff
+        MockedAuthor.first_name = 'John'
+        MockedAuthor.last_name = 'Newton'
+        MockedAuthor.display_name = 'John Newton'
+        mocked_new_author = MagicMock()
+        mocked_new_author.first_name = 'John'
+        mocked_new_author.last_name = 'Newton'
+        mocked_new_author.display_name = 'John Newton'
+        mocked_and.return_value = True
+        mocked_authors = [MagicMock(), MagicMock()]
+        self.mocked_manager.get_all_objects.return_value = mocked_authors
+
+        # WHEN: check_author_exists() is called
+        with patch.object(self.form, '_check_object_exists') as mocked_check_object_exists:
+            mocked_check_object_exists.return_value = True
+            result = self.form.check_author_exists(mocked_new_author, edit=True)
+
+        # THEN: The correct result is returned
+        mocked_and.assert_called_once_with(True, True, True)
+        self.mocked_manager.get_all_objects.assert_called_once_with(MockedAuthor, True)
+        mocked_check_object_exists.assert_called_once_with(mocked_authors, mocked_new_author, True)
+        assert result is True
+
+    @patch('openlp.plugins.songs.forms.songmaintenanceform.Topic')
+    def test_check_topic_exists(self, MockedTopic):
+        """
+        Test the check_topic_exists() method
+        """
+        # GIVEN: Some mocked stuff
+        MockedTopic.name = 'Grace'
+        mocked_new_topic = MagicMock()
+        mocked_new_topic.name = 'Grace'
+        mocked_topics = [MagicMock(), MagicMock()]
+        self.mocked_manager.get_all_objects.return_value = mocked_topics
+
+        # WHEN: check_topic_exists() is run
+        with patch.object(self.form, '_check_object_exists') as mocked_check_object_exists:
+            mocked_check_object_exists.return_value = True
+            result = self.form.check_topic_exists(mocked_new_topic, True)
+
+        # THEN: The correct things should have been called
+        self.mocked_manager.get_all_objects.assert_called_once_with(MockedTopic, True)
+        mocked_check_object_exists.assert_called_once_with(mocked_topics, mocked_new_topic, True)
+        assert result is True
+
+    @patch('openlp.plugins.songs.forms.songmaintenanceform.and_')
+    @patch('openlp.plugins.songs.forms.songmaintenanceform.Book')
+    def test_check_song_book_exists(self, MockedBook, mocked_and):
+        """
+        Test the check_song_book_exists() method
+        """
+        # GIVEN: Some mocked stuff
+        MockedBook.name = 'Hymns'
+        MockedBook.publisher = 'Christian Songs'
+        mocked_new_book = MagicMock()
+        mocked_new_book.name = 'Hymns'
+        mocked_new_book.publisher = 'Christian Songs'
+        mocked_and.return_value = True
+        mocked_books = [MagicMock(), MagicMock()]
+        self.mocked_manager.get_all_objects.return_value = mocked_books
+
+        # WHEN: check_book_exists() is run
+        with patch.object(self.form, '_check_object_exists') as mocked_check_object_exists:
+            mocked_check_object_exists.return_value = True
+            result = self.form.check_song_book_exists(mocked_new_book, True)
+
+        # THEN: The correct things should have been called
+        mocked_and.assert_called_once_with(True, True)
+        self.mocked_manager.get_all_objects.assert_called_once_with(MockedBook, True)
+        mocked_check_object_exists.assert_called_once_with(mocked_books, mocked_new_book, True)
+        assert result is True
+
+    def test_check_object_exists_no_existing_objects(self):
+        """
+        Test the _check_object_exists() method when there are no existing objects
+        """
+        # GIVEN: A SongMaintenanceForm instance
+        # WHEN: _check_object_exists() is called without existing objects
+        result = self.form._check_object_exists([], None, False)
+
+        # THEN: The result should be True
+        assert result is True
+
+    def test_check_object_exists_without_edit(self):
+        """
+        Test the _check_object_exists() method when edit is false
+        """
+        # GIVEN: A SongMaintenanceForm instance
+        # WHEN: _check_object_exists() is called with edit set to false
+        result = self.form._check_object_exists([MagicMock()], None, False)
+
+        # THEN: The result should be False
+        assert result is False
+
+    def test_check_object_exists_not_found(self):
+        """
+        Test the _check_object_exists() method when the object is not found
+        """
+        # GIVEN: A SongMaintenanceForm instance and some mocked objects
+        mocked_existing_objects = [MagicMock(id=1)]
+        mocked_new_object = MagicMock(id=2)
+
+        # WHEN: _check_object_exists() is called with edit set to false
+        result = self.form._check_object_exists(mocked_existing_objects, mocked_new_object, True)
+
+        # THEN: The result should be False
+        assert result is False
+
+    def test_check_object_exists(self):
+        """
+        Test the _check_object_exists() method
+        """
+        # GIVEN: A SongMaintenanceForm instance and some mocked objects
+        mocked_existing_objects = [MagicMock(id=1)]
+        mocked_new_object = MagicMock(id=1)
+
+        # WHEN: _check_object_exists() is called with edit set to false
+        result = self.form._check_object_exists(mocked_existing_objects, mocked_new_object, True)
+
+        # THEN: The result should be False
+        assert result is True


Follow ups