/** * Spell a number. * * @param int $number Number to spelling. * @param string $type Tye type of spelling. * * @return string */ public function spell($number, $type = self::SPELLING_NUMBER) { // Split numbers in lands (eg. *100.000* should be [ 0, 100 ]) $numberLands = static::getNumberLands($number); $numberLandsSpelled = []; // Process each number lands and get a raw spelled term. // Eg. *1.002* should be (reversed) [ 'two', 'one' ]. foreach ($numberLands as $numberLandKey => $numberLand) { // Process the number in current land, getting it simplified spelling. $numberLandSpelled = $this->locale->simple($numberLands[$numberLandKey]); // Numbers that can't be spelled naturally should be ignored. // A good example is *zero*, that will be processed only on formatter. if ($numberLandSpelled === null) { continue; } // Store the spelled number in the current land. $numberLandsSpelled[$numberLandKey] = $numberLandSpelled; } /** @var int[] $numberLands */ return $this->locale->format($this->locale, $numberLandsSpelled, $numberLands, $type); }
/** * Format the number lands to spelling. * * @param Locale $locale The locale used to spell numbers. * @param string[] $numberLandsSpelled The number lands spelled. * @param int[] $numberLands The original number lands (as integer). * @param string $spellingType The spelling type. * * @return null|string */ public function format($locale, $numberLandsSpelled, $numberLands, $spellingType) { if (!$numberLandsSpelled) { // If no lands, then spells zero. return $this->formatType($this->options->zeroSpell, 0, $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } $numberLandsCount = count($numberLandsSpelled); if ($numberLandsCount === 1 && array_key_exists('0', $numberLandsSpelled)) { // Simple spell with only the first land (1 to 999). return $this->formatType($numberLandsSpelled[0], $numberLands[0], $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } // Reprocess all lands, applying the suffixes. $numberLandsKeys = array_keys($numberLandsSpelled); foreach ($numberLandsKeys as $numberLandsKey) { if ($numberLandsKey === 1) { if ($this->options->includeOneThousand !== true && $numberLands[$numberLandsKey] === 1) { // Exclusively for the one thousand, just use suffix (*um mil* to *mil*). $numberLandsSpelled[$numberLandsKey] = $this->options->thousandSpell; continue; } // Else, just append the thousand suffix (*dois* to *dois mil*). $numberLandsSpelled[$numberLandsKey] .= ' ' . $this->options->thousandSpell; continue; } if ($numberLandsKey >= 2) { // Numbers over one million. // Stores the million root (eg. *milh*) and the million suffix (eg. *ões*). // Together it'll be *milhões* if number is over 2 millions. $millionRoot = $this->options->millionRoots[$numberLandsKey - 2]; $millionSuffix = $this->options->millionSuffixes[$numberLands[$numberLandsKey] >= 2]; $numberLandsSpelled[$numberLandsKey] .= ' ' . $millionRoot . $millionSuffix; continue; } if ($numberLandsKey === -1) { // Consider decimals ten times less. $numberLandsSpelled[$numberLandsKey] = $locale->simple($numberLands[$numberLandsKey] / 10); continue; } } // Currency: if decimal was defined, so we get it first. $numberLandsDecimal = null; if (array_key_exists('-1', $numberLandsSpelled)) { $numberLandsCount--; $numberLandsDecimal = $this->formatType($numberLandsSpelled[-1], $numberLands[-1] / 10, $numberLandsSpelled, Count::SIDE_DECIMAL, $spellingType); unset($numberLands[-1], $numberLandsSpelled[-1]); } // If there are just one land, just return it. // Currency: it's always pluralized because numbers where is always greater or equal to one thousand. $numberResult = null; if ($numberLandsCount === 1) { $numberResult = $this->formatType(reset($numberLandsSpelled), 2, $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } else { if ($numberLandsCount > 1) { // If the first land is equal or lower than 100, the result will be treated differently. // Or if the first land is divisible by 100 (eg. *200*, but not *201*). // In this case, it'll group the last land by *e* instead of comma. $numberLandsFirst = reset($numberLands); if ($numberLandsFirst <= 100 || $numberLandsFirst % 100 === 0) { $numberLandsReverse = array_reverse($numberLandsSpelled); $numberResult = implode($this->options->defaultSeparator ?: ' ', array_slice($numberLandsReverse, 0, -1)) . ($this->options->lastSeparator ?: ' ') . end($numberLandsReverse); } else { // Else, just implode all by comma. $numberResult = implode($this->options->defaultSeparator ?: ' ', array_reverse($numberLandsSpelled)); } // Compose the integer result. $numberResult = $this->formatType($numberResult, 2, $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } } // Currency: if decimals exists, just append it to result. if ($numberLandsDecimal) { if ($numberResult) { $numberResult .= $this->options->currencyDecimalSeparator; } $numberResult .= $numberLandsDecimal; } return $numberResult; }
/** * Teste LocaleUnsupportedException exception. * * @expectedException \Rentalhost\VanillaCount\Exception\LocaleUnsupportedException */ public function testLocaleUnsupportedException() { Locale::getLocale('unknowLocale'); }
/** * Format the number lands to spelling. * * @param Locale $locale The locale used to spell numbers. * @param string[] $numberLandsSpelled The number lands spelled. * @param int[] $numberLands The original number lands (as integer). * @param string $spellingType The spelling type. * * @return null|string */ public function format($locale, $numberLandsSpelled, $numberLands, $spellingType) { if (!$numberLandsSpelled) { // If no lands, then spells zero. return $this->formatType($this->options->zeroSpell, 0, $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } $numberLandsCount = count($numberLandsSpelled); if ($numberLandsCount === 1 && array_key_exists('0', $numberLandsSpelled)) { // If current number value is over 100 and starts with 1, we should apply first one identifier. if ($this->options->firstOneIdentifier !== 'one' && $numberLands[0] >= 100 && strpos($numberLands[0], '1') === 0) { $numberLandsSpelled[0] = str_replace('one ', $this->options->firstOneIdentifier ? $this->options->firstOneIdentifier . ' ' : null, $numberLandsSpelled[0]); } // Simple spell with only the first land (1 to 999). return $this->formatType($numberLandsSpelled[0], $numberLands[0], $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } /** @var int $numberLandsKey */ // Reprocess all lands, applying the suffixes. end($numberLandsSpelled); $numberLandsKeysLast = key($numberLandsSpelled); $numberLandsKeys = array_keys($numberLandsSpelled); foreach ($numberLandsKeys as $numberLandsKey) { // Numbers over one thousand. if ($numberLandsKey >= 1) { // If current number value is one and is the first one spelled, // we should apply the first one identifier option. if ($numberLandsKey === $numberLandsKeysLast && $numberLands[$numberLandsKey] === 1) { $numberLandsSpelled[$numberLandsKey] = ($this->options->firstOneIdentifier ? $this->options->firstOneIdentifier . ' ' : null) . $this->options->highSpells[$numberLandsKey - 1]; continue; } $numberLandsSpelled[$numberLandsKey] .= ' ' . $this->options->highSpells[$numberLandsKey - 1]; continue; } // Consider decimals ten times less. if ($numberLandsKey === -1) { $numberLandsSpelled[$numberLandsKey] = $locale->simple($numberLands[$numberLandsKey] / 10); continue; } } // Currency: if decimal was defined, so we get it first. $numberLandsDecimal = null; if (array_key_exists('-1', $numberLandsSpelled)) { $numberLandsCount--; $numberLandsDecimal = $this->formatType($numberLandsSpelled[-1], $numberLands[-1] / 10, $numberLandsSpelled, Count::SIDE_DECIMAL, $spellingType); unset($numberLands[-1], $numberLandsSpelled[-1]); } // If there are just one land, just return it. // Currency: it's always pluralized because numbers where is always greater or equal to one thousand. $numberResult = null; if ($numberLandsCount === 1) { $numberResult = $this->formatType(reset($numberLandsSpelled), 2, $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } else { if ($numberLandsCount > 1) { // If the first land is equal or lower than 100, the result will be treated differently. // Or if the first land is divisible by 100 (eg. *200*, but not *201*). // In this case, it'll group the last land by *e* instead of comma. $numberLandsFirst = reset($numberLands); if ($numberLandsFirst <= 100 || $numberLandsFirst % 100 === 0) { $numberLandsReverse = array_reverse($numberLandsSpelled); $numberResult = implode($this->options->defaultSeparator ?: ' ', array_slice($numberLandsReverse, 0, -1)) . ($this->options->lastSeparator ?: ' ') . end($numberLandsReverse); } else { // Else, just implode all by comma. $numberResult = implode($this->options->defaultSeparator ?: ' ', array_reverse($numberLandsSpelled)); } // Compose the integer result. $numberResult = $this->formatType($numberResult, 2, $numberLandsSpelled, Count::SIDE_INTEGER, $spellingType); } } // Currency: if decimals exists, just append it to result. if ($numberLandsDecimal) { if ($numberResult) { $numberResult .= $this->options->currencyDecimalSeparator ?: ' '; } $numberResult .= $numberLandsDecimal; } return $numberResult; }