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 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 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_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 __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 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 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_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 _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 _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 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 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: >>> try: ... parse_decimal('2,109,998', locale='de') ... except NumberFormatError as e: ... msg = str(e) >>> msg "'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: `Decimal` :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("'%s' is not a valid decimal number" % string)
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 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_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 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 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 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 getGlobalPOTimestamp(self, locale): ''' @see: IPOFileManager.getGlobalPOTimestamp ''' try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) return self._lastModified(locale)
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 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_metadata(app, docname): ''' Extracts metadata from a document. ''' env = app.builder.env language = app.config.language locale = Locale.parse(language) if language else Locale('en', 'US') 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 _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 __init__(self, locale=None, domain=None, header_comment=DEFAULT_HEADER, project=None, version=None, copyright_holder=None, msgid_bugs_address=None, creation_date=None, revision_date=None, last_translator=None, language_team=None, charset=None, fuzzy=True): """Initialize the catalog object. :param locale: the locale identifier or `Locale` object, or `None` if the catalog is not bound to a locale (which basically means it's a template) :param domain: the message domain :param header_comment: the header comment as string, or `None` for the default header :param project: the project's name :param version: the project's version :param copyright_holder: the copyright holder of the catalog :param msgid_bugs_address: the email address or URL to submit bug reports to :param creation_date: the date the catalog was created :param revision_date: the date the catalog was revised :param last_translator: the name and email of the last translator :param language_team: the name and email of the language team :param charset: the encoding to use in the output (defaults to utf-8) :param fuzzy: the fuzzy bit on the catalog header """ self.domain = domain #: The message domain if locale: locale = Locale.parse(locale) self.locale = locale #: The locale or `None` self._header_comment = header_comment self._messages = odict() self.project = project or 'PROJECT' #: The project name self.version = version or 'VERSION' #: The project version self.copyright_holder = copyright_holder or 'ORGANIZATION' self.msgid_bugs_address = msgid_bugs_address or 'EMAIL@ADDRESS' self.last_translator = last_translator or 'FULL NAME <EMAIL@ADDRESS>' """Name and email address of the last translator.""" self.language_team = language_team or 'LANGUAGE <*****@*****.**>' """Name and email address of the language team.""" self.charset = charset or 'utf-8' if creation_date is None: creation_date = datetime.now(LOCALTZ) elif isinstance(creation_date, datetime) and not creation_date.tzinfo: creation_date = creation_date.replace(tzinfo=LOCALTZ) self.creation_date = creation_date #: Creation date of the template if revision_date is None: revision_date = 'YEAR-MO-DA HO:MI+ZONE' elif isinstance(revision_date, datetime) and not revision_date.tzinfo: revision_date = revision_date.replace(tzinfo=LOCALTZ) self.revision_date = revision_date #: Last revision date of the catalog self.fuzzy = fuzzy #: Catalog header fuzzy bit (`True` or `False`) self.obsolete = odict() #: Dictionary of obsolete messages self._num_plurals = None self._plural_expr = None
def getGlobalPOFile(self, locale): ''' @see: IPOFileManager.getGlobalPOFile ''' try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) catalog = self._build(locale, self.messageService.getMessages(), self._filePath(locale)) return self._toPOFile(catalog)
def __init__(self, locale, tzinfo=None): """Initialize the formatter. :param locale: the locale identifier or `Locale` instance :param tzinfo: the time-zone info (a `tzinfo` instance or `None`) """ self.locale = Locale.parse(locale) self.tzinfo = tzinfo
def getPluginPOTimestamp(self, plugin, locale): ''' @see: IPOFileManager.getComponentPOTimestamp ''' assert isinstance(plugin, str), 'Invalid plugin id %s' % plugin try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) return self._lastModified(locale, plugin=plugin)
def get_translation(locale: str = _fallback_ns) -> Translations: """Gets the loaded translation by locale. If nothing matches, return fallback translation or null translation. """ null_trans = _translations_dict[None] try: locale = Locale.parse(locale) except: if locale is None: return null_trans if not locale == _fallback_ns: locale = _fallback_ns return _translations_dict.get(locale, null_trans)
def getComponentAsDict(self, component, locale): ''' @see: IPOFileManager.getComponentAsDict ''' try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) messages = self.messageService.getComponentMessages( component, qs=QSource(type=TYPE_JAVA_SCRIPT)) catalog = self._build(locale, messages, self._filePath(locale, component=component), self._filePath(locale)) return self._toDict(component, catalog)
def getPluginAsDict(self, plugin, locale): ''' @see: IPOFileManager.getPluginAsDict ''' try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) messages = self.messageService.getPluginMessages( plugin, qs=QSource(type=TYPE_JAVA_SCRIPT)) catalog = self._build(locale, messages, self._filePath(locale, plugin=plugin), self._filePath(locale)) return self._toDict(plugin, catalog)
def updateGlobalPOFile(self, locale, poFile): ''' @see: IPOFileManager.updateGlobalPOFile ''' try: locale = Locale.parse(locale) except UnknownLocaleError: raise InvalidLocaleError(locale) assert isinstance(poFile, IInputStream), 'Invalid file object %s' % poFile return self._update(locale, self.messageService.getMessages(), poFile, self._filePath(locale), self._filePath(locale, format=FORMAT_MO))
def format_percent(number, format=None, locale=LC_NUMERIC, decimal_quantization=True, group_separator=True): """Return formatted percent value for a specific locale. >>> format_percent(0.34, locale='en_US') u'34%' >>> format_percent(25.1234, locale='en_US') u'2,512%' >>> format_percent(25.1234, locale='sv_SE') u'2\\xa0512\\xa0%' The format pattern can also be specified explicitly: >>> format_percent(25.1234, u'#,##0\u2030', locale='en_US') u'25,123\u2030' 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_percent(23.9876, locale='en_US') u'2,399%' >>> format_percent(23.9876, locale='en_US', decimal_quantization=False) u'2,398.76%' >>> format_percent(229291.1234, locale='pt_BR', group_separator=False) u'22929112%' >>> format_percent(229291.1234, locale='pt_BR', group_separator=True) u'22.929.112%' :param number: the percent 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`. :param group_separator: Boolean to switch group separator on/off in a locale's number format. """ locale = Locale.parse(locale) if not format: format = locale.percent_formats.get(format) pattern = parse_pattern(format) return pattern.apply(number, locale, decimal_quantization=decimal_quantization, group_separator=group_separator)
def get_era_names(width='wide', locale=LC_TIME): """Return the era names used by the locale for the specified format. >>> get_era_names('wide', locale='en_US')[1] u'Anno Domini' >>> get_era_names('abbreviated', locale='de_DE')[1] u'n. Chr.' :param width: the width to use, either "wide", "abbreviated", or "narrow" :param locale: the `Locale` object, or a locale string :return: the dictionary of era names :rtype: `dict` """ return Locale.parse(locale).eras[width]
def __init__(self, locale='en_US', group_symbol=None, decimal_symbol=None, currency_symbols=DEFAULT_CURRENCY_SYMBOLS, **kwargs): super(Number, self).__init__(**kwargs) self.locale = Locale.parse(locale) self.currency_symbols = currency_symbols # Suppress Babel warning on Python 3.6 # See #665 with warnings.catch_warnings(): warnings.simplefilter("ignore") self.group_symbol = group_symbol or self.locale.number_symbols.get('group', ',') self.decimal_symbol = decimal_symbol or self.locale.number_symbols.get('decimal', '.')
def format_datetime(datetime=None, format='medium', tzinfo=None, locale=LC_TIME): """Return a date formatted according to the given pattern. >>> dt = datetime(2007, 04, 01, 15, 30) >>> format_datetime(dt, locale='en_US') u'Apr 1, 2007 3:30:00 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 >>> format_datetime(dt, 'full', tzinfo=timezone('Europe/Paris'), ... locale='fr_FR') u'dimanche 1 avril 2007 17:30:00 HEC' >>> format_datetime(dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz", ... tzinfo=timezone('US/Eastern'), locale='en') u'2007.04.01 AD at 11:30:00 EDT' :param datetime: the `datetime` object; if `None`, the current date and time is used :param format: one of "full", "long", "medium", or "short", or a custom date/time pattern :param tzinfo: the timezone to apply to the time for display :param locale: a `Locale` object or a locale identifier :rtype: `unicode` """ if datetime is None: datetime = datetime_.utcnow() elif isinstance(datetime, (int, long)): datetime = datetime_.utcfromtimestamp(datetime) elif isinstance(datetime, time): datetime = datetime_.combine(date.today(), datetime) if datetime.tzinfo is None: datetime = datetime.replace(tzinfo=UTC) if tzinfo is not None: datetime = datetime.astimezone(tzinfo) if hasattr(tzinfo, 'normalize'): # pytz datetime = tzinfo.normalize(datetime) locale = Locale.parse(locale) if format in ('full', 'long', 'medium', 'short'): return get_datetime_format(format, locale=locale) \ .replace('{0}', format_time(datetime, format, tzinfo=None, locale=locale)) \ .replace('{1}', format_date(datetime, format, locale=locale)) else: return parse_pattern(format).apply(datetime, locale)
def test_rtl(self): """ Test rtl :return: void """ locale = Locale.parse('nl_BE', sep='_') time_zone = get_timezone('Europe/Brussels') time_obj = Time(locale=locale, time_zone=time_zone) number_obj = Number(locale=locale) localization_obj = Localization(locale=locale, number=number_obj, time=time_obj) self.assert_false(localization_obj.rtl) locale = Locale.parse('ar_DZ', sep='_') time_zone = get_timezone('Europe/Brussels') time_obj = Time(locale=locale, time_zone=time_zone) number_obj = Number(locale=locale) localization_obj = Localization(locale=locale, number=number_obj, time=time_obj) self.assert_true(localization_obj.rtl)
def get_time_format(format='medium', locale=LC_TIME): """Return the time formatting patterns used by the locale for the specified format. >>> get_time_format(locale='en_US') <DateTimePattern u'h:mm:ss a'> >>> get_time_format('full', locale='de_DE') <DateTimePattern u'HH:mm:ss zzzz'> :param format: the format to use, one of "full", "long", "medium", or "short" :param locale: the `Locale` object, or a locale string """ return Locale.parse(locale).time_formats[format]
def normalize_locale_code(locale: Union[Locale, str]) -> str: """Determine the normalized locale code string. >>> normalize_locale_code('ko-kr') 'ko_KR' >>> normalize_locale_code('zh_TW') 'zh_Hant_TW' >>> normalize_locale_code(Locale.parse('en_US')) 'en_US' """ if not isinstance(locale, Locale): locale = Locale.parse(locale.replace('-', '_')) return str(locale)
def get_month_names(width='wide', context='format', locale=LC_TIME): """Return the month names used by the locale for the specified format. >>> get_month_names('wide', locale='en_US')[1] u'January' >>> get_month_names('abbreviated', locale='es')[1] u'ene.' >>> get_month_names('narrow', context='stand-alone', locale='de_DE')[1] u'J' :param width: the width to use, one of "wide", "abbreviated", or "narrow" :param context: the context, either "format" or "stand-alone" :param locale: the `Locale` object, or a locale string """ return Locale.parse(locale).months[context][width]
def languages(): # Note the extra space between English and [en]. This makes it sort above # the other translations of english, but is invisible to the user. result = [('en', u'English [en]')] for name in get_available_locales(): locale = Locale.parse(name) lang = locale.languages[locale.language].capitalize() if locale.territory: lang += u' (%s)' % locale.territories[locale.territory] else: lang += u' ' lang += u' [%s]' % locale result.append((name, lang)) result.sort(key=itemgetter(1)) return result
def test_parse_likely_subtags(self): l = Locale.parse('zh-TW', sep='-') assert l.language == 'zh' assert l.territory == 'TW' assert l.script == 'Hant' l = Locale.parse('zh_CN') assert l.language == 'zh' assert l.territory == 'CN' assert l.script == 'Hans' l = Locale.parse('zh_SG') assert l.language == 'zh' assert l.territory == 'SG' assert l.script == 'Hans' l = Locale.parse('und_AT') assert l.language == 'de' assert l.territory == 'AT' l = Locale.parse('und_UK') assert l.language == 'en' assert l.territory == 'GB' assert l.script is None
def get_quarter_names(width='wide', context='format', locale=LC_TIME): """Return the quarter names used by the locale for the specified format. >>> get_quarter_names('wide', locale='en_US')[1] u'1st quarter' >>> get_quarter_names('abbreviated', locale='de_DE')[1] u'Q1' :param width: the width to use, one of "wide", "abbreviated", or "narrow" :param context: the context, either "format" or "stand-alone" :param locale: the `Locale` object, or a locale string :return: the dictionary of quarter names :rtype: `dict` """ return Locale.parse(locale).quarters[context][width]
def test_add_jquery_ui_first_week_day(self): def first_week_day(locale, lc_time, languages): chrome = Chrome(self.env) languages = ','.join(languages) if languages else '' req = MockRequest(self.env, locale=locale, lc_time=lc_time, language=languages) chrome.add_jquery_ui(req) return req.chrome['script_data']['jquery_ui']['first_week_day'] # Babel is unavailable self.assertEqual(0, first_week_day(None, None, None)) self.assertEqual(1, first_week_day(None, 'iso8601', None)) if locale_en: # We expect the following aliases from babel.core import LOCALE_ALIASES, Locale self.assertEqual('ja_JP', LOCALE_ALIASES['ja']) self.assertEqual('de_DE', LOCALE_ALIASES['de']) self.assertEqual('fr_FR', LOCALE_ALIASES['fr']) self.assertEqual(0, first_week_day(locale_en, locale_en, [])) self.assertEqual(1, first_week_day(locale_en, 'iso8601', [])) ja = Locale.parse('ja') self.assertEqual(0, first_week_day(ja, ja, [])) self.assertEqual(0, first_week_day(ja, ja, ['ja', 'ja-jp'])) de = Locale.parse('de') self.assertEqual(1, first_week_day(de, de, [])) self.assertEqual(1, first_week_day(de, de, ['de', 'de-de'])) fr = Locale.parse('fr') self.assertEqual(1, first_week_day(fr, fr, [])) self.assertEqual(1, first_week_day(fr, fr, ['fr', 'fr-fr'])) self.assertEqual(0, first_week_day(fr, fr, ['fr', 'fr-ca'])) # invalid locale identifier (#12408) self.assertEqual(1, first_week_day(fr, fr, ['fr', 'fr-'])) self.assertEqual(0, first_week_day(fr, fr, ['fr', 'fr-', 'fr-ca']))
def get_datetime_format(format='medium', locale=LC_TIME): """Return the datetime formatting patterns used by the locale for the specified format. >>> get_datetime_format(locale='en_US') u'{1}, {0}' :param format: the format to use, one of "full", "long", "medium", or "short" :param locale: the `Locale` object, or a locale string """ patterns = Locale.parse(locale).datetime_formats if format not in patterns: format = None return patterns[format]
def format_price(value, currency, html=False, normalize=False): """ Format decimal value as currency """ try: value = Decimal(value) except (TypeError, InvalidOperation): return '' 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) currency_format = locale.currency_formats.get('standard') pattern = currency_format.pattern if value.normalize().as_tuple().exponent < 0: normalize = False pattern = change_pattern(pattern, currency, normalize) if html: pattern = re.sub('(\xa4+)', '<span class="currency">\\1</span>', pattern) result = format_currency(value, currency, pattern, locale=locale_code, currency_digits=(not normalize)) return mark_safe(result)
def render_admin_panel(self, req, cat, page, path_info): req.perm.require('TRAC_ADMIN') if Locale: locales = [ Locale.parse(locale) for locale in get_available_locales() ] languages = sorted( (str(locale), locale.display_name) for locale in locales) else: locales, languages = [], [] if req.method == 'POST': for option in ('name', 'url', 'descr'): self.config.set('project', option, req.args.get(option)) default_timezone = req.args.get('default_timezone') if default_timezone not in all_timezones: default_timezone = '' self.config.set('trac', 'default_timezone', default_timezone) default_language = req.args.get('default_language') if default_language not in locales: default_language = '' self.config.set('trac', 'default_language', default_language) default_date_format = req.args.get('default_date_format') if default_date_format != 'iso8601': default_date_format = '' self.config.set('trac', 'default_date_format', default_date_format) _save_config(self.config, req, self.log) req.redirect(req.href.admin(cat, page)) default_timezone = self.config.get('trac', 'default_timezone') default_language = self.config.get('trac', 'default_language') default_date_format = self.config.get('trac', 'default_date_format') data = { 'default_timezone': default_timezone, 'timezones': all_timezones, 'has_pytz': pytz is not None, 'default_language': default_language.replace('-', '_'), 'languages': languages, 'default_date_format': default_date_format, } Chrome(self.env).add_textarea_grips(req) return 'admin_basics.html', data
def _find_compound_unit(numerator_unit, denominator_unit, locale=LC_NUMERIC): """ Find a predefined compound unit pattern. Used internally by format_compound_unit. >>> _find_compound_unit("kilometer", "hour", locale="en") 'speed-kilometer-per-hour' >>> _find_compound_unit("mile", "gallon", locale="en") 'consumption-mile-per-gallon' If no predefined compound pattern can be found, `None` is returned. >>> _find_compound_unit("gallon", "mile", locale="en") >>> _find_compound_unit("horse", "purple", locale="en") :param numerator_unit: The numerator unit's identifier :param denominator_unit: The denominator unit's identifier :param locale: the `Locale` object or locale identifier :return: A key to the `unit_patterns` mapping, or None. :rtype: str|None """ locale = Locale.parse(locale) # Qualify the numerator and denominator units. This will turn possibly partial # units like "kilometer" or "hour" into actual units like "length-kilometer" and # "duration-hour". numerator_unit = _find_unit_pattern(numerator_unit, locale=locale) denominator_unit = _find_unit_pattern(denominator_unit, locale=locale) # If either was not found, we can't possibly build a suitable compound unit either. if not (numerator_unit and denominator_unit): return None # Since compound units are named "speed-kilometer-per-hour", we'll have to slice off # the quantities (i.e. "length", "duration") from both qualified units. bare_numerator_unit = numerator_unit.split("-", 1)[-1] bare_denominator_unit = denominator_unit.split("-", 1)[-1] # Now we can try and rebuild a compound unit specifier, then qualify it: return _find_unit_pattern("%s-per-%s" % (bare_numerator_unit, bare_denominator_unit), locale=locale)
def get_date_format(format='medium', locale=LC_TIME): """Return the date formatting patterns used by the locale for the specified format. >>> get_date_format(locale='en_US') <DateTimePattern u'MMM d, yyyy'> >>> get_date_format('full', locale='de_DE') <DateTimePattern u'EEEE, d. MMMM yyyy'> :param format: the format to use, one of "full", "long", "medium", or "short" :param locale: the `Locale` object, or a locale string :return: the date format pattern :rtype: `DateTimePattern` """ return Locale.parse(locale).date_formats[format]
def defaultLocale(): try: lang, _ = locale.getdefaultlocale() except Exception: lang = None if lang is not None: try: return Locale.parse(lang) except UnknownLocaleError: pass else: try: return Locale.default() except UnknownLocaleError: return Locale('en', 'US')
def list_currencies(locale=None): """ Return a `set` of normalized currency codes. .. versionadded:: 2.5.0 :param locale: filters returned currency codes by the provided locale. Expected to be a locale instance or code. If no locale is provided, returns the list of all currencies from all locales. """ # Get locale-scoped currencies. if locale: currencies = Locale.parse(locale).currencies.keys() else: currencies = get_global('all_currencies') return set(currencies)
def load_translation(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`). Might be a list of directories. 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. """ if not isinstance(dirname, (list, tuple)): dirname = [dirname] locale = None trans = None for lang in langs: short = lang[:2].lower() try: locale = Locale.parse(lang) if (domain, short) in _languages: return _languages[(domain, short)] # Get all translation from all directories. trans = None for d in dirname: t = Translations.load(d, short, domain) if not isinstance(t, Translations): continue if trans: trans.add_fallback(t) else: trans = t 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 get_timezone_gmt(datetime=None, width='long', locale=LC_TIME): """Return the timezone associated with the given `datetime` object formatted as string indicating the offset from GMT. >>> dt = datetime(2007, 4, 1, 15, 30) >>> get_timezone_gmt(dt, locale='en') u'GMT+00:00' >>> from pytz import timezone >>> tz = timezone('America/Los_Angeles') >>> dt = datetime(2007, 4, 1, 15, 30, tzinfo=tz) >>> get_timezone_gmt(dt, locale='en') u'GMT-08:00' >>> get_timezone_gmt(dt, 'short', locale='en') u'-0800' The long format depends on the locale, for example in France the acronym UTC string is used instead of GMT: >>> get_timezone_gmt(dt, 'long', locale='fr_FR') u'UTC-08:00' :param datetime: the ``datetime`` object; if `None`, the current date and time in UTC is used :param width: either "long" or "short" :param locale: the `Locale` object, or a locale string :return: the GMT offset representation of the timezone :rtype: `unicode` :since: version 0.9 """ if datetime is None: datetime = datetime_.utcnow() elif isinstance(datetime, (int, long)): datetime = datetime_.utcfromtimestamp(datetime).time() if datetime.tzinfo is None: datetime = datetime.replace(tzinfo=UTC) locale = Locale.parse(locale) offset = datetime.utcoffset() seconds = offset.days * 24 * 60 * 60 + offset.seconds hours, seconds = divmod(seconds, 3600) if width == 'short': pattern = u'%+03d%02d' else: pattern = locale.zone_formats['gmt'] % '%+03d:%02d' return pattern % (hours, seconds // 60)
def test_number(self): """ Test number :return: void """ locale = Locale.parse('nl_BE', sep='_') number_obj = Number(locale=locale) data = [ ('34', 34), ('0,34', 0.34), ('9,23', 9.23), ('232.339', 232339), ] for expected, given_value in data: self.assert_equal(expected, number_obj.number(given_value))
def test_percent(self): """ Test percent :return: void """ locale = Locale.parse('nl_BE', sep='_') number_obj = Number(locale=locale) data = [ ('34%', 0.34), ('0%', 0.0034), ('9%', 0.0923), ('232.339%', 2323.39), ] for expected, given_value in data: self.assert_equal(expected, number_obj.percent(given_value))
def test_scientific(self): """ Test scientific :return: void """ locale = Locale.parse('nl_BE', sep='_') number_obj = Number(locale=locale) data = [ ('3E1', 34), ('3E-1', 0.34), ('9E0', 9.23), ('2E5', 232339), ] for expected, given_value in data: self.assert_equal(expected, number_obj.scientific(given_value))
def get_day_names(width='wide', context='format', locale=LC_TIME): """Return the day names used by the locale for the specified format. >>> get_day_names('wide', locale='en_US')[1] == u('Tuesday') True >>> get_day_names('abbreviated', locale='es')[1] == u('mar') True >>> get_day_names('narrow', context='stand-alone', locale='de_DE')[1] == u('D') True :param width: the width to use, one of "wide", "abbreviated", or "narrow" :param context: the context, either "format" or "stand-alone" :param locale: the `Locale` object, or a locale string :return: the dictionary of day names :rtype: `dict` """ return Locale.parse(locale).days[context][width]
def get_locale(*codes): locale = None for code in codes: try: locale = Locale.parse('zh_Hans_CN.UTF-8' if code.lower() in ( 'zh-cn', 'zh_cn', 'cn') else code.replace('-', '_')) except Exception: LOGGER.exception( 'Cannot parse locale from the given locale identifier: %(code)s, %(codes)s', { 'code': code, 'codes': codes }) continue else: break return locale