root/galaxy-central/eggs/Babel-0.9.4-py2.6.egg/babel/core.py @ 3

リビジョン 3, 25.4 KB (コミッタ: kohda, 14 年 前)

Install Unix tools  http://hannonlab.cshl.edu/galaxy_unix_tools/galaxy.html

行番号 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2007 Edgewall Software
4# All rights reserved.
5#
6# This software is licensed as described in the file COPYING, which
7# you should have received as part of this distribution. The terms
8# are also available at http://babel.edgewall.org/wiki/License.
9#
10# This software consists of voluntary contributions made by many
11# individuals. For the exact contribution history, see the revision
12# history and logs, available at http://babel.edgewall.org/log/.
13
14"""Core locale representation and locale data access."""
15
16import os
17import pickle
18
19from babel import localedata
20
21__all__ = ['UnknownLocaleError', 'Locale', 'default_locale', 'negotiate_locale',
22           'parse_locale']
23__docformat__ = 'restructuredtext en'
24
25_global_data = None
26
27def get_global(key):
28    """Return the dictionary for the given key in the global data.
29   
30    The global data is stored in the ``babel/global.dat`` file and contains
31    information independent of individual locales.
32   
33    >>> get_global('zone_aliases')['UTC']
34    'Etc/GMT'
35    >>> get_global('zone_territories')['Europe/Berlin']
36    'DE'
37   
38    :param key: the data key
39    :return: the dictionary found in the global data under the given key
40    :rtype: `dict`
41    :since: version 0.9
42    """
43    global _global_data
44    if _global_data is None:
45        dirname = os.path.join(os.path.dirname(__file__))
46        filename = os.path.join(dirname, 'global.dat')
47        fileobj = open(filename, 'rb')
48        try:
49            _global_data = pickle.load(fileobj)
50        finally:
51            fileobj.close()
52    return _global_data.get(key, {})
53
54
55LOCALE_ALIASES = {
56    'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ',
57    'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES',
58    'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES',
59    'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT',
60    'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV',
61    'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL',
62    'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI',
63    'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA'
64}
65
66
67class UnknownLocaleError(Exception):
68    """Exception thrown when a locale is requested for which no locale data
69    is available.
70    """
71
72    def __init__(self, identifier):
73        """Create the exception.
74       
75        :param identifier: the identifier string of the unsupported locale
76        """
77        Exception.__init__(self, 'unknown locale %r' % identifier)
78        self.identifier = identifier
79
80
81class Locale(object):
82    """Representation of a specific locale.
83   
84    >>> locale = Locale('en', 'US')
85    >>> repr(locale)
86    '<Locale "en_US">'
87    >>> locale.display_name
88    u'English (United States)'
89   
90    A `Locale` object can also be instantiated from a raw locale string:
91   
92    >>> locale = Locale.parse('en-US', sep='-')
93    >>> repr(locale)
94    '<Locale "en_US">'
95   
96    `Locale` objects provide access to a collection of locale data, such as
97    territory and language names, number and date format patterns, and more:
98   
99    >>> locale.number_symbols['decimal']
100    u'.'
101   
102    If a locale is requested for which no locale data is available, an
103    `UnknownLocaleError` is raised:
104   
105    >>> Locale.parse('en_DE')
106    Traceback (most recent call last):
107        ...
108    UnknownLocaleError: unknown locale 'en_DE'
109   
110    :see: `IETF RFC 3066 <http://www.ietf.org/rfc/rfc3066.txt>`_
111    """
112
113    def __init__(self, language, territory=None, script=None, variant=None):
114        """Initialize the locale object from the given identifier components.
115       
116        >>> locale = Locale('en', 'US')
117        >>> locale.language
118        'en'
119        >>> locale.territory
120        'US'
121       
122        :param language: the language code
123        :param territory: the territory (country or region) code
124        :param script: the script code
125        :param variant: the variant code
126        :raise `UnknownLocaleError`: if no locale data is available for the
127                                     requested locale
128        """
129        self.language = language
130        self.territory = territory
131        self.script = script
132        self.variant = variant
133        self.__data = None
134
135        identifier = str(self)
136        if not localedata.exists(identifier):
137            raise UnknownLocaleError(identifier)
138
139    def default(cls, category=None, aliases=LOCALE_ALIASES):
140        """Return the system default locale for the specified category.
141       
142        >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:
143        ...     os.environ[name] = ''
144        >>> os.environ['LANG'] = 'fr_FR.UTF-8'
145        >>> Locale.default('LC_MESSAGES')
146        <Locale "fr_FR">
147
148        :param category: one of the ``LC_XXX`` environment variable names
149        :param aliases: a dictionary of aliases for locale identifiers
150        :return: the value of the variable, or any of the fallbacks
151                 (``LANGUAGE``, ``LC_ALL``, ``LC_CTYPE``, and ``LANG``)
152        :rtype: `Locale`
153        :see: `default_locale`
154        """
155        return cls(default_locale(category, aliases=aliases))
156    default = classmethod(default)
157
158    def negotiate(cls, preferred, available, sep='_', aliases=LOCALE_ALIASES):
159        """Find the best match between available and requested locale strings.
160       
161        >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT'])
162        <Locale "de_DE">
163        >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de'])
164        <Locale "de">
165        >>> Locale.negotiate(['de_DE', 'de'], ['en_US'])
166       
167        You can specify the character used in the locale identifiers to separate
168        the differnet components. This separator is applied to both lists. Also,
169        case is ignored in the comparison:
170       
171        >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-')
172        <Locale "de_DE">
173       
174        :param preferred: the list of locale identifers preferred by the user
175        :param available: the list of locale identifiers available
176        :param aliases: a dictionary of aliases for locale identifiers
177        :return: the `Locale` object for the best match, or `None` if no match
178                 was found
179        :rtype: `Locale`
180        :see: `negotiate_locale`
181        """
182        identifier = negotiate_locale(preferred, available, sep=sep,
183                                      aliases=aliases)
184        if identifier:
185            return Locale.parse(identifier, sep=sep)
186    negotiate = classmethod(negotiate)
187
188    def parse(cls, identifier, sep='_'):
189        """Create a `Locale` instance for the given locale identifier.
190       
191        >>> l = Locale.parse('de-DE', sep='-')
192        >>> l.display_name
193        u'Deutsch (Deutschland)'
194       
195        If the `identifier` parameter is not a string, but actually a `Locale`
196        object, that object is returned:
197       
198        >>> Locale.parse(l)
199        <Locale "de_DE">
200       
201        :param identifier: the locale identifier string
202        :param sep: optional component separator
203        :return: a corresponding `Locale` instance
204        :rtype: `Locale`
205        :raise `ValueError`: if the string does not appear to be a valid locale
206                             identifier
207        :raise `UnknownLocaleError`: if no locale data is available for the
208                                     requested locale
209        :see: `parse_locale`
210        """
211        if isinstance(identifier, basestring):
212            return cls(*parse_locale(identifier, sep=sep))
213        return identifier
214    parse = classmethod(parse)
215
216    def __eq__(self, other):
217        return str(self) == str(other)
218
219    def __repr__(self):
220        return '<Locale "%s">' % str(self)
221
222    def __str__(self):
223        return '_'.join(filter(None, [self.language, self.script,
224                                      self.territory, self.variant]))
225
226    def _data(self):
227        if self.__data is None:
228            self.__data = localedata.LocaleDataDict(localedata.load(str(self)))
229        return self.__data
230    _data = property(_data)
231
232    def get_display_name(self, locale=None):
233        """Return the display name of the locale using the given locale.
234       
235        The display name will include the language, territory, script, and
236        variant, if those are specified.
237       
238        >>> Locale('zh', 'CN', script='Hans').get_display_name('en')
239        u'Chinese (Simplified Han, China)'
240       
241        :param locale: the locale to use
242        :return: the display name
243        """
244        if locale is None:
245            locale = self
246        locale = Locale.parse(locale)
247        retval = locale.languages.get(self.language)
248        if self.territory or self.script or self.variant:
249            details = []
250            if self.script:
251                details.append(locale.scripts.get(self.script))
252            if self.territory:
253                details.append(locale.territories.get(self.territory))
254            if self.variant:
255                details.append(locale.variants.get(self.variant))
256            details = filter(None, details)
257            if details:
258                retval += ' (%s)' % u', '.join(details)
259        return retval
260
261    display_name = property(get_display_name, doc="""\
262        The localized display name of the locale.
263       
264        >>> Locale('en').display_name
265        u'English'
266        >>> Locale('en', 'US').display_name
267        u'English (United States)'
268        >>> Locale('sv').display_name
269        u'svenska'
270       
271        :type: `unicode`
272        """)
273
274    def english_name(self):
275        return self.get_display_name(Locale('en'))
276    english_name = property(english_name, doc="""\
277        The english display name of the locale.
278       
279        >>> Locale('de').english_name
280        u'German'
281        >>> Locale('de', 'DE').english_name
282        u'German (Germany)'
283       
284        :type: `unicode`
285        """)
286
287    #{ General Locale Display Names
288
289    def languages(self):
290        return self._data['languages']
291    languages = property(languages, doc="""\
292        Mapping of language codes to translated language names.
293       
294        >>> Locale('de', 'DE').languages['ja']
295        u'Japanisch'
296       
297        :type: `dict`
298        :see: `ISO 639 <http://www.loc.gov/standards/iso639-2/>`_
299        """)
300
301    def scripts(self):
302        return self._data['scripts']
303    scripts = property(scripts, doc="""\
304        Mapping of script codes to translated script names.
305       
306        >>> Locale('en', 'US').scripts['Hira']
307        u'Hiragana'
308       
309        :type: `dict`
310        :see: `ISO 15924 <http://www.evertype.com/standards/iso15924/>`_
311        """)
312
313    def territories(self):
314        return self._data['territories']
315    territories = property(territories, doc="""\
316        Mapping of script codes to translated script names.
317       
318        >>> Locale('es', 'CO').territories['DE']
319        u'Alemania'
320       
321        :type: `dict`
322        :see: `ISO 3166 <http://www.iso.org/iso/en/prods-services/iso3166ma/>`_
323        """)
324
325    def variants(self):
326        return self._data['variants']
327    variants = property(variants, doc="""\
328        Mapping of script codes to translated script names.
329       
330        >>> Locale('de', 'DE').variants['1901']
331        u'Alte deutsche Rechtschreibung'
332       
333        :type: `dict`
334        """)
335
336    #{ Number Formatting
337
338    def currencies(self):
339        return self._data['currency_names']
340    currencies = property(currencies, doc="""\
341        Mapping of currency codes to translated currency names.
342       
343        >>> Locale('en').currencies['COP']
344        u'Colombian Peso'
345        >>> Locale('de', 'DE').currencies['COP']
346        u'Kolumbianischer Peso'
347       
348        :type: `dict`
349        """)
350
351    def currency_symbols(self):
352        return self._data['currency_symbols']
353    currency_symbols = property(currency_symbols, doc="""\
354        Mapping of currency codes to symbols.
355       
356        >>> Locale('en', 'US').currency_symbols['USD']
357        u'$'
358        >>> Locale('es', 'CO').currency_symbols['USD']
359        u'US$'
360       
361        :type: `dict`
362        """)
363
364    def number_symbols(self):
365        return self._data['number_symbols']
366    number_symbols = property(number_symbols, doc="""\
367        Symbols used in number formatting.
368       
369        >>> Locale('fr', 'FR').number_symbols['decimal']
370        u','
371       
372        :type: `dict`
373        """)
374
375    def decimal_formats(self):
376        return self._data['decimal_formats']
377    decimal_formats = property(decimal_formats, doc="""\
378        Locale patterns for decimal number formatting.
379       
380        >>> Locale('en', 'US').decimal_formats[None]
381        <NumberPattern u'#,##0.###'>
382       
383        :type: `dict`
384        """)
385
386    def currency_formats(self):
387        return self._data['currency_formats']
388    currency_formats = property(currency_formats, doc=r"""\
389        Locale patterns for currency number formatting.
390       
391        >>> print Locale('en', 'US').currency_formats[None]
392        <NumberPattern u'\xa4#,##0.00'>
393       
394        :type: `dict`
395        """)
396
397    def percent_formats(self):
398        return self._data['percent_formats']
399    percent_formats = property(percent_formats, doc="""\
400        Locale patterns for percent number formatting.
401       
402        >>> Locale('en', 'US').percent_formats[None]
403        <NumberPattern u'#,##0%'>
404       
405        :type: `dict`
406        """)
407
408    def scientific_formats(self):
409        return self._data['scientific_formats']
410    scientific_formats = property(scientific_formats, doc="""\
411        Locale patterns for scientific number formatting.
412       
413        >>> Locale('en', 'US').scientific_formats[None]
414        <NumberPattern u'#E0'>
415       
416        :type: `dict`
417        """)
418
419    #{ Calendar Information and Date Formatting
420
421    def periods(self):
422        return self._data['periods']
423    periods = property(periods, doc="""\
424        Locale display names for day periods (AM/PM).
425       
426        >>> Locale('en', 'US').periods['am']
427        u'AM'
428       
429        :type: `dict`
430        """)
431
432    def days(self):
433        return self._data['days']
434    days = property(days, doc="""\
435        Locale display names for weekdays.
436       
437        >>> Locale('de', 'DE').days['format']['wide'][3]
438        u'Donnerstag'
439       
440        :type: `dict`
441        """)
442
443    def months(self):
444        return self._data['months']
445    months = property(months, doc="""\
446        Locale display names for months.
447       
448        >>> Locale('de', 'DE').months['format']['wide'][10]
449        u'Oktober'
450       
451        :type: `dict`
452        """)
453
454    def quarters(self):
455        return self._data['quarters']
456    quarters = property(quarters, doc="""\
457        Locale display names for quarters.
458       
459        >>> Locale('de', 'DE').quarters['format']['wide'][1]
460        u'1. Quartal'
461       
462        :type: `dict`
463        """)
464
465    def eras(self):
466        return self._data['eras']
467    eras = property(eras, doc="""\
468        Locale display names for eras.
469       
470        >>> Locale('en', 'US').eras['wide'][1]
471        u'Anno Domini'
472        >>> Locale('en', 'US').eras['abbreviated'][0]
473        u'BC'
474       
475        :type: `dict`
476        """)
477
478    def time_zones(self):
479        return self._data['time_zones']
480    time_zones = property(time_zones, doc="""\
481        Locale display names for time zones.
482       
483        >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight']
484        u'British Summer Time'
485        >>> Locale('en', 'US').time_zones['America/St_Johns']['city']
486        u"St. John's"
487       
488        :type: `dict`
489        """)
490
491    def meta_zones(self):
492        return self._data['meta_zones']
493    meta_zones = property(meta_zones, doc="""\
494        Locale display names for meta time zones.
495       
496        Meta time zones are basically groups of different Olson time zones that
497        have the same GMT offset and daylight savings time.
498       
499        >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight']
500        u'Central European Summer Time'
501       
502        :type: `dict`
503        :since: version 0.9
504        """)
505
506    def zone_formats(self):
507        return self._data['zone_formats']
508    zone_formats = property(zone_formats, doc=r"""\
509        Patterns related to the formatting of time zones.
510       
511        >>> Locale('en', 'US').zone_formats['fallback']
512        u'%(1)s (%(0)s)'
513        >>> Locale('pt', 'BR').zone_formats['region']
514        u'Hor\xe1rio %s'
515       
516        :type: `dict`
517        :since: version 0.9
518        """)
519
520    def first_week_day(self):
521        return self._data['week_data']['first_day']
522    first_week_day = property(first_week_day, doc="""\
523        The first day of a week, with 0 being Monday.
524       
525        >>> Locale('de', 'DE').first_week_day
526        0
527        >>> Locale('en', 'US').first_week_day
528        6
529       
530        :type: `int`
531        """)
532
533    def weekend_start(self):
534        return self._data['week_data']['weekend_start']
535    weekend_start = property(weekend_start, doc="""\
536        The day the weekend starts, with 0 being Monday.
537       
538        >>> Locale('de', 'DE').weekend_start
539        5
540       
541        :type: `int`
542        """)
543
544    def weekend_end(self):
545        return self._data['week_data']['weekend_end']
546    weekend_end = property(weekend_end, doc="""\
547        The day the weekend ends, with 0 being Monday.
548       
549        >>> Locale('de', 'DE').weekend_end
550        6
551       
552        :type: `int`
553        """)
554
555    def min_week_days(self):
556        return self._data['week_data']['min_days']
557    min_week_days = property(min_week_days, doc="""\
558        The minimum number of days in a week so that the week is counted as the
559        first week of a year or month.
560       
561        >>> Locale('de', 'DE').min_week_days
562        4
563       
564        :type: `int`
565        """)
566
567    def date_formats(self):
568        return self._data['date_formats']
569    date_formats = property(date_formats, doc="""\
570        Locale patterns for date formatting.
571       
572        >>> Locale('en', 'US').date_formats['short']
573        <DateTimePattern u'M/d/yy'>
574        >>> Locale('fr', 'FR').date_formats['long']
575        <DateTimePattern u'd MMMM yyyy'>
576       
577        :type: `dict`
578        """)
579
580    def time_formats(self):
581        return self._data['time_formats']
582    time_formats = property(time_formats, doc="""\
583        Locale patterns for time formatting.
584       
585        >>> Locale('en', 'US').time_formats['short']
586        <DateTimePattern u'h:mm a'>
587        >>> Locale('fr', 'FR').time_formats['long']
588        <DateTimePattern u'HH:mm:ss z'>
589       
590        :type: `dict`
591        """)
592
593    def datetime_formats(self):
594        return self._data['datetime_formats']
595    datetime_formats = property(datetime_formats, doc="""\
596        Locale patterns for datetime formatting.
597       
598        >>> Locale('en').datetime_formats[None]
599        u'{1} {0}'
600        >>> Locale('th').datetime_formats[None]
601        u'{1}, {0}'
602       
603        :type: `dict`
604        """)
605
606
607def default_locale(category=None, aliases=LOCALE_ALIASES):
608    """Returns the system default locale for a given category, based on
609    environment variables.
610   
611    >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:
612    ...     os.environ[name] = ''
613    >>> os.environ['LANG'] = 'fr_FR.UTF-8'
614    >>> default_locale('LC_MESSAGES')
615    'fr_FR'
616
617    The "C" or "POSIX" pseudo-locales are treated as aliases for the
618    "en_US_POSIX" locale:
619
620    >>> os.environ['LC_MESSAGES'] = 'POSIX'
621    >>> default_locale('LC_MESSAGES')
622    'en_US_POSIX'
623
624    :param category: one of the ``LC_XXX`` environment variable names
625    :param aliases: a dictionary of aliases for locale identifiers
626    :return: the value of the variable, or any of the fallbacks (``LANGUAGE``,
627             ``LC_ALL``, ``LC_CTYPE``, and ``LANG``)
628    :rtype: `str`
629    """
630    varnames = (category, 'LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG')
631    for name in filter(None, varnames):
632        locale = os.getenv(name)
633        if locale:
634            if name == 'LANGUAGE' and ':' in locale:
635                # the LANGUAGE variable may contain a colon-separated list of
636                # language codes; we just pick the language on the list
637                locale = locale.split(':')[0]
638            if locale in ('C', 'POSIX'):
639                locale = 'en_US_POSIX'
640            elif aliases and locale in aliases:
641                locale = aliases[locale]
642            return '_'.join(filter(None, parse_locale(locale)))
643
644def negotiate_locale(preferred, available, sep='_', aliases=LOCALE_ALIASES):
645    """Find the best match between available and requested locale strings.
646   
647    >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT'])
648    'de_DE'
649    >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de'])
650    'de'
651   
652    Case is ignored by the algorithm, the result uses the case of the preferred
653    locale identifier:
654   
655    >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at'])
656    'de_DE'
657   
658    >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at'])
659    'de_DE'
660   
661    By default, some web browsers unfortunately do not include the territory
662    in the locale identifier for many locales, and some don't even allow the
663    user to easily add the territory. So while you may prefer using qualified
664    locale identifiers in your web-application, they would not normally match
665    the language-only locale sent by such browsers. To workaround that, this
666    function uses a default mapping of commonly used langauge-only locale
667    identifiers to identifiers including the territory:
668   
669    >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US'])
670    'ja_JP'
671   
672    Some browsers even use an incorrect or outdated language code, such as "no"
673    for Norwegian, where the correct locale identifier would actually be "nb_NO"
674    (Bokmテ・l) or "nn_NO" (Nynorsk). The aliases are intended to take care of
675    such cases, too:
676   
677    >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE'])
678    'nb_NO'
679   
680    You can override this default mapping by passing a different `aliases`
681    dictionary to this function, or you can bypass the behavior althogher by
682    setting the `aliases` parameter to `None`.
683   
684    :param preferred: the list of locale strings preferred by the user
685    :param available: the list of locale strings available
686    :param sep: character that separates the different parts of the locale
687                strings
688    :param aliases: a dictionary of aliases for locale identifiers
689    :return: the locale identifier for the best match, or `None` if no match
690             was found
691    :rtype: `str`
692    """
693    available = [a.lower() for a in available if a]
694    for locale in preferred:
695        ll = locale.lower()
696        if ll in available:
697            return locale
698        if aliases:
699            alias = aliases.get(ll)
700            if alias:
701                alias = alias.replace('_', sep)
702                if alias.lower() in available:
703                    return alias
704        parts = locale.split(sep)
705        if len(parts) > 1 and parts[0].lower() in available:
706            return parts[0]
707    return None
708
709def parse_locale(identifier, sep='_'):
710    """Parse a locale identifier into a tuple of the form::
711   
712      ``(language, territory, script, variant)``
713   
714    >>> parse_locale('zh_CN')
715    ('zh', 'CN', None, None)
716    >>> parse_locale('zh_Hans_CN')
717    ('zh', 'CN', 'Hans', None)
718   
719    The default component separator is "_", but a different separator can be
720    specified using the `sep` parameter:
721   
722    >>> parse_locale('zh-CN', sep='-')
723    ('zh', 'CN', None, None)
724   
725    If the identifier cannot be parsed into a locale, a `ValueError` exception
726    is raised:
727   
728    >>> parse_locale('not_a_LOCALE_String')
729    Traceback (most recent call last):
730      ...
731    ValueError: 'not_a_LOCALE_String' is not a valid locale identifier
732   
733    Encoding information and locale modifiers are removed from the identifier:
734   
735    >>> parse_locale('it_IT@euro')
736    ('it', 'IT', None, None)
737    >>> parse_locale('en_US.UTF-8')
738    ('en', 'US', None, None)
739    >>> parse_locale('de_DE.iso885915@euro')
740    ('de', 'DE', None, None)
741   
742    :param identifier: the locale identifier string
743    :param sep: character that separates the different components of the locale
744                identifier
745    :return: the ``(language, territory, script, variant)`` tuple
746    :rtype: `tuple`
747    :raise `ValueError`: if the string does not appear to be a valid locale
748                         identifier
749   
750    :see: `IETF RFC 4646 <http://www.ietf.org/rfc/rfc4646.txt>`_
751    """
752    if '.' in identifier:
753        # this is probably the charset/encoding, which we don't care about
754        identifier = identifier.split('.', 1)[0]
755    if '@' in identifier:
756        # this is a locale modifier such as @euro, which we don't care about
757        # either
758        identifier = identifier.split('@', 1)[0]
759
760    parts = identifier.split(sep)
761    lang = parts.pop(0).lower()
762    if not lang.isalpha():
763        raise ValueError('expected only letters, got %r' % lang)
764
765    script = territory = variant = None
766    if parts:
767        if len(parts[0]) == 4 and parts[0].isalpha():
768            script = parts.pop(0).title()
769
770    if parts:
771        if len(parts[0]) == 2 and parts[0].isalpha():
772            territory = parts.pop(0).upper()
773        elif len(parts[0]) == 3 and parts[0].isdigit():
774            territory = parts.pop(0)
775
776    if parts:
777        if len(parts[0]) == 4 and parts[0][0].isdigit() or \
778                len(parts[0]) >= 5 and parts[0][0].isalpha():
779            variant = parts.pop()
780
781    if parts:
782        raise ValueError('%r is not a valid locale identifier' % identifier)
783
784    return lang, territory, script, variant
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。