[Zope3-checkins] CVS: Zope3/src/zope/i18n/tests - test_formats.py:1.1 test_locales.py:1.1 test_xmllocales.py:1.1

Stephan Richter srichter@cbu.edu
Sun, 5 Jan 2003 15:20:23 -0500


Update of /cvs-repository/Zope3/src/zope/i18n/tests
In directory cvs.zope.org:/tmp/cvs-serv28404/i18n/tests

Added Files:
	test_formats.py test_locales.py test_xmllocales.py 
Log Message:
I am proud to check in this code, which implements a modified version of
the I18nFormatLocaleSupport proposal.

This codes adds real hardcore Locale support to Zope, including number 
and date/time parsing/formatting using patterns that are compliant to the 
emerging ICU standard. 
Note: The formatting code can be used independent of the Locale.

This standard compliance allowed me to use the ICU Locale XML Files as 
data source, so that we basically have locale support now for virtually
any locale that ICU supports (therefore all the XML files in the checkin).

I am surprised by the speed the minidom Python library parses the XML
(maybe someone can write a cleaner XML file parser). Also I think the 
two pattern parsers, parsing from text to objects and formatting objects 
is very fast, so it is definitely suitable for frequent usage.

There are some tasks left however:

- Integrate this new code into the TranslationService mechanism. Well, I
  would actually propose to review all of the old code and adapt it more 
  to the way the new Locales work. I really do not like the gettext 
  standard too much, and ICU has also a lot of commercial support.

- Implement currency parsing and formatting. While this is a smaller task
  it still needs to be done.

- As mentioned above, maybe implement a new XML File parser and replacing 
  the minidom course.

Ah yeah, the tests contain a multitude of examples on how it all works.


=== Added File Zope3/src/zope/i18n/tests/test_formats.py === (673/773 lines abridged)
##############################################################################
#
# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""This module tests the Formats and everything that goes with it.

$Id: test_formats.py,v 1.1 2003/01/05 20:20:21 srichter Exp $
"""
import os
import datetime
from unittest import TestCase, TestSuite, makeSuite

from zope.i18n.interfaces import IDateTimeFormat
from zope.i18n.format import DateTimeFormat
from zope.i18n.format import parseDateTimePattern, buildDateTimeParseInfo
from zope.i18n.format import DateTimePatternParseError, DateTimeParseError

from zope.i18n.interfaces import INumberFormat
from zope.i18n.format import NumberFormat
from zope.i18n.format import parseNumberPattern

from test_locales import testdir, ICUXMLLocaleFactory

class LocaleStub:
    pass


class TestDateTimePatternParser(TestCase):
    """Extensive tests for the ICU-based-syntax datetime pattern parser."""

    def testParseSimpleTimePattern(self):
        self.assertEqual(parseDateTimePattern('HH'),
                         [('H', 2)])
        self.assertEqual(parseDateTimePattern('HH:mm'),
                         [('H', 2), ':', ('m', 2)])
        self.assertEqual(parseDateTimePattern('HH:mm:ss'),
                         [('H', 2), ':', ('m', 2), ':', ('s', 2)])
        self.assertEqual(parseDateTimePattern('mm:ss'),
                         [('m', 2), ':', ('s', 2)])
        self.assertEqual(parseDateTimePattern('H:m:s'),
                         [('H', 1), ':', ('m', 1), ':', ('s', 1)])

[-=- -=- -=- 673 lines omitted -=- -=- -=-]

        self.assertEqual(self.format.format(-41.02, '* 0.0####E0;*_0.0####E0'),
                         '__4.102E1')
        self.assertEqual(self.format.format(41.02, '* +0.0###E0;*_-0.0###E0'),
                         ' +4.102E1')
        self.assertEqual(self.format.format(-41.02, '* +0.0###E0;*_-0.0###E0'),
                         '_-4.102E1')

    def testFormatPadding1Padding2WithPrefix(self):
        self.assertEqual(self.format.format(41, '* +* ###0;*_-*_###0'),
                         '  + 41')
        self.assertEqual(self.format.format(-41, '* +* ###0;*_-*_###0'),
                         '__-_41')

    def testFormatPadding3WithoutSufffix(self):
        self.assertEqual(self.format.format(41.02, '#0.0###* ;#0.0###*_'),
                         '41.02  ')
        self.assertEqual(self.format.format(-41.02, '#0.0###* ;#0.0###*_'),
                         '41.02__')
        
    def testFormatPadding3WithSufffix(self):
        self.assertEqual(self.format.format(41.02, '[#0.0###* ];(#0.0###*_)'),
                         '[41.02  ]')
        self.assertEqual(self.format.format(-41.02, '[#0.0###* ];(#0.0###*_)'),
                         '(41.02__)')

    def testFormatPadding3Scientific(self):
        self.assertEqual(self.format.format(41.02, '0.0##E0##* ;0.0##E0##*_'),
                         '4.102E1  ')
        self.assertEqual(self.format.format(-41.02, '0.0##E0##* ;0.0##E0##*_'),
                         '4.102E1__')
        self.assertEqual(self.format.format(41.02, '(0.0##E0##* );0.0E0'),
                         '(4.102E1  )')
        self.assertEqual(self.format.format(-41.02, '0.0E0;[0.0##E0##*_]'),
                         '[4.102E1__]')

    def testFormatPadding3Padding4WithSuffix(self):
        self.assertEqual(self.format.format(41.02, '(#0.0###* )* '),
                         '(41.02 )  ')
        self.assertEqual(self.format.format(41.02, '(0.0##E0##* )* '),
                         '(4.102E1 )  ')


def test_suite():
    return TestSuite((
        makeSuite(TestDateTimePatternParser),
        makeSuite(TestBuildDateTimeParseInfo),
        makeSuite(TestDateTimeFormat),
        makeSuite(TestNumberPatternParser),
        makeSuite(TestNumberFormat),
        ))


=== Added File Zope3/src/zope/i18n/tests/test_locales.py === (606/706 lines abridged)
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""This module tests the LocaleProvider and everything that goes with it.

$Id: test_locales.py,v 1.1 2003/01/05 20:20:21 srichter Exp $
"""
import os, sys
import datetime
from unittest import TestCase, TestSuite, makeSuite

from zope.i18n.interfaces import ILocaleProvider, ILocale 
from zope.i18n.interfaces import ILocaleVersion, ILocaleIdentity
from zope.i18n.interfaces import ILocaleTimeZone, ILocaleCalendar
from zope.i18n.interfaces import ILocaleNumberFormat, ILocaleCurrency

from zope.i18n.locales import NoGeneralLocaleError, LoadLocaleError
from zope.i18n.locales import LocaleProvider, ICULocale, ICUXMLLocaleFactory
from zope.i18n.locales import locales
from zope.i18n.locales import ICULocaleVersion, ICULocaleIdentity
from zope.i18n.locales import ICULocaleTimeZone, ICULocaleCalendar 
from zope.i18n.locales import ICULocaleNumberFormat, ICULocaleCurrency 

def testdir():
    from zope.i18n import tests
    return os.path.dirname(tests.__file__)


class TestILocaleProvider(TestCase):
    """Test the functionality of an implmentation of the ILocaleProvider
    interface.""" 

    def _makeNewProvider(self):
        raise NotImplemented

    def setUp(self):
        self.locales = self._makeNewProvider()

    def testInterfaceConformity(self):
        self.assert_(ILocaleProvider.isImplementedBy(self.locales))

[-=- -=- -=- 606 lines omitted -=- -=- -=-]

        formatter = self.locale.getDateTimeFormatter('medium')
        self.assertEqual(formatter.getPattern(), 'dd.MM.yyyy HH:mm:ss ')
        self.assertEqual(
            formatter.format(datetime.datetime(2003, 01, 02, 12, 30)),
            '02.01.2003 12:30:00 ')
        self.assertEqual(formatter.parse('02.01.2003 12:30:00 '),
                         datetime.datetime(2003, 01, 02, 12, 30))

    def test_getNumberFormatter(self):
        formatter = self.locale.getNumberFormatter('decimal')
        self.assertEqual(formatter.getPattern(), '#,##0.###;-#,##0.###')
        self.assertEqual(formatter.format(1234.5678), '1,234.567')
        self.assertEqual(formatter.format(-1234.5678), '-1,234.567')
        self.assertEqual(formatter.parse('1,234.567'), 1234.567)
        self.assertEqual(formatter.parse('-1,234.567'), -1234.567)

        
class TestGlobalLocaleProvider(TestCase):

    def testLoading(self):
        locales.loadLocale(None, None, None)
        self.assert_(locales._locales.has_key((None, None, None)))
        locales.loadLocale('de', None, None)
        self.assert_(locales._locales.has_key(('de', None, None)))
        locales.loadLocale('de', 'DE', None)
        self.assert_(locales._locales.has_key(('de', 'DE', None)))
        locales.loadLocale('de', 'DE', 'PREEURO')
        self.assert_(locales._locales.has_key(('de', 'DE', 'PREEURO')))

    def test_getLocale(self):
        locale = locales.getLocale('de', 'AT')
        self.assertEqual(locale.id.getLanguage(), 'de')
        self.assertEqual(locale.id.getCountry(), 'AT')
        self.assertEqual(locale.id.getVariant(), None)


def test_suite():
    return TestSuite((
        makeSuite(TestLocaleProvider),
        makeSuite(TestICULocaleIdentity),
        makeSuite(TestICULocaleVersion),
        makeSuite(TestICULocaleTimeZone),
        makeSuite(TestICULocaleCalendar),
        makeSuite(TestICULocaleNumberFormat),
        makeSuite(TestICULocaleCurrency),
        makeSuite(TestICUXMLLocaleFactory),
        makeSuite(TestICULocale),
        makeSuite(TestICULocaleAndProvider),
        makeSuite(TestGlobalLocaleProvider),
        ))


=== Added File Zope3/src/zope/i18n/tests/test_xmllocales.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Testing all XML Locale functionality.

$Id: test_xmllocales.py,v 1.1 2003/01/05 20:20:21 srichter Exp $
"""
import os
from unittest import TestCase, TestSuite, makeSuite

from zope.i18n.locales import ICUXMLLocaleFactory
from zope.i18n.format import parseDateTimePattern, parseNumberPattern

class LocaleXMLFileTestCase(TestCase):
    """This test verifies that every locale XML fiel can be loaded."""

    def __init__(self, path):
        self.__path = path
        super(LocaleXMLFileTestCase, self).__init__()
        
    # For unittest.
    def shortDescription(self):
        filename = os.path.split(self.__path)[-1]
        return '%s (Test ICU XML-Locale Files)' %filename

    def runTest(self):
        # Loading Locale object 
        locale = ICUXMLLocaleFactory(self.__path)()

        # Making sure all number format patterns parse
        for klass in locale.getNumberFormatClasses():
            format = locale.getNumberFormat(klass)
            for id in format.getAllPatternIds():
                self.assert_(
                    parseNumberPattern(format.getPattern(id)) is not None)

        # Making sure all datetime patterns parse
        for klass in locale.getCalendarClasses():
            calendar = locale.getCalendar(klass)
            for pattern in calendar._date_patterns.values():
                    self.assert_(parseDateTimePattern(pattern) is not None)
            for pattern in calendar._time_patterns.values():
                    self.assert_(parseDateTimePattern(pattern) is not None)
                    

def test_suite():
    suite = TestSuite()
    from zope import i18n
    locale_dir = os.path.join(os.path.dirname(i18n.__file__), 'locales')
    org = os.curdir
    os.chdir(locale_dir)
    for file in filter(lambda f: f.endswith('.xml'),
                       os.listdir(locale_dir))[:]:
        path = os.path.join(locale_dir, file)
        case = LocaleXMLFileTestCase(path)
        suite.addTest(case)
    os.chdir(org)
    return suite