mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-13 10:56:38 +00:00
Merge branch '2.x' into 3.x
* 2.x: added the Intl extension
This commit is contained in:
@@ -12,11 +12,13 @@ before_install:
|
||||
install:
|
||||
- travis_retry composer install
|
||||
- (cd extra/html-extra && travis_retry composer install)
|
||||
- (cd extra/intl-extra && travis_retry composer install)
|
||||
- (cd extra/markdown-extra && travis_retry composer install)
|
||||
|
||||
script:
|
||||
- ./vendor/bin/simple-phpunit
|
||||
- (cd extra/html-extra && ./vendor/bin/simple-phpunit)
|
||||
- (cd extra/intl-extra && ./vendor/bin/simple-phpunit)
|
||||
- (cd extra/markdown-extra && ./vendor/bin/simple-phpunit)
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -19,8 +19,15 @@
|
||||
|
||||
* 2.12.0 (2019-XX-XX)
|
||||
|
||||
* added the Markdown extension in the "extra" repositories
|
||||
* added the HtmlExtension extension in the "extra" repositories
|
||||
* added Intl extension in the "extra" repositories: "country_name",
|
||||
"currency_name", "currency_symbol", "language_name", "locale_name",
|
||||
"timezone_name", "country_timezones", "format_currency", "format_number",
|
||||
"format_*_number", "format_datetime", "format_date", and "format_time"
|
||||
filters
|
||||
* added the Markdown extension in the "extra" repositories: "markdown_to_html",
|
||||
and "html_to_markdown" filters
|
||||
* added the HtmlExtension extension in the "extra" repositories: "date_uri"
|
||||
filter, and "html_classes" function
|
||||
* fixed cache when opcache is installed but disabled
|
||||
* fixed using macros in arrow functions
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
``country_name``
|
||||
================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``country_name`` filter was added in Twig 2.12.
|
||||
|
||||
The ``country_name`` filter returns the country name given its ISO-3166
|
||||
two-letter code:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# France #}
|
||||
{{ 'FR'|country_name }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# États-Unis #}
|
||||
{{ 'US'|country_name('fr') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``country_name`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
@@ -0,0 +1,29 @@
|
||||
``country_timezones``
|
||||
=====================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``country_timezones`` filter was added in Twig 2.12.
|
||||
|
||||
The ``country_timezones`` filter returns the names of the countries associated
|
||||
with a given timezone:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# Europe/Paris #}
|
||||
{{ 'FR'|country_timezones|join(', ') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``country_timezones`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
@@ -0,0 +1,44 @@
|
||||
``currency_name``
|
||||
================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``currency_name`` filter was added in Twig 2.12.
|
||||
|
||||
The ``currency_name`` filter returns the currency name given its three-letter
|
||||
code:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# Euro #}
|
||||
{{ 'EUR'|currency_name }}
|
||||
|
||||
{# Japanese Yen #}
|
||||
{{ 'JPY'|currency_name }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# yen japonais #}
|
||||
{{ 'JPY'|currency_name('fr_FR') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``currency_name`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
@@ -0,0 +1,44 @@
|
||||
``currency_symbol``
|
||||
===================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``currency_symbol`` filter was added in Twig 2.12.
|
||||
|
||||
The ``currency_symbol`` filter returns the currency name given its three-letter
|
||||
code:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# € #}
|
||||
{{ 'EUR'|currency_symbol }}
|
||||
|
||||
{# ¥ #}
|
||||
{{ 'JPY'|currency_symbol }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# ¥ #}
|
||||
{{ 'JPY'|currency_symbol('fr') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``currency_symbol`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
@@ -0,0 +1,73 @@
|
||||
``format_currency``
|
||||
===================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``format_currency`` filter was added in Twig 2.12.
|
||||
|
||||
The ``format_currency`` filter formats a number as a currency:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# €1,000,000.00 #}
|
||||
{{ '1000000'|format_currency('EUR') }}
|
||||
|
||||
You can pass attributes to tweak the output:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# €12.34 #}
|
||||
{{ '12.345'|format_currency('EUR', {rounding_mode: 'floor'}) }}
|
||||
|
||||
{# €1,000,000.0000 #}
|
||||
{{ '1000000'|format_currency('EUR', {fraction_digit: 4}) }}
|
||||
|
||||
The list of supported options:
|
||||
|
||||
* ``grouping_used``;
|
||||
* ``decimal_always_shown``;
|
||||
* ``max_integer_digit``;
|
||||
* ``min_integer_digit``;
|
||||
* ``integer_digit``;
|
||||
* ``max_fraction_digit``;
|
||||
* ``min_fraction_digit``;
|
||||
* ``fraction_digit``;
|
||||
* ``multiplier``;
|
||||
* ``grouping_size``;
|
||||
* ``rounding_mode``;
|
||||
* ``rounding_increment``;
|
||||
* ``format_width``;
|
||||
* ``padding_position``;
|
||||
* ``secondary_grouping_size``;
|
||||
* ``significant_digits_used``;
|
||||
* ``min_significant_digits_used``;
|
||||
* ``max_significant_digits_used``;
|
||||
* ``lenient_parse``.
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 1.000.000,00 € #}
|
||||
{{ '1000000'|format_currency('EUR', locale='de') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``format_currency`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
* ``attrs``: A map of attributes
|
||||
@@ -0,0 +1,31 @@
|
||||
``format_date``
|
||||
===============
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``format_date`` filter was added in Twig 2.12.
|
||||
|
||||
The ``format_date`` filter formats a date. It behaves in the exact same way as
|
||||
the ``format_datetime`` filter, but without the time.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``format_date`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
* ``dateFormat``: The date format
|
||||
* ``pattern``: A date time pattern
|
||||
@@ -0,0 +1,67 @@
|
||||
``format_datetime``
|
||||
===================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``format_datetime`` filter was added in Twig 2.12.
|
||||
|
||||
The ``format_datetime`` filter formats a date time:
|
||||
|
||||
public function formatDateTime(Environment $env, $date, ?string $dateFormat = 'medium', ?string $timeFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', string $locale = null): string
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# Aug 7, 2019, 11:39:12 PM #}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime() }}
|
||||
|
||||
You can tweak the output for the date part and the time part:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 23:39 #}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime('none', 'short', locale='fr') }}
|
||||
|
||||
{# 07/08/2019 #}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime('short', 'none', locale='fr') }}
|
||||
|
||||
{# mercredi 7 août 2019 23:39:12 UTC #}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime('full', 'full', locale='fr') }}
|
||||
|
||||
Supported values are: ``none``, ``short``, ``medium``, ``long``, and ``full``.
|
||||
|
||||
For greater flexiblity, you can even define your own pattern:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 11 oclock PM, GMT #}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime(pattern="hh 'oclock' a, zzzz") }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 7 août 2019 23:39:12 #}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime(locale='fr') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``format_datetime`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
* ``dateFormat``: The date format
|
||||
* ``timeFormat``: The time format
|
||||
* ``pattern``: A date time pattern
|
||||
@@ -0,0 +1,117 @@
|
||||
``format_number``
|
||||
=================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``format_number`` filter was added in Twig 2.12.
|
||||
|
||||
The ``format_number`` filter formats a number:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{{ '12.345'|format_number }}
|
||||
|
||||
You can pass attributes to tweak the output:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 12.34 #}
|
||||
{{ '12.345'|format_number({rounding_mode: 'floor'}) }}
|
||||
|
||||
{# 1000000.0000 #}
|
||||
{{ '1000000'|format_number({fraction_digit: 4}) }}
|
||||
|
||||
The list of supported options:
|
||||
|
||||
* ``grouping_used``;
|
||||
* ``decimal_always_shown``;
|
||||
* ``max_integer_digit``;
|
||||
* ``min_integer_digit``;
|
||||
* ``integer_digit``;
|
||||
* ``max_fraction_digit``;
|
||||
* ``min_fraction_digit``;
|
||||
* ``fraction_digit``;
|
||||
* ``multiplier``;
|
||||
* ``grouping_size``;
|
||||
* ``rounding_mode``;
|
||||
* ``rounding_increment``;
|
||||
* ``format_width``;
|
||||
* ``padding_position``;
|
||||
* ``secondary_grouping_size``;
|
||||
* ``significant_digits_used``;
|
||||
* ``min_significant_digits_used``;
|
||||
* ``max_significant_digits_used``;
|
||||
* ``lenient_parse``.
|
||||
|
||||
Besides plain numbers, the filter can also format numbers in various styles:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 1,234% #}
|
||||
{{ '12.345'|format_number(style='percent') }}
|
||||
|
||||
{# twelve point three four five #}
|
||||
{{ '12.345'|format_number(style='spellout') }}
|
||||
|
||||
{# 12 sec. #}
|
||||
{{ '12'|format_duration_number }}
|
||||
|
||||
The list of supported styles:
|
||||
|
||||
* ``decimal``;
|
||||
* ``currency``;
|
||||
* ``percent``;
|
||||
* ``scientific``;
|
||||
* ``spellout``;
|
||||
* ``ordinal``;
|
||||
* ``duration``.
|
||||
|
||||
As a shortcut, you can use the ``format_*_number`` filters by replacing `*` with
|
||||
a style:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 1,234% #}
|
||||
{{ '12.345'|format_percent_number }}
|
||||
|
||||
{# twelve point three four five #}
|
||||
{{ '12.345'|format_spellout_number }}
|
||||
|
||||
You can pass attributes to tweak the output:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# €12.34 #}
|
||||
{{ '12.345'|format_number('EUR', {rounding_mode: 'floor'}) }}
|
||||
|
||||
{# €1,000,000.0000 #}
|
||||
{{ '1000000'|format_number('EUR', {fraction_digit: 4}) }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# 12,345 #}
|
||||
{{ '12.345'|format_number(locale='fr') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``format_number`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
* ``attrs``: A map of attributes
|
||||
* ``style``: The style of the number output
|
||||
@@ -0,0 +1,31 @@
|
||||
``format_time``
|
||||
===============
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``format_time`` filter was added in Twig 2.12.
|
||||
|
||||
The ``format_time`` filter formats a time. It behaves in the exact same way as
|
||||
the ``format_timetime`` filter, but without the date.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``format_time`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
* ``timeFormat``: The time format
|
||||
* ``pattern``: A date time pattern
|
||||
@@ -9,6 +9,10 @@ Filters
|
||||
capitalize
|
||||
column
|
||||
convert_encoding
|
||||
country_name
|
||||
country_timezones
|
||||
currency_name
|
||||
currency_symbol
|
||||
data_uri
|
||||
date
|
||||
date_modify
|
||||
@@ -17,12 +21,19 @@ Filters
|
||||
filter
|
||||
first
|
||||
format
|
||||
format_currency
|
||||
format_date
|
||||
format_datetime
|
||||
format_number
|
||||
format_time
|
||||
html_to_markdown
|
||||
join
|
||||
json_encode
|
||||
keys
|
||||
language_name
|
||||
last
|
||||
length
|
||||
locale_name
|
||||
lower
|
||||
map
|
||||
markdown_to_html
|
||||
@@ -39,6 +50,7 @@ Filters
|
||||
spaceless
|
||||
split
|
||||
striptags
|
||||
timezone_name
|
||||
title
|
||||
trim
|
||||
upper
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
``language_name``
|
||||
=================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``language_name`` filter was added in Twig 2.12.
|
||||
|
||||
The ``language_name`` filter returns the language name given its two-letter
|
||||
code:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# German #}
|
||||
{{ 'de'|language_name }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# allemand #}
|
||||
{{ 'de'|language_name('fr') }}
|
||||
|
||||
{# français canadien #}
|
||||
{{ 'fr_CA'|language_name('fr_FR') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``language_name`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
@@ -0,0 +1,44 @@
|
||||
``locale_name``
|
||||
===============
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``locale_name`` filter was added in Twig 2.12.
|
||||
|
||||
The ``locale_name`` filter returns the locale name given its two-letter
|
||||
code:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# German #}
|
||||
{{ 'de'|locale_name }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# allemand #}
|
||||
{{ 'de'|locale_name('fr') }}
|
||||
|
||||
{# français (Canada) #}
|
||||
{{ 'fr_CA'|locale_name('fr_FR') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``locale_name`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
@@ -0,0 +1,44 @@
|
||||
``timezone_name``
|
||||
=================
|
||||
|
||||
.. versionadded:: 2.12
|
||||
The ``timezone_name`` filter was added in Twig 2.12.
|
||||
|
||||
The ``timezone_name`` filter returns the timezone name given its two-letter
|
||||
code:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# Central European Time (Paris) #}
|
||||
{{ 'Europe/Paris'|timezone_name }}
|
||||
|
||||
{# Pacific Time (Los Angeles) #}
|
||||
{{ 'America/Los_Angeles'|timezone_name }}
|
||||
|
||||
By default, the filter uses the current locale. You can pass it explicitly:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
{# heure du Pacifique nord-américain (Los Angeles) #}
|
||||
{{ 'America/Los_Angeles'|timezone_name('fr') }}
|
||||
|
||||
.. note::
|
||||
|
||||
The ``timezone_name`` filter is part of the ``IntlExtension`` which is not
|
||||
installed by default. Install it first:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer req twig/intl-extra
|
||||
|
||||
Then, add it on the Twig environment::
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
|
||||
$twig = new \Twig\Environment(...);
|
||||
$twig->addExtension(new IntlExtension());
|
||||
|
||||
Arguments
|
||||
---------
|
||||
|
||||
* ``locale``: The locale
|
||||
@@ -0,0 +1,4 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
.phpunit.result.cache
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2019 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,29 @@
|
||||
Twig Intl Extension
|
||||
===================
|
||||
|
||||
This package is a Twig extension that provides the following:
|
||||
|
||||
* [`country_name`][1] filter: returns the country name given its ISO-3166 two-letter code;
|
||||
* [`currency_name`][2] filter: returns the currency name given its three-letter code;
|
||||
* [`currency_symbol`][3] filter: returns the currency symbol given its three-letter code;
|
||||
* [`language_name`][4] filter: returns the language name given its two-letter code;
|
||||
* [`locale_name`][5] filter: returns the language name given its two-letter code;
|
||||
* [`timezone_name`][6] filter: returns the timezone name given its identifier;
|
||||
* [`country_timezones`][7] filter: returns the names of the countries associated with a given timezone;
|
||||
* [`format_currency`][8] filter: formats a number as a currency;
|
||||
* [`format_number`][9] filter: formats a number;
|
||||
* [`format_datetime`][9] filter: formats a date time;
|
||||
* [`format_date`][10] filter: formats a date;
|
||||
* [`format_time`][11] filter: formats a time.
|
||||
|
||||
[1]: https://twig.symfony.com/country_name
|
||||
[2]: https://twig.symfony.com/currency_name
|
||||
[3]: https://twig.symfony.com/currency_symbol
|
||||
[4]: https://twig.symfony.com/language_name
|
||||
[5]: https://twig.symfony.com/locale_name
|
||||
[6]: https://twig.symfony.com/timezone_name
|
||||
[7]: https://twig.symfony.com/country_timezones
|
||||
[8]: https://twig.symfony.com/format_currency
|
||||
[9]: https://twig.symfony.com/format_number
|
||||
[10]: https://twig.symfony.com/format_datetime
|
||||
[11]: https://twig.symfony.com/format_time
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "twig/intl-extra",
|
||||
"type": "library",
|
||||
"description": "A Twig extension for Intl",
|
||||
"keywords": ["twig", "intl"],
|
||||
"homepage": "https://twig.symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": "http://fabien.potencier.org",
|
||||
"role": "Lead Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"twig/twig": "^2.4|^3.0",
|
||||
"symfony/intl": "^4.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^4.4@dev"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4" : {
|
||||
"Twig\\Extra\\Intl\\" : "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4" : {
|
||||
"Twig\\Extra\\Intl\\Tests\\" : "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.12-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
>
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1" />
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Twig Intl Extension Test Suite">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./</directory>
|
||||
<exclude>
|
||||
<directory>./tests</directory>
|
||||
<directory>./vendor</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Extra\Intl;
|
||||
|
||||
use Symfony\Component\Intl\Countries;
|
||||
use Symfony\Component\Intl\Currencies;
|
||||
use Symfony\Component\Intl\Languages;
|
||||
use Symfony\Component\Intl\Locales;
|
||||
use Symfony\Component\Intl\Timezones;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\RuntimeError;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
final class IntlExtension extends AbstractExtension
|
||||
{
|
||||
private const DATE_FORMATS = [
|
||||
'none' => \IntlDateFormatter::NONE,
|
||||
'short' => \IntlDateFormatter::SHORT,
|
||||
'medium' => \IntlDateFormatter::MEDIUM,
|
||||
'long' => \IntlDateFormatter::LONG,
|
||||
'full' => \IntlDateFormatter::FULL,
|
||||
];
|
||||
private const NUMBER_TYPES = [
|
||||
'default' => \NumberFormatter::TYPE_DEFAULT,
|
||||
'int32' => \NumberFormatter::TYPE_INT32,
|
||||
'int64' => \NumberFormatter::TYPE_INT64,
|
||||
'double' => \NumberFormatter::TYPE_DOUBLE,
|
||||
'currency' => \NumberFormatter::TYPE_CURRENCY,
|
||||
];
|
||||
private const NUMBER_STYLES = [
|
||||
'decimal' => \NumberFormatter::DECIMAL,
|
||||
'currency' => \NumberFormatter::CURRENCY,
|
||||
'percent' => \NumberFormatter::PERCENT,
|
||||
'scientific' => \NumberFormatter::SCIENTIFIC,
|
||||
'spellout' => \NumberFormatter::SPELLOUT,
|
||||
'ordinal' => \NumberFormatter::ORDINAL,
|
||||
'duration' => \NumberFormatter::DURATION,
|
||||
];
|
||||
private const NUMBER_ATTRIBUTES = [
|
||||
'grouping_used' => \NumberFormatter::GROUPING_USED,
|
||||
'decimal_always_shown' => \NumberFormatter::DECIMAL_ALWAYS_SHOWN,
|
||||
'max_integer_digit' => \NumberFormatter::MAX_INTEGER_DIGITS,
|
||||
'min_integer_digit' => \NumberFormatter::MIN_INTEGER_DIGITS,
|
||||
'integer_digit' => \NumberFormatter::INTEGER_DIGITS,
|
||||
'max_fraction_digit' => \NumberFormatter::MAX_FRACTION_DIGITS,
|
||||
'min_fraction_digit' => \NumberFormatter::MIN_FRACTION_DIGITS,
|
||||
'fraction_digit' => \NumberFormatter::FRACTION_DIGITS,
|
||||
'multiplier' => \NumberFormatter::MULTIPLIER,
|
||||
'grouping_size' => \NumberFormatter::GROUPING_SIZE,
|
||||
'rounding_mode' => \NumberFormatter::ROUNDING_MODE,
|
||||
'rounding_increment' => \NumberFormatter::ROUNDING_INCREMENT,
|
||||
'format_width' => \NumberFormatter::FORMAT_WIDTH,
|
||||
'padding_position' => \NumberFormatter::PADDING_POSITION,
|
||||
'secondary_grouping_size' => \NumberFormatter::SECONDARY_GROUPING_SIZE,
|
||||
'significant_digits_used' => \NumberFormatter::SIGNIFICANT_DIGITS_USED,
|
||||
'min_significant_digits_used' => \NumberFormatter::MIN_SIGNIFICANT_DIGITS,
|
||||
'max_significant_digits_used' => \NumberFormatter::MAX_SIGNIFICANT_DIGITS,
|
||||
'lenient_parse' => \NumberFormatter::LENIENT_PARSE,
|
||||
];
|
||||
private const NUMBER_ROUNDING_ATTRIBUTES = [
|
||||
'ceiling' => \NumberFormatter::ROUND_CEILING,
|
||||
'floor' => \NumberFormatter::ROUND_FLOOR,
|
||||
'down' => \NumberFormatter::ROUND_DOWN,
|
||||
'up' => \NumberFormatter::ROUND_UP,
|
||||
'halfeven' => \NumberFormatter::ROUND_HALFEVEN,
|
||||
'halfdown' => \NumberFormatter::ROUND_HALFDOWN,
|
||||
'halfup' => \NumberFormatter::ROUND_HALFUP,
|
||||
];
|
||||
private const NUMBER_PADDONG_ATTRIBUTES = [
|
||||
'before_prefix' => \NumberFormatter::PAD_BEFORE_PREFIX,
|
||||
'after_prefix' => \NumberFormatter::PAD_AFTER_PREFIX,
|
||||
'before_suffix' => \NumberFormatter::PAD_BEFORE_SUFFIX,
|
||||
'after_suffix' => \NumberFormatter::PAD_AFTER_SUFFIX,
|
||||
];
|
||||
private const NUMBER_TEXT_ATTRIBUTES = [
|
||||
'positive_prefix' => \NumberFormatter::POSITIVE_PREFIX,
|
||||
'positive_suffix' => \NumberFormatter::POSITIVE_SUFFIX,
|
||||
'negative_prefix' => \NumberFormatter::NEGATIVE_PREFIX,
|
||||
'negative_suffix' => \NumberFormatter::NEGATIVE_SUFFIX,
|
||||
'padding_character' => \NumberFormatter::PADDING_CHARACTER,
|
||||
'currency_mode' => \NumberFormatter::CURRENCY_CODE,
|
||||
'default_ruleset' => \NumberFormatter::DEFAULT_RULESET,
|
||||
'public_rulesets' => \NumberFormatter::PUBLIC_RULESETS,
|
||||
];
|
||||
private const NUMBER_SYMBOLS = [
|
||||
'decimal_separator' => \NumberFormatter::DECIMAL_SEPARATOR_SYMBOL,
|
||||
'grouping_separator' => \NumberFormatter::GROUPING_SEPARATOR_SYMBOL,
|
||||
'pattern_separator' => \NumberFormatter::PATTERN_SEPARATOR_SYMBOL,
|
||||
'percent' => \NumberFormatter::PERCENT_SYMBOL,
|
||||
'zero_digit' => \NumberFormatter::ZERO_DIGIT_SYMBOL,
|
||||
'digit' => \NumberFormatter::DIGIT_SYMBOL,
|
||||
'minus_sign' => \NumberFormatter::MINUS_SIGN_SYMBOL,
|
||||
'plus_sign' => \NumberFormatter::PLUS_SIGN_SYMBOL,
|
||||
'currency' => \NumberFormatter::CURRENCY_SYMBOL,
|
||||
'intl_currency' => \NumberFormatter::INTL_CURRENCY_SYMBOL,
|
||||
'monetary_separator' => \NumberFormatter::MONETARY_SEPARATOR_SYMBOL,
|
||||
'exponential' => \NumberFormatter::EXPONENTIAL_SYMBOL,
|
||||
'permill' => \NumberFormatter::PERMILL_SYMBOL,
|
||||
'pad_escape' => \NumberFormatter::PAD_ESCAPE_SYMBOL,
|
||||
'infinity' => \NumberFormatter::INFINITY_SYMBOL,
|
||||
'nan' => \NumberFormatter::NAN_SYMBOL,
|
||||
'significant_digit' => \NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL,
|
||||
'monetary_grouping_separator' => \NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL,
|
||||
];
|
||||
|
||||
private $dateFormatters = [];
|
||||
private $numberFormatters = [];
|
||||
private $dateFormatterPrototype;
|
||||
private $numberFormatterPrototype;
|
||||
|
||||
public function __construct(\IntlDateFormatter $dateFormatterPrototype = null, \NumberFormatter $numberFormatterPrototype = null)
|
||||
{
|
||||
$this->dateFormatterPrototype = $dateFormatterPrototype;
|
||||
$this->numberFormatterPrototype = $numberFormatterPrototype;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
// internationalized names
|
||||
new TwigFilter('country_name', [$this, 'getCountryName']),
|
||||
new TwigFilter('currency_name', [$this, 'getCurrencyName']),
|
||||
new TwigFilter('currency_symbol', [$this, 'getCurrencySymbol']),
|
||||
new TwigFilter('language_name', [$this, 'getLanguageName']),
|
||||
new TwigFilter('locale_name', [$this, 'getLocaleName']),
|
||||
new TwigFilter('timezone_name', [$this, 'getTimezoneName']),
|
||||
new TwigFilter('country_timezones', [$this, 'getCountryTimezones']),
|
||||
|
||||
// localized formatters
|
||||
new TwigFilter('format_currency', [$this, 'formatCurrency']),
|
||||
new TwigFilter('format_number', [$this, 'formatNumber']),
|
||||
new TwigFilter('format_*_number', [$this, 'formatNumberStyle']),
|
||||
new TwigFilter('format_datetime', [$this, 'formatDateTime'], ['needs_environment' => true]),
|
||||
new TwigFilter('format_date', [$this, 'formatDate'], ['needs_environment' => true]),
|
||||
new TwigFilter('format_time', [$this, 'formatTime'], ['needs_environment' => true]),
|
||||
];
|
||||
}
|
||||
|
||||
public function getCountryName(string $country, string $locale = null): string
|
||||
{
|
||||
return Countries::getName($country, $locale);
|
||||
}
|
||||
|
||||
public function getCurrencyName(string $currency, string $locale = null): string
|
||||
{
|
||||
return Currencies::getName($currency, $locale);
|
||||
}
|
||||
|
||||
public function getCurrencySymbol(string $currency, string $locale = null): string
|
||||
{
|
||||
return Currencies::getSymbol($currency, $locale);
|
||||
}
|
||||
|
||||
public function getLanguageName(string $language, string $locale = null): string
|
||||
{
|
||||
return Languages::getName($language, $locale);
|
||||
}
|
||||
|
||||
public function getLocaleName(string $data, string $locale = null): string
|
||||
{
|
||||
return Locales::getName($data, $locale);
|
||||
}
|
||||
|
||||
public function getTimezoneName(string $timezone, string $locale = null): string
|
||||
{
|
||||
return Timezones::getName($timezone, $locale);
|
||||
}
|
||||
|
||||
public function getCountryTimezones(string $country): array
|
||||
{
|
||||
return Timezones::forCountryCode($country);
|
||||
}
|
||||
|
||||
public function formatCurrency($amount, string $currency, array $attrs = [], string $locale = null): string
|
||||
{
|
||||
$formatter = $this->createNumberFormatter($locale, 'currency', $attrs);
|
||||
|
||||
if (false === $ret = $formatter->formatCurrency($amount, $currency)) {
|
||||
throw new RuntimeError('Unable to format the given number as a currency.');
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function formatNumber($number, array $attrs = [], string $style = 'decimal', string $type = 'default', string $locale = null): string
|
||||
{
|
||||
if (!isset(self::NUMBER_TYPES[$type])) {
|
||||
throw new RuntimeError(sprintf('The type "%s" does not exist, known types are: "%s".', $type, implode('", "', array_keys(self::NUMBER_TYPES))));
|
||||
}
|
||||
|
||||
$formatter = $this->createNumberFormatter($locale, $style, $attrs);
|
||||
|
||||
if (false === $ret = $formatter->format($number, self::NUMBER_TYPES[$type])) {
|
||||
throw new RuntimeError('Unable to format the given number.');
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function formatNumberStyle(string $style, $number, array $attrs = [], string $type = 'default', string $locale = null): string
|
||||
{
|
||||
return $this->formatNumber($number, $attrs, $style, $type, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeInterface|string|null $date A date or null to use the current time
|
||||
* @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
|
||||
*/
|
||||
public function formatDateTime(Environment $env, $date, ?string $dateFormat = 'medium', ?string $timeFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', string $locale = null): string
|
||||
{
|
||||
$date = \twig_date_converter($env, $date, $timezone);
|
||||
$formatter = $this->createDateFormatter($locale, $dateFormat, $timeFormat, $pattern, $date->getTimezone(), $calendar);
|
||||
|
||||
if (false === $ret = $formatter->format($date)) {
|
||||
throw new RuntimeError('Unable to format the given date.');
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeInterface|string|null $date A date or null to use the current time
|
||||
* @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
|
||||
*/
|
||||
public function formatDate(Environment $env, $date, ?string $dateFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', string $locale = null): string
|
||||
{
|
||||
return $this->formatDateTime($env, $date, $dateFormat, 'none', $pattern, $timezone, $calendar, $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeInterface|string|null $date A date or null to use the current time
|
||||
* @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged
|
||||
*/
|
||||
public function formatTime(Environment $env, $date, ?string $timeFormat = 'medium', string $pattern = '', $timezone = null, string $calendar = 'gregorian', string $locale = null): string
|
||||
{
|
||||
return $this->formatDateTime($env, $date, 'none', $timeFormat, $pattern, $timezone, $calendar, $locale);
|
||||
}
|
||||
|
||||
private function createDateFormatter(?string $locale, ?string $dateFormat, ?string $timeFormat, string $pattern = '', \DateTimeZone $timezone, string $calendar): \IntlDateFormatter
|
||||
{
|
||||
if (null !== $dateFormat && !isset(self::DATE_FORMATS[$dateFormat])) {
|
||||
throw new RuntimeError(sprintf('The date format "%s" does not exist, known formats are: "%s".', $dateFormat, implode('", "', array_keys(self::DATE_FORMATS))));
|
||||
}
|
||||
|
||||
if (null !== $timeFormat && !isset(self::DATE_FORMATS[$timeFormat])) {
|
||||
throw new RuntimeError(sprintf('The time format "%s" does not exist, known formats are: "%s".', $timeFormat, implode('", "', array_keys(self::DATE_FORMATS))));
|
||||
}
|
||||
|
||||
if (null === $locale) {
|
||||
$locale = \Locale::getDefault();
|
||||
}
|
||||
|
||||
$calendar = 'gregorian' === $calendar ? \IntlDateFormatter::GREGORIAN : \IntlDateFormatter::TRADITIONAL;
|
||||
|
||||
$dateFormatValue = self::DATE_FORMATS[$dateFormat] ?? null;
|
||||
$timeFormatValue = self::DATE_FORMATS[$timeFormat] ?? null;
|
||||
|
||||
if ($this->dateFormatterPrototype) {
|
||||
$dateFormatValue = $dateFormatValue ?: $this->dateFormatterPrototype->getDateType();
|
||||
$timeFormatValue = $timeFormatValue ?: $this->dateFormatterPrototype->getTimeType();
|
||||
$timezone = $timezone ?: $this->dateFormatterPrototype->getTimeType();
|
||||
$calendar = $calendar ?: $this->dateFormatterPrototype->getCalendar();
|
||||
$pattern = $pattern ?: $this->dateFormatterPrototype->getPattern();
|
||||
}
|
||||
|
||||
$hash = $locale.'|'.$dateFormatValue.'|'.$timeFormatValue.'|'.$timezone->getName().'|'.$calendar.'|'.$pattern;
|
||||
|
||||
if (!isset($this->dateFormatters[$hash])) {
|
||||
$this->dateFormatters[$hash] = new \IntlDateFormatter($locale, $dateFormatValue, $timeFormatValue, $timezone, $calendar, $pattern);
|
||||
}
|
||||
|
||||
return $this->dateFormatters[$hash];
|
||||
}
|
||||
|
||||
private function createNumberFormatter(?string $locale, string $style, array $attrs = []): \NumberFormatter
|
||||
{
|
||||
if (!isset(self::NUMBER_STYLES[$style])) {
|
||||
throw new RuntimeError(sprintf('The style "%s" does not exist, known styles are: "%s".', $style, implode('", "', array_keys(self::NUMBER_STYLES))));
|
||||
}
|
||||
|
||||
if (null === $locale) {
|
||||
$locale = \Locale::getDefault();
|
||||
}
|
||||
|
||||
// textAttrs and symbols can only be set on the prototype as there is probably no
|
||||
// use case for setting it on each call.
|
||||
$textAttrs = [];
|
||||
$symbols = [];
|
||||
if ($this->numberFormatterPrototype) {
|
||||
foreach (self::NUMBER_ATTRIBUTES as $name) {
|
||||
if (!isset($attrs[$name])) {
|
||||
$attrs[$name] = $this->numberFormatterPrototype->getAttribute($name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (self::NUMBER_TEXT_ATTRIBUTES as $name) {
|
||||
$textAttrs[$name] = $this->numberFormatterPrototype->getTextAttribute($name);
|
||||
}
|
||||
|
||||
foreach (self::NUMBER_SYMBOLS as $name) {
|
||||
$symbols[$name] = $this->numberFormatterPrototype->getSymbol($name);
|
||||
}
|
||||
}
|
||||
|
||||
ksort($attrs);
|
||||
$hash = $locale.'|'.$style.'|'.json_encode($attrs).'|'.json_encode($textAttrs).'|'.json_encode($symbols);
|
||||
|
||||
if (!isset($this->numberFormatters[$hash])) {
|
||||
$this->numberFormatters[$hash] = new \NumberFormatter($locale, self::NUMBER_STYLES[$style]);
|
||||
}
|
||||
|
||||
foreach ($attrs as $name => $value) {
|
||||
if (!isset(self::NUMBER_ATTRIBUTES[$name])) {
|
||||
throw new RuntimeError(sprintf('The number formatter attribute "%s" does not exist, known attributes are: "%s".', $name, implode('", "', array_keys(self::NUMBER_ATTRIBUTES))));
|
||||
}
|
||||
|
||||
if ('rounding_mode' === $name) {
|
||||
if (!isset(self::NUMBER_ROUNDING_ATTRIBUTES[$value])) {
|
||||
throw new RuntimeError(sprintf('The number formatter rounding mode "%s" does not exist, known modes are: "%s".', $value, implode('", "', array_keys(self::NUMBER_ROUNDING_ATTRIBUTES))));
|
||||
}
|
||||
|
||||
$value = self::NUMBER_ROUNDING_ATTRIBUTES[$value];
|
||||
} elseif ('padding_position' === $name) {
|
||||
if (!isset(self::NUMBER_PADDONG_ATTRIBUTES[$value])) {
|
||||
throw new RuntimeError(sprintf('The number formatter padding position "%s" does not exist, known positions are: "%s".', $value, implode('", "', array_keys(self::NUMBER_PADDONG_ATTRIBUTES))));
|
||||
}
|
||||
|
||||
$value = self::NUMBER_PADDONG_ATTRIBUTES[$value];
|
||||
}
|
||||
|
||||
$this->numberFormatters[$hash]->setAttribute(self::NUMBER_ATTRIBUTES[$name], $value);
|
||||
}
|
||||
|
||||
foreach ($textAttrs as $name => $value) {
|
||||
$this->numberFormatters[$hash]->setTextAttribute($name, $value);
|
||||
}
|
||||
|
||||
foreach ($symbols as $name => $value) {
|
||||
$this->numberFormatters[$hash]->setSymbol($name, $value);
|
||||
}
|
||||
|
||||
return $this->numberFormatters[$hash];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
"country_name" filter
|
||||
--TEMPLATE--
|
||||
{{ 'FR'|country_name }}
|
||||
{{ 'US'|country_name }}
|
||||
{{ 'US'|country_name('fr') }}
|
||||
{{ 'CH'|country_name('fr_CA') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
France
|
||||
United States
|
||||
États-Unis
|
||||
Suisse
|
||||
@@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
"country_timezones" filter
|
||||
--TEMPLATE--
|
||||
{{ 'FR'|country_timezones|join(', ') }}
|
||||
{{ 'US'|country_timezones|join(', ') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
Europe/Paris
|
||||
America/Adak, America/Anchorage, America/Boise, America/Chicago, America/Denver, America/Detroit, America/Indiana/Knox, America/Indiana/Marengo, America/Indiana/Petersburg, America/Indiana/Tell_City, America/Indiana/Vevay, America/Indiana/Vincennes, America/Indiana/Winamac, America/Indianapolis, America/Juneau, America/Kentucky/Monticello, America/Los_Angeles, America/Louisville, America/Menominee, America/Metlakatla, America/New_York, America/Nome, America/North_Dakota/Beulah, America/North_Dakota/Center, America/North_Dakota/New_Salem, America/Phoenix, America/Sitka, America/Yakutat, Pacific/Honolulu
|
||||
@@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
"currency_name" filter
|
||||
--TEMPLATE--
|
||||
{{ 'EUR'|currency_name }}
|
||||
{{ 'JPY'|currency_name }}
|
||||
{{ 'EUR'|currency_name('fr') }}
|
||||
{{ 'JPY'|currency_name('fr_FR') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
Euro
|
||||
Japanese Yen
|
||||
euro
|
||||
yen japonais
|
||||
@@ -0,0 +1,10 @@
|
||||
--TEST--
|
||||
"currency_symbol" filter
|
||||
--TEMPLATE--
|
||||
{{ 'EUR'|currency_symbol }}
|
||||
{{ 'JPY'|currency_symbol }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
€
|
||||
¥
|
||||
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
"format_currency" filter
|
||||
--TEMPLATE--
|
||||
{{ '1000000'|format_currency('EUR') }}
|
||||
{{ '1000000'|format_currency('EUR', locale='de') }}
|
||||
{{ '1000000'|format_currency('EUR', {fraction_digit: 2}) }}
|
||||
{{ '12.345'|format_currency('EUR', {rounding_mode: 'floor'}) }}
|
||||
{{ '125000'|format_currency('YEN') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
€1,000,000.00
|
||||
1.000.000,00 €
|
||||
€1,000,000.00
|
||||
€12.34
|
||||
YEN125,000.00
|
||||
@@ -0,0 +1,26 @@
|
||||
--TEST--
|
||||
"format_date" filter
|
||||
--TEMPLATE--
|
||||
{{ '2019-08-07 23:39:12'|format_datetime() }}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime(locale='fr') }}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime('none', 'short', locale='fr') }}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime('short', 'none', locale='fr') }}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime('full', 'full', locale='fr') }}
|
||||
{{ '2019-08-07 23:39:12'|format_datetime(pattern="hh 'oclock' a, zzzz") }}
|
||||
|
||||
{{ '2019-08-07 23:39:12'|format_date }}
|
||||
{{ '2019-08-07 23:39:12'|format_date(locale='fr') }}
|
||||
{{ '2019-08-07 23:39:12'|format_time }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
Aug 7, 2019, 11:39:12 PM
|
||||
7 août 2019 23:39:12
|
||||
23:39
|
||||
07/08/2019
|
||||
mercredi 7 août 2019 23:39:12 UTC
|
||||
11 oclock PM, GMT
|
||||
|
||||
Aug 7, 2019
|
||||
7 août 2019
|
||||
11:39:12 PM
|
||||
@@ -0,0 +1,28 @@
|
||||
--TEST--
|
||||
"format_number" filter
|
||||
--TEMPLATE--
|
||||
{{ '12.345'|format_number }}
|
||||
{{ '12.345'|format_number(locale='fr') }}
|
||||
{{ '12.345'|format_number(style='percent') }}
|
||||
{{ '12.345'|format_number(style='spellout') }}
|
||||
{{ '12.345'|format_percent_number }}
|
||||
{{ '12.345'|format_spellout_number }}
|
||||
{{ '80.345'|format_spellout_number(locale='fr_FR') }}
|
||||
{{ '80.345'|format_spellout_number(locale='fr_CH') }}
|
||||
{{ '12'|format_duration_number }}
|
||||
{{ '0.12'|format_percent_number({fraction_digit: 1}) }}
|
||||
{{ '0.12345'|format_percent_number({rounding_mode: 'ceiling'}) }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
12.345
|
||||
12,345
|
||||
1,234%
|
||||
twelve point three four five
|
||||
1,234%
|
||||
twelve point three four five
|
||||
quatre-vingts virgule trois quatre cinq
|
||||
huitante virgule trois quatre cinq
|
||||
12 sec.
|
||||
12.0%
|
||||
13%
|
||||
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
"language_name" filter
|
||||
--TEMPLATE--
|
||||
{{ 'de'|language_name }}
|
||||
{{ 'fr'|language_name }}
|
||||
{{ 'de'|language_name('fr') }}
|
||||
{{ 'fr'|language_name('fr_FR') }}
|
||||
{{ 'fr_CA'|language_name('fr_FR') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
German
|
||||
French
|
||||
allemand
|
||||
français
|
||||
français canadien
|
||||
@@ -0,0 +1,16 @@
|
||||
--TEST--
|
||||
"locale_name" filter
|
||||
--TEMPLATE--
|
||||
{{ 'de'|locale_name }}
|
||||
{{ 'fr'|locale_name }}
|
||||
{{ 'de'|locale_name('fr') }}
|
||||
{{ 'fr'|locale_name('fr_FR') }}
|
||||
{{ 'fr_CA'|locale_name('fr_FR') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
German
|
||||
French
|
||||
allemand
|
||||
français
|
||||
français (Canada)
|
||||
@@ -0,0 +1,12 @@
|
||||
--TEST--
|
||||
"timezone_name" filter
|
||||
--TEMPLATE--
|
||||
{{ 'Europe/Paris'|timezone_name }}
|
||||
{{ 'America/Los_Angeles'|timezone_name }}
|
||||
{{ 'America/Los_Angeles'|timezone_name('fr') }}
|
||||
--DATA--
|
||||
return [];
|
||||
--EXPECT--
|
||||
Central European Time (Paris)
|
||||
Pacific Time (Los Angeles)
|
||||
heure du Pacifique nord-américain (Los Angeles)
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Extra\Intl\Tests;
|
||||
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
use Twig\Test\IntegrationTestCase;
|
||||
|
||||
class IntegrationTest extends IntegrationTestCase
|
||||
{
|
||||
public function getExtensions()
|
||||
{
|
||||
return [
|
||||
new IntlExtension(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getFixturesDir()
|
||||
{
|
||||
return __DIR__.'/Fixtures/';
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Twig\Extra\TwigExtraBundle\DependencyInjection;
|
||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Twig\Extra\Html\HtmlExtension;
|
||||
use Twig\Extra\Intl\IntlExtension;
|
||||
use Twig\Extra\Markdown\MarkdownExtension;
|
||||
|
||||
class Configuration implements ConfigurationInterface
|
||||
@@ -39,6 +40,14 @@ class Configuration implements ConfigurationInterface
|
||||
->end()
|
||||
;
|
||||
|
||||
$rootNode
|
||||
->children()
|
||||
->arrayNode('intl')
|
||||
->{class_exists(IntlExtension::class) ? 'canBeDisabled' : 'canBeEnabled'}()
|
||||
->end()
|
||||
->end()
|
||||
;
|
||||
|
||||
return $treeBuilder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,5 +38,9 @@ class TwigExtraExtension extends Extension
|
||||
if ($this->isConfigEnabled($container, $config['markdown'])) {
|
||||
$loader->load('markdown.xml');
|
||||
}
|
||||
|
||||
if ($this->isConfigEnabled($container, $config['intl'])) {
|
||||
$loader->load('intl.xml');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,31 @@ use Twig\Error\SyntaxError;
|
||||
final class MissingExtensionSuggestor
|
||||
{
|
||||
private const FILTERS = [
|
||||
// HTML
|
||||
'data_uri' => ['HtmlExtension', 'twig/html-extra'],
|
||||
'markdown_to_html' => ['MarkdownExtension', 'twig/markdown-extra'],
|
||||
|
||||
// Markdown
|
||||
'html_to_markdown' => ['MarkdownExtension', 'twig/markdown-extra'],
|
||||
'markdown_to_html' => ['MarkdownExtension', 'twig/markdown-extra'],
|
||||
|
||||
// Intl
|
||||
'country_name' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'currency_name' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'currency_symbol' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'language_name' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'country_timezones' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_currency' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_decimal_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_currency_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_percent_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_scientific_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_spellout_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_ordinal_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_duration_number' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_date' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_datetime' => ['IntlExtension', 'twig/intl-extra'],
|
||||
'format_time' => ['IntlExtension', 'twig/intl-extra'],
|
||||
];
|
||||
|
||||
private const FUNCTIONS = [
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<services>
|
||||
<defaults public="false" />
|
||||
|
||||
<service id="twig.extension.intl" class="Twig\Extra\Html\IntlExtension">
|
||||
<tag name="twig.extension" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
Reference in New Issue
Block a user