-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Bulgarian currency transformer. (#169)
* Added Bulgarian currency transformer. * Added Bulgarian currency. * Fixed PSR12 compatibility. Added unit tests for Bulgarian currency transformer. * Updated tests. * Removed not needed plural form in tests. * Fixed currency code in tests. * Test updates. Simplified singular and plural form. Removed unused units. * Updates to PSR12 compliance. * Final touches. * Fixed problem with teens cents in Bulgarian. * Removed spaces. * Updated README.md --------- Co-authored-by: Georgi Angelov <[email protected]>
- Loading branch information
1 parent
cfab3d8
commit bf8e9d9
Showing
10 changed files
with
499 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
namespace NumberToWords\CurrencyTransformer; | ||
|
||
use NumberToWords\Exception\NumberToWordsException; | ||
use NumberToWords\Language\Bulgarian\BulgarianDictionary; | ||
use NumberToWords\Language\Bulgarian\BulgarianExponentInflector; | ||
use NumberToWords\Language\Bulgarian\BulgarianFemaleTripletTransformer; | ||
use NumberToWords\Language\Bulgarian\BulgarianNounGenderInflector; | ||
use NumberToWords\Language\Bulgarian\BulgarianTripletTransformer; | ||
use NumberToWords\NumberTransformer\NumberTransformerBuilder; | ||
use NumberToWords\Service\NumberToTripletsConverter; | ||
use NumberToWords\TransformerOptions\CurrencyTransformerOptions; | ||
|
||
class BulgarianCurrencyTransformer implements CurrencyTransformer | ||
{ | ||
public function toWords(int $amount, string $currency, ?CurrencyTransformerOptions $options = null): string | ||
{ | ||
$dictionary = new BulgarianDictionary(); | ||
$nounGenderInflector = new BulgarianNounGenderInflector(); | ||
$numberToTripletsConverter = new NumberToTripletsConverter(); | ||
$tripletTransformer = new BulgarianTripletTransformer($dictionary); | ||
$femaleTripletTransformer = new BulgarianFemaleTripletTransformer($dictionary); | ||
$exponentInflector = new BulgarianExponentInflector($nounGenderInflector); | ||
|
||
$numberTransformer = (new NumberTransformerBuilder()) | ||
->withDictionary($dictionary) | ||
->withWordsSeparatedBy($dictionary->getSeparator()) | ||
->transformNumbersBySplittingIntoPowerAwareTriplets($numberToTripletsConverter, $tripletTransformer) | ||
->inflectExponentByNumbers($exponentInflector) | ||
->build(); | ||
|
||
$decimal = (int) ($amount / 100); | ||
$fraction = abs($amount % 100); | ||
|
||
if ($fraction === 0) { | ||
$fraction = null; | ||
} | ||
|
||
$currency = strtoupper($currency); | ||
|
||
if (!array_key_exists($currency, BulgarianDictionary::$currencyNames)) { | ||
throw new NumberToWordsException( | ||
sprintf('Currency "%s" is not available for "%s" language', $currency, get_class($this)) | ||
); | ||
} | ||
|
||
$currencyNames = BulgarianDictionary::$currencyNames[$currency]; | ||
|
||
$words = []; | ||
|
||
$words[] = $numberTransformer->toWords($decimal); | ||
$words[] = $nounGenderInflector->inflectNounByNumber( | ||
$decimal, | ||
$currencyNames[0][0], | ||
$currencyNames[0][1], | ||
$currencyNames[0][1], | ||
); | ||
|
||
$words[] = BulgarianDictionary::$and; | ||
if (null !== $fraction) { | ||
$centTransformer = (new NumberTransformerBuilder()) | ||
->withDictionary($dictionary) | ||
->withWordsSeparatedBy($dictionary->getSeparator()) | ||
->transformNumbersBySplittingIntoPowerAwareTriplets( | ||
$numberToTripletsConverter, | ||
$femaleTripletTransformer | ||
) | ||
->inflectExponentByNumbers($exponentInflector) | ||
->build(); | ||
|
||
$words[] = $centTransformer->toWords($fraction); | ||
$words[] = $nounGenderInflector->inflectNounByNumber( | ||
$fraction, | ||
$currencyNames[1][0], | ||
$currencyNames[1][1], | ||
$currencyNames[1][1], | ||
); | ||
} else { | ||
$words[] = $dictionary->getZero(); | ||
$words[] = $currencyNames[1][1]; | ||
} | ||
|
||
return implode(' ', $words); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
<?php | ||
|
||
namespace NumberToWords\Language\Bulgarian; | ||
|
||
use NumberToWords\Language\Dictionary; | ||
|
||
class BulgarianDictionary implements Dictionary | ||
{ | ||
public const LOCALE = 'bg_BG'; | ||
public const LANGUAGE_NAME = 'Bulgarian'; | ||
public const LANGUAGE_NAME_NATIVE = 'български'; | ||
|
||
protected string $zero = "нула"; | ||
protected string $minus = "минус"; | ||
/** Token to separate words in triplets and chunks in final string */ | ||
protected string $separator = " "; | ||
|
||
protected static array $units = ['', 'един', 'два', 'три', 'четири', 'пет', 'шест', 'седем', 'осем', 'девет']; | ||
protected static array $unitsFemale = [ | ||
'', | ||
'една', | ||
'две', | ||
'три', | ||
'четири', | ||
'пет', | ||
'шест', | ||
'седем', | ||
'осем', | ||
'девет', | ||
]; | ||
|
||
protected static array $teens = [ | ||
'десет', | ||
'единадесет', | ||
'дванадесет', | ||
'тринадесет', | ||
'четиринадесет', | ||
'петнадесет', | ||
'шестнадесет', | ||
'седемнадесет', | ||
'осемнадесет', | ||
'деветнадесет' | ||
]; | ||
|
||
protected static array $tens = [ | ||
'', | ||
'десет', | ||
'двадесет', | ||
'тридесет', | ||
'четиридесет', | ||
'петдесет', | ||
'шестдесет', | ||
'седемдесет', | ||
'осемдесет', | ||
'деветдесет' | ||
]; | ||
|
||
private static array $hundreds = [ | ||
0 => '', | ||
1 => 'сто', | ||
2 => 'двеста', | ||
3 => 'триста', | ||
4 => 'четиристотин', | ||
5 => 'петстотин', | ||
6 => 'шестстотин', | ||
7 => 'седемстотин', | ||
8 => 'осемстотин', | ||
9 => 'деветстотин' | ||
]; | ||
|
||
public static string $and = 'и'; | ||
public static array $currencyNames = [ | ||
'ALL' => [['lek'], ['qindarka']], | ||
'AED' => [['Dirham'], ['Fils']], | ||
'AUD' => [['Australian dollar'], ['cent']], | ||
'BAM' => [['convertible marka'], ['fenig']], | ||
'BGN' => [['лев', 'лева'], ['стотинка', 'стотинки']], | ||
'BRL' => [['real'], ['centavos']], | ||
'BYR' => [['Belarussian rouble'], ['kopiejka']], | ||
'CAD' => [['Canadian dollar'], ['cent']], | ||
'CHF' => [['Swiss franc'], ['rapp']], | ||
'CYP' => [['Cypriot pound'], ['cent']], | ||
'CZK' => [['Czech koruna'], ['halerz']], | ||
'DKK' => [['Danish krone'], ['ore']], | ||
'DZD' => [['dinar'], ['cent']], | ||
'EEK' => [['kroon'], ['senti']], | ||
'EGP' => [['Egyptian Pound'], ['piastre']], | ||
'EUR' => [['euro'], ['euro-cent']], | ||
'GBP' => [['pound', 'pounds'], ['pence', 'pence']], | ||
'HKD' => [['Hong Kong dollar'], ['cent']], | ||
'HRK' => [['Croatian kuna'], ['lipa']], | ||
'HUF' => [['forint'], ['filler']], | ||
'ILS' => [['new sheqel', 'new sheqels'], ['agora', 'agorot']], | ||
'ISK' => [['Icelandic króna'], ['aurar']], | ||
'JPY' => [['yen'], ['sen']], | ||
'LTL' => [['litas'], ['cent']], | ||
'LVL' => [['lat'], ['sentim']], | ||
'LYD' => [['dinar'], ['cent']], | ||
'MAD' => [['dirham'], ['cent']], | ||
'MKD' => [['Macedonian dinar'], ['deni']], | ||
'MRO' => [['ouguiya'], ['khoums']], | ||
'MTL' => [['Maltese lira'], ['centym']], | ||
'NGN' => [['Naira'], ['kobo']], | ||
'NOK' => [['Norwegian krone'], ['oere']], | ||
'PHP' => [['peso'], ['centavo']], | ||
'PLN' => [['zloty', 'zlotys'], ['grosz']], | ||
'ROL' => [['Romanian leu'], ['bani']], | ||
'RUB' => [['Russian Federation rouble'], ['kopiejka']], | ||
'SAR' => [['Riyal'], ['Halalah']], | ||
'SEK' => [['Swedish krona'], ['oere']], | ||
'SIT' => [['Tolar'], ['stotinia']], | ||
'SKK' => [['Slovak koruna'], []], | ||
'TMT' => [['manat'], ['tenge']], | ||
'TND' => [['dinar'], ['millime']], | ||
'TRL' => [['lira'], ['kuruş']], | ||
'TRY' => [['lira'], ['kuruş']], | ||
'UAH' => [['hryvna'], ['cent']], | ||
'USD' => [['dollar'], ['cent']], | ||
'XAF' => [['CFA franc'], ['cent']], | ||
'XOF' => [['CFA franc'], ['cent']], | ||
'XPF' => [['CFP franc'], ['centime']], | ||
'YUM' => [['dinar'], ['para']], | ||
'ZAR' => [['rand'], ['cent']], | ||
'UZS' => [['sum'], ['tiyin']], | ||
]; | ||
|
||
public function getSeparator(): string | ||
{ | ||
return $this->separator; | ||
} | ||
|
||
public function getZero(): string | ||
{ | ||
return $this->zero; | ||
} | ||
|
||
public function getMinus(): string | ||
{ | ||
return $this->minus; | ||
} | ||
|
||
public function getCorrespondingUnit(int $unit): string | ||
{ | ||
return self::$units[$unit]; | ||
} | ||
|
||
public function getCorrespondingUnitFemale(int $unit): string | ||
{ | ||
return self::$unitsFemale[$unit]; | ||
} | ||
|
||
public function getCorrespondingTen(int $ten): string | ||
{ | ||
return self::$tens[$ten]; | ||
} | ||
|
||
public function getCorrespondingTeen(int $teen): string | ||
{ | ||
return self::$teens[$teen]; | ||
} | ||
|
||
public function getCorrespondingHundred(int $hundred): string | ||
{ | ||
return self::$hundreds[$hundred]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
namespace NumberToWords\Language\Bulgarian; | ||
|
||
use NumberToWords\Language\ExponentInflector; | ||
|
||
class BulgarianExponentInflector implements ExponentInflector | ||
{ | ||
protected static array $exponent = [ | ||
['', ''], | ||
['хиляда', 'хиляди'], | ||
['милион', 'милиона'], | ||
['милиард', 'милиарда'], | ||
['трилион', 'трилиона'], | ||
['квадрилион', 'квадрилиона'], | ||
['квинтилион', 'квинтилиона'], | ||
['секстилион', 'секстилиона'], | ||
['септилион', 'септилиона'], | ||
['октилион', 'октилиона'], | ||
['ноналион', 'ноналиона'], | ||
['декалион', 'декалиона'], | ||
['ундекалион', 'ундекалиона'], | ||
['дуодекалион', 'дуодекалиона'], | ||
['тредекалион', 'тредекалиона'], | ||
['кватордекалион', 'кватордекалиона'], | ||
['квинтдекалион', 'квинтдекалиона'], | ||
['сексдекалион', 'сексдекалиона'], | ||
['септдекалион', 'септдекалиона'], | ||
['октодекалион', 'октодекалиона'], | ||
['новемдекалион', 'новемдекалиона'], | ||
['вигинтилион', 'вигинтилион'], | ||
]; | ||
|
||
protected BulgarianNounGenderInflector $inflector; | ||
|
||
public function __construct(BulgarianNounGenderInflector $inflector) | ||
{ | ||
$this->inflector = $inflector; | ||
} | ||
|
||
public function inflectExponent(int $number, int $power): string | ||
{ | ||
return $this->inflector->inflectNounByNumber( | ||
$number, | ||
self::$exponent[$power][0], | ||
self::$exponent[$power][1], | ||
self::$exponent[$power][1], | ||
); | ||
} | ||
} |
40 changes: 40 additions & 0 deletions
40
src/Language/Bulgarian/BulgarianFemaleTripletTransformer.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<?php | ||
|
||
namespace NumberToWords\Language\Bulgarian; | ||
|
||
/** | ||
* Class used only for getting the proper translation of the cents-values to words. | ||
* It was needed, because in Bulgarian, the main unit ("лев") and the cent-unit ("стотинка") are of different gender. | ||
*/ | ||
class BulgarianFemaleTripletTransformer extends BulgarianTripletTransformer | ||
{ | ||
public function transformToWords(int $number, int $power): string | ||
{ | ||
$units = $number % 10; | ||
$tens = (int) ($number / 10) % 10; | ||
$hundreds = (int) ($number / 100) % 10; | ||
$words = []; | ||
|
||
if ($hundreds > 0) { | ||
$words[] = $this->dictionary->getCorrespondingHundred($hundreds); | ||
} | ||
|
||
if ($tens === 1) { | ||
$words[] = $this->dictionary->getCorrespondingTeen($units); | ||
} | ||
|
||
if ($tens > 1) { | ||
$words[] = $this->dictionary->getCorrespondingTen($tens); | ||
} | ||
|
||
if ($units > 0 && ($hundreds > 0 || $tens > 1)) { | ||
$words[] = BulgarianDictionary::$and; | ||
} | ||
|
||
if ($tens != 1) { | ||
$words[] = $this->dictionary->getCorrespondingUnitFemale($units); | ||
} | ||
|
||
return implode($this->dictionary->getSeparator(), $words); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
namespace NumberToWords\Language\Bulgarian; | ||
|
||
class BulgarianNounGenderInflector | ||
{ | ||
public function inflectNounByNumber(int $number, string $singular, string $plural, string $genitivePlural): string | ||
{ | ||
if ($number === 1) { | ||
return $singular; | ||
} | ||
|
||
return $plural; | ||
} | ||
} |
Oops, something went wrong.