kwn/number-to-words

View on GitHub
src/Legacy/Numbers/Words/Locale/Ru.php

Summary

Maintainability
D
1 day
Test Coverage
C
75%
<?php

namespace NumberToWords\Legacy\Numbers\Words\Locale;

use NumberToWords\Exception\NumberToWordsException;
use NumberToWords\Legacy\Numbers\Words;

class Ru extends Words
{
    const LOCALE = 'ru';
    const LANGUAGE_NAME = 'Russian';
    const LANGUAGE_NAME_NATIVE = 'Русский';
    const MINUS = 'минус';

    const MALE = 0;
    const FEMALE = 1;
    const NEUTER = 2;

    protected $zero = 'ноль';

    protected static $ten = [
        ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять'],
        ['', 'одна', 'две', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять'],
    ];

    protected static $teens = [
        'десять',
        'одиннадцать',
        'двенадцать',
        'тринадцать',
        'четырнадцать',
        'пятнадцать',
        'шестнадцать',
        'семнадцать',
        'восемнадцать',
        'девятнадцать',
    ];

    protected static $tens = [
        2 => 'двадцать',
        'тридцать',
        'сорок',
        'пятьдесят',
        'шестьдесят',
        'семьдесят',
        'восемьдесят',
        'девяносто',
    ];

    protected static $hundred = [
        '',
        'сто',
        'двести',
        'триста',
        'четыреста',
        'пятьсот',
        'шестьсот',
        'семьсот',
        'восемьсот',
        'девятьсот',
    ];

    protected static $mega = [
        [3 => self::FEMALE],
        [3 => self::MALE],
        ['тысяча', 'тысячи', 'тысяч', self::FEMALE],
        ['миллион', 'миллиона', 'миллионов', self::MALE],
        ['миллиард', 'милиарда', 'миллиардов', self::MALE],
        ['триллион', 'триллиона', 'триллионов', self::MALE],
        ['квадриллион', 'квадриллиона', 'квадриллионов', self::MALE],
        ['секстиллион', 'секстиллиона', 'секстиллионов', self::MALE],
    ];


    protected static $currencyNames = [
        'ALL' => [
            [1, 'лек', 'лека', 'леков'],
            [2, 'киндарка', 'киндарки', 'киндарок']
        ],
        'AUD' => [
            [1, 'австралийский доллар', 'австралийских доллара', 'австралийских долларов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'BGN' => [
            [1, 'лев', 'лева', 'левов'],
            [2, 'стотинка', 'стотинки', 'стотинок']
        ],
        'BRL' => [
            [1, 'бразильский реал', 'бразильских реала', 'бразильских реалов'],
            [1, 'сентаво', 'сентаво', 'сентаво']
        ],
        'BYN' => [
            [1, 'белорусский рубль', 'белорусских рубля', 'белорусских рублей'],
            [2, 'копейка', 'копейки', 'копеек']
        ],
        'BYR' => [
            [1, 'белорусский рубль', 'белорусских рубля', 'белорусских рублей'],
            [2, 'копейка', 'копейки', 'копеек']
        ],
        'CAD' => [
            [1, 'канадский доллар', 'канадских доллара', 'канадских долларов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'CHF' => [
            [1, 'швейцарский франк', 'швейцарских франка', 'швейцарских франков'],
            [1, 'сантим', 'сантима', 'сантимов']
        ],
        'CNY' => [
            [1, 'китайский юань', 'китайских юаня', 'китайских юаней'],
            [1, 'фынь', 'фыня', 'фыней']
        ],
        'CYP' => [
            [1, 'кипрский фунт', 'кипрских фунта', 'кипрских фунтов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'CZK' => [
            [2, 'чешская крона', 'чешских кроны', 'чешских крон'],
            [1, 'галирж', 'галиржа', 'галиржей']
        ],
        'DKK' => [
            [2, 'датская крона', 'датских кроны', 'датских крон'],
            [1, 'эре', 'эре', 'эре']
        ],
        'EEK' => [
            [2, 'эстонская крона', 'эстонских кроны', 'эстонских крон'],
            [1, 'сенти', 'сенти', 'сенти']
        ],
        'EUR' => [
            [1, 'евро', 'евро', 'евро'],
            [1, 'цент', 'цента', 'центов']
        ],
        'GBP' => [
            [1, 'фунт стерлингов', 'фунта стерлингов', 'фунтов стерлингов'],
            [1, 'пенс', 'пенса', 'пенсов']
        ],
        'HKD' => [
            [1, 'гонконгский доллар', 'гонконгских доллара', 'гонконгских долларов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'HRK' => [
            [2, 'хорватская куна', 'хорватских куны', 'хорватских кун'],
            [2, 'липа', 'липы', 'лип']
        ],
        'HUF' => [
            [1, 'венгерский форинт', 'венгерских форинта', 'венгерских форинтов'],
            [1, 'филлер', 'филлера', 'филлеров']
        ],
        'IRR' => [
            [1, 'иранский риал', 'иранских риала', 'иранских риалов'],
            [1, 'динар', 'динара', 'динаров']
        ],
        'ISK' => [
            [2, 'исландская крона', 'исландских кроны', 'исландских крон'],
            [1, 'эре', 'эре', 'эре']
        ],
        'JPY' => [
            [2, 'иена', 'иены', 'иен'],
            [2, 'сена', 'сены', 'сен']
        ],
        'KGS' => [
            [1, 'киргизский сом', 'киргизских сома', 'киргизских сомов'],
            [1, 'тыйын', 'тыйына', 'тыйынов']
        ],
        'KZT' => [
            [0, 'казахский тенге', 'казахских тенге', 'казахских тенге'],
            [1, 'тиын', 'тиына', 'тиынов']
        ],
        'KWD' => [
            [1, 'кувейтский динар', 'кувейтских динара', 'кувейтских динаров'],
            [1, 'филс', 'филса', 'филсов']
        ],
        'LTL' => [
            [1, 'лит', 'лита', 'литов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'LVL' => [
            [1, 'лат', 'лата', 'латов'],
            [1, 'сентим', 'сентима', 'сентимов']
        ],
        'MDL' => [
            [1, 'молдавский лей', 'молдавских лея', 'молдавских леев'],
            [1, 'бань', 'баня', 'баней']
        ],
        'MKD' => [
            [1, 'македонский динар', 'македонских динара', 'македонских динаров'],
            [1, 'дени', 'дени', 'дени']
        ],
        'MTL' => [
            [2, 'мальтийская лира', 'мальтийских лиры', 'мальтийских лир'],
            [1, 'сентим', 'сентима', 'сентимов']
        ],
        'NOK' => [
            [2, 'норвежская крона', 'норвежских кроны', 'норвежских крон'],
            [0, 'эре', 'эре', 'эре']
        ],
        'NZD' => [
            [1, 'новозеландский доллар', 'новозеландских доллара', 'новозеландских долларов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'PLN' => [
            [1, 'злотый', 'злотых', 'злотых'],
            [1, 'грош', 'гроша', 'грошей']
        ],
        'ROL' => [
            [1, 'румынский лей', 'румынских лей', 'румынских лей'],
            [1, 'бани', 'бани', 'бани']
        ],
        'RUB' => [
            [1, 'рубль', 'рубля', 'рублей'],
            [2, 'копейка', 'копейки', 'копеек']
        ],
        'RUR' => [
            [1, 'российский рубль', 'российских рубля', 'российских рублей'],
            [2, 'копейка', 'копейки', 'копеек']
        ],
        'SEK' => [
            [2, 'шведская крона', 'шведских кроны', 'шведских крон'],
            [1, 'эре', 'эре', 'эре']
        ],
        'SGD' => [
            [1, 'сингапурский доллар', 'сингапурских доллара', 'сингапурских долларов'],
            [1, 'цент', 'цента', 'центов']
        ],
        'SIT' => [
            [1, 'словенский толар', 'словенских толара', 'словенских толаров'],
            [2, 'стотина', 'стотины', 'стотин']
        ],
        'SKK' => [
            [2, 'словацкая крона', 'словацких кроны', 'словацких крон'],
            [0, '', '', '']
        ],
        'TRL' => [
            [2, 'турецкая лира', 'турецких лиры', 'турецких лир'],
            [1, 'пиастр', 'пиастра', 'пиастров']
        ],
        'TRY' => [
            [2, 'турецкая лира', 'турецкие лиры', 'турецких лир'],
            [1, 'куруш', 'куруша', 'курушей']
        ],
        'TMT' => [
            [1, 'манат', 'маната', 'манатов'],
            [1, 'тенге', 'тенге', 'тенге']
        ],
        'UAH' => [
            [2, 'гривна', 'гривны', 'гривен'],
            [2, 'копейка', 'копейки', 'копеек'],
        ],
        'USD' => [
            [1, 'доллар США', 'доллара США', 'долларов США'],
            [1, 'цент', 'цента', 'центов']
        ],
        'UZS' => [
            [1, 'сум', 'сума', 'сумов'],
            [1, 'тийин', 'тийина', 'тийинов'],
        ],
        'YUM' => [
            [1, 'югославский динар', 'югославских динара', 'югославских динаров'],
            [1, 'пара', 'пара', 'пара']
        ],
        'ZAR' => [
            [1, 'ранд', 'ранда', 'рандов'],
            [1, 'цент', 'цента', 'центов']
        ]
    ];

    /**
     * @param int $n
     * @param string $f1
     * @param string $f2
     * @param string $f5
     *
     * @return string
     */
    public function morph($n, $f1, $f2, $f5)
    {
        $n = abs((int) $n) % 100;
        if ($n > 10 && $n < 20) {
            return $f5;
        }
        $n = $n % 10;
        if ($n > 1 && $n < 5) {
            return $f2;
        }
        if ($n == 1) {
            return $f1;
        }

        return $f5;
    }

    /**
     * @param int $number
     * @param int $currencyGender
     *
     * @return string
     */
    protected function toWords($number, $currencyGender = -1)
    {
        if ($number === 0) {
            return $this->zero;
        }

        $out = [];

        if ($number < 0) {
            $out[] = static::MINUS;
            $number *= -1;
        }

        $megaSize = count(static::$mega);
        $signs = $megaSize * 3;

        // $signs equal quantity of zeros of the biggest number in self::$mega
        // + 3 additional sign (point and two zero)
        [$unit, $subunit] = explode('.', sprintf("%{$signs}.2F", (float) $number));

        foreach (str_split($unit, 3) as $megaKey => $value) {
            if (!(int) $value) {
                continue;
            }

            $megaKey = $megaSize - $megaKey - 1;
            $gender = $megaKey === 1 && $currencyGender !== -1 ? $currencyGender : static::$mega[$megaKey][3];
            [$i1, $i2, $i3] = array_map('intval', str_split($value, 1));
            // mega-logic
            $out[] = static::$hundred[$i1]; # 1xx-9xx

            if ($i2 > 1) { # 20-99
                $out[] = static::$tens[$i2] . ' ' . static::$ten[$gender][$i3];
            } else { # 10-19 | 1-9
                $out[] = ($i2 > 0) ? static::$teens[$i3] : static::$ten[$gender][$i3];
            }

            if ($megaKey > 1) {
                $out[] = $this->morph(
                    $value,
                    static::$mega[$megaKey][0],
                    static::$mega[$megaKey][1],
                    static::$mega[$megaKey][2]
                );
            }
        }

        return trim(preg_replace('/\s+/', ' ', implode(' ', $out)));
    }

    /**
     * @param string $currency
     * @param int $decimal
     * @param int $fraction
     *
     * @return string
     * @throws NumberToWordsException
     */
    public function toCurrencyWords($currency, $decimal, $fraction = null)
    {
        $currency = strtoupper($currency);

        if (!array_key_exists($currency, static::$currencyNames)) {
            throw new NumberToWordsException(
                sprintf('Currency "%s" is not available for "%s" language', $currency, get_class($this))
            );
        }

        $currencyNames = static::$currencyNames[$currency];
        $return = '';

        if ($decimal === 0 && !$fraction) {
            $return .= $this->toWords($decimal) . ' ' . $this->morph(
                    $decimal,
                    $currencyNames[0][1],
                    $currencyNames[0][2],
                    $currencyNames[0][3]
                );

            return $return;
        }

        if ($decimal || (0 === $decimal && $this->options->isShowDecimalIfZero())) {
            $return .= $this->toWords($decimal, $currencyNames[0][0] - 1) . ' ' . $this->morph(
                    $decimal,
                    $currencyNames[0][1],
                    $currencyNames[0][2],
                    $currencyNames[0][3]
                );
        }

        if (null !== $fraction) {
            if ($this->options->isConvertFraction()) {
                $return .= ' ' . $this->toWords($fraction, $currencyNames[1][0] - 1) . ' ' . $this->morph(
                        $fraction,
                        $currencyNames[1][1],
                        $currencyNames[1][2],
                        $currencyNames[1][3]
                    );
            } else {
                $return .= ' ' . $fraction . ' ' . $this->morph(
                        $fraction,
                        $currencyNames[1][1],
                        $currencyNames[1][2],
                        $currencyNames[1][3]
                    );
            }
        }

        if (null === $fraction && $this->options->isShowFractionIfZero()) {
            if ($this->options->isConvertFractionIfZero()) {
                $return .= ' ' . $this->zero . ' ' . $this->morph(
                        $fraction,
                        $currencyNames[1][1],
                        $currencyNames[1][2],
                        $currencyNames[1][3]
                    );
            } else {
                $return .= ' 00 ' . $this->morph(
                        $fraction,
                        $currencyNames[1][1],
                        $currencyNames[1][2],
                        $currencyNames[1][3]
                    );
            }
        }

        return $return;
    }
}