CLDR-Number

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

   Moo::Role method modifiers but not a requirement of Moo::Role itself

0.18 2016-03-17
 [ New CLDR version ]
 - Upgrade CLDR data from v28 (2015-09-17) to v29 (2016-03-16)
 - Release notes: http://cldr.unicode.org/index/downloads/cldr-29

 [ New languages ]
 - yue (Cantonese)

 [ New locales for existing languages ]
 - es-BR (Spanish in Brazil)
 - pt-CH (Portuguese in Switzerland)
 - pt-GQ (Portuguese in Equatorial Guinea)
 - pt-LU (Portuguese in Luxembourg)

 [ Updated locales ]
 - da (Danish):   at_least pattern
 - gl (Galician): currency pattern
 - ka (Georgian): GEL (Georgian Lari) currency symbol
 - os (Ossetic):  GEL (Georgian Lari) currency symbol

0.17 2016-03-10
 - Bugfix: prohibit Moo v2.001000 because it introduced a bug that breaks this
   module, which was fixed in v2.001001, as tested and reported by Slaven Rezić
   @eserte++ and fixed by Graham Knop @haarg++ in
   https://rt.cpan.org/Public/Bug/Display.html?id=112677 [#48]
 - Docs: new FAQ entry on fallback for non-existant locales by Michael LaGrasta
   @mnlagrasta++ [#41]
 - Docs: update example output for CLDR v28

0.16 2015-09-23
 [ Minimum grouping digits ]
 - Add support for minimum grouping digits, introduced in the CLDR v26 spec and
   data [#36]
 - Add minimum_grouping_digits attribute with default value `1` (which has no
   effect on formatting) to all classes
 - Locales with value `1`: root (Root), es-419 (Latin American Spanish)

Changes  view on Meta::CPAN

 - Bugfix: fix formatting negative numbers along with a custom
   rounding_increment value, which had caused double negative signs
 - Bugfix: fix formatting of string values `inf` and `nan` which weren’t treated
   as numeric on combinations of some operating systems with some older versions
   of Perl [#44, #45]
 - Docs: typo fix by Fred Moyer @redhotpenguin++ [#43]

0.13 2015-09-20
 [ New CLDR version ]
 - Upgrade CLDR data from v27.0.1 (2015-03-30) to v28 (2015-09-17)
 - “Added several English locales for Europe and W Asia”
 - “Major review of and improvement to Spanish locales for Latin America”
 - See also: http://cldr.unicode.org/index/downloads/cldr-28

 [ New languages ]
 - ce (Chechen)
 - ckb (Central Kurdish)
 - cu (Church Slavic)
 - lrc (Northern Luri)
 - mzn (Mazanderani)
 - tk (Turkmen)

 [ New locales for existing languages ]
 - en-AT (English in Austria)
 - en-BI (English in Burundi)
 - en-CH (English in Switzerland)
 - en-DE (English in Germany)
 - en-DK (English in Denmark)
 - en-FI (English in Finland)
 - en-NL (English in Netherlands)
 - en-SE (English in Sweden)
 - es-DO (Spanish in Dominican Republic)
 - es-GT (Spanish in Guatemala)

Changes  view on Meta::CPAN

   formatting methods (format, at_least, range) on all formatting classes
   (decimal, percent, currency), because those are valid numeric values in Perl,
   which are now all localized even though it doesn’t always make
   sense [issue #26]
 - Add `infinity` and `nan` attributes to all classes in addition to the decimal
   formatter

0.11 2015-08-25
 - Upgrade CLDR data from v24 (2013-09-18) to v27.0.1 (2015-03-30) [issue #33]
 - Add bin/generate-cldr-data.pl script to update Perl data from CLDR JSON
 - Add new locales including dsb (Lower Sorbian), fy (West Frisian),
   hsb (Upper Sorbian), lb (Luxembourgish), qu (Quechua), smn (Inari Sami),
   and ug (Uyghur)
 - Remove CLDR data with draft status of 'provisional' or 'unconfirmed', only
   including 'contributed' or 'approved', which is the same threshold as the
   ICU Project as well as the CLDR JSON data as of v27.0.1
 - Remove 'provisional' draft numbering systems until they become at least
   'contributed': brah (Brahmi), cakm (Chakma), osma (Osmanya), shrd (Sharada),
   sora (Sora Sompeng), takr (Takri)
 - Change various symbols for several locales, including grouping symbol in
   es (Spanish, not including Latin American Spanish locales) from
   ' ' (no-break space) to '.' (full stop) and fr-SH (Swiss French) from
   "'" (apostrophe) to ' ' (no-break space)
 - Change negative number format for any locales using formats with parentheses
   like '(N)', including ko (Korean), to using the minus sign like '-N', except
   for accounting format which is not yet supported
 - Change currency decimal symbol for sv (Swedish) from ':' to ',' now matching
   the regular (non-currency) decimal symbol and common usage, resulting in no
   locale having a different decimal symbol for currencies
 - Change THB (Thai Baht) symbol from '฿' to 'THB' for most locales including
   root and th (Thai), due to its general obscurity
 - Change many other currency symbols for many locales, but generally minor
   changes, for example DKK (Danish Krone) in da (Danish) from 'kr' to 'kr.' and
   USD (US Dollar) in fr-CA (Canadian French) from '$US' to '$ US'
 - Change CLF (Chilean Unit of Account (UF)) currency fraction digits
   from 0 to 4
 - Change CZK (Czech Republic Koruna) currency cash fraction digits from 2 to 0
   with default fraction digits remaining 2
 - Change HUF (Hungarian Forint) currency fraction digits from 0 to 2 with
   cash fraction digits remaining 0
 - Change UYI (Uruguayan Peso (Indexed Units)) currency fraction digits
   from 2 to 0

0.10 2015-03-26
 - Improve documentation and unit tests (no functional changes)
 - Docs: Fix attribute name in CLDR::Number::Format::Currency
   synopsis [issue #40] (by Olaf Alders @oalders++)

0.09 2014-11-12
 - Deprecate use of the the `locale` method as a setter. In the future the
   formatter objects’ locale will become immutable. Please see [issue #38] for
   details and to submit comments or concerns:
   https://github.com/patch/cldr-number-pm5/issues/38
 - Add items to the FAQ and TODO docs

0.08 2014-03-28
 - Improve locale inheritance to use parent overrides from CLDR data [issue #34]

0.07 2014-03-25
 - Add numbering_system attribute and support non-Latin decimal numbering
   systems [issue #8]
 - Use default numbering system for locale [issue #9]
 - Use numbering system from Unicode extension of locale when provided
 - Integrate Travis CI, Devel::Cover, and Coveralls with GitHub repo

0.06 2014-02-28
 - Improve documentation
 - Add FAQ

0.05 2014-01-26
 - Validate numeric arguments to methods in the same way as core Perl functions:
   warn on non-numeric values and use the leading numeric portion when
   available, otherwise 0 [issue #23]

MANIFEST  view on Meta::CPAN

README
t/00-load.t
t/currency.t
t/format.t
t/from-icu4c.t
t/from-shutterstock.t
t/from-twittercldr.t
t/from-uts35.t
t/inf-nan.t
t/inheritance.t
t/locales.t
t/minmax-digits.t
t/numbering-system.t
t/objects.t
t/pattern-coerce.t
t/pattern-trigger.t
t/quoting.t
t/range.t
t/rounding.t

README  view on Meta::CPAN

NAME
    CLDR::Number - Localized number formatters using the Unicode CLDR

VERSION
    This document describes CLDR::Number v0.19, built with Unicode CLDR v29.

SYNOPSIS
        use CLDR::Number;

        # new object with 'es' (Spanish) locale
        $cldr = CLDR::Number->new(locale => 'es');

        # decimals
        $decf = $cldr->decimal_formatter;

        # when locale is 'es' (Spanish)
        say $decf->format(1234.5);  # '1234,5'

        # when locale is 'es-MX' (Mexican Spanish)
        say $decf->format(1234.5);  # '1,234.5'

        # when locale is 'ar' (Arabic)
        say $decf->format(1234.5);  # '١٬٢٣٤٫٥'

        # percents
        $perf = $cldr->percent_formatter;

        # when locale is 'tr' (Turkish)
        say $perf->format(0.05);  # '%5'

        # currencies
        $curf = $cldr->currency_formatter(currency_code => 'USD');

        # when locale is 'en' (English) and currency is USD (US dollars)
        say $curf->format(9.99);  # '$9.99'

        # when locale is 'en-CA' (Canadian English) and currency is USD
        say $curf->format(9.99);  # 'US$9.99'

        # when locale is 'fr-CA' (Canadian French) and currency is USD
        say $curf->format(9.99);  # '9,99 $ US'

DEPRECATION
    Using the "locale" method as a setter is deprecated. In the future the
    object’s locale will become immutable. Please see issue #38
    <https://github.com/patch/cldr-number-pm5/issues/38> for details and to
    submit comments or concerns.

DESCRIPTION
    Software localization includes much more than just translations.
    Numbers, prices, and even percents should all be localized based on the
    user’s language, script, and region. Fortunately, the Unicode Common
    Locale Data Repository (CLDR) provides locale data and specifications
    for formatting numeric data to use with many of the world’s locales.

    This class provides common attributes shared among the supported
    formatter classes as well as methods to instantiate decimal, percent,
    and currency formatter objects. The value for any attribute (such as
    locale or decimal_sign) will be passed to the formatter objects on
    instantiation but can be overwritten by manually passing another value
    for the attribute or calling a setter method on the formatter object.

  Methods
    decimal_formatter
        Returns a decimal formatter, which is a
        CLDR::Number::Format::Decimal object instantiated with all of the
        attributes from your CLDR::Number object as well as any attributes
        passed to this method.

README  view on Meta::CPAN

        passed to this method.

    currency_formatter
        Returns a currency formatter, which is a
        CLDR::Number::Format::Currency object instantiated with all of the
        attributes from your CLDR::Number object as well as any attributes
        passed to this method.

  Common Attributes
    These are common attributes among this class and all formatter classes.
    All attributes other than locale, default_locale, and cldr_version have
    defaults that change depending on the current locale. All string
    attributes are expected to be character strings, not byte strings.

    locale
        Default: value of default_locale attribute if it exists, otherwise
        "root"

        Valid: Unicode locale identifiers

        Examples: "es" (Spanish), "es-ES" (European Spanish), "es-419"
        (Latin American Spanish), "zh-Hant" (Traditional Chinese), "zh-Hans"
        (Simplified Chinese), "chr" (Cherokee)

        The locale is case-insensitive and can use either "-" (hyphen-minus)
        or "_" (low line) as a separator.

    default_locale
        Default: none

        Valid: Unicode locale identifiers

        Use this if you want a locale other than the generic "root" if the
        locale attribute is not set or not valid.

    numbering_system
        Valid: currently only decimal numbering systems are supported

        Examples: "latn" (Western Digits), "arab" (Arabic-Indic Digits),
        "hanidec" (Chinese Decimal Numerals), "fullwide" (Full Width Digits)

        In the future, algorithmic numbering systems like "hant"
        (Traditional Chinese Numerals), "hebr" (Hebrew Numerals), and
        "roman" (Roman Numerals) will be supported.

        The numbering system may alternately be provided as a Unicode locale
        extension subtag. For example, locale "ja-u-nu-fullwide" for the
        Japanese language ("ja") with the numbering system ("nu") set to
        Full Width Digits ("fullwide").

    decimal_sign
        Examples: "." (full stop) for root, en; "," (comma) for de, fr

    group_sign
        Examples: "," (comma) for root, en; "." (full stop) for de; " "
        (no-break space) for fr

    plus_sign
        Examples: "+" (plus sign) for root, en, and most locales

    minus_sign
        Examples: "-" (hyphen-minus) for root, en, and most locales

    infinity
        Examples: "∞" (infinity) for root, en, and almost all locales

    nan Examples: "NaN" for root, en, and most locales; many other
        variations for individual locales like "не число" for ru and "非數值"
        for zh-Hant

    cldr_version
        Value: 29

        This is a read-only attribute that will always reflect the currently
        supported Unicode CLDR version.

NOTES
    The Unicode private-use characters U+F8F0 through U+F8F4 are used

lib/CLDR/Number.pm  view on Meta::CPAN

sub currency_formatter {
    my ($self, %args) = @_;

    require CLDR::Number::Format::Currency;
    CLDR::Number::Format::Currency->new($self->_make_args(%args));
}

sub _make_args {
    my ($self, %new_args) = @_;

    my %args = (locale => $self->locale, %new_args);

    return %args;
}

1;

__END__

=encoding UTF-8

lib/CLDR/Number.pm  view on Meta::CPAN

CLDR::Number - Localized number formatters using the Unicode CLDR

=head1 VERSION

This document describes CLDR::Number v0.19, built with Unicode CLDR v29.

=head1 SYNOPSIS

    use CLDR::Number;

    # new object with 'es' (Spanish) locale
    $cldr = CLDR::Number->new(locale => 'es');

    # decimals
    $decf = $cldr->decimal_formatter;

    # when locale is 'es' (Spanish)
    say $decf->format(1234.5);  # '1234,5'

    # when locale is 'es-MX' (Mexican Spanish)
    say $decf->format(1234.5);  # '1,234.5'

    # when locale is 'ar' (Arabic)
    say $decf->format(1234.5);  # '١٬٢٣٤٫٥'

    # percents
    $perf = $cldr->percent_formatter;

    # when locale is 'tr' (Turkish)
    say $perf->format(0.05);  # '%5'

    # currencies
    $curf = $cldr->currency_formatter(currency_code => 'USD');

    # when locale is 'en' (English) and currency is USD (US dollars)
    say $curf->format(9.99);  # '$9.99'

    # when locale is 'en-CA' (Canadian English) and currency is USD
    say $curf->format(9.99);  # 'US$9.99'

    # when locale is 'fr-CA' (Canadian French) and currency is USD
    say $curf->format(9.99);  # '9,99 $ US'

=head1 DEPRECATION

Using the C<locale> method as a setter is deprecated. In the future the object’s
locale will become immutable. Please see
L<issue #38|https://github.com/patch/cldr-number-pm5/issues/38> for details and
to submit comments or concerns.

=head1 DESCRIPTION

Software localization includes much more than just translations. Numbers,
prices, and even percents should all be localized based on the user’s language,
script, and region. Fortunately, the Unicode Common Locale Data Repository
(CLDR) provides locale data and specifications for formatting numeric data to
use with many of the world’s locales.

This class provides common attributes shared among the supported formatter
classes as well as methods to instantiate decimal, percent, and currency
formatter objects. The value for any attribute (such as B<locale> or
B<decimal_sign>) will be passed to the formatter objects on instantiation but
can be overwritten by manually passing another value for the attribute or
calling a setter method on the formatter object.

=head2 Methods

=over

=item decimal_formatter

lib/CLDR/Number.pm  view on Meta::CPAN


Returns a currency formatter, which is a L<CLDR::Number::Format::Currency>
object instantiated with all of the attributes from your CLDR::Number object as
well as any attributes passed to this method.

=back

=head2 Common Attributes

These are common attributes among this class and all formatter classes. All
attributes other than B<locale>, B<default_locale>, and B<cldr_version> have
defaults that change depending on the current B<locale>. All string attributes
are expected to be character strings, not byte strings.

=over

=item locale

Default: value of B<default_locale> attribute if it exists, otherwise C<root>

Valid: Unicode locale identifiers

Examples: C<es> (Spanish), C<es-ES> (European Spanish), C<es-419> (Latin
American Spanish), C<zh-Hant> (Traditional Chinese), C<zh-Hans> (Simplified
Chinese), C<chr> (Cherokee)

The locale is case-insensitive and can use either C<-> (hyphen-minus) or C<_>
(low line) as a separator.

=item default_locale

Default: none

Valid: Unicode locale identifiers

Use this if you want a locale other than the generic C<root> if the B<locale>
attribute is not set or not valid.

=item numbering_system

Valid: currently only decimal numbering systems are supported

Examples: C<latn> (Western Digits), C<arab> (Arabic-Indic Digits), C<hanidec>
(Chinese Decimal Numerals), C<fullwide> (Full Width Digits)

In the future, algorithmic numbering systems like C<hant> (Traditional Chinese
Numerals), C<hebr> (Hebrew Numerals), and C<roman> (Roman Numerals) will be
supported.

The numbering system may alternately be provided as a Unicode locale extension
subtag. For example, locale C<ja-u-nu-fullwide> for the Japanese language
(C<ja>) with the numbering system (C<nu>) set to Full Width Digits
(C<fullwide>).

=item decimal_sign

Examples: C<.> (full stop) for B<root>, B<en>; C<,> (comma) for B<de>, B<fr>

=item group_sign

Examples: C<,> (comma) for B<root>, B<en>; C<.> (full stop) for B<de>; C< >
(no-break space) for B<fr>

=item plus_sign

Examples: C<+> (plus sign) for B<root>, B<en>, and most locales

=item minus_sign

Examples: C<-> (hyphen-minus) for B<root>, B<en>, and most locales

=item infinity

Examples: C<∞> (infinity) for B<root>, B<en>, and almost all locales

=item nan

Examples: C<NaN> for B<root>, B<en>, and most locales; many other variations for
individual locales like C<не число> for B<ru> and C<非數值> for B<zh-Hant>

=item cldr_version

Value: C<29>

This is a read-only attribute that will always reflect the currently supported
Unicode CLDR version.

=back

lib/CLDR/Number/FAQ.pod  view on Meta::CPAN

When displaying whole monetary numbers, it is sometimes desired to leave off the
fraction digits (e.g. cents) for marketing purposes. To do this, set the
C<maximum_fraction_digits> attribute to C<0>. Beware though that some currencies
have a number of fraction digits other than two, so it is not safe to set
C<minimum_fraction_digits> and C<maximum_fraction_digits> to C<2> for arbitrary
currencies.

=item How do I set a default currency?

L<CLDR::Number::Format::Currency> does not provide a default currency for the
C<currency_code> attribute like we have for the C<locale> attribute nor does it
provide a I<default_currency_code> attribute like the C<default_locale>
attribute. This is because a price without a known currency has no known value.
Setting a default currency is just as inaccurate as setting a default number. If
your application depends on a default currency, the C<currency_code> attribute
can be explicitly set.

“B<Note:> I<Currency values should B<never> be interchanged without a known
currency code. You never want the number 3.5 interpreted as $3.50 by one user
and €3.50 by another.> Locale data contains localization information for
currencies, not a currency value for a country. A currency amount logically
consists of a numeric value, plus an accompanying currency code (or

lib/CLDR/Number/FAQ.pod  view on Meta::CPAN


=item How do I format years?

Years are a type of date, and dates have very different formatting rules than
regular numbers. Resources for localized date/time formatting include
L<DateTime>, L<DateTime::Locale>, and L<UTS #35: Unicode LDML, Part 4:
Dates|http://unicode.org/reports/tr35/tr35-dates.html>.

=item Why is the format different than expected?

Users occasionally report incorrect formatting for several non-existent locales.
This is most often the result of specifying a locale composed of an unrecognized
combination of language and country, which will cause the formatting to default
to the base language. Two common examples of this are C<en-MX> (Mexican English)
and C<es-BR> (Brazilian Spanish), which would default to C<en> (English) and
C<es> (Spanish), respectively. However, if demand is shown for them, they may be
added to the CLDR, such as C<es-BR>, which was added to CLDR v29.

=back

=head1 SEE ALSO

lib/CLDR/Number/Format/Currency.pm  view on Meta::CPAN

    coerce  => sub { $_[0] ? 1 : 0 },
    trigger => 1,
    default => 0,
);

has _pattern_type => (
    is      => 'ro',
    default => 'currency',
);

after _trigger_locale => sub {
    my ($self) = @_;

    if ($self->currency_code) {
        $self->_build_currency_sign;
    }

    if (my $decimal = $self->_get_data(symbol => 'currency_decimal')) {
        $self->decimal_sign($decimal);
    }
};

lib/CLDR/Number/Format/Currency.pm  view on Meta::CPAN

    $self->_trigger_cash;
}

sub _build_currency_sign {
    my ($self) = @_;
    my $data = $CLDR::Number::Data::Currency::LOCALES;
    my $currency_sign;

    return if $self->_has_init_arg('currency_sign');

    for my $locale (@{$self->_locale_inheritance}) {
        next if !exists $data->{$locale} || !exists $data->{$locale}{$self->currency_code};
        $currency_sign = $data->{$locale}{$self->currency_code};
        last;
    }

    $self->currency_sign($currency_sign || $self->currency_code);
}

sub _trigger_cash {
    my ($self) = @_;
    my $currencies = $CLDR::Number::Data::Currency::CURRENCIES;
    my $currency_data

lib/CLDR/Number/Format/Currency.pm  view on Meta::CPAN

=head1 VERSION

This document describes CLDR::Number::Format::Currency v0.19, built with Unicode
CLDR v29.

=head1 SYNOPSIS

    # either
    use CLDR::Number::Format::Currency;
    $curf = CLDR::Number::Format::Currency->new(
        locale        => 'en',
        currency_code => 'USD',
    );

    # or
    use CLDR::Number;
    $cldr = CLDR::Number->new(locale => 'en');
    $curf = $cldr->currency_formatter(currency_code => 'USD');

    # when locale is 'en' (English) and currency is USD (US dollars)
    say $curf->format(9.99);  # '$9.99'

    # when locale is 'en-CA' (Canadian English) and currency is USD
    say $curf->format(9.99);  # 'US$9.99'

    # when locale is 'fr-CA' (Canadian French) and currency is USD
    say $curf->format(9.99);  # '9,99 $ US'

    # when locale is 'bn' (Bengali) and currency is INR (Indian rupees)
    say $curf->format(123456);  # '১,২৩,৪৫৬.০০₹'

=head1 DEPRECATION

Using the C<locale> method as a setter is deprecated. In the future the object’s
locale will become immutable. Please see
L<issue #38|https://github.com/patch/cldr-number-pm5/issues/38> for details and
to submit comments or concerns.

=head1 DESCRIPTION

Localized currency formatter using the Unicode Common Locale Data Repository
(CLDR).

=head2 Methods

=over

=item format

Accepts a number and returns a formatted currency value as a character string,
using the currency from the B<currency_code> attribute and localized for the
current locale.

=back

=head2 Attributes

The common attributes B<locale>, B<default_locale>, B<numbering_system>,
B<decimal_sign>, B<group_sign>, B<plus_sign>, B<minus_sign>, and B<cldr_version>
are described under L<common attributes in
CLDR::Number|CLDR::Number/"Common Attributes">. All attributes described here
other than B<currency_code> and B<cash> have defaults that change depending on
the current B<locale>. The attributes B<currency_sign>,
B<minimum_fraction_digits>, B<maximum_fraction_digits>, and
B<rounding_increment> also change depending on the B<currency_code> and B<cash>
values. All string attributes are expected to be character strings, not byte
strings.

=over

=item currency_code

Default: none

Valid: ISO 4217 3-letter alphabetic currency codes

Examples: C<EUR> (Euro), C<USD> (US Dollar), C<JPY> (Japanese Yen)

The currency code is case-insensitive and is required in order to call the
B<format> method, but not required to instantiate this formatter object.

=item currency_sign

Default: based on both B<locale> and B<currency_code>

Examples: C<US$> for B<root>, B<en-CA> with B<USD>; C<$> for B<en>, B<de> with
B<USD>; C<$US> for B<fr> with B<USD>; C<USD> for B<es-MX> with B<USD>

=item cash

Default: false (C<0>)

Formatting for cash can be different for some currencies. Setting B<cash> to
true (C<1>) enables cash formatting when different from standard formatting.

=item pattern

Examples: C<¤ #,##0.00> for B<root>; C<¤#,##0.00> for B<en>; C<#,##0.00 ¤> for
B<de>, B<fr>; C<¤ #,##0.00;¤ -#,##0.00> for B<nl>; and many other variations for
different locales

=item minimum_integer_digits

Examples: C<1> for all locales

=item minimum_fraction_digits

Examples: C<2> for most currencies; C<3> for B<BHD>; C<0> for B<JPY> or for
B<TWD> when B<cash> is true

=item maximum_fraction_digits

Examples: C<2> for most currencies; C<3> for B<BHD>; C<0> for B<JPY> or for
B<TWD> when B<cash> is true

=item primary_grouping_size

Examples: C<3> for B<root> and almost all locales

Not used when value is C<0>.

=item secondary_grouping_size

Examples: C<0> for B<root>, B<en>, and most locales; C<2> for B<hi>, B<bn>,
B<en-IN>, and other locales of the Indian subcontinent

Not used when value is C<0>.

=item minimum_grouping_digits

Examples: C<1> for B<root>, B<en>, and most locales; C<2> for C<es> (excluding
C<es-419>), C<pt-PT>, C<pl>, and several others; C<3> for C<lv> and C<my>

=item rounding_increment

Examples: C<0> for all currencies; C<5> for B<CAD>, B<CHF> when B<cash> is true

C<0> and C<1> are treated the same.

=back

lib/CLDR/Number/Format/Decimal.pm  view on Meta::CPAN


=head1 VERSION

This document describes CLDR::Number::Format::Decimal v0.19, built with Unicode
CLDR v29.

=head1 SYNOPSIS

    # either
    use CLDR::Number::Format::Decimal;
    $decf = CLDR::Number::Format::Decimal->new(locale => 'es');

    # or
    use CLDR::Number;
    $cldr = CLDR::Number->new(locale => 'es');
    $decf = $cldr->decimal_formatter;

    # when locale is 'es' (Spanish)
    say $decf->format(1234.5);  # '1234,5'

    # when locale is 'es-MX' (Mexican Spanish)
    say $decf->format(1234.5);  # '1,234.5'

    # when locale is 'ar' (Arabic)
    say $decf->format(1234.5);  # '١٬٢٣٤٫٥'

    # when locale is 'bn' (Bengali)
    say $curf->format(123456);  # '১,২৩,৪৫৬'

=head1 DEPRECATION

Using the C<locale> method as a setter is deprecated. In the future the object’s
locale will become immutable. Please see
L<issue #38|https://github.com/patch/cldr-number-pm5/issues/38> for details and
to submit comments or concerns.

=head1 DESCRIPTION

Localized decimal formatter using the Unicode Common Locale Data Repository
(CLDR).

=head2 Methods

Any argument that Perl can treat as a number is supported, including infinity,
negative infinity, and NaN, which are all localized appropriately. All methods
return character strings, not encoded byte strings.

=over

=item format

Accepts a number and returns a formatted decimal, localized for the current
locale.

=item at_least

Accepts a number and returns a formatted decimal for at least the supplied
number.

    say $decf->at_least(100);  # '100+'

=item range

Accepts two numbers and returns a formatted range of decimals.

    say $decf->range(1, 10);  # '1–10'

=back

=head2 Attributes

The common attributes B<locale>, B<default_locale>, B<numbering_system>,
B<decimal_sign>, B<group_sign>, B<plus_sign>, B<minus_sign>, and B<cldr_version>
are described under L<common attributes in
CLDR::Number|CLDR::Number/"Common Attributes">. All attributes described here
have defaults that change depending on the current B<locale>. All string
attributes are expected to be character strings, not byte strings.

=over

=item pattern

Examples: C<#,##0.###> for B<root>, B<en>, and most locales; C<#,##,##0.###> for
B<hi>, B<bn>, B<en-IN>, and other locales of the Indian subcontinent

=item minimum_integer_digits

Examples: C<1> for all locales

=item minimum_fraction_digits

Examples: C<0> for all locales

=item maximum_fraction_digits

Examples: C<3> for B<root> and almost all locales

=item primary_grouping_size

Examples: C<3> for B<root> and almost all locales

Not used when value is C<0>.

=item secondary_grouping_size

Examples: C<0> for B<root>, B<en>, and most locales; C<2> for B<hi>, B<bn>,
B<en-IN>, and other locales of the Indian subcontinent

Not used when value is C<0>.

=item minimum_grouping_digits

Examples: C<1> for B<root>, B<en>, and most locales; C<2> for C<es> (excluding
C<es-419>), C<pt-PT>, C<pl>, and several others; C<3> for C<lv> and C<my>

=item rounding_increment

Examples: C<0> for all locales

C<0> and C<1> are treated the same.

=back

=head1 SEE ALSO

L<CLDR::Number>

=head1 AUTHOR

lib/CLDR/Number/Format/Percent.pm  view on Meta::CPAN


has permil_sign => (
    is => 'rw',
);

has _pattern_type => (
    is      => 'ro',
    default => 'percent',
);

after _trigger_locale => sub {
    my ($self) = @_;

    $self->_build_signs(qw{ percent_sign permil_sign });
};

sub BUILD {}

sub format {
    my ($self, $num) = @_;
    my ($factor, $sign);

lib/CLDR/Number/Format/Percent.pm  view on Meta::CPAN


=head1 VERSION

This document describes CLDR::Number::Format::Percent v0.19, built with Unicode
CLDR v29.

=head1 SYNOPSIS

    # either
    use CLDR::Number::Format::Percent;
    $perf = CLDR::Number::Format::Percent->new(locale => 'tr');

    # or
    use CLDR::Number;
    $cldr = CLDR::Number->new(locale => 'tr');
    $perf = $cldr->percent_formatter;

    # when locale is 'tr' (Turkish)
    say $perf->format(0.05);  # '%5'

    # when locale is 'ar' (Arabic)
    say $perf->format(0.05);  # '٥٪'

    # when locale is 'fr' (French)
    say $perf->format(0.05);  # '5 %'

    $perf->permil(1);         # per mil
    say $perf->format(0.05);  # '50 ‰'

=head1 DEPRECATION

Using the C<locale> method as a setter is deprecated. In the future the object’s
locale will become immutable. Please see
L<issue #38|https://github.com/patch/cldr-number-pm5/issues/38> for details and
to submit comments or concerns.

=head1 DESCRIPTION

Localized percent formatter using the Unicode Common Locale Data Repository
(CLDR).

=head2 Methods

=over

=item format

Accepts a number and returns a formatted percent as a character string,
localized for the current locale. If the B<permil> attribute is true, formats as
I<per mil> instead of I<percent>.

=back

=head2 Attributes

The common attributes B<locale>, B<default_locale>, B<numbering_system>,
B<decimal_sign>, B<group_sign>, B<plus_sign>, B<minus_sign>, and B<cldr_version>
are described under L<common attributes in
CLDR::Number|CLDR::Number/"Common Attributes">. All attributes described here
other than B<permil> have defaults that change depending on the current
B<locale>. All string attributes are expected to be character strings, not byte
strings.

=over

=item permil

Default: false (C<0>)

=item percent_sign

Examples: C<%> (percent sign) for all locales

=item permil_sign

Examples: C<‰> (per mille sign) for B<root> and almost all locales

=item pattern

Examples: C<#,##0%> for B<root>, B<en>; C<#,##0 %> for B<de>, B<fr>;
C<#,##,##0%> for B<hi>, B<bn>, B<en-IN>, and other locales of the Indian
subcontinent

=item minimum_integer_digits

Examples: C<1> for all locales

=item minimum_fraction_digits

Examples: C<0> for all locales

=item maximum_fraction_digits

Examples: C<0> for all locales

=item primary_grouping_size

Examples: C<3> for B<root> and almost all locales

Not used when value is C<0>.

=item secondary_grouping_size

Examples: C<0> for B<root>, B<en>, and most locales; C<2> for B<hi>, B<bn>,
B<en-IN>, and other locales of the Indian subcontinent

Not used when value is C<0>.

=item minimum_grouping_digits

Examples: C<1> for B<root>, B<en>, and most locales; C<2> for C<es> (excluding
C<es-419>), C<pt-PT>, C<pl>, and several others; C<3> for C<lv> and C<my>

=item rounding_increment

Examples: C<0> for all locales

C<0> and C<1> are treated the same.

=back

=head1 SEE ALSO

L<CLDR::Number>

=head1 AUTHOR

lib/CLDR/Number/Role/Base.pm  view on Meta::CPAN

has version => (
    is      => 'ro',
    default => $VERSION,
);

has cldr_version => (
    is      => 'ro',
    default => $CLDR::Number::Data::Base::CLDR_VERSION,
);

has locale => (
    is      => 'rw',
    trigger => 1,
);

has default_locale => (
    is     => 'ro',
    coerce => sub {
        my ($locale) = @_;

        if (!defined $locale) {
            carp 'default_locale is not defined';
        }
        elsif (!exists $CLDR::Number::Data::Base::DATA->{$locale}) {
            carp "default_locale '$locale' is unknown";
        }
        else {
            return $locale;
        }

        return;
    },
);

has numbering_system => (
    is  => 'rw',
    isa => sub {
        carp 'numbering_system is not defined'

lib/CLDR/Number/Role/Base.pm  view on Meta::CPAN

);

has infinity => (
    is => 'rw',
);

has nan => (
    is => 'rw',
);

has _locale_inheritance => (
    is      => 'rw',
    default => sub { [] },
);

has _init_args => (
    is => 'rw',
);

around BUILDARGS => sub {
    my ($orig, $class, @args) = @_;

    return $class->$orig(@args) if @args % 2;
    return $class->$orig(@args, _init_args => {@args});
};

before BUILD => sub {
    my ($self) = @_;

    return if $self->_has_init_arg('locale');

    $self->_trigger_locale;
};

after BUILD => sub {
    my ($self) = @_;

    $self->_init_args({});
};

sub _has_init_arg {
    my ($self, $arg) = @_;

lib/CLDR/Number/Role/Base.pm  view on Meta::CPAN

        my $attribute = $sign;

        next if $self->_has_init_arg($attribute);

        $sign =~ s{ _sign $ }{}x;

        $self->$attribute($self->_get_data(symbol => $sign));
    }
}

sub _trigger_locale {
    my ($self, $locale) = @_;
    my ($lang, $script, $region, $ext) = _split_locale($locale);

    if ($lang && exists $CLDR::Number::Data::Base::DATA->{$lang}) {
        $self->_locale_inheritance(
            _build_inheritance($lang, $script, $region, $ext)
        );
        $locale = $self->_locale_inheritance->[0];
    }
    elsif ($self->default_locale) {
        $locale = $self->default_locale;
        ($lang, $script, $region, $ext) = _split_locale($locale);
        $self->_locale_inheritance(
            _build_inheritance($lang, $script, $region, $ext)
        );
    }
    else {
        $locale = 'root';
        $self->_locale_inheritance( [$locale] );
    }

    if ($ext && $ext =~ m{ -nu- ( [^-]+ ) }x) {
        $self->numbering_system($1);
    }
    else {
        $self->_trigger_numbering_system;
    }

    $self->{locale} = $locale;

    $self->_build_signs(qw{
        decimal_sign group_sign plus_sign minus_sign infinity nan
    });

    $self->_set_unless_init_arg(
        minimum_grouping_digits => $self->_get_data(attr => 'min_group')
    );
}

sub _trigger_numbering_system {
    my ($self, $system) = @_;

    return if defined $system
           && exists $CLDR::Number::Data::System::DATA->{$system};

    $self->{numbering_system} = $self->_get_data(attr => 'system');
}

sub _split_locale {
    my ($locale) = @_;

    return unless defined $locale;

    $locale = lc $locale;
    $locale =~ tr{_}{-};

    my ($lang, $script, $region, $ext) = $locale =~ m{ ^
              ( [a-z]{2,3}          )     # language
        (?: - ( [a-z]{4}            ) )?  # script
        (?: - ( [a-z]{2} | [0-9]{3} ) )?  # country or region
        (?: - ( u- .+               ) )?  # extension
            -?                            # trailing separator
    $ }xi;

    $script = ucfirst $script if $script;
    $region = uc      $region if $region;

lib/CLDR/Number/Role/Base.pm  view on Meta::CPAN

    my @tree;

    for my $subtags (
        [$lang, $region, $ext],
        [$lang, $script, $region],
        [$lang, $script],
        [$lang, $region],
        [$lang],
    ) {
        next if grep { !$_ } @$subtags;
        my $locale = join '-', @$subtags;
        next if !exists $CLDR::Number::Data::Base::DATA->{$locale};
        push @tree, $locale;

        if (my $parent = $CLDR::Number::Data::Base::PARENT->{$locale}) {
            push @tree, @{_build_inheritance(_split_locale($parent))};
            last;
        }
    }

    if (!@tree || $tree[-1] ne 'root') {
        push @tree, 'root';
    }

    return \@tree;
}

sub _get_data {
    my ($self, $type, $key) = @_;
    my $data = $CLDR::Number::Data::Base::DATA;

    for my $locale (@{$self->_locale_inheritance}) {
        return $data->{$locale}{$type}{$key}
            if exists $data->{$locale}
            && exists $data->{$locale}{$type}
            && exists $data->{$locale}{$type}{$key};
    }

    return undef;
}

1;

lib/CLDR/Number/Role/Format.pm  view on Meta::CPAN

    is => 'rw',
);

has _negative_pattern => (
    is => 'rw',
);

before BUILD => sub {
    my ($self) = @_;

    return if $self->_has_init_arg('locale');

    $self->_build_pattern;
};

after _trigger_locale => sub {
    my ($self) = @_;

    $self->_build_pattern;
};

sub _build_pattern {
    my ($self) = @_;

    $self->_set_unless_init_arg(
        pattern => $self->_get_data(pattern => $self->_pattern_type)

lib/CLDR/Number/TODO.pod  view on Meta::CPAN


=item * number parsers
I<L<#19|https://github.com/patch/cldr-number-pm5/issues/19>>

=back

=head2 Optimization

=over

=item * deprecate mutable locales (in progress)
I<L<#38|https://github.com/patch/cldr-number-pm5/issues/38>>

=item * locale subtag attributes for use without locale attribute parsing
I<L<#4|https://github.com/patch/cldr-number-pm5/issues/4>>

=item * passing prebuilt locales to formatters from CLDR::Number
I<L<#5|https://github.com/patch/cldr-number-pm5/issues/5>>

=item * parsed pattern caching
I<L<#6|https://github.com/patch/cldr-number-pm5/issues/6>>

=back

=head1 SEE ALSO

=over

t/currency.t  view on Meta::CPAN

use Test::Exception;
use CLDR::Number;

my ($cldr, $curf, $decf);

$cldr = CLDR::Number->new;
$curf = $cldr->currency_formatter;
throws_ok { $curf->format(1.99) } qr{Missing required attribute: currency_code};

{
    # currency decimal is no longer used by any locale, so we manually add it here
    # to test the feature in case it’s reintroduced in the future
    local $CLDR::Number::Data::Base::DATA->{sv}{symbol}{currency_decimal} = ':';

    $cldr = CLDR::Number->new(locale => 'sv');
    is $cldr->decimal_sign, ',', 'Swedish decimal from format generator';

    $decf = $cldr->decimal_formatter;
    is $decf->decimal_sign, ',', 'Swedish decimal from decimal formatter';
    is $decf->format(1.99), '1,99', 'formatted Swedish decimal';

    $curf = $cldr->currency_formatter(currency_code => 'SEK');
    is $curf->decimal_sign, ':', 'Swedish currency decimal from currency formatter';
    is $curf->format(1.99), '1:99 kr', 'formatted Swedish currency';
}

$curf = $cldr->currency_formatter(
    locale        => 'en-AU',
    currency_code => 'AUD',
);

is $curf->format(10), '$10.00', 'en-AU with AUD uses currency sign $ instead of A$';

$curf = $cldr->currency_formatter(
    locale                  => 'en',
    currency_code           => 'USD',
    maximum_fraction_digits => 0,
);

is $curf->maximum_fraction_digits, 0, 'max frac digits spared by currency code';
is $curf->format(10), '$10',          'max frac digits spared by currency code';

$curf = $cldr->currency_formatter(
    locale        => 'en',
    currency_code => 'USD',
    pattern       => '¤00',
);

is $curf->pattern,   '¤00', 'pattern spared by locale on create';
is $curf->format(5), '$05', 'pattern spared by locale on create';

$curf = $cldr->currency_formatter(
    currency_code => 'USD',
    currency_sign => '!!!',
    pattern       => '¤ 0',
);

is $curf->currency_sign, '!!!',   'sign spared by currency code on create';
is $curf->format(1),     '!!! 1', 'sign spared by currency code on create';

t/format.t  view on Meta::CPAN

use open qw( :encoding(UTF-8) :std );
use Test::More tests => 60;
use Test::Warn;
use CLDR::Number;

my $cldr = CLDR::Number->new;
my $decf = $cldr->decimal_formatter;
my $perf = $cldr->percent_formatter;
my $curf = $cldr->currency_formatter(currency_code => 'EUR');

$decf->locale('en');
is $decf->format(5.0),              '5';
is $decf->format(0),                '0';
is $decf->format(.5),               '0.5';
is $decf->format(.05),              '0.05';
is $decf->format(.005),             '0.005';
is $decf->format(50_000.05),        '50,000.05';
is $decf->format(5_000_000.05),     '5,000,000.05';
is $decf->format(5_000_000_000.05), '5,000,000,000.05';
is $decf->format(-50_000.05),       '-50,000.05';

$decf->locale('fr');
is $decf->format(5.0),              '5';
is $decf->format(0),                '0';
is $decf->format(.5),               '0,5';
is $decf->format(.05),              '0,05';
is $decf->format(.005),             '0,005';
is $decf->format(50_000.05),        '50 000,05';
is $decf->format(5_000_000.05),     '5 000 000,05';
is $decf->format(5_000_000_000.05), '5 000 000 000,05';
is $decf->format(-50_000.05),       '-50 000,05';

$decf->locale('ar');
is $decf->format(-50.0),   "\N{RIGHT-TO-LEFT MARK}-٥٠";
is $decf->format(-50_000), "\N{RIGHT-TO-LEFT MARK}-٥٠٬٠٠٠";
is $decf->format(-50.05),  "\N{RIGHT-TO-LEFT MARK}-٥٠٫٠٥";
is $decf->format(-.05),    "\N{RIGHT-TO-LEFT MARK}-٠٫٠٥";

$decf->locale('en-IN');
is $decf->format(1_23_456),    '1,23,456';
is $decf->format(1_23_45_678), '1,23,45,678';

warning_is {
    is $decf->format(undef), undef, 'decimal format when undef';
} 'Use of uninitialized value in CLDR::Number::Format::Decimal::format';

warning_is {
    is $decf->at_least(undef), undef, 'decimal at_least when undef';
} 'Use of uninitialized value in CLDR::Number::Format::Decimal::at_least';

t/format.t  view on Meta::CPAN

warning_is {
    my $perf = $cldr->percent_formatter;
    is $perf->format(undef), undef, 'percent format when undef';
} 'Use of uninitialized value in CLDR::Number::Format::Percent::format';

warning_is {
    my $curf = $cldr->currency_formatter(currency_code => 'EUR');
    is $curf->format(undef), undef, 'currency format when undef';
} 'Use of uninitialized value in CLDR::Number::Format::Currency::format';

$decf->locale('it');
$perf->locale('it');
$curf->locale('it');

warning_is {
    is $decf->format('X'), '0', 'decimal format when not num';
} q{Argument "X" isn't numeric in CLDR::Number::Format::Decimal::format};

warning_is {
    is $decf->format('1.5X'), '1,5', 'decimal format when not all num';
} q{Argument "1.5X" isn't numeric in CLDR::Number::Format::Decimal::format};

warning_is {

t/from-shutterstock.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 59;
use CLDR::Number::Format::Currency;

# Tests using locales and currencies supported by Shutterstock

while (my $line = <DATA>) {
    chomp $line;
    my ($currency, $locale, $expected) = split /\t/, $line;
    my $curf = CLDR::Number::Format::Currency->new(
        locale        => $locale,
        currency_code => $currency,
    );
    is $curf->format(1000), $expected, "1000 $currency in $locale";
}

__DATA__
AUD	en-AU	$1,000.00
BRL	en-BR	R$1,000.00
BRL	pt-BR	R$1.000,00
CAD	en-CA	$1,000.00
CAD	fr-CA	1 000,00 $
CHF	de-CH	CHF 1'000.00
CHF	en-CH	CHF 1.000,00

t/from-twittercldr.t  view on Meta::CPAN

use Test::More tests => 22;
use CLDR::Number;

my $cldr = CLDR::Number->new;

# Tests adapted from:
# TwitterCldr (twitter-cldr-rb)
# https://github.com/twitter/twitter-cldr-rb/tree/master/spec/formatters/numbers

# number_formatter_spec.rb
my $decf = $cldr->decimal_formatter(locale => 'sv');
is $decf->format(12),      '12',       'format a basic integer';
is $decf->format(12.0),    '12',       'format a basic decimal';
is $decf->format(1337),    '1 337',    'formats an integer larger than 999';
is $decf->format(1337.37), '1 337,37', 'formats a decimal larger than 999.9';
$decf->maximum_fraction_digits(0); is $decf->format(12.1),  '12',   'formats with precision of 0';
$decf->maximum_fraction_digits(1); is $decf->format(12.25), '12,2', 'half-even rounding and formats with precision of 1';

# decimal_formatter_spec.rb
$decf->locale('sv');
is $decf->format(12.0),  '12',    'format positive decimals correctly';
is $decf->format(-12.0), '−12',   'format negative decimals correctly';
$decf->minimum_fraction_digits(3);
is $decf->format(-12), '−12,000', 'respect the minimum_fraction_digits attribute';

# percent_formatter_spec.rb
my $perf = $cldr->percent_formatter(locale => 'da');
is $perf->format(0.12),  '12 %',      'format the number correctly';
is $perf->format(-0.12), '-12 %',     'format negative numbers correctly';
$perf->minimum_fraction_digits(3);
is $perf->format(-0.12), '-12,000 %', 'respect the minimum_fraction_digits attribute';

# currency_formatter_spec.rb
my $curf = $cldr->currency_formatter(locale => 'ko', currency_code => 'USD');
is $curf->format(12),  'US$12.00',  'handles positive numbers';
is $curf->format(-12), '-US$12.00', 'handles negative numbers';
$curf->locale('ms');
$curf->currency_sign('S/.');       is $curf->format(12), 'S/. 12.00',  'use the specified currency symbol when specified';
$curf->currency_code('XYZ');       is $curf->format(12), 'XYZ 12.00',  'use the currency code as the symbol if the currency code cannot be identified';
$curf->currency_code('THB');       is $curf->format(12), 'THB 12.00',  'use the currency symbol for the corresponding currency code';
$curf->currency_code('TND');       is $curf->format(12), 'TND 12.000', 'use the currency-specific default minimum fraction digits';
$curf->currency_code('CAD');       is $curf->format(12), 'CAD 12.00',  'use the currency-specific default minimum fraction digits';
$curf->minimum_fraction_digits(3); is $curf->format(12), 'CAD 12.000', 'overrides the default minimum fraction digits';

$curf->currency_code('CHF');
$curf->rounding_increment(0.05);  # TODO: should this be 5?
is $curf->format(12.03), 'CHF 12.05', 'use the currency rounding for the currency code';

t/from-uts35.t  view on Meta::CPAN

use CLDR::Number;

my $cldr = CLDR::Number->new;
my ($decf, $perf, $scif, $curf);

# Tests adapted from examples in:
# UTS #35: Unicode LDML, Part 1: Core
# http://www.unicode.org/reports/tr35/tr35.html

TODO: {
    local $TODO = 'Unicode locale extensions not currently retained';

    # 3.7 Unicode BCP 47 Extension Data
    $cldr->locale('th-u-foo-bar-nu-thai-ca-buddhist');
    is $cldr->locale, 'th-u-bar-foo-ca-buddhist-nu-thai', 'sort attributes & keywords';
};

# Tests adapted from examples in:
# UTS #35: Unicode LDML, Part 3: Numbers
# http://www.unicode.org/reports/tr35/tr35-numbers.html

# 2.3 Number Symbols
$decf = $cldr->decimal_formatter(locale => 'en');
$decf->pattern('#,###');         is $decf->format(100_000_000),  '100,000,000',  'group by 3';
$decf->pattern('#,####');        is $decf->format(1_0000_0000),  '1,0000,0000',  'group by 4';
$decf->pattern('#,##,###');      is $decf->format(12_34_56_789), '12,34,56,789', 'primary group by 3, secondary group by 2';
$decf->pattern('###,###,####');  is $decf->format(100_000_0000), '100,000,0000', 'primary group by 4, secondary group by 3';
$decf->pattern('#,##,###,####'); is $decf->format(100_000_0000), '100,000,0000', 'ignore tertiary group';
$decf->pattern('##,#,###,####'); is $decf->format(100_000_0000), '100,000,0000', 'ignore tertiary group';
$perf = $cldr->percent_formatter(locale => 'en', permil => 1);
is $perf->format(1.23), '1,230‰', 'per mille multiplied by 1,000 before formatting';

SKIP: {
    skip 'format_short NYI', 1;
    # 2.4.1 Compact Number Formats
    $decf = $cldr->decimal_formatter(locale => 'fr');
    is $decf->format_short(12_345), '12 K', 'short decimal format';
};

# 2.4.2 Currency Formats
$curf = $cldr->currency_formatter(locale => 'en', currency_code => 'USD');
$curf->pattern('¤#,##0.00');             is $curf->format(-3.27), '-$3.27',  'default negative currency';
$curf->pattern('¤#,##0.00;(¤#,##0.00)'); is $curf->format(-3.27), '($3.27)', 'custom negative currency';

# 2.5 Miscellaneous Patterns
$decf = $cldr->decimal_formatter(locale => 'en');
is $decf->at_least(99),   '99+',    'at least 99';
is $decf->range(99, 103), '99–103', 'range from 99 to 103';

# 3.1 Number Patterns
$decf = $cldr->decimal_formatter(locale => 'fr');
$decf->pattern('#,##0.##');   is $decf->format(1_234.567), '1 234,57';
$decf->pattern('#,##0.###');  is $decf->format(1_234.567), '1 234,567';
$decf->pattern('###0.#####'); is $decf->format(1_234.567), '1234,567';
$decf->pattern('###0.0000#'); is $decf->format(1_234.567), '1234,5670';
$decf->pattern('00000.0000'); is $decf->format(1_234.567), '01234,5670';
$curf = $cldr->currency_formatter(locale => 'fr', pattern => '#,##0.00 ¤');
$curf->currency_code('EUR'); is $curf->format(1_234.567), '1 234,57 €';
$curf->currency_code('JPY'); is $curf->format(1_234.567), '1 235 JPY';

# 3.2 Special Pattern Characters
$decf = $cldr->decimal_formatter(locale => 'en');
$decf->pattern("'#'#");       is $decf->format(123), '#123',      'quote special characters';
$decf->pattern("# o''clock"); is $decf->format(1),   "1 o'clock", 'single quote itself';
# minimumGroupingDigits
$decf = $cldr->decimal_formatter(locale => 'pl');
is $decf->minimum_grouping_digits, 2, 'pl: default min group';
is $decf->primary_grouping_size,   3, 'pl: default primary_grouping_size';
is $decf->format(9_999),      '9999', 'pl: under min group';
is $decf->format(10_000),   '10 000', 'pl: at min group';
$decf = $cldr->decimal_formatter(locale => 'en');
is $decf->minimum_grouping_digits, 1, 'en: default min group';
is $decf->primary_grouping_size,   3, 'en: default primary_grouping_size';
is $decf->format(1_000),     '1,000', 'en: at min group';
is $decf->format(10_000),   '10,000', 'en: over min group';
$decf->minimum_grouping_digits(2);
is $decf->format(1_000),      '1000', 'under custom min group';
is $decf->format(10_000),   '10,000', 'at custom min group';
$decf->minimum_grouping_digits(1);
$decf->primary_grouping_size(4);
is $decf->format(10_000),   '1,0000', 'at min group w/ custom grouping size';
$decf->minimum_grouping_digits(2);
is $decf->format(10_000),    '10000', 'under min group w/ custom grouping size';

# 3.3 Formatting
$decf = $cldr->decimal_formatter(locale => 'en');
# TODO: maximum integer digits
$decf->pattern('00000');  is $decf->format(1997),    '01997',  'minimum integer digits';
$decf->pattern('0.##');   is $decf->format(0.125),   '0.12',   'maximum fraction digits';
$decf->pattern('0.0000'); is $decf->format(0.125),   '0.1250', 'minimum fraction digits';
$decf->pattern('0.####'); is $decf->format(0.10004), '0.1',    'trailing fractional zeros are not displayed';

# 3.4 Scientific Notation
SKIP: {
    skip 'scientific_formatter NYI', 7;
    $scif = $cldr->scientific_formatter(locale => 'en');
    $scif->pattern('0.###E0');
    is $scif->format(1234), '1.234E3', 'scientific notation';
    $scif->pattern('0.###E+0');
    is $scif->format(10),  '1E+1', 'scientific with explicit positive exponent';
    is $scif->format(1),   '1E+0', 'scientific with explicit positive exponent';
    is $scif->format(0.1), '1E-1', 'scientific with explicit positive exponent when negative';
    $scif->pattern('00.###E0');   is $scif->format(0.00123), '12.3E-4',  'scientific with minimum integer digits';
    $scif->pattern('##0.####E0'); is $scif->format(12345),   '12.345E3', 'scientific with maximum integer digits';
    $scif->pattern('##0.##E0');   is $scif->format(12345),   '12.3E3',   'scientific with significant digits logic';
};

# 3.5 Significant Digits
SKIP: {
    skip 'significant digits NYI', 5;
    $decf = $cldr->decimal_formatter(locale => 'en');
    $decf->pattern('@@@');  is $decf->format(12345),   '12300', 'significant digits; min/max: 3';
    $decf->pattern('@@@');  is $decf->format(0.12345), '0.123', 'significant digits; min/max: 3';
    $decf->pattern('@@##'); is $decf->format(3.14159), '3.142', 'significant digits; min: 2, max: 4';
    $decf->pattern('@@##'); is $decf->format(1.23004), '1.23',  'significant digits; min: 2, max: 4';
    $decf->pattern('@##');  is $decf->format(0.1203),  '0.12',  'significant digits; min: 1, max: 3';
}

# 3.6 Padding
TODO: {
    local $TODO = 'padding NYI';
    $curf = $cldr->currency_formatter(locale => 'en', currency_code => 'USD');
    $curf->pattern('¤*x#,##0.00');
    is $curf->format(123),  '$xx123.00', 'padding (applied)';
}
is $curf->format(1234), '$1,234.00', 'padding (not applied)';

# Rounding
$decf = $cldr->decimal_formatter(locale => 'en');
$decf->pattern('0.65');
is $decf->format(1.234), '1.30', 'rounding to 0.65';

# 3.7 Quoting Rules
$decf = $cldr->decimal_formatter(locale => 'en');
$decf->pattern("'X '#' Q '");
is $decf->format(1939), 'X 1939 Q ', 'pattern quoting';

# 4 Currencies
$curf = $cldr->currency_formatter(currency_code => 'USD');
$curf->locale('lg');
is $curf->currency_sign, 'US$',       'expected currency sign';
is $curf->pattern,       '#,##0.00¤', 'expected pattern';
is $curf->format(1),     '1.00 US$',  'currency spacing inserted';
$curf->locale('ak');
is $curf->currency_sign, 'US$',       'expected currency sign';
is $curf->pattern,       '¤#,##0.00', 'expected pattern';
is $curf->format(1),     'US$1.00',   'no currency spacing inserted';
$curf->currency_code('RUR');
$curf->locale('ru'); is $curf->format(1234.57), '1 234,57 р.',  'RUR in ru';
$curf->locale('en'); is $curf->format(1234.57), 'RUR 1,234.57', 'RUR in en';

t/inf-nan.t  view on Meta::CPAN

use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 28;
use CLDR::Number;

my $inf = 9**9**9;
my $neg = -$inf;
my $nan = -sin($inf);

my $cldr = CLDR::Number->new(locale => 'en');
my $decf = $cldr->decimal_formatter;
my $perf = $cldr->percent_formatter;
my $curf = $cldr->currency_formatter(currency_code => 'EUR');

is $cldr->infinity, '∞',   'infinity attribute';
is $cldr->nan,      'NaN', 'nan attribute';

is $decf->format($inf), '∞',   'format infinity';
is $decf->format($neg), '-∞',  'format negative infinity';
is $decf->format($nan), 'NaN', 'format NaN';

t/inf-nan.t  view on Meta::CPAN

is $curf->format($inf), '€∞',   'format infinity euros';
is $curf->format($neg), '-€∞',  'format negative infinity euros';
is $curf->format($nan), '€NaN', 'format NaN euros';

is $decf->at_least($inf), '∞+',   'format at least infinity';
is $decf->at_least($nan), 'NaN+', 'format at least NaN';

is $decf->range($neg, $inf), '-∞–∞',    'format range of infinity';
is $decf->range($nan, $nan), 'NaN–NaN', 'format range of NaN';

$cldr = CLDR::Number->new(locale => 'dz');
$decf = $cldr->decimal_formatter;
$perf = $cldr->percent_formatter;
$curf = $cldr->currency_formatter(currency_code => 'BTN');

is $cldr->infinity, 'གྲངས་མེད', 'infinity attribute (dz)';
is $cldr->nan,      'ཨང་མད',  'nan attribute (dz)';

is $decf->format($inf), 'གྲངས་མེད',  'format infinity (dz)';
is $decf->format($neg), '-གྲངས་མེད', 'format negative infinity (dz)';
is $decf->format($nan), 'ཨང་མད',   'format NaN (dz)';

t/inheritance.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 15;
use Test::Differences;
use CLDR::Number;

my $cldr = CLDR::Number->new;

$cldr->locale('ar-DZ');
is $cldr->decimal_sign, ',', 'decimal directly from ar-DZ';

$cldr->locale('ar-EG');
is $cldr->decimal_sign, 'Ù«', 'decimal inherited from ar';

$cldr->locale('lu');
is $cldr->decimal_sign, ',', 'decimal directly from lu';
is $cldr->minus_sign,   '-', 'minus inherited from root';

$cldr->locale('es-US');
is $cldr->decimal_sign, '.', 'decimal inherited from es-419, not es';
is $cldr->group_sign,   ',', 'group inherited from es-419, not es';

{
    # currency decimal is no longer used by any locale, so we manually add it here
    # to test the feature in case it’s reintroduced in the future
    local $CLDR::Number::Data::Base::DATA->{sv}{symbol}{currency_decimal} = ':';

    my $curf = $cldr->currency_formatter(locale => 'sv-FI');
    is $curf->decimal_sign, ':', 'currency decimal inherited from sv';
}

my $curf = $cldr->currency_formatter(locale => 'en-NZ');
$curf->currency_code('NZD');
is $curf->currency_sign, '$', 'currency sign directly from en-NZ';
$curf->currency_code('JPY');
is $curf->currency_sign, 'JPÂ¥', 'currency sign inherited from en-001';

$cldr->locale('sr-Cyrl-XK');
eq_or_diff(
    $cldr->_locale_inheritance,
    [qw( sr-Cyrl-XK sr-Cyrl sr root )],
    'locale inheritance'
);

$cldr->locale('root');
eq_or_diff(
    $cldr->_locale_inheritance,
    [qw( root )],
    'root has a single level of inheritance'
);

$cldr->locale('es-MX');
eq_or_diff(
    $cldr->_locale_inheritance,
    [qw( es-MX es-419 es root )],
    'locale inheritance with added step'
);

$cldr->locale('az-Cyrl');
eq_or_diff(
    $cldr->_locale_inheritance,
    [qw( az-Cyrl root )],
    'locale inheritance with removed step'
);

$cldr->locale('zh-Hant-MO');
eq_or_diff(
    $cldr->_locale_inheritance,
    [qw( zh-Hant-MO zh-Hant-HK zh-Hant root )],
    'locale inheritance with added and removed steps'
);

$cldr->locale('en-US-u-va-posix');
eq_or_diff(
    $cldr->_locale_inheritance,
    [qw( en-US-u-va-posix en root )],
    'locale inheritance with Unicode extension'
);

t/locales.t  view on Meta::CPAN

use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 24;
use Test::Warn;
use CLDR::Number;

my $cldr = CLDR::Number->new;

# conversion
$cldr->locale('zh_Hant_HK');
is $cldr->locale, 'zh-Hant-HK', 'convert undercore to dash';

$cldr->locale('ZH-Hant-HK');
is $cldr->locale, 'zh-Hant-HK', 'convert language to lowercase';

$cldr->locale('zh-hANT-hk');
is $cldr->locale, 'zh-Hant-HK', 'convert script to titlecase';

$cldr->locale('zh-Hant-hk');
is $cldr->locale, 'zh-Hant-HK', 'convert region to uppercase';

$cldr->locale('AST');
is $cldr->locale, 'ast', 'convert 3-letter language to lowercase';

$cldr->locale('en-');
is $cldr->locale, 'en', 'allow trailing dash and remove';

$cldr->locale('fr_');
is $cldr->locale, 'fr', 'allow trailing underscore and remove';

# BCP 47 conversion
$cldr->locale('und');
is $cldr->locale, 'root', 'und → root';

# Unicode locale extensions
TODO: {
    local $TODO = 'Unicode locale extensions not currently retained';
    $cldr->locale('ja-u-nu-fullwide-cu-jpy');
    is $cldr->locale, 'ja-u-cu-jpy-nu-fullwide', 'sort keywords';
};

# defaults
$cldr = CLDR::Number->new;
is $cldr->locale, 'root', 'locale is root when undefined with no default';
ok !$cldr->default_locale, 'no default for the default locale';

$cldr->locale('xx');
is $cldr->locale, 'root', 'locale is root when invalid with no default';

warning_is {
    $cldr = CLDR::Number->new(default_locale => 'xx');
    ok !$cldr->default_locale, 'default locale does not fallback like locale';
} q{default_locale 'xx' is unknown};

$cldr = CLDR::Number->new(default_locale => 'en-GB');
is $cldr->default_locale, 'en-GB', 'default locale is set';
is $cldr->locale, 'en-GB', 'locale is default when undefined with default';

$cldr->locale('xx');
is $cldr->locale, 'en-GB', 'locale is default when invalid with default';

# fallbacks
$cldr = CLDR::Number->new;
$cldr->locale('en-XX');
is $cldr->locale, 'en', 'locale is language when invalid country';

$cldr->locale('eo-IR');
is $cldr->locale, 'eo', 'locale is language when unavailable country';

$cldr->locale('en-Xxxx');
is $cldr->locale, 'en', 'locale is language when invalid script';

$cldr->locale('zh-Latn');
is $cldr->locale, 'zh', 'locale is language when unavailable script';

$cldr->locale('zh-Hant-GB');
is $cldr->locale, 'zh-Hant', 'locale is language-script when unavailable country';

$cldr->locale('en-Hant-GB');
is $cldr->locale, 'en-GB', 'locale is language-country when unavailable script';

$cldr->locale('es-419');
is $cldr->locale, 'es-419', 'numeric regions are supported';

t/minmax-digits.t  view on Meta::CPAN

    minimum_fraction_digits => 1,
    maximum_fraction_digits => 2,
);

is $decf->minimum_integer_digits,  2, 'set min integer digits on create';
is $decf->minimum_fraction_digits, 1, 'set min fraction digits on create';
is $decf->maximum_fraction_digits, 2, 'set max fraction digits on create';

is $decf->format(5), '05.0', 'integer less than min';

my $curf = $cldr->currency_formatter(locale => 'en', currency_code => 'USD');

is $curf->minimum_fraction_digits, 2, 'default currency min fraction digits';
is $curf->maximum_fraction_digits, 2, 'default currency max fraction digits';

is $curf->format(5),     '$5.00', 'fraction less than min';
is $curf->format(7.777), '$7.78', 'fraction greater than max';

t/numbering-system.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 29;
use Test::Warn;
use CLDR::Number;

my $cldr = CLDR::Number->new(locale => 'en');
my $decf = $cldr->decimal_formatter;
my $perf = $cldr->percent_formatter;
my $curf = $cldr->currency_formatter(currency_code => 'USD');

can_ok $cldr, 'numbering_system';
can_ok $decf, 'numbering_system';
can_ok $perf, 'numbering_system';
can_ok $curf, 'numbering_system';

is $cldr->numbering_system, 'latn', 'default numbering system (base)';

t/numbering-system.t  view on Meta::CPAN


is $cldr->numbering_system, 'thai', 'set numbering system to thai (base)';
is $decf->numbering_system, 'thai', 'set numbering system to thai (decimal)';
is $perf->numbering_system, 'thai', 'set numbering system to thai (percent)';
is $curf->numbering_system, 'thai', 'set numbering system to thai (currency)';

is $decf->format(1234.09), '๑,๒๓๔.๐๙',  'format in thai (decimal)';
is $perf->format(1234.09), '๑๒๓,๔๐๙%',  'format in thai (percent)';
is $curf->format(1234.09), '$๑,๒๓๔.๐๙', 'format in thai (currency)';

$cldr->locale('en-u-nu-latn');
is $cldr->numbering_system, 'latn', 'set numbering system to latn via locale';
$cldr->locale('en-u-nu-thai');
is $cldr->numbering_system, 'thai', 'set numbering system to thai via locale';

$decf->locale('ar');
is $decf->numbering_system, 'arab',     'default numbering system (ar)';
is $decf->format(1234.09),  '١٬٢٣٤٫٠٩', 'format in arab (ar)';

$decf->locale('ar-DZ');
is $decf->numbering_system, 'latn',     'default numbering system (ar-DZ)';
is $decf->format(1234.09),  '1.234,09', 'format in latn (ar-DZ)';

$decf->locale('uz');
is $decf->numbering_system, 'latn',     'default numbering system (uz)';
is $decf->format(1234.09),  '1 234,09', 'format in latn (uz)';

$decf->locale('uz-Arab');
is $decf->numbering_system, 'arabext',  'default numbering system (uz-Arab)';
is $decf->format(1234.09),  'Û±Ù¬Û²Û³Û´Ù«Û°Û¹', 'format in arabext (uz-Arab)';

$cldr = CLDR::Number->new(locale => 'bn');
is $cldr->numbering_system, 'beng', 'num sytem on generator instantiation';

$decf = $cldr->decimal_formatter(locale => 'ar');
is $decf->numbering_system, 'arab', 'num system on formatter instantiation';

warning_is {
    $cldr = CLDR::Number->new(locale => 'ar', numbering_system => 'xxxx');
    is $cldr->numbering_system, 'arab', 'never set unknown numbering system';
} q{numbering_system 'xxxx' is unknown};

t/objects.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 31;
use CLDR::Number;
use CLDR::Number::Data::Base;

my $cldr = new_ok 'CLDR::Number' => [locale => 'zh'], 'CLDR::Number';
is $cldr->locale, 'zh', 'generator locale set on instantiation';

$cldr->locale('ja');
is $cldr->locale, 'ja', 'generator locale updated';

is $cldr->version, $CLDR::Number::VERSION,
    'version attribute matches $VERSION';
is $cldr->version, $CLDR::Number::Data::Base::VERSION,
    'version attribute matches data $VERSION';
is $cldr->cldr_version, $CLDR::Number::Data::Base::CLDR_VERSION,
    'cldr_version attribute matches data $CLDR_VERSION';

my $decf = $cldr->decimal_formatter;
isa_ok $decf, 'CLDR::Number::Format::Decimal';
is $decf->locale, 'ja', 'generator locale passed to formatter';

$decf->locale('ko');
is $decf->locale, 'ko', 'formatter locale updated';
is $cldr->locale, 'ja', 'generator locale remains the same';

$cldr->locale('vi');
is $cldr->locale, 'vi', 'generator locale updated';
is $decf->locale, 'ko', 'formatter locale remains the same';

$decf = $cldr->decimal_formatter(
    locale                  => 'en',
    minimum_integer_digits  => 2,
    maximum_integer_digits  => 3,
    minimum_fraction_digits => 1,
    maximum_fraction_digits => 2,
    primary_grouping_size   => 2,
    secondary_grouping_size => 1,
    minimum_grouping_digits => 2,
    rounding_increment      => 2,
);

is $decf->minimum_integer_digits,  2, 'min int spared by locale on create';
is $decf->maximum_integer_digits,  3, 'max int spared by locale on create';
is $decf->minimum_fraction_digits, 1, 'min frac spared by locale on create';
is $decf->maximum_fraction_digits, 2, 'max frac spared by locale on create';
is $decf->primary_grouping_size,   2, '1st group spared by locale on create';
is $decf->secondary_grouping_size, 1, '2nd group spared by locale on create';
is $decf->minimum_grouping_digits, 2, 'min group spared by locale on create';
is $decf->rounding_increment,      2, 'rounding spared by locale on create';

$decf = $cldr->decimal_formatter(
    locale  => 'en',
    pattern => '00.0#',
);

is $decf->pattern,   '00.0#', 'pattern spared by locale on create';
is $decf->format(5), '05.0',  'pattern spared by locale on create';

my $perf = $cldr->percent_formatter;
my $curf = $cldr->currency_formatter;

ok !$cldr->can('has'),   'generator: has should not be inherited';
ok !$decf->can('has'),   'decimal: has should not be inherited';
ok !$perf->can('has'),   'percent: has should not be inherited';
ok !$curf->can('has'),   'currency: has should not be inherited';
ok !$cldr->can('croak'), 'generator: croak should not be inherited';
ok !$decf->can('croak'), 'decimal: croak should not be inherited';

t/quoting.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 7;
use CLDR::Number;

my $cldr = CLDR::Number->new;
my $decf = $cldr->decimal_formatter(locale => 'en');

$decf->pattern("'foo'");  is $decf->format(123), 'foo';
$decf->pattern("'#'");    is $decf->format(123), '#';
$decf->pattern("'#");     is $decf->format(123), '#';
$decf->pattern("#'#'");   is $decf->format(123), '123#';
$decf->pattern("#'#");    is $decf->format(123), '123#';
$decf->pattern("''#''");  is $decf->format(123), "'123'";
$decf->pattern("'#''#'"); is $decf->format(123), "#'#";

t/range.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 6;
use CLDR::Number;

my ($cldr, $decf, $perf, $curf);

$cldr = CLDR::Number->new(locale => 'en');
$decf = $cldr->decimal_formatter;
$perf = $cldr->percent_formatter;
$curf = $cldr->currency_formatter(currency_code => 'EUR');

is $decf->range(1, 5),       '1–5',         'range of numbers (en)';
is $perf->range(0.01, 0.05), '1%–5%',       'range of percents (en)';
is $curf->range(1, 5),       '€1.00–€5.00', 'range of prices (en)';

$cldr = CLDR::Number->new(locale => 'es-CO');
$decf = $cldr->decimal_formatter;
$perf = $cldr->percent_formatter;
$curf = $cldr->currency_formatter(currency_code => 'COP');

is $decf->range(1, 5),       'de 1 a 5',           'range of numbers (es-CO)';
is $perf->range(0.01, 0.05), 'de 1% a 5%',         'range of percents (es-CO)';
is $curf->range(1, 5),       'de $ 1,00 a $ 5,00', 'range of prices (es-CO)';

t/rounding.t  view on Meta::CPAN

use utf8;
use strict;
use warnings;
use open qw( :encoding(UTF-8) :std );
use Test::More tests => 37;
use CLDR::Number;

my $cldr = CLDR::Number->new;
my $decf = $cldr->decimal_formatter(locale => 'fr');

$decf->maximum_fraction_digits(1);
is $decf->format(0.05),   '0';
is $decf->format(0.051),  '0,1';
is $decf->format(0.149),  '0,1';
is $decf->format(0.15),   '0,2';
is $decf->format(0.25),   '0,2';
is $decf->format(0.251),  '0,3';
is $decf->format(0.349),  '0,3';
is $decf->format(0.35),   '0,4';



( run in 1.379 second using v1.01-cache-2.11-cpan-ceb78f64989 )