plugins/common/classes/common/yf_common_num2string.class.php
<?php
class yf_common_num2string
{
protected $_lang_id = null;
protected $_currency_id = null;
// gender: 0 - male; 1 - female;
protected $words = [
'RU' => [
'currency' => [
'UAH' => [
['копейка', 'копейки', 'копеек', 1],
['гривна', 'гривни', 'гривен', 1],
],
'RUB' => [
['копейка', 'копейки', 'копеек', 1],
['рубль', 'рубля', 'рублей', 0],
],
'USD' => [
['цент', 'цента', 'центов', 0],
['доллар', 'доллара', 'долларов', 0],
],
'EUR' => [
['цент', 'цента', 'центов', 0],
['евро', 'евро', 'евро', 0],
],
],
'units' => [
[],
[],
['тысяча', 'тысячи', 'тысяч', 1],
['миллион', 'миллиона', 'миллионов', 0],
['миллиард', 'милиарда', 'миллиардов', 0],
['триллион', 'триллиона', 'триллионов', 0],
],
'zero' => 'ноль',
'signs' => ['плюс', 'минус'],
'digits' => [
// 1-9
[
[null, 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять'],
[null, 'одна', 'две', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять'],
],
// 10-19
['десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать'],
// 20-99
[null, null, 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто'],
// 1xx-9xx
[null, 'сто', 'двести', 'триста', 'четыреста', 'пятьсот', 'шестьсот', 'семьсот', 'восемьсот', 'девятьсот'],
],
],
'UA' => [
'currency' => [
'UAH' => [
['копійка', 'копійки', 'копійок', 1],
['гривня', 'гривні', 'гривень', 1],
],
'RUB' => [
['копійка', 'копійки', 'копійок', 1],
['рубль', 'рубля', 'рублів', 0],
],
'USD' => [
['цент', 'цента', 'центів', 0],
['долар', 'долара', 'доларів', 0],
],
'EUR' => [
['цент', 'цента', 'центів', 0],
['євро', 'євро', 'євро', 0],
],
],
'units' => [
[],
[],
['тисяча', 'тисячі', 'тисяч', 1],
['мільйон', 'мільйона', 'мільйонів', 0],
['мільярд', 'мільярда', 'мільярдів', 0],
['трильйон', 'трильйона', 'трильйонів', 0],
],
'zero' => 'нуль',
'signs' => ['плюс', 'мінус'],
'digits' => [
// 1-9
[
[null, 'один', 'два', 'три', 'чотири', 'п`ять', 'шість', 'сім', 'вісім', 'дев`ять'],
[null, 'одна', 'дві', 'три', 'чотири', 'п`ять', 'шість', 'сім', 'вісім', 'дев`ять'],
],
// 10-19
['десять', 'одиннадцять', 'дванадцать', 'тринадцать', 'чотирнадцать', 'п`ятнадцать', 'шістнадцять', 'сімнадцять', 'вісімнадцять', 'дев`ятнадцать'],
// 20-99
[null, null, 'двадцять', 'тридцять', 'сорок', 'п`ятьдесят', 'шістдесят', 'сімідесят', 'вісімдесят', 'дев`яносто'],
// 1xx-9xx
[null, 'сто', 'двісті', 'триста', 'чотиреста', 'п`ятьсот', 'шістсот', 'сімсот', 'вісімсот', 'дев`ятсот'],
],
],
'EN' => [
'currency' => [
'UAH' => [
['kopeck', 'kopecks', 'kopecks', 1],
['grivna', 'grivnas', 'grivnas', 1],
],
'RUB' => [
['kopeck', 'kopecks', 'kopecks', 1],
['rouble', 'roubles', 'roubles', 0],
],
'USD' => [
['cent', 'cents', 'cents', 0],
['dollar', 'dollars', 'dollars', 0],
],
'EUR' => [
['cent', 'cents', 'cents', 0],
['euro', 'euros', 'euros', 0],
],
],
'units' => [
[],
[],
['thousand', 'thousands', 'thousands', 1],
['million', 'millions', 'millions', 0],
['billion', 'milliards', 'billions', 0],
['trillion', 'trillions', 'trillions', 0],
],
'zero' => 'zero',
'signs' => ['plus', 'minus'],
'digits' => [
// 1-9
[
[null, 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'],
[null, 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'],
],
// 10-19
['ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'],
// 20-99
[null, null, 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'],
// 1xx-9xx
[null, 'one hundred', 'two hundred', 'three hundred', 'four hundred', 'five hundred', 'six hundred', 'seven hundred', 'eight hundred', 'nine hundred'],
],
],
];
protected $_sign_force = false;
protected $_cent_zero_force = true;
protected $_cent_number_force = true;
public function _init()
{
$_lang_id = &$this->_lang_id;
$_currency_id = &$this->_currency_id;
$words = &$this->words;
// set as default: first lang, currency from words options
$_lang_id = current(array_keys($words));
$_currency_id = current(array_keys($words[$_lang_id]['currency']));
}
public function lang_id($lang_id = null, $set = true)
{
$_lang_id = &$this->_lang_id;
if (empty($lang_id)) {
$result = $_lang_id;
} else {
$words = &$this->words;
$result = strtoupper($lang_id);
$result = isset($words[$result]) ? $result : $_lang_id;
$set && $_lang_id = $result;
}
return $result;
}
public function currency_id($currency_id = null, $set = true)
{
$_lang_id = $this->lang_id();
$_currency_id = &$this->_currency_id;
$currency = &$this->words[$_lang_id]['currency'];
if (empty($currency_id)) {
$result = $_currency_id;
} else {
$result = strtoupper($currency_id);
$result = isset($currency[$result]) ? $result : $_currency_id;
$set && $_currency_id = $result;
}
return $result;
}
public function sign($force = null)
{
if ($force === null) {
$result = $this->_sign_force;
} else {
$result = (bool) $force;
$this->_sign_force = $result;
}
return $result;
}
public function cent_number($force = null)
{
if ($force === null) {
$result = $this->_cent_number_force;
} else {
$result = (bool) $force;
$this->_cent_number_force = $result;
}
return $result;
}
public function cent_zero($force = null)
{
if ($force === null) {
$result = $this->_cent_zero_force;
} else {
$result = (bool) $force;
$this->_cent_zero_force = $result;
}
return $result;
}
/**
* Returns number to words for money (number spelling).
* @param mixed $float
* @param null|mixed $currency_id
* @param null|mixed $lang_id
* @param mixed $set
*/
public function num2str($float, $currency_id = null, $lang_id = null, $set = false)
{
$lang_id = $this->lang_id($lang_id, $set);
$currency_id = $this->currency_id($currency_id, $set);
$words = &$this->words[$lang_id];
$digits = &$words['digits'];
$signs = &$words['signs'];
$units = &$words['units'];
// prepare options
$sign_force = $this->sign();
$cent_number_force = $this->cent_number();
$cent_zero_force = $this->cent_zero();
$units[0] = &$words['currency'][$currency_id][0];
$units[1] = &$words['currency'][$currency_id][1];
// separate float on sign, integer, fractional
$result = [];
$number = trim((float) $float);
// trim fractional by 2 digits
$number_format = localeconv();
$decimal_point = $number_format['decimal_point'];
// $thousands_sep = $number_format[ 'thousands_sep' ];
$thousands_sep = [' ', '.', ',', "'", '`'];
list($part1, $part2) = explode($decimal_point, $number);
$part2 = substr($part2 . '00', 0, 2);
$number = str_replace($thousands_sep, '', $part1) . '0' . $part2;
// add sign word
$sign_minus = substr($number, 0, 1) == '-';
// minus
$sign_minus && $result[] = $signs[1];
// plus
! $sign_minus > 0 && $sign_force && $result[] = $signs[0];
// remove sign
$sign_minus && $number = substr($number, 1);
// format number by 3 digits
while (strlen($number) % 3) {
$number = '0' . $number;
}
// processing number digits
$digits_array = str_split($number, 3);
$units_count = count((array) $digits_array) - 1;
foreach ($digits_array as $unit => $digits3) {
$unit = $units_count - $unit;
// skip zero if not dollar or cent
if ((int) $digits3 == 0 && ($unit > 1 || ! ($cent_zero_force || $unit))) {
continue;
}
if ($unit < 2 && ! (int) $digits3) {
// zero if dollar or cent
$result[] = $cent_number_force && ! $unit ? 0 : $words['zero'];
} else {
if ($cent_number_force && ! $unit) {
// cent as int
$result[] = (int) $digits3;
} else {
// separate by 1 digit
$d3 = substr($digits3, 0, 1);
$d2 = substr($digits3, 1, 1);
$d1 = substr($digits3, 2, 1);
// 1xx-9xx
if ($d3 > 0) {
$result[] = $digits[3][$d3];
}
// 20-99
if ($d2 > 1) {
$result[] = $digits[2][$d2];
}
// 10-19
if ($d2 == 1) {
$result[] = $digits[1][$d1];
}
// 1-9
if ($d1 > 0 && $d2 != 1) {
$gender = $units[$unit][3];
if ($gender > -1) {
$result[] = $digits[0][$gender][$d1];
}
}
}
}
$result[] = $this->morph($digits3, $units[$unit]);
}
$result = implode(' ', $result);
return $result;
}
/**
* Bow word form.
* @param mixed $n
* @param mixed $unit
*/
protected function morph($n, $unit)
{
$n = abs((int) $n) % 100;
if ($n > 10 && $n < 20) {
return $unit[2];
}
$n = $n % 10;
if ($n > 1 && $n < 5) {
return $unit[1];
}
if ($n == 1) {
return $unit[0];
}
return $unit[2];
}
}