← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~m2j/openlp/i18n into lp:openlp

 

Meinert Jordan has proposed merging lp:~m2j/openlp/i18n into lp:openlp.

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~m2j/openlp/i18n/+merge/88930

locale.strcoll does not work correct on Windows with utf-8 [http://sgehrig.wordpress.com/2008/12/08/update-on-strcoll-utf-8-issue/].
The performance ICU is similar to locale.strcoll on Linux (12% faster for a English word list, 10% slower on a German one)

Should we completely switch to ICU (which is said to give better results and makes less cross platform troubles), or just for Windows?

Bug #687638

Some additional change made it into this tree: I've enabled translation of bible references and added different hypens.
-- 
https://code.launchpad.net/~m2j/openlp/i18n/+merge/88930
Your team OpenLP Core is requested to review the proposed merge of lp:~m2j/openlp/i18n into lp:openlp.
=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py	2012-01-04 17:19:49 +0000
+++ openlp/core/ui/thememanager.py	2012-01-17 20:29:31 +0000
@@ -29,8 +29,11 @@
 import zipfile
 import shutil
 import logging
+<<<<<<< TREE
 import locale
 import re
+=======
+>>>>>>> MERGE-SOURCE
 
 from xml.etree.ElementTree import ElementTree, XML
 from PyQt4 import QtCore, QtGui
@@ -44,7 +47,12 @@
     context_menu_action, context_menu_separator
 from openlp.core.theme import Theme
 from openlp.core.ui import FileRenameForm, ThemeForm
+<<<<<<< TREE
 from openlp.core.utils import AppLocation, delete_file, get_filesystem_encoding
+=======
+from openlp.core.utils import AppLocation, delete_file, file_is_unicode, \
+    get_filesystem_encoding, get_local_collator
+>>>>>>> MERGE-SOURCE
 
 log = logging.getLogger(__name__)
 
@@ -459,7 +467,7 @@
         # Sort the themes by its name considering language specific characters.
         # lower() is needed for windows!
         files.sort(key=lambda filename: unicode(filename).lower(),
-           cmp=locale.strcoll)
+           cmp=get_local_collator)
         # now process the file list of png files
         for name in files:
             # check to see file is in theme root directory

=== modified file 'openlp/core/utils/__init__.py'
--- openlp/core/utils/__init__.py	2011-12-27 10:33:55 +0000
+++ openlp/core/utils/__init__.py	2012-01-17 20:29:31 +0000
@@ -33,6 +33,7 @@
 import sys
 import time
 import urllib2
+import locale
 from datetime import datetime
 from subprocess import Popen, PIPE
 
@@ -45,6 +46,18 @@
     except ImportError:
         XDG_BASE_AVAILABLE = False
 
+LOCALE_COLLATOR = locale.strcoll
+if sys.platform == u'win32':
+    try:
+        import icu
+        try:
+            icu_locale = icu.Locale(locale.getlocale()[0])
+            LOCALE_COLLATOR = icu.Collator.createInstance(icu_locale).compare
+        except icu.InvalidArgsError:
+            pass
+    except ImportError:
+        pass
+
 import openlp
 from openlp.core.lib import Receiver, translate, check_directory_exists
 
@@ -482,10 +495,22 @@
         return resolver.resolve(u'uno:socket,host=localhost,port=2002;' \
             + u'urp;StarOffice.ComponentContext')
 
+def get_local_collator(string1, string2):
+    """
+    Returns a collator for locale aware string sorting.
+    """
+    return LOCALE_COLLATOR(string1, string2)
+
 from languagemanager import LanguageManager
 from actions import ActionList
 
 __all__ = [u'AppLocation', u'get_application_version', u'check_latest_version',
     u'add_actions', u'get_filesystem_encoding', u'LanguageManager',
+<<<<<<< TREE
     u'ActionList', u'get_web_page', u'get_uno_command', u'get_uno_instance',
     u'delete_file', u'clean_filename']
+=======
+    u'ActionList', u'get_web_page', u'file_is_unicode', u'get_uno_command',
+    u'get_uno_instance', u'get_local_collator', u'delete_file',
+    u'clean_filename']
+>>>>>>> MERGE-SOURCE

=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
--- openlp/plugins/bibles/forms/bibleimportform.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/bibles/forms/bibleimportform.py	2012-01-17 20:29:31 +0000
@@ -30,7 +30,6 @@
 import logging
 import os
 import os.path
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -38,7 +37,7 @@
 from openlp.core.lib.db import delete_database
 from openlp.core.lib.ui import UiStrings, critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
-from openlp.core.utils import AppLocation
+from openlp.core.utils import AppLocation, get_local_collator
 from openlp.plugins.bibles.lib.manager import BibleFormat
 from openlp.plugins.bibles.lib.db import BiblesResourcesDB, clean_filename
 
@@ -522,7 +521,7 @@
         """
         self.webTranslationComboBox.clear()
         bibles = self.web_bible_list[index].keys()
-        bibles.sort(cmp=locale.strcoll)
+        bibles.sort(cmp=get_local_collator)
         self.webTranslationComboBox.addItems(bibles)
 
     def onOsisBrowseButtonClicked(self):

=== modified file 'openlp/plugins/bibles/lib/__init__.py'
--- openlp/plugins/bibles/lib/__init__.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/bibles/lib/__init__.py	2012-01-17 20:29:31 +0000
@@ -31,6 +31,8 @@
 import logging
 import re
 
+from openlp.core.lib import translate
+
 log = logging.getLogger(__name__)
 
 class LayoutStyle(object):
@@ -60,28 +62,40 @@
     ``match_type``
         The type of reference information trying to be extracted in this call.
     """
-    local_separator = unicode(u':;;\s*[:vV]\s*;;-;;\s*-\s*;;,;;\s*,\s*;;end'
-        ).split(u';;') # English
-    # local_separator = unicode(u',;;\s*,\s*;;-;;\s*-\s*;;.;;\.;;[Ee]nde'
-    #   ).split(u';;') # German
+    local_separator = unicode(translate('BiblesPlugin',
+        ':;;:|v|V;;-;;-;;,;;,;;end',
+        'Seperators for parsing references. There are 7 values separated each '
+        'by two semicolons. Verse, range and list separators have each one '
+        'display symbol which appears on slides and in the GUI and a regular '
+        'expression for detecting this symbols.\n'
+        'Please ask a developer to double check your translation or make '
+        'yourself familar with regular experssions on: '
+        'http://docs.python.org/library/re.html')
+        ).split(u';;')
     separators = {
-        u'sep_v_display': local_separator[0], u'sep_v': local_separator[1],
-        u'sep_r_display': local_separator[2], u'sep_r': local_separator[3],
-        u'sep_l_display': local_separator[4], u'sep_l': local_separator[5],
-        u'sep_e': local_separator[6]}
-
+        u'sep_v_display': local_separator[0],
+        u'sep_v': u'\s*(?:' + local_separator[1] + u')\s*',
+        u'sep_r_display': local_separator[2],
+        u'sep_r': u'\s*(?:' + local_separator[3] + u')\s*',
+        u'sep_l_display': local_separator[4],
+        u'sep_l': u'\s*(?:' + local_separator[5] + u')\s*',
+        u'sep_e': u'\s*(?:' + local_separator[6] + u')\s*'}
+    for role in [u'sep_v', u'sep_r', u'sep_l', u'sep_e']:
+        separators[role] = separators[role].replace(u'-',
+            u'(?:[-\u00AD\u2010\u2011\u2012\u2013\u2014\u2212\uFE63\uFF0D])')
+        separators[role] = separators[role].replace(u',', u'(?:[,\u201A])')
     # verse range match: (<chapter>:)?<verse>(-((<chapter>:)?<verse>|end)?)?
-    range_string = str(r'(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?(?P<from_verse>'
-        r'[0-9]+)(?P<range_to>%(sep_r)s(?:(?:(?P<to_chapter>[0-9]+)%(sep_v)s)?'
-        r'(?P<to_verse>[0-9]+)|%(sep_e)s)?)?') % separators
+    range_string = unicode(u'(?:(?P<from_chapter>[0-9]+)%(sep_v)s)?'
+        u'(?P<from_verse>[0-9]+)(?P<range_to>%(sep_r)s(?:(?:(?P<to_chapter>'
+        u'[0-9]+)%(sep_v)s)?(?P<to_verse>[0-9]+)|%(sep_e)s)?)?') % separators
     if match_type == u'range':
-        return re.compile(r'^\s*' + range_string + r'\s*$', re.UNICODE)
+        return re.compile(u'^\s*' + range_string + u'\s*$', re.UNICODE)
     elif match_type == u'range_separator':
-        return re.compile(separators[u'sep_l'])
+        return re.compile(separators[u'sep_l'], re.UNICODE)
     elif match_type == u'full':
         # full reference match: <book>(<range>(,|(?=$)))+
-        return re.compile(str(r'^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*'
-            r'(?P<ranges>(?:' + range_string + r'(?:%(sep_l)s|(?=\s*$)))+)\s*$')
+        return re.compile(unicode(u'^\s*(?!\s)(?P<book>[\d]*[^\d]+)(?<!\s)\s*'
+            u'(?P<ranges>(?:' + range_string + u'(?:%(sep_l)s|(?=\s*$)))+)\s*$')
                 % separators, re.UNICODE)
     else:
         return separators[match_type]

=== modified file 'openlp/plugins/bibles/lib/mediaitem.py'
--- openlp/plugins/bibles/lib/mediaitem.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/bibles/lib/mediaitem.py	2012-01-17 20:29:31 +0000
@@ -26,7 +26,6 @@
 ###############################################################################
 
 import logging
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -36,6 +35,7 @@
 from openlp.core.lib.ui import UiStrings, add_widget_completer, \
     media_item_combo_box, critical_error_message_box, \
     find_and_set_in_combo_box, build_icon
+from openlp.core.utils import get_local_collator
 from openlp.plugins.bibles.forms import BibleImportForm
 from openlp.plugins.bibles.lib import LayoutStyle, DisplayStyle, \
     VerseReferenceList, get_reference_match
@@ -373,7 +373,7 @@
         self.advancedSecondComboBox.addItem(u'')
         # Get all bibles and sort the list.
         bibles = self.plugin.manager.get_bibles().keys()
-        bibles.sort(cmp=locale.strcoll)
+        bibles.sort(cmp=get_local_collator)
         # Load the bibles into the combo boxes.
         for bible in bibles:
             if bible:
@@ -481,7 +481,7 @@
                                 book_data_temp.append(book)
                     book_data = book_data_temp
                 books = [book.name + u' ' for book in book_data]
-                books.sort(cmp=locale.strcoll)
+                books.sort(cmp=get_local_collator)
         add_widget_completer(books, self.quickSearchEdit)
 
     def onQuickVersionComboBox(self):

=== modified file 'openlp/plugins/custom/lib/mediaitem.py'
--- openlp/plugins/custom/lib/mediaitem.py	2011-12-30 21:40:13 +0000
+++ openlp/plugins/custom/lib/mediaitem.py	2012-01-17 20:29:31 +0000
@@ -26,7 +26,6 @@
 ###############################################################################
 
 import logging
-import locale
 
 from PyQt4 import QtCore, QtGui
 from sqlalchemy.sql import or_, func
@@ -34,6 +33,7 @@
 from openlp.core.lib import MediaManagerItem, Receiver, ItemCapabilities, \
     check_item_selected, translate
 from openlp.core.lib.ui import UiStrings
+from oprnlp.core.utils import get_local_collator
 from openlp.plugins.custom.forms import EditCustomForm
 from openlp.plugins.custom.lib import CustomXMLParser
 from openlp.plugins.custom.lib.db import CustomSlide
@@ -109,7 +109,7 @@
         # Sort the customs by its title considering language specific
         # characters. lower() is needed for windows!
         custom_slides.sort(
-            cmp=locale.strcoll, key=lambda custom: custom.title.lower())
+            cmp=get_local_collator, key=lambda custom: custom.title.lower())
         for custom_slide in custom_slides:
             custom_name = QtGui.QListWidgetItem(custom_slide.title)
             custom_name.setData(

=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/images/lib/mediaitem.py	2012-01-17 20:29:31 +0000
@@ -27,7 +27,6 @@
 
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -35,7 +34,8 @@
     SettingsManager, translate, check_item_selected, check_directory_exists, \
     Receiver, create_thumb, validate_thumb
 from openlp.core.lib.ui import UiStrings, critical_error_message_box
-from openlp.core.utils import AppLocation, delete_file, get_images_filter
+from openlp.core.utils import AppLocation, delete_file, get_images_filter, \
+    get_local_collator
 
 log = logging.getLogger(__name__)
 
@@ -120,7 +120,7 @@
             self.plugin.formparent.displayProgressBar(len(images))
         # Sort the themes by its filename considering language specific
         # characters. lower() is needed for windows!
-        images.sort(cmp=locale.strcoll,
+        images.sort(cmp=get_local_collator,
             key=lambda filename: os.path.split(unicode(filename))[1].lower())
         for imageFile in images:
             if not initialLoad:

=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/media/lib/mediaitem.py	2012-01-17 20:29:31 +0000
@@ -27,7 +27,6 @@
 
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -37,6 +36,7 @@
 from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
     media_item_combo_box
 from openlp.core.ui import Controller, Display
+from openlp.core.utils import get_local_collator
 
 log = logging.getLogger(__name__)
 
@@ -278,7 +278,7 @@
     def loadList(self, media):
         # Sort the themes by its filename considering language specific
         # characters. lower() is needed for windows!
-        media.sort(cmp=locale.strcoll,
+        media.sort(cmp=get_local_collator,
             key=lambda filename: os.path.split(unicode(filename))[1].lower())
         for track in media:
             track_info = QtCore.QFileInfo(track)
@@ -298,7 +298,7 @@
 
     def getList(self, type=MediaType.Audio):
         media = SettingsManager.load_list(self.settingsSection, u'media')
-        media.sort(cmp=locale.strcoll,
+        media.sort(cmp=get_local_collator,
             key=lambda filename: os.path.split(unicode(filename))[1].lower())
         ext = []
         if type == MediaType.Audio:

=== modified file 'openlp/plugins/presentations/lib/mediaitem.py'
--- openlp/plugins/presentations/lib/mediaitem.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/presentations/lib/mediaitem.py	2012-01-17 20:29:31 +0000
@@ -27,7 +27,6 @@
 
 import logging
 import os
-import locale
 
 from PyQt4 import QtCore, QtGui
 
@@ -36,6 +35,7 @@
     validate_thumb
 from openlp.core.lib.ui import UiStrings, critical_error_message_box, \
     media_item_combo_box
+from openlp.core.utils import get_local_collator
 from openlp.plugins.presentations.lib import MessageListener
 
 log = logging.getLogger(__name__)
@@ -168,7 +168,7 @@
             self.plugin.formparent.displayProgressBar(len(files))
         # Sort the themes by its filename considering language specific
         # characters. lower() is needed for windows!
-        files.sort(cmp=locale.strcoll,
+        files.sort(cmp=get_local_collator,
             key=lambda filename: os.path.split(unicode(filename))[1].lower())
         for file in files:
             if not initialLoad:

=== modified file 'openlp/plugins/songs/forms/songexportform.py'
--- openlp/plugins/songs/forms/songexportform.py	2011-12-27 10:33:55 +0000
+++ openlp/plugins/songs/forms/songexportform.py	2012-01-17 20:29:31 +0000
@@ -28,7 +28,6 @@
 The :mod:`songexportform` module provides the wizard for exporting songs to the
 OpenLyrics format.
 """
-import locale
 import logging
 
 from PyQt4 import QtCore, QtGui
@@ -36,6 +35,7 @@
 from openlp.core.lib import build_icon, Receiver, SettingsManager, translate
 from openlp.core.lib.ui import UiStrings, critical_error_message_box
 from openlp.core.ui.wizard import OpenLPWizard, WizardStrings
+from openlp.core.utils import get_local_collator
 from openlp.plugins.songs.lib.db import Song
 from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport
 
@@ -250,7 +250,7 @@
         # Load the list of songs.
         Receiver.send_message(u'cursor_busy')
         songs = self.plugin.manager.get_all_objects(Song)
-        songs.sort(cmp=locale.strcoll, key=lambda song: song.title.lower())
+        songs.sort(cmp=get_local_collator, key=lambda song: song.title.lower())
         for song in songs:
             # No need to export temporary songs.
             if song.temporary:

=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py	2011-12-30 21:40:13 +0000
+++ openlp/plugins/songs/lib/mediaitem.py	2012-01-17 20:29:31 +0000
@@ -26,7 +26,6 @@
 ###############################################################################
 
 import logging
-import locale
 import re
 import os
 import shutil
@@ -38,7 +37,7 @@
     translate, check_item_selected, PluginStatus
 from openlp.core.lib.ui import UiStrings, context_menu_action, \
     context_menu_separator
-from openlp.core.utils import AppLocation
+from openlp.core.utils import AppLocation, get_local_collator
 from openlp.plugins.songs.forms import EditSongForm, SongMaintenanceForm, \
     SongImportForm, SongExportForm
 from openlp.plugins.songs.lib import OpenLyrics, SongXML, VerseType, \
@@ -240,7 +239,7 @@
         # Sort the songs by its title considering language specific characters.
         # lower() is needed for windows!
         searchresults.sort(
-            cmp=locale.strcoll, key=lambda song: song.title.lower())
+            cmp=get_local_collator, key=lambda song: song.title.lower())
         for song in searchresults:
             # Do not display temporary songs
             if song.temporary:


Follow ups