Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsgiehl <stefan@piwik.org>2015-09-25 00:26:36 +0300
committersgiehl <stefan@piwik.org>2015-10-11 12:08:57 +0300
commit3e02a250be06c5295ae821cfeeaa8619e27b6333 (patch)
tree852dd8648592b59e18ed0723663ea6a8502673b6
parent0a92194e024b365bbe4778593ce4a2c9f68530fd (diff)
added first version of numberformatter & use it for datatables
-rw-r--r--core/Intl/Locale.php2
-rw-r--r--core/NumberFormatter.php215
-rwxr-xr-xcore/Twig.php15
-rw-r--r--plugins/CoreHome/templates/_dataTableCell.twig4
4 files changed, 233 insertions, 3 deletions
diff --git a/core/Intl/Locale.php b/core/Intl/Locale.php
index 0c7676569a..05cf51a8e3 100644
--- a/core/Intl/Locale.php
+++ b/core/Intl/Locale.php
@@ -31,6 +31,8 @@ class Locale
setlocale(LC_ALL, $newLocale);
setlocale(LC_CTYPE, '');
+ // Always use english for numbers. otherwise the decimal separator might get localized when casting a float to string
+ setlocale(LC_NUMERIC, array('en_US.UTF-8', 'en-US'));
}
public static function setDefaultLocale()
diff --git a/core/NumberFormatter.php b/core/NumberFormatter.php
new file mode 100644
index 0000000000..d2d56f189a
--- /dev/null
+++ b/core/NumberFormatter.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik;
+
+use Piwik\Container\StaticContainer;
+
+/**
+ * Class NumberFormatter
+ *
+ * Used to format numbers according to current language
+ */
+class NumberFormatter extends Singleton
+{
+ /** @var string language specific pattern for positive numbers */
+ protected $patternPositive;
+
+ /** @var string language specific pattern for negative numbers */
+ protected $patternNegative;
+
+ /** @var string language specific pattern for percent numbers */
+ protected $patternPercent;
+
+ /** @var string language specific plus sign */
+ protected $symbolPlus;
+
+ /** @var string language specific minus sign */
+ protected $symbolMinus;
+
+ /** @var string language specific percent sign */
+ protected $symbolPercent;
+
+ /** @var string language specific symbol used as decimal separator */
+ protected $symbolDecimal;
+
+ /** @var string language specific symbol used as group separator */
+ protected $symbolGroup;
+
+ /** @var bool indicates if language uses grouping for numbers */
+ protected $usesGrouping;
+
+ /** @var int language specific size for primary group numbers */
+ protected $primaryGroupSize;
+
+ /** @var int language specific size for secondary group numbers */
+ protected $secondaryGroupSize;
+
+ /**
+ * @return NumberFormatter
+ */
+ public static function getInstance()
+ {
+ return StaticContainer::get('Piwik\NumberFormatter');
+ }
+
+ /**
+ * Loads all required data from Intl plugin
+ */
+ public function __construct()
+ {
+ $this->patternPositive = Piwik::translate('Intl_NumberFormat');
+ $this->patternNegative = Piwik::translate('Intl_NumberFormatNegative');
+ $this->patternPercent = Piwik::translate('Intl_NumberFormatPercent');
+ $this->symbolPlus = Piwik::translate('Intl_NumberSymbolPlus');
+ $this->symbolMinus = Piwik::translate('Intl_NumberSymbolMinus');
+ $this->symbolPercent = Piwik::translate('Intl_NumberSymbolPercent');
+ $this->symbolGroup = Piwik::translate('Intl_NumberSymbolGroup');
+ $this->symbolDecimal = Piwik::translate('Intl_NumberSymbolDecimal');
+
+ $this->usesGrouping = (strpos($this->patternPositive, ',') !== false);
+ // if pattern has number groups, parse them.
+ if ($this->usesGrouping) {
+ preg_match('/#+0/', $this->patternPositive, $primaryGroupMatches);
+ $this->primaryGroupSize = $this->secondaryGroupSize = strlen($primaryGroupMatches[0]);
+ $numberGroups = explode(',', $this->patternPositive);
+ // check for distinct secondary group size.
+ if (count($numberGroups) > 2) {
+ $this->secondaryGroupSize = strlen($numberGroups[1]);
+ }
+ }
+ }
+
+ /**
+ * Formats a given number
+ *
+ * @param string|int|float $value
+ * @param int $maximumFractionDigits
+ * @param int $minimumFractionDigits
+ * @return mixed|string
+ */
+ public function format($value, $maximumFractionDigits=0, $minimumFractionDigits=0)
+ {
+ $negative = (bccomp('0', $value, 12) == 1);
+ $pattern = $negative ? $this->patternNegative : $this->patternPositive;
+ return $this->formatNumberWithPattern($pattern, $value, $maximumFractionDigits, $minimumFractionDigits);
+ }
+
+ /**
+ * Formats a given number
+ *
+ * @see \Piwik\NumberFormatter::format()
+ *
+ * @param string|int|float $value
+ * @param int $maximumFractionDigits
+ * @param int $minimumFractionDigits
+ * @return mixed|string
+ */
+ public function formatNumber($value, $maximumFractionDigits=0, $minimumFractionDigits=0)
+ {
+ return $this->format($value, $maximumFractionDigits, $minimumFractionDigits);
+ }
+
+ /**
+ * Formats given number as percent value
+ * @param string|int|float $value
+ * @param int $maximumFractionDigits
+ * @param int $minimumFractionDigits
+ * @return mixed|string
+ */
+ public function formatPercent($value, $maximumFractionDigits=0, $minimumFractionDigits=0)
+ {
+ $newValue = trim($value, " \0\x0B%");
+ if (!is_numeric($newValue)) {
+ return $value;
+ }
+ return $this->formatNumberWithPattern($this->patternPercent, $newValue, $maximumFractionDigits, $minimumFractionDigits);
+ }
+
+ /**
+ * Formats the given number with the given pattern
+ *
+ * @param string $pattern
+ * @param string|int|float $value
+ * @param int $maximumFractionDigits
+ * @param int $minimumFractionDigits
+ * @return mixed|string
+ */
+ protected function formatNumberWithPattern($pattern, $value, $maximumFractionDigits=0, $minimumFractionDigits=0)
+ {
+ $orig = $value;
+ if (!is_numeric($value)) {
+ return $value;
+ }
+ // Ensure that the value is positive and has the right number of digits.
+ $negative = (bccomp('0', $value, 12) == 1);
+ $signMultiplier = $negative ? '-1' : '1';
+ $value = bcdiv($value, $signMultiplier, $maximumFractionDigits);
+ // Split the number into major and minor digits.
+ $valueParts = explode('.', $value);
+ $majorDigits = $valueParts[0];
+ // Account for maximumFractionDigits = 0, where the number won't
+ // have a decimal point, and $valueParts[1] won't be set.
+ $minorDigits = isset($valueParts[1]) ? $valueParts[1] : '';
+ if ($this->usesGrouping) {
+ // Reverse the major digits, since they are grouped from the right.
+ $majorDigits = array_reverse(str_split($majorDigits));
+ // Group the major digits.
+ $groups = [];
+ $groups[] = array_splice($majorDigits, 0, $this->primaryGroupSize);
+ while (!empty($majorDigits)) {
+ $groups[] = array_splice($majorDigits, 0, $this->secondaryGroupSize);
+ }
+ // Reverse the groups and the digits inside of them.
+ $groups = array_reverse($groups);
+ foreach ($groups as &$group) {
+ $group = implode(array_reverse($group));
+ }
+ // Reconstruct the major digits.
+ $majorDigits = implode(',', $groups);
+ }
+ if ($minimumFractionDigits < $maximumFractionDigits) {
+ // Strip any trailing zeroes.
+ $minorDigits = rtrim($minorDigits, '0');
+ if (strlen($minorDigits) < $minimumFractionDigits) {
+ // Now there are too few digits, re-add trailing zeroes
+ // until the desired length is reached.
+ $neededZeroes = $minimumFractionDigits - strlen($minorDigits);
+ $minorDigits .= str_repeat('0', $neededZeroes);
+ }
+ }
+ // Assemble the final number and insert it into the pattern.
+ $value = $minorDigits ? $majorDigits . '.' . $minorDigits : $majorDigits;
+ $value = preg_replace('/#(?:[\.,]#+)*0(?:[,\.][0#]+)*/', $value, $pattern);
+ // Localize the number.
+ $value = $this->replaceSymbols($value);
+ return $value;
+ }
+
+
+ /**
+ * Replaces number symbols with their localized equivalents.
+ *
+ * @param string $value The value being formatted.
+ *
+ * @return string
+ *
+ * @see http://cldr.unicode.org/translation/number-symbols
+ */
+ protected function replaceSymbols($value)
+ {
+ $replacements = [
+ '.' => $this->symbolDecimal,
+ ',' => $this->symbolGroup,
+ '+' => $this->symbolPlus,
+ '-' => $this->symbolMinus,
+ '%' => $this->symbolPercent,
+ ];
+ return strtr($value, $replacements);
+ }
+} \ No newline at end of file
diff --git a/core/Twig.php b/core/Twig.php
index 09720eefdd..7267e98fed 100755
--- a/core/Twig.php
+++ b/core/Twig.php
@@ -86,6 +86,7 @@ class Twig
$this->addFilter_percentage();
$this->addFilter_prettyDate();
$this->addFilter_safeDecodeRaw();
+ $this->addFilter_number();
$this->twig->addFilter(new Twig_SimpleFilter('implode', 'implode'));
$this->twig->addFilter(new Twig_SimpleFilter('ucwords', 'ucwords'));
$this->twig->addFilter(new Twig_SimpleFilter('lcfirst', 'lcfirst'));
@@ -272,11 +273,23 @@ class Twig
protected function addFilter_percentage()
{
$percentage = new Twig_SimpleFilter('percentage', function ($string, $totalValue, $precision = 1) {
- return Piwik::getPercentageSafe($string, $totalValue, $precision) . '%';
+ return NumberFormatter::getInstance()->formatPercent(Piwik::getPercentageSafe($string, $totalValue, $precision), $precision);
});
$this->twig->addFilter($percentage);
}
+ protected function addFilter_number()
+ {
+ $formatter = new Twig_SimpleFilter('number', function ($string, $minFractionDigits = 0, $maxFractionDigits = 0) {
+ // if a leading/trailing percent sign is found, format as percent number
+ if ($string != trim($string, '%')) {
+ return NumberFormatter::getInstance()->formatPercent($string, $minFractionDigits, $maxFractionDigits);
+ }
+ return NumberFormatter::getInstance()->format($string, $minFractionDigits, $maxFractionDigits);
+ });
+ $this->twig->addFilter($formatter);
+ }
+
protected function addFilter_truncate()
{
$truncateFilter = new Twig_SimpleFilter('truncate', function ($string, $size) {
diff --git a/plugins/CoreHome/templates/_dataTableCell.twig b/plugins/CoreHome/templates/_dataTableCell.twig
index 40e61541f3..4b42afd9b4 100644
--- a/plugins/CoreHome/templates/_dataTableCell.twig
+++ b/plugins/CoreHome/templates/_dataTableCell.twig
@@ -25,7 +25,7 @@
{% if siteTotal and siteTotal > reportTotal %}
{% set totalPercentage = row.getColumn(column)|percentage(siteTotal, 1) %}
- {% set totalRatioTooltip = 'General_TotalRatioTooltip'|translate(totalPercentage, siteTotal, metricTitle) %}
+ {% set totalRatioTooltip = 'General_TotalRatioTooltip'|translate(totalPercentage, siteTotal|number(2,0), metricTitle) %}
{% else %}
{% set totalRatioTooltip = '' %}
{% endif %}
@@ -41,7 +41,7 @@
{{ piwik.logoHtml(row.getMetadata(), row.getColumn('label')) }}
{% if row.getMetadata('html_label_prefix') %}<span class='label-prefix'>{{ row.getMetadata('html_label_prefix') | raw }}&nbsp;</span>{% endif -%}
{%- if row.getMetadata('html_label_suffix') %}<span class='label-suffix'>{{ row.getMetadata('html_label_suffix') | raw }}</span>{% endif -%}
-{% endif %}<span class="value">{% if row.getColumn(column) %}{{- row.getColumn(column)|raw -}}{% else %}-{% endif %}</span>
+{% endif %}<span class="value">{% if row.getColumn(column) %}{{- row.getColumn(column)|number(2,0)|raw -}}{% else %}-{% endif %}</span>
{% if column=='label' %}</span>{% endif %}
{% if not row.getIdSubDataTable() and column=='label' and row.getMetadata('url') %}
</a>