def test_negotiate(self): de_DE = Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT']) assert (de_DE.language, de_DE.territory) == ('de', 'DE') de = Locale.negotiate(['de_DE', 'en_US'], ['en', 'de']) assert (de.language, de.territory) == ('de', None) nothing = Locale.negotiate(['de_DE', 'de'], ['en_US']) assert nothing is None
def get_metadata(app, docname): ''' Extracts metadata from a document. ''' env = app.builder.env language = app.config.language locale = Locale.parse(language) if language else Locale.default() format_ui_date = partial( format_date, format=UIStr.TIMESTAMP_FMT, locale=locale) format_short_ui_short = partial( format_date, format=UIStr.TIMESTAMP_FMT_SHORT, locale=locale) env.blog_metadata[docname] = Metadata() metadata = env.blog_metadata[docname] # if it's a page if docname.startswith("pages/"): metadata.is_page = True return # posts are identified by ($YEAR)/($MONTH)/($DAY) paths match = re.match(r"\d{4}/\d{2}/\d{2}/", docname) # if not post return if not match: return metadata.is_post = True metadata.link = docname metadata.date = datetime.datetime.strptime(match.group(), "%Y/%m/%d/") # we format date here instead of inside template due to localization issues # and Python2 vs Python3 incompatibility metadata.formatted_date = format_ui_date(metadata.date) metadata.formatted_date_short = format_short_ui_short(metadata.date)
def test_value_error(self, Locale): """ If Locale.parse raises a ValueError, return the en-US locale object. """ Locale.parse.side_effect = ValueError eq_(helpers.current_locale(), Locale.return_value) Locale.assert_called_with('en', 'US')
def test_unknown_locale(self, Locale): """ If Locale.parse raises an UnknownLocaleError, return the en-US locale object. """ Locale.parse.side_effect = UnknownLocaleError('foo') eq_(helpers.current_locale(), Locale.return_value) Locale.assert_called_with('en', 'US')
def negotiate(cls, locale): """ Negotiate proper RBNF rules based on global data item `rbnf_locales` Caching is not necessary the Locale object does that pretty well """ loc = Locale.negotiate([str(Locale.parse(locale))], get_global('rbnf_locales')) print('TL', type(loc)) return cls(loc)
def getLocale(self, request): ## FIXME: implement request.locale() tags = ACCEPT_LANGUAGE.parse(request.environ()) if tags: try: return Locale.parse(tags[0], sep='-') except UnknownLocaleError, e: try: return Locale.parse(tags[0]) except UnknownLocaleError, e: logger.error('Locale parsing error: %s' % e) return defaultLocale()
def defaultLocale(): try: lang, _ = locale.getdefaultlocale() except Exception: lang = None if lang is not None: return Locale.parse(lang) else: try: return Locale.default() except UnknownLocaleError: return Locale('en', 'US')
def get_locale_data(): language = get_language() if not language: language = settings.LANGUAGE_CODE locale_code = to_locale(language) locale = None try: locale = Locale.parse(locale_code) except (ValueError, UnknownLocaleError): # Invalid format or unknown locale # Fallback to the default language language = settings.LANGUAGE_CODE locale_code = to_locale(language) locale = Locale.parse(locale_code) return locale, locale_code
def babel_date(date, format='long'): """ Format a date properly for the current locale. Format can be one of 'short', 'medium', 'long', or 'full'. """ locale = Locale.parse(get_language(), sep='-') return format_date(date, format, locale)
def format_list(lst, locale=DEFAULT_LOCALE): """ Formats `lst` as a list e.g. >>> format_list(['apples', 'oranges', 'pears'], 'en') u'apples, oranges, and pears' >>> format_list(['apples', 'oranges', 'pears'], 'zh') u'apples\u3001oranges\u548cpears' :param lst: a sequence of items to format in to a list :param locale: the locale """ locale = Locale.parse(locale) if not lst: return '' if len(lst) == 1: return lst[0] if len(lst) == 2: return locale.list_patterns['2'].format(*lst) result = locale.list_patterns['start'].format(lst[0], lst[1]) for elem in lst[2:-1]: result = locale.list_patterns['middle'].format(result, elem) result = locale.list_patterns['end'].format(result, lst[-1]) return result
def format_date(date=None, format='medium', locale=LC_TIME): """Return a date formatted according to the given pattern. >>> d = date(2007, 04, 01) >>> format_date(d, locale='en_US') u'Apr 1, 2007' >>> format_date(d, format='full', locale='de_DE') u'Sonntag, 1. April 2007' If you don't want to use the locale default formats, you can specify a custom date pattern: >>> format_date(d, "EEE, MMM d, ''yy", locale='en') u"Sun, Apr 1, '07" :param date: the ``date`` or ``datetime`` object; if `None`, the current date is used :param format: one of "full", "long", "medium", or "short", or a custom date/time pattern :param locale: a `Locale` object or a locale identifier """ if date is None: date = date_.today() elif isinstance(date, datetime): date = date.date() locale = Locale.parse(locale) if format in ('full', 'long', 'medium', 'short'): format = get_date_format(format, locale=locale) pattern = parse_pattern(format) return pattern.apply(date, locale)
def format_scientific( number, format=None, locale=LC_NUMERIC, decimal_quantization=True): """Return value formatted in scientific notation for a specific locale. >>> format_scientific(10000, locale='en_US') u'1E4' The format pattern can also be specified explicitly: >>> format_scientific(1234567, u'##0.##E00', locale='en_US') u'1.23E06' By default the locale is allowed to truncate and round a high-precision number by forcing its format pattern onto the decimal part. You can bypass this behavior with the `decimal_quantization` parameter: >>> format_scientific(1234.9876, u'#.##E0', locale='en_US') u'1.23E3' >>> format_scientific(1234.9876, u'#.##E0', locale='en_US', decimal_quantization=False) u'1.2349876E3' :param number: the number to format :param format: :param locale: the `Locale` object or locale identifier :param decimal_quantization: Truncate and round high-precision numbers to the format pattern. Defaults to `True`. """ locale = Locale.parse(locale) if not format: format = locale.scientific_formats.get(format) pattern = parse_pattern(format) return pattern.apply( number, locale, decimal_quantization=decimal_quantization)
def _format_currency_long_name( number, currency, format=None, locale=LC_NUMERIC, currency_digits=True, format_type='standard', decimal_quantization=True): # Algorithm described here: # https://www.unicode.org/reports/tr35/tr35-numbers.html#Currencies locale = Locale.parse(locale) # Step 1. # There are no examples of items with explicit count (0 or 1) in current # locale data. So there is no point implementing that. # Step 2. # Correct number to numeric type, important for looking up plural rules: if isinstance(number, string_types): number_n = float(number) else: number_n = number # Step 3. unit_pattern = get_currency_unit_pattern(currency, count=number_n, locale=locale) # Step 4. display_name = get_currency_name(currency, count=number_n, locale=locale) # Step 5. if not format: format = locale.decimal_formats.get(format) pattern = parse_pattern(format) number_part = pattern.apply( number, locale, currency=currency, currency_digits=currency_digits, decimal_quantization=decimal_quantization) return unit_pattern.format(number_part, display_name)
def load_translation(self,langs, dirname, domain): """Loads the first existing translations for known locale and saves the `Lang` object in a global cache for faster lookup on the next request. :parameters: langs : List List of languages as returned by `parse_accept_language_header`. dirname : String Directory of the translations (`tools.I18nTool.mo_dir`). domain : String Gettext domain of the catalog (`tools.I18nTool.domain`). :returns: Lang object with two attributes (Lang.trans = the translations object, Lang.locale = the corresponding Locale object). :rtype: Lang :raises: ImproperlyConfigured if no locale where known. """ locale = None for lang in langs: short = lang[:2].lower() try: locale = Locale.parse(lang) if (domain, short) in _languages: return _languages[(domain, short)] trans = Translations.load(dirname, short, domain) except (ValueError, UnknownLocaleError): continue # If the translation was found, exit loop if isinstance(trans, Translations): break if locale is None: raise ImproperlyConfigured('Default locale not known.') _languages[(domain, short)] = res = Lang(locale, trans) return res
def format_decimal(number, format=None, locale=LC_NUMERIC): u"""Return the given decimal number formatted for a specific locale. >>> format_decimal(1.2345, locale='en_US') u'1.234' >>> format_decimal(1.2346, locale='en_US') u'1.235' >>> format_decimal(-1.2346, locale='en_US') u'-1.235' >>> format_decimal(1.2345, locale='sv_SE') u'1,234' >>> format_decimal(1.2345, locale='de') u'1,234' The appropriate thousands grouping and the decimal separator are used for each locale: >>> format_decimal(12345.5, locale='en_US') u'12,345.5' :param number: the number to format :param format: :param locale: the `Locale` object or locale identifier """ locale = Locale.parse(locale) if not format: format = locale.decimal_formats.get(format) pattern = parse_pattern(format) return pattern.apply(number, locale)
def parse_decimal(string, locale=LC_NUMERIC): """Parse localized decimal string into a decimal. >>> parse_decimal('1,099.98', locale='en_US') Decimal('1099.98') >>> parse_decimal('1.099,98', locale='de') Decimal('1099.98') When the given string cannot be parsed, an exception is raised: >>> parse_decimal('2,109,998', locale='de') Traceback (most recent call last): ... NumberFormatError: '2,109,998' is not a valid decimal number :param string: the string to parse :param locale: the `Locale` object or locale identifier :raise NumberFormatError: if the string can not be converted to a decimal number """ locale = Locale.parse(locale) try: return Decimal(string.replace(get_group_symbol(locale), '') .replace(get_decimal_symbol(locale), '.')) except InvalidOperation: raise NumberFormatError('%r is not a valid decimal number' % string)
def format_currency(number, currency, format=None, locale=LC_NUMERIC): """Return formatted currency value. >>> format_currency(1099.98, 'USD', locale='en_US') u'$1,099.98' >>> format_currency(1099.98, 'USD', locale='es_CO') u'1.099,98\\xa0US$' >>> format_currency(1099.98, 'EUR', locale='de_DE') u'1.099,98\\xa0\\u20ac' The pattern can also be specified explicitly. The currency is placed with the '¤' sign. As the sign gets repeated the format expands (¤ being the symbol, ¤¤ is the currency abbreviation and ¤¤¤ is the full name of the currency): >>> format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00', locale='en_US') u'EUR 1,099.98' >>> format_currency(1099.98, 'EUR', u'#,##0.00 \xa4\xa4\xa4', locale='en_US') u'1,099.98 euros' :param number: the number to format :param currency: the currency code :param locale: the `Locale` object or locale identifier """ locale = Locale.parse(locale) if not format: format = locale.currency_formats.get(format) pattern = parse_pattern(format) return pattern.apply(number, locale, currency=currency)
def parse_decimal(string, locale=LC_NUMERIC): """Parse localized decimal string into a float. >>> parse_decimal('1,099.98', locale='en_US') 1099.98 >>> parse_decimal('1.099,98', locale='de') 1099.98 When the given string cannot be parsed, an exception is raised: >>> parse_decimal('2,109,998', locale='de') Traceback (most recent call last): ... NumberFormatError: '2,109,998' is not a valid decimal number :param string: the string to parse :param locale: the `Locale` object or locale identifier :return: the parsed decimal number :rtype: `float` :raise `NumberFormatError`: if the string can not be converted to a decimal number """ locale = Locale.parse(locale) try: return float(string.replace(get_group_symbol(locale), "").replace(get_decimal_symbol(locale), ".")) except ValueError: raise NumberFormatError("%r is not a valid decimal number" % string)
def get_unit_name(measurement_unit, length='long', locale=LC_NUMERIC): """ Get the display name for a measurement unit in the given locale. >>> get_unit_name("radian", locale="en") 'radians' Unknown units will raise exceptions: >>> get_unit_name("battery", locale="fi") Traceback (most recent call last): ... UnknownUnitError: battery/long is not a known unit/length in fi :param measurement_unit: the code of a measurement unit. Known units can be found in the CLDR Unit Validity XML file: http://unicode.org/repos/cldr/tags/latest/common/validity/unit.xml :param length: "short", "long" or "narrow" :param locale: the `Locale` object or locale identifier :return: The unit display name, or None. """ locale = Locale.parse(locale) unit = _find_unit_pattern(measurement_unit, locale=locale) if not unit: raise UnknownUnitError(unit=measurement_unit, locale=locale) return locale.unit_display_names.get(unit, {}).get(length)
def get_currency_unit_pattern(currency, count=None, locale=LC_NUMERIC): """ Return the unit pattern used for long display of a currency value for a given locale. This is a string containing ``{0}`` where the numeric part should be substituted and ``{1}`` where the currency long display name should be substituted. >>> get_currency_unit_pattern('USD', locale='en_US', count=10) u'{0} {1}' .. versionadded:: 2.7.0 :param currency: the currency code. :param count: the optional count. If provided the unit pattern for that number will be returned. :param locale: the `Locale` object or locale identifier. """ loc = Locale.parse(locale) if count is not None: plural_form = loc.plural_form(count) try: return loc._data['currency_unit_patterns'][plural_form] except LookupError: # Fall back to 'other' pass return loc._data['currency_unit_patterns']['other']
def _babel_locale(): """Return the current locale in Babel's format.""" try: return Locale.parse(get_language(), sep='-') except UnknownLocaleError: # Default to en-US return Locale('en', 'US')
def _language_select(self): out = {'automatic': _('automatic')} i18n_dir = os.path.join(xdm.APP_PATH, 'i18n') # http://stackoverflow.com/questions/800197/get-all-of-the-immediate-subdirectories-in-python for language in [name for name in os.listdir(i18n_dir) if os.path.isdir(os.path.join(i18n_dir, name))]: out[language] = Locale.parse(language, sep='_').display_name return out
def get_plural(locale=LC_CTYPE): """A tuple with the information catalogs need to perform proper pluralization. The first item of the tuple is the number of plural forms, the second the plural expression. >>> get_plural(locale='en') (2, '(n != 1)') >>> get_plural(locale='ga') (3, '(n==1 ? 0 : n==2 ? 1 : 2)') The object returned is a special tuple with additional members: >>> tup = get_plural("ja") >>> tup.num_plurals 1 >>> tup.plural_expr '0' >>> tup.plural_forms 'npurals=1; plural=0' Converting the tuple into a string prints the plural forms for a gettext catalog: >>> str(tup) 'npurals=1; plural=0' """ locale = Locale.parse(locale) try: tup = PLURALS[str(locale)] except KeyError: try: tup = PLURALS[locale.language] except KeyError: tup = DEFAULT_PLURAL return _PluralTuple(tup)
def format_percent(number, format=None, locale=LC_NUMERIC): """Return formatted percent value for a specific locale. >>> format_percent(0.34, locale='en_US') == u('34%') True >>> format_percent(25.1234, locale='en_US') == u('2,512%') True >>> format_percent(25.1234, locale='sv_SE') == u('2\\xa0512\\xa0%') True The format pattern can also be specified explicitly: >>> format_percent(25.1234, u('#,##0\u2030'), locale='en_US') == u('25,123\u2030') True :param number: the percent number to format :param format: :param locale: the `Locale` object or locale identifier :return: the formatted percent number :rtype: `unicode` """ locale = Locale.parse(locale) if not format: format = locale.percent_formats.get(format) pattern = parse_pattern(format) return pattern.apply(number, locale)
def format_currency(number, currency, format=None, locale=LC_NUMERIC): """Return formatted currency value. >>> format_currency(1099.98, 'USD', locale='en_US') == u('$1,099.98') True >>> format_currency(1099.98, 'USD', locale='es_CO') == u('US$\\xa01.099,98') True >>> format_currency(1099.98, 'EUR', locale='de_DE') == u('1.099,98\\xa0\\u20ac') True The pattern can also be specified explicitly: >>> format_currency(1099.98, 'EUR', u('\u00a4\u00a4 #,##0.00'), locale='en_US') == u('EUR 1,099.98') True :param number: the number to format :param currency: the currency code :param locale: the `Locale` object or locale identifier :return: the formatted currency value :rtype: `unicode` """ locale = Locale.parse(locale) if not format: format = locale.currency_formats.get(format) pattern = parse_pattern(format) return pattern.apply(number, locale, currency=currency)
def get_locale(lang): """Return a babel Locale object for lang. defaults to LANGUAGE_CODE.""" lang = babel_format_locale_map.get(lang) or lang try: return Locale.parse(lang, sep='-') except (UnknownLocaleError, ValueError): return Locale(*settings.LANGUAGE_CODE.split('-'))
def __init__(self, locale, locale_dirs): """Initialize this translator for the given locale. :type locale: :class:`babel.Locale` or ``str``. :param locale: The locale to load translations for. :type locale_dirs: dict :param locale_dirs: A mapping of translation domain names to the localedir where they can be found. See :func:`gettext.translation` for more details. :raises DomainError: If no locale dir has been configured for this domain and the fallback is off. :raises LanguageError: If no translations could be found for this locale in the 'mediadrop' domain and the fallback is off. """ self.locale = locale = Locale.parse(locale) # Save configuration required for loading translations self._locale_dirs = locale_dirs # If the locale is pt_BR, look for both pt_BR and pt translations self._languages = [str(locale)] if locale.territory: self._languages.append(locale.language) # Storage for all message catalogs keyed by their domain name self._domains = {} # Fetch the 'mediadrop' domain immediately & cache a direct ref for perf self._mediadrop = self._load_domain(MEDIACORE)
def _set_mime_headers(self, headers): for name, value in headers: name = name.lower() if name == 'project-id-version': parts = value.split(' ') self.project = u' '.join(parts[:-1]) self.version = parts[-1] elif name == 'report-msgid-bugs-to': self.msgid_bugs_address = value elif name == 'last-translator': self.last_translator = value elif name == 'language': self.locale = Locale.parse(value) elif name == 'language-team': self.language_team = value elif name == 'content-type': mimetype, params = parse_header(value) if 'charset' in params: self.charset = params['charset'].lower() elif name == 'plural-forms': _, params = parse_header(' ;' + value) self._num_plurals = int(params.get('nplurals', 2)) self._plural_expr = params.get('plural', '(n != 1)') elif name == 'pot-creation-date': self.creation_date = _parse_datetime_header(value) elif name == 'po-revision-date': # Keep the value if it's not the default one if 'YEAR' not in value: self.revision_date = _parse_datetime_header(value)
def format_skeleton(skeleton, datetime=None, tzinfo=None, locale=LC_TIME): r"""Return a time and/or date formatted according to the given pattern. The skeletons are defined in the CLDR data and provide more flexibility than the simple short/long/medium formats, but are a bit harder to use. The are defined using the date/time symbols without order or punctuation and map to a suitable format for the given locale. >>> t = datetime(2007, 4, 1, 15, 30) >>> format_skeleton('MMMEd', t, locale='fr') u'dim. 1 avr.' >>> format_skeleton('MMMEd', t, locale='en') u'Sun, Apr 1' After the skeleton is resolved to a pattern `format_datetime` is called so all timezone processing etc is the same as for that. :param skeleton: A date time skeleton as defined in the cldr data. :param datetime: the ``time`` or ``datetime`` object; if `None`, the current time in UTC is used :param tzinfo: the time-zone to apply to the time for display :param locale: a `Locale` object or a locale identifier """ locale = Locale.parse(locale) format = locale.datetime_skeletons[skeleton] return format_datetime(datetime, format, tzinfo, locale)
def getGlobalPOTimestamp(self, locale): ''' @see: IPOFileManager.getGlobalPOTimestamp ''' try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) return self._lastModified(locale)
def test_decimal_formats(self): assert Locale('en', 'US').decimal_formats[None].pattern == '#,##0.###'
def test_number_symbols_property(self): assert Locale('fr', 'FR').number_symbols['decimal'] == ','
def test_currency_symbols_property(self): assert Locale('en', 'US').currency_symbols['USD'] == '$' assert Locale('es', 'CO').currency_symbols['USD'] == 'US$'
def test_currencies_property(self): assert Locale('en').currencies['COP'] == 'Colombian Peso' assert Locale('de', 'DE').currencies['COP'] == 'Kolumbianischer Peso'
def test_variants_property(self): assert (Locale( 'de', 'DE').variants['1901'] == 'Alte deutsche Rechtschreibung')
def get_timezone_name(dt_or_tzinfo=None, width='long', uncommon=False, locale=LC_TIME): r"""Return the localized display name for the given timezone. The timezone may be specified using a ``datetime`` or `tzinfo` object. >>> from pytz import timezone >>> dt = time(15, 30, tzinfo=timezone('America/Los_Angeles')) >>> get_timezone_name(dt, locale='en_US') u'Pacific Standard Time' >>> get_timezone_name(dt, width='short', locale='en_US') u'PST' If this function gets passed only a `tzinfo` object and no concrete `datetime`, the returned display name is indenpendent of daylight savings time. This can be used for example for selecting timezones, or to set the time of events that recur across DST changes: >>> tz = timezone('America/Los_Angeles') >>> get_timezone_name(tz, locale='en_US') u'Pacific Time' >>> get_timezone_name(tz, 'short', locale='en_US') u'PT' If no localized display name for the timezone is available, and the timezone is associated with a country that uses only a single timezone, the name of that country is returned, formatted according to the locale: >>> tz = timezone('Europe/Berlin') >>> get_timezone_name(tz, locale='de_DE') u'Deutschland' >>> get_timezone_name(tz, locale='pt_BR') u'Hor\xe1rio Alemanha' On the other hand, if the country uses multiple timezones, the city is also included in the representation: >>> tz = timezone('America/St_Johns') >>> get_timezone_name(tz, locale='de_DE') u"Kanada (St. John's)" The `uncommon` parameter can be set to `True` to enable the use of timezone representations that are not commonly used by the requested locale. For example, while in frensh the central europian timezone is usually abbreviated as "HEC", in Canadian French, this abbreviation is not in common use, so a generic name would be chosen by default: >>> tz = timezone('Europe/Paris') >>> get_timezone_name(tz, 'short', locale='fr_CA') u'France' >>> get_timezone_name(tz, 'short', uncommon=True, locale='fr_CA') u'HEC' :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines the timezone; if a ``tzinfo`` object is used, the resulting display name will be generic, i.e. independent of daylight savings time; if `None`, the current date in UTC is assumed :param width: either "long" or "short" :param uncommon: whether even uncommon timezone abbreviations should be used :param locale: the `Locale` object, or a locale string :return: the timezone display name :rtype: `unicode` :since: version 0.9 :see: `LDML Appendix J: Time Zone Display Names <http://www.unicode.org/reports/tr35/#Time_Zone_Fallback>`_ """ if dt_or_tzinfo is None or isinstance(dt_or_tzinfo, (int, long)): dt = None tzinfo = UTC elif isinstance(dt_or_tzinfo, (datetime, time)): dt = dt_or_tzinfo if dt.tzinfo is not None: tzinfo = dt.tzinfo else: tzinfo = UTC else: dt = None tzinfo = dt_or_tzinfo locale = Locale.parse(locale) if hasattr(tzinfo, 'zone'): zone = tzinfo.zone else: zone = tzinfo.tzname(dt) # Get the canonical time-zone code zone = get_global('zone_aliases').get(zone, zone) info = locale.time_zones.get(zone, {}) # Try explicitly translated zone names first if width in info: if dt is None: field = 'generic' else: dst = tzinfo.dst(dt) if dst is None: field = 'generic' elif dst == 0: field = 'standard' else: field = 'daylight' if field in info[width]: return info[width][field] metazone = get_global('meta_zones').get(zone) if metazone: metazone_info = locale.meta_zones.get(metazone, {}) if width in metazone_info and (uncommon or metazone_info.get('common')): if dt is None: field = 'generic' else: field = tzinfo.dst(dt) and 'daylight' or 'standard' if field in metazone_info[width]: return metazone_info[width][field] # If we have a concrete datetime, we assume that the result can't be # independent of daylight savings time, so we return the GMT offset if dt is not None: return get_timezone_gmt(dt, width=width, locale=locale) return get_timezone_location(dt_or_tzinfo, locale=locale)
def __init__(self, value, locale): assert isinstance(value, (date, datetime, time)) if isinstance(value, (datetime, time)) and value.tzinfo is None: value = value.replace(tzinfo=UTC) self.value = value self.locale = Locale.parse(locale)
def test_display_name_property(self): assert Locale('en').display_name == 'English' assert Locale('en', 'US').display_name == 'English (United States)' assert Locale('sv').display_name == 'svenska'
def get_data(self): """ Defines some attributes for the Sage notebook localization system. It must be overridden if subclassing for another project. Mandatory attributes that must be defined by this method: :attribute keywords: the file name of this script. :attribute method_map: files with localizable messages in the sources. (see `babel.messages.extract.extract_from_dir() documentation) :attribute options_map: options for every class of localizable files, (see `babel.messages.extract.extract_from_dir() documentation) :attribute charset: charset for `babel.messages.catalog.Catalog`. :attribute sort_by_file: message ordering for po and pot files. This option keeps changes in po and pot files small when changes in notebook sources are small. :attribute width: max line length for po and pot files. This option contributes to keep changes in po and pot files small when changes in notebook sources are small. :attribute langs: list of identifiers for available localizations in the notebook. :attribute lang_names: localized names of available localizations. """ #: function names surrounding translatable strings self.keywords = { '_': None, 'gettext': None, 'ngettext': (1, 2), 'ugettext': None, 'ungettext': (1, 2), 'dgettext': (2,), 'dngettext': (2, 3), 'N_': None, 'nN_': (1,2), 'pgettext': ((1, 'c'), 2), 'npgettext': ((1, 'c'), 2, 3), 'lazy_gettext': None, 'lazy_pgettext': ((1, 'c'), 2), } #: Source files to extract messages self.method_map = [ ('sagewui/*.py', 'python'), ('sagewui/blueprints/**.py', 'python'), ('sagewui/util/**.py', 'python'), ('sagewui/gui/**.py', 'python'), ('sagewui/templates/html/**.html', 'jinja2'), ('sagewui/templates/js/**.js', 'jinja2')] #: Some configuration for each type of file opts = { 'jinja2': { 'encoding': 'utf-8', 'extensions': 'jinja2.ext.autoescape,jinja2.ext.with_'}, 'python': {}, } self.options_map = dict((m[0], opts[m[1]]) for m in self.method_map) #: Some defaults for babel package self.charset = 'utf-8' self.sort_by_file = True self.width = 76 #: Available translations in the source tree names = os.listdir(self.path.trans) self.langs = [] self.lang_names = [] for name in names: try: locale = Locale.parse(name) except UnknownLocaleError: pass else: self.langs.append(name) self.lang_names.append(locale.display_name)
def parse_locale_set(codes: List[str]) -> Set[Locale]: return {Locale.parse(code) for code in codes}
def _locale(request): """ Computes a babel.core:Locale() object for this request. """ return Locale.parse(request.locale_name)
def test_currency_formats_property(self): assert (Locale( 'en', 'US').currency_formats['standard'].pattern == u'\xa4#,##0.00') assert (Locale('en', 'US').currency_formats['accounting'].pattern == u'\xa4#,##0.00;(\xa4#,##0.00)')
def test_percent_formats_property(self): assert Locale('en', 'US').percent_formats[None].pattern == '#,##0%'
def format_time(time=None, format='medium', tzinfo=None, locale=LC_TIME): """Return a time formatted according to the given pattern. >>> t = time(15, 30) >>> format_time(t, locale='en_US') u'3:30:00 PM' >>> format_time(t, format='short', locale='de_DE') u'15:30' If you don't want to use the locale default formats, you can specify a custom time pattern: >>> format_time(t, "hh 'o''clock' a", locale='en') u"03 o'clock PM" For any pattern requiring the display of the time-zone, the third-party ``pytz`` package is needed to explicitly specify the time-zone: >>> from pytz import timezone >>> t = datetime(2007, 4, 1, 15, 30) >>> tzinfo = timezone('Europe/Paris') >>> t = tzinfo.localize(t) >>> format_time(t, format='full', tzinfo=tzinfo, locale='fr_FR') u'15:30:00 HEC' >>> format_time(t, "hh 'o''clock' a, zzzz", tzinfo=timezone('US/Eastern'), ... locale='en') u"09 o'clock AM, Eastern Daylight Time" As that example shows, when this function gets passed a ``datetime.datetime`` value, the actual time in the formatted string is adjusted to the timezone specified by the `tzinfo` parameter. If the ``datetime`` is "naive" (i.e. it has no associated timezone information), it is assumed to be in UTC. These timezone calculations are **not** performed if the value is of type ``datetime.time``, as without date information there's no way to determine what a given time would translate to in a different timezone without information about whether daylight savings time is in effect or not. This means that time values are left as-is, and the value of the `tzinfo` parameter is only used to display the timezone name if needed: >>> t = time(15, 30) >>> format_time(t, format='full', tzinfo=timezone('Europe/Paris'), ... locale='fr_FR') u'15:30:00 HEC' >>> format_time(t, format='full', tzinfo=timezone('US/Eastern'), ... locale='en_US') u'3:30:00 PM ET' :param time: the ``time`` or ``datetime`` object; if `None`, the current time in UTC is used :param format: one of "full", "long", "medium", or "short", or a custom date/time pattern :param tzinfo: the time-zone to apply to the time for display :param locale: a `Locale` object or a locale identifier :rtype: `unicode` :note: If the pattern contains date fields, an `AttributeError` will be raised when trying to apply the formatting. This is also true if the value of ``time`` parameter is actually a ``datetime`` object, as this function automatically converts that to a ``time``. """ if time is None: time = datetime.utcnow() elif isinstance(time, (int, long)): time = datetime.utcfromtimestamp(time) if time.tzinfo is None: time = time.replace(tzinfo=UTC) if isinstance(time, datetime): if tzinfo is not None: time = time.astimezone(tzinfo) if hasattr(tzinfo, 'localize'): # pytz time = tzinfo.normalize(time) time = time.timetz() elif tzinfo is not None: time = time.replace(tzinfo=tzinfo) locale = Locale.parse(locale) if format in ('full', 'long', 'medium', 'short'): format = get_time_format(format, locale=locale) return parse_pattern(format).apply(time, locale)
def format_list(lst, style='standard', locale=DEFAULT_LOCALE): """ Format the items in `lst` as a list. >>> format_list(['apples', 'oranges', 'pears'], locale='en') u'apples, oranges, and pears' >>> format_list(['apples', 'oranges', 'pears'], locale='zh') u'apples\u3001oranges\u548cpears' >>> format_list(['omena', 'peruna', 'aplari'], style='or', locale='fi') u'omena, peruna tai aplari' These styles are defined, but not all are necessarily available in all locales. The following text is verbatim from the Unicode TR35-49 spec [1]. * standard: A typical 'and' list for arbitrary placeholders. eg. "January, February, and March" * standard-short: A short version of a 'and' list, suitable for use with short or abbreviated placeholder values. eg. "Jan., Feb., and Mar." * or: A typical 'or' list for arbitrary placeholders. eg. "January, February, or March" * or-short: A short version of an 'or' list. eg. "Jan., Feb., or Mar." * unit: A list suitable for wide units. eg. "3 feet, 7 inches" * unit-short: A list suitable for short units eg. "3 ft, 7 in" * unit-narrow: A list suitable for narrow units, where space on the screen is very limited. eg. "3′ 7″" [1]: https://www.unicode.org/reports/tr35/tr35-49/tr35-general.html#ListPatterns :param lst: a sequence of items to format in to a list :param style: the style to format the list with. See above for description. :param locale: the locale """ locale = Locale.parse(locale) if not lst: return '' if len(lst) == 1: return lst[0] if style not in locale.list_patterns: raise ValueError( 'Locale %s does not support list formatting style %r (supported are %s)' % ( locale, style, list(sorted(locale.list_patterns)), )) patterns = locale.list_patterns[style] if len(lst) == 2: return patterns['2'].format(*lst) result = patterns['start'].format(lst[0], lst[1]) for elem in lst[2:-1]: result = patterns['middle'].format(result, elem) result = patterns['end'].format(result, lst[-1]) return result
def test_2_num_plurals_checkers(self): # in this testcase we add an extra msgstr[idx], we should be # disregarding it for _locale in [p for p in PLURALS if PLURALS[p][0] == 2]: if _locale in ['nn', 'no']: _locale = 'nn_NO' num_plurals = PLURALS[_locale.split('_')[0]][0] plural_expr = PLURALS[_locale.split('_')[0]][1] else: num_plurals = PLURALS[_locale][0] plural_expr = PLURALS[_locale][1] try: locale = Locale(_locale) date = format_datetime(datetime.now(LOCALTZ), 'yyyy-MM-dd HH:mmZ', tzinfo=LOCALTZ, locale=_locale), except UnknownLocaleError: # Just an alias? Not what we're testing here, let's continue continue po_file = (ur"""\ # %(english_name)s translations for TestProject. # Copyright (C) 2007 FooBar, Inc. # This file is distributed under the same license as the TestProject # project. # FIRST AUTHOR <EMAIL@ADDRESS>, 2007. # msgid "" msgstr "" "Project-Id-Version: TestProject 0.1\n" "Report-Msgid-Bugs-To: [email protected]\n" "POT-Creation-Date: 2007-04-01 15:30+0200\n" "PO-Revision-Date: %(date)s\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: %(locale)s <*****@*****.**>\n" "Plural-Forms: nplurals=%(num_plurals)s; plural=%(plural_expr)s\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel %(version)s\n" #. This will be a translator comment, #. that will include several lines #: project/file1.py:8 msgid "bar" msgstr "" #: project/file2.py:9 msgid "foobar" msgid_plural "foobars" msgstr[0] "" msgstr[1] "" msgstr[2] "" """ % dict(locale=_locale, english_name=locale.english_name, version=VERSION, year=time.strftime('%Y'), date=date, num_plurals=num_plurals, plural_expr=plural_expr)).encode('utf-8') # we should be adding the missing msgstr[0] # This test will fail for revisions <= 406 because so far # catalog.num_plurals was neglected catalog = read_po(StringIO(po_file), _locale) message = catalog['foobar'] checkers.num_plurals(catalog, message)
COUNTRY_CODES = """ AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HM HN HR HT HU ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PK PL PM PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SV SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI VN VU WF WS YE YT ZA ZM ZW """.split() COUNTRIES = make_sorted_dict(COUNTRY_CODES, Locale('en').territories) LANGUAGE_CODES_2 = """ aa af ak am ar as az be bg bm bn bo br bs ca cs cy da de dz ee el en eo es et eu fa ff fi fo fr ga gd gl gu gv ha he hi hr hu hy ia id ig ii is it ja ka ki kk kl km kn ko ks kw ky lg ln lo lt lu lv mg mk ml mn mr ms mt my nb nd ne nl nn nr om or os pa pl ps pt rm rn ro ru rw se sg si sk sl sn so sq sr ss st sv sw ta te tg th ti tn to tr ts uk ur uz ve vi vo xh yo zh zu """.split() LANGUAGES_2 = make_sorted_dict(LANGUAGE_CODES_2, Locale('en').languages) LOCALES = {} LOCALE_EN = LOCALES['en'] = Locale('en') LOCALE_EN.catalog = Catalog('en') LOCALE_EN.catalog.plural_func = lambda n: n != 1
def get_timezone_location(dt_or_tzinfo=None, locale=LC_TIME): """Return a representation of the given timezone using "location format". The result depends on both the local display name of the country and the city assocaited with the time zone: >>> from pytz import timezone >>> tz = timezone('America/St_Johns') >>> get_timezone_location(tz, locale='de_DE') u"Kanada (St. John's)" >>> tz = timezone('America/Mexico_City') >>> get_timezone_location(tz, locale='de_DE') u'Mexiko (Mexiko-Stadt)' If the timezone is associated with a country that uses only a single timezone, just the localized country name is returned: >>> tz = timezone('Europe/Berlin') >>> get_timezone_name(tz, locale='de_DE') u'Deutschland' :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines the timezone; if `None`, the current date and time in UTC is assumed :param locale: the `Locale` object, or a locale string :return: the localized timezone name using location format :rtype: `unicode` :since: version 0.9 """ if dt_or_tzinfo is None or isinstance(dt_or_tzinfo, (int, long)): dt = None tzinfo = UTC elif isinstance(dt_or_tzinfo, (datetime, time)): dt = dt_or_tzinfo if dt.tzinfo is not None: tzinfo = dt.tzinfo else: tzinfo = UTC else: dt = None tzinfo = dt_or_tzinfo locale = Locale.parse(locale) if hasattr(tzinfo, 'zone'): zone = tzinfo.zone else: zone = tzinfo.tzname(dt or datetime.utcnow()) # Get the canonical time-zone code zone = get_global('zone_aliases').get(zone, zone) info = locale.time_zones.get(zone, {}) # Otherwise, if there is only one timezone for the country, return the # localized country name region_format = locale.zone_formats['region'] territory = get_global('zone_territories').get(zone) if territory not in locale.territories: territory = 'ZZ' # invalid/unknown territory_name = locale.territories[territory] if territory and len(get_global('territory_zones').get(territory, [])) == 1: return region_format % (territory_name) # Otherwise, include the city in the output fallback_format = locale.zone_formats['fallback'] if 'city' in info: city_name = info['city'] else: metazone = get_global('meta_zones').get(zone) metazone_info = locale.meta_zones.get(metazone, {}) if 'city' in metazone_info: city_name = metainfo['city'] elif '/' in zone: city_name = zone.split('/', 1)[1].replace('_', ' ') else: city_name = zone.replace('_', ' ') return region_format % (fallback_format % { '0': city_name, '1': territory_name })
def format_timedelta(delta, granularity='second', threshold=.85, add_direction=False, format='long', locale=LC_TIME): """Return a time delta according to the rules of the given locale. >>> format_timedelta(timedelta(weeks=12), locale='en_US') u'3 months' >>> format_timedelta(timedelta(seconds=1), locale='es') u'1 segundo' The granularity parameter can be provided to alter the lowest unit presented, which defaults to a second. >>> format_timedelta(timedelta(hours=3), granularity='day', ... locale='en_US') u'1 day' The threshold parameter can be used to determine at which value the presentation switches to the next higher unit. A higher threshold factor means the presentation will switch later. For example: >>> format_timedelta(timedelta(hours=23), threshold=0.9, locale='en_US') u'1 day' >>> format_timedelta(timedelta(hours=23), threshold=1.1, locale='en_US') u'23 hours' In addition directional information can be provided that informs the user if the date is in the past or in the future: >>> format_timedelta(timedelta(hours=1), add_direction=True, locale='en') u'in 1 hour' >>> format_timedelta(timedelta(hours=-1), add_direction=True, locale='en') u'1 hour ago' :param delta: a ``timedelta`` object representing the time difference to format, or the delta in seconds as an `int` value :param granularity: determines the smallest unit that should be displayed, the value can be one of "year", "month", "week", "day", "hour", "minute" or "second" :param threshold: factor that determines at which point the presentation switches to the next higher unit :param add_direction: if this flag is set to `True` the return value will include directional information. For instance a positive timedelta will include the information about it being in the future, a negative will be information about the value being in the past. :param format: the format (currently only "long" and "short" are supported, "medium" is deprecated, currently converted to "long" to maintain compatibility) :param locale: a `Locale` object or a locale identifier """ if format not in ('short', 'medium', 'long'): raise TypeError('Format can only be one of "short" or "medium"') if format == 'medium': warnings.warn( '"medium" value for format param of format_timedelta' ' is deprecated. Use "long" instead', category=DeprecationWarning) format = 'long' if isinstance(delta, timedelta): seconds = int((delta.days * 86400) + delta.seconds) else: seconds = delta locale = Locale.parse(locale) def _iter_patterns(a_unit): if add_direction: unit_rel_patterns = locale._data['date_fields'][a_unit] if seconds >= 0: yield unit_rel_patterns['future'] else: yield unit_rel_patterns['past'] a_unit = 'duration-' + a_unit yield locale._data['unit_patterns'].get(a_unit + ':' + format) yield locale._data['unit_patterns'].get(a_unit) for unit, secs_per_unit in TIMEDELTA_UNITS: value = abs(seconds) / secs_per_unit if value >= threshold or unit == granularity: if unit == granularity and value > 0: value = max(1, value) value = int(round(value)) plural_form = locale.plural_form(value) pattern = None for patterns in _iter_patterns(unit): if patterns is not None: pattern = patterns[plural_form] break # This really should not happen if pattern is None: return u'' return pattern.replace('{0}', str(value)) return u''
def test_territories_property(self): assert Locale('es', 'CO').territories['DE'] == 'Alemania'
def load_i18n(canonical_host, canonical_scheme, project_root, tell_sentry): # Load the locales localeDir = os.path.join(project_root, 'i18n', 'core') locales = LOCALES for file in os.listdir(localeDir): try: parts = file.split(".") if not (len(parts) == 2 and parts[1] == "po"): continue lang = parts[0] with open(os.path.join(localeDir, file)) as f: l = locales[lang.lower()] = Locale(lang) c = l.catalog = read_po(f) c.plural_func = get_function_from_rule(c.plural_expr) try: l.countries = make_sorted_dict(COUNTRIES, l.territories) except KeyError: l.countries = COUNTRIES try: l.languages_2 = make_sorted_dict(LANGUAGES_2, l.languages) except KeyError: l.languages_2 = LANGUAGES_2 except Exception as e: tell_sentry(e, {}, allow_reraise=True) # Prepare a unique and sorted list for use in the language switcher percent = lambda l: sum((percent(s) if isinstance(s, tuple) else 1) for s in l if s) / len(l) for l in locales.values(): if l.language == 'en': l.completion = 1 continue l.completion = percent([m.string for m in l.catalog if m.id]) loc_url = canonical_scheme+'://%s.'+canonical_host lang_list = sorted( ( (l.completion, l.language, l.language_name.title(), loc_url % l.language) for l in set(locales.values()) if l.completion ), key=lambda t: (-t[0], t[1]), ) # Add aliases for k, v in list(locales.items()): locales.setdefault(ALIASES.get(k, k), v) locales.setdefault(ALIASES_R.get(k, k), v) for k, v in list(locales.items()): locales.setdefault(k.split('_', 1)[0], v) # Patch the locales to look less formal locales['fr'].currency_formats[None] = parse_pattern('#,##0.00\u202f\xa4') locales['fr'].currency_symbols['USD'] = '$' # Load the markdown files docs = {} heading_re = re.compile(r'^(#+ )', re.M) for path in find_files(os.path.join(project_root, 'i18n'), '*.md'): d, b = os.path.split(path) doc = os.path.basename(d) lang = b[:-3] with open(path, 'rb') as f: md = f.read().decode('utf8') if md.startswith('# '): md = '\n'.join(md.split('\n')[1:]).strip() md = heading_re.sub(r'##\1', md) docs.setdefault(doc, {}).__setitem__(lang, markdown.render(md)) return {'docs': docs, 'lang_list': lang_list, 'locales': locales}
def format_currency(number, currency, format=None, locale=LC_NUMERIC, currency_digits=True, format_type='standard'): u"""Return formatted currency value. >>> format_currency(1099.98, 'USD', locale='en_US') u'$1,099.98' >>> format_currency(1099.98, 'USD', locale='es_CO') u'US$\\xa01.099,98' >>> format_currency(1099.98, 'EUR', locale='de_DE') u'1.099,98\\xa0\\u20ac' The format can also be specified explicitly. The currency is placed with the '¤' sign. As the sign gets repeated the format expands (¤ being the symbol, ¤¤ is the currency abbreviation and ¤¤¤ is the full name of the currency): >>> format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00', locale='en_US') u'EUR 1,099.98' >>> format_currency(1099.98, 'EUR', u'#,##0.00 \xa4\xa4\xa4', locale='en_US') u'1,099.98 euros' Currencies usually have a specific number of decimal digits. This function favours that information over the given format: >>> format_currency(1099.98, 'JPY', locale='en_US') u'\\xa51,100' >>> format_currency(1099.98, 'COP', u'#,##0.00', locale='es_ES') u'1.100' However, the number of decimal digits can be overriden from the currency information, by setting the last parameter to ``False``: >>> format_currency(1099.98, 'JPY', locale='en_US', currency_digits=False) u'\\xa51,099.98' >>> format_currency(1099.98, 'COP', u'#,##0.00', locale='es_ES', currency_digits=False) u'1.099,98' If a format is not specified the type of currency format to use from the locale can be specified: >>> format_currency(1099.98, 'EUR', locale='en_US', format_type='standard') u'\\u20ac1,099.98' When the given currency format type is not available, an exception is raised: >>> format_currency('1099.98', 'EUR', locale='root', format_type='unknown') Traceback (most recent call last): ... UnknownCurrencyFormatError: "'unknown' is not a known currency format type" :param number: the number to format :param currency: the currency code :param format: the format string to use :param locale: the `Locale` object or locale identifier :param currency_digits: use the currency's number of decimal digits :param format_type: the currency format type to use """ locale = Locale.parse(locale) if format: pattern = parse_pattern(format) else: try: pattern = locale.currency_formats[format_type] except KeyError: raise UnknownCurrencyFormatError( "%r is not a known currency format" " type" % format_type) if currency_digits: precision = get_currency_precision(currency) frac = (precision, precision) else: frac = None return pattern.apply(number, locale, currency=currency, force_frac=frac)
def format_unit(value, measurement_unit, length='long', format=None, locale=LC_NUMERIC): """Format a value of a given unit. Values are formatted according to the locale's usual pluralization rules and number formats. >>> format_unit(12, 'length-meter', locale='ro_RO') u'12 metri' >>> format_unit(15.5, 'length-mile', locale='fi_FI') u'15,5 mailia' >>> format_unit(1200, 'pressure-inch-hg', locale='nb') u'1\\xa0200 tommer kvikks\\xf8lv' Number formats may be overridden with the ``format`` parameter. >>> from babel._compat import Decimal >>> format_unit(Decimal("-42.774"), 'temperature-celsius', 'short', format='#.0', locale='fr') u'-42,8 \\xb0C' The locale's usual pluralization rules are respected. >>> format_unit(1, 'length-meter', locale='ro_RO') u'1 metru' >>> format_unit(0, 'length-picometer', locale='cy') u'0 picometr' >>> format_unit(2, 'length-picometer', locale='cy') u'2 bicometr' >>> format_unit(3, 'length-picometer', locale='cy') u'3 phicometr' >>> format_unit(15, 'length-horse', locale='fi') Traceback (most recent call last): ... UnknownUnitError: length-horse is not a known unit in fi .. versionadded:: 2.2.0 :param value: the value to format. If this is a string, no number formatting will be attempted. :param measurement_unit: the code of a measurement unit. Known units can be found in the CLDR Unit Validity XML file: http://unicode.org/repos/cldr/tags/latest/common/validity/unit.xml :param length: "short", "long" or "narrow" :param format: An optional format, as accepted by `format_decimal`. :param locale: the `Locale` object or locale identifier """ locale = Locale.parse(locale) q_unit = _find_unit_pattern(measurement_unit, locale=locale) if not q_unit: raise UnknownUnitError(unit=measurement_unit, locale=locale) unit_patterns = locale._data["unit_patterns"][q_unit].get(length, {}) if isinstance( value, string_types): # Assume the value is a preformatted singular. formatted_value = value plural_form = "one" else: formatted_value = format_decimal(value, format, locale) plural_form = locale.plural_form(value) if plural_form in unit_patterns: return unit_patterns[plural_form].format(formatted_value) # Fall back to a somewhat bad representation. # nb: This is marked as no-cover, as the current CLDR seemingly has no way for this to happen. return '%s %s' % ( # pragma: no cover formatted_value, (get_unit_name(measurement_unit, length=length, locale=locale) or measurement_unit))
def get_timezone_name(dt_or_tzinfo=None, width='long', uncommon=False, locale=LC_TIME, zone_variant=None): r"""Return the localized display name for the given timezone. The timezone may be specified using a ``datetime`` or `tzinfo` object. >>> dt = time(15, 30, tzinfo=get_timezone('America/Los_Angeles')) >>> get_timezone_name(dt, locale='en_US') u'Pacific Standard Time' >>> get_timezone_name(dt, width='short', locale='en_US') u'PST' If this function gets passed only a `tzinfo` object and no concrete `datetime`, the returned display name is indenpendent of daylight savings time. This can be used for example for selecting timezones, or to set the time of events that recur across DST changes: >>> tz = get_timezone('America/Los_Angeles') >>> get_timezone_name(tz, locale='en_US') u'Pacific Time' >>> get_timezone_name(tz, 'short', locale='en_US') u'PT' If no localized display name for the timezone is available, and the timezone is associated with a country that uses only a single timezone, the name of that country is returned, formatted according to the locale: >>> tz = get_timezone('Europe/Berlin') >>> get_timezone_name(tz, locale='de_DE') u'Mitteleurop\xe4ische Zeit' >>> get_timezone_name(tz, locale='pt_BR') u'Hor\xe1rio da Europa Central' On the other hand, if the country uses multiple timezones, the city is also included in the representation: >>> tz = get_timezone('America/St_Johns') >>> get_timezone_name(tz, locale='de_DE') u'Neufundland-Zeit' Note that short format is currently not supported for all timezones and all locales. This is partially because not every timezone has a short code in every locale. In that case it currently falls back to the long format. For more information see `LDML Appendix J: Time Zone Display Names <http://www.unicode.org/reports/tr35/#Time_Zone_Fallback>`_ .. versionadded:: 0.9 .. versionchanged:: 1.0 Added `zone_variant` support. :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines the timezone; if a ``tzinfo`` object is used, the resulting display name will be generic, i.e. independent of daylight savings time; if `None`, the current date in UTC is assumed :param width: either "long" or "short" :param uncommon: deprecated and ignored :param zone_variant: defines the zone variation to return. By default the variation is defined from the datetime object passed in. If no datetime object is passed in, the ``'generic'`` variation is assumed. The following values are valid: ``'generic'``, ``'daylight'`` and ``'standard'``. :param locale: the `Locale` object, or a locale string """ if dt_or_tzinfo is None: dt = datetime.now() tzinfo = LOCALTZ elif isinstance(dt_or_tzinfo, string_types): dt = None tzinfo = get_timezone(dt_or_tzinfo) elif isinstance(dt_or_tzinfo, integer_types): dt = None tzinfo = UTC elif isinstance(dt_or_tzinfo, (datetime, time)): dt = dt_or_tzinfo if dt.tzinfo is not None: tzinfo = dt.tzinfo else: tzinfo = UTC else: dt = None tzinfo = dt_or_tzinfo locale = Locale.parse(locale) if hasattr(tzinfo, 'zone'): zone = tzinfo.zone else: zone = tzinfo.tzname(dt) if zone_variant is None: if dt is None: zone_variant = 'generic' else: dst = tzinfo.dst(dt) if dst: zone_variant = 'daylight' else: zone_variant = 'standard' else: if zone_variant not in ('generic', 'standard', 'daylight'): raise ValueError('Invalid zone variation') # Get the canonical time-zone code zone = get_global('zone_aliases').get(zone, zone) info = locale.time_zones.get(zone, {}) # Try explicitly translated zone names first if width in info: if zone_variant in info[width]: return info[width][zone_variant] metazone = get_global('meta_zones').get(zone) if metazone: metazone_info = locale.meta_zones.get(metazone, {}) if width in metazone_info: if zone_variant in metazone_info[width]: return metazone_info[width][zone_variant] # If we have a concrete datetime, we assume that the result can't be # independent of daylight savings time, so we return the GMT offset if dt is not None: return get_timezone_gmt(dt, width=width, locale=locale) return get_timezone_location(dt_or_tzinfo, locale=locale)
def test_english_name_property(self): assert Locale('de').english_name == 'German' assert Locale('de', 'DE').english_name == 'German (Germany)'
def format_compound_unit(numerator_value, numerator_unit=None, denominator_value=1, denominator_unit=None, length='long', format=None, locale=LC_NUMERIC): """ Format a compound number value, i.e. "kilometers per hour" or similar. Both unit specifiers are optional to allow for formatting of arbitrary values still according to the locale's general "per" formatting specifier. >>> format_compound_unit(7, denominator_value=11, length="short", locale="pt") '7/11' >>> format_compound_unit(150, "kilometer", denominator_unit="hour", locale="sv") '150 kilometer per timme' >>> format_compound_unit(150, "kilowatt", denominator_unit="year", locale="fi") '150 kilowattia vuodessa' >>> format_compound_unit(32.5, "ton", 15, denominator_unit="hour", locale="en") '32.5 tons per 15 hours' >>> format_compound_unit(160, denominator_unit="square-meter", locale="fr") '160 par m\\xe8tre carr\\xe9' >>> format_compound_unit(4, "meter", "ratakisko", length="short", locale="fi") '4 m/ratakisko' >>> format_compound_unit(35, "minute", denominator_unit="fathom", locale="sv") '35 minuter per famn' >>> from babel.numbers import format_currency >>> format_compound_unit(format_currency(35, "JPY", locale="de"), denominator_unit="liter", locale="de") '35\\xa0\\xa5 pro Liter' See http://www.unicode.org/reports/tr35/tr35-general.html#perUnitPatterns :param numerator_value: The numerator value. This may be a string, in which case it is considered preformatted and the unit is ignored. :param numerator_unit: The numerator unit. See `format_unit`. :param denominator_value: The denominator value. This may be a string, in which case it is considered preformatted and the unit is ignored. :param denominator_unit: The denominator unit. See `format_unit`. :param length: The formatting length. "short", "long" or "narrow" :param format: An optional format, as accepted by `format_decimal`. :param locale: the `Locale` object or locale identifier :return: A formatted compound value. """ locale = Locale.parse(locale) # Look for a specific compound unit first... if numerator_unit and denominator_unit and denominator_value == 1: compound_unit = _find_compound_unit(numerator_unit, denominator_unit, locale=locale) if compound_unit: return format_unit(numerator_value, compound_unit, length=length, format=format, locale=locale) # ... failing that, construct one "by hand". if isinstance(numerator_value, string_types): # Numerator is preformatted formatted_numerator = numerator_value elif numerator_unit: # Numerator has unit formatted_numerator = format_unit(numerator_value, numerator_unit, length=length, format=format, locale=locale) else: # Unitless numerator formatted_numerator = format_decimal(numerator_value, format=format, locale=locale) if isinstance(denominator_value, string_types): # Denominator is preformatted formatted_denominator = denominator_value elif denominator_unit: # Denominator has unit if denominator_value == 1: # support perUnitPatterns when the denominator is 1 denominator_unit = _find_unit_pattern(denominator_unit, locale=locale) per_pattern = locale._data["unit_patterns"].get( denominator_unit, {}).get(length, {}).get("per") if per_pattern: return per_pattern.format(formatted_numerator) # See TR-35's per-unit pattern algorithm, point 3.2. # For denominator 1, we replace the value to be formatted with the empty string; # this will make `format_unit` return " second" instead of "1 second". denominator_value = "" formatted_denominator = format_unit(denominator_value, denominator_unit, length=length, format=format, locale=locale).strip() else: # Bare denominator formatted_denominator = format_decimal(denominator_value, format=format, locale=locale) per_pattern = locale._data["compound_unit_patterns"].get("per", {}).get( length, "{0}/{1}") return per_pattern.format(formatted_numerator, formatted_denominator)
def test_languages_property(self): assert Locale('de', 'DE').languages['ja'] == 'Japanisch'
def test_scripts_property(self): assert Locale('en', 'US').scripts['Hira'] == 'Hiragana'
def test_get_display_name(self): zh_CN = Locale('zh', 'CN', script='Hans') assert zh_CN.get_display_name('en') == 'Chinese (Simplified, China)'
def __init__(self, locale: str): self.locale = Locale.parse(locale) # This attribute can be set to `True` to differentiate multiple # locales currently available (supported) for the same language. self.use_display_name = False