-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Complete rework. Languages separated in their own classes. Added deci…
…mal part spelling configuration options.
- Loading branch information
Showing
8 changed files
with
982 additions
and
779 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,13 +1,12 @@ | ||
numbers2words | ||
============= | ||
This class is meant for general-purpose number to word conversion for use in, e.g. some documents. | ||
This class is meant for general-purpose number to word conversion for use in, e.g. legal documents, bills. | ||
Currently the supported languages include Latvian ('lv'), Russian ('ru'), English ('en'), Lithuanian ('lt') and Spanish ('es'). | ||
The class doesn't have a method for outputting correct currency names, that's in the TODO list. | ||
|
||
Usage: | ||
```php | ||
NumberConversion::numberToWords(123, 'ru'); | ||
NumberConversion::spellNumber(123, 'ru'); | ||
// output: сто двадцать три | ||
NumberConversion::currencyToWords(123.45, 'en', 'USD'); | ||
NumberConversion::spellCurrency(123.45, 'en', 'USD', true, true); | ||
// output: one hundred and twenty three dollars and forty five cents | ||
``` |
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,126 @@ | ||
<?php | ||
namespace languages; | ||
|
||
final class English extends \NumberConversion | ||
{ | ||
protected $minus = 'minus'; | ||
protected $decimalSeparator = ' and '; | ||
|
||
protected function spellHundred($number, $groupOfThrees, $isDecimalPart, $currency) | ||
{ | ||
static $tens = array( | ||
1 => 'ten', | ||
2 => 'twenty', | ||
3 => 'thirty', | ||
4 => 'fourty', | ||
5 => 'fifty', | ||
6 => 'sixty', | ||
7 => 'seventy', | ||
8 => 'eighty', | ||
9 => 'ninety', | ||
); | ||
static $teens = array( | ||
11 => 'eleven', | ||
12 => 'twelve', | ||
13 => 'thirteen', | ||
14 => 'fourteen', | ||
15 => 'fifteen', | ||
16 => 'sixteen', | ||
17 => 'seventeen', | ||
18 => 'eighteen', | ||
19 => 'nineteen', | ||
); | ||
static $singles = array( | ||
0 => 'zero', | ||
1 => 'one', | ||
2 => 'two', | ||
3 => 'three', | ||
4 => 'four', | ||
5 => 'five', | ||
6 => 'six', | ||
7 => 'seven', | ||
8 => 'eight', | ||
9 => 'nine', | ||
); | ||
|
||
$text = ''; | ||
|
||
if ($number >= 100) | ||
{ | ||
$text .= $singles[intval(substr("$number", 0, 1))] . ' hundred'; | ||
$number = $number % 100; | ||
|
||
if ($number === 0) // exact hundreds | ||
{ | ||
return $text; | ||
} | ||
|
||
$text .= ' '; | ||
} | ||
|
||
if ($number < 10) | ||
{ | ||
$text .= $singles[intval($number)]; | ||
} | ||
else if (($number > 10) && ($number < 20)) | ||
{ | ||
$text .= $teens[intval($number)]; | ||
} | ||
else | ||
{ | ||
$text .= $tens[intval(substr("$number", 0, 1))]; | ||
|
||
if ($number % 10 > 0) // twenty five | ||
{ | ||
$text .= ' ' . $singles[$number % 10]; | ||
} | ||
} | ||
|
||
return $text; | ||
} | ||
|
||
protected function getName($type, $number, $currency) | ||
{ | ||
if ($type === 'million') | ||
{ | ||
return 'million'; | ||
} | ||
|
||
if ($type === 'thousand') | ||
{ | ||
return 'thousand'; | ||
} | ||
|
||
static $names = array( | ||
'EUR' => array( | ||
'whole' => array('euro', 'euro'), | ||
'decimal' => array('cent', 'cents'), | ||
), | ||
'LTL' => array( | ||
'whole' => array('litas', 'litai'), | ||
'decimal' => array('centas', 'centai'), | ||
), | ||
'LVL' => array( | ||
'whole' => array('lat', 'lats'), | ||
'decimal' => array('santim', 'santims'), | ||
), | ||
'RUR' => array( | ||
'whole' => array('ruble', 'rubles'), | ||
'decimal' => array('kopek', 'kopeks'), | ||
), | ||
'USD' => array( | ||
'whole' => array('dollar', 'dollars'), // twenty one dollars | ||
'decimal' => array('cent', 'cents'), | ||
), | ||
); | ||
|
||
if (!isset($names[$currency])) | ||
{ | ||
throw new \InvalidArgumentException('Unsupported currency'); | ||
} | ||
|
||
$index = (($number === 1) ? 0 : 1); | ||
|
||
return $names[$currency][$type][$index]; | ||
} | ||
} |
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,185 @@ | ||
<?php | ||
namespace languages; | ||
|
||
final class Latvian extends \NumberConversion | ||
{ | ||
protected $minus = 'mīnus'; | ||
protected $decimalSeparator = ' un '; | ||
|
||
protected function spellHundred($number, $groupOfThrees, $isDecimalPart, $currency) | ||
{ | ||
static $hundreds = array( | ||
1 => 'viens simts', | ||
2 => 'divi simti', | ||
3 => 'trīs simti', | ||
4 => 'četri simti', | ||
5 => 'pieci simti', | ||
6 => 'seši simti', | ||
7 => 'septiņi simti', | ||
8 => 'astoņi simti', | ||
9 => 'deviņi simti', | ||
); | ||
static $teens = array( | ||
11 => 'vienpadsmit', | ||
12 => 'divpadsmit', | ||
13 => 'trīspadsmit', | ||
14 => 'četrpadsmit', | ||
15 => 'piecpadsmit', | ||
16 => 'sešpadsmit', | ||
17 => 'septiņpadsmit', | ||
18 => 'astoņpadsmit', | ||
19 => 'deviņpadsmit', | ||
); | ||
static $tens = array( | ||
1 => 'desmit', | ||
2 => 'divdesmit', | ||
3 => 'trīsdesmit', | ||
4 => 'četrdesmit', | ||
5 => 'piecdesmit', | ||
6 => 'sešdesmit', | ||
7 => 'septiņdesmit', | ||
8 => 'astoņdesmit', | ||
9 => 'deviņdesmit', | ||
); | ||
|
||
$text = ''; | ||
|
||
if ($number >= 100) | ||
{ | ||
$text .= $hundreds[intval(substr("$number", 0, 1))]; | ||
$number = $number % 100; | ||
|
||
if ($number === 0) // exact hundreds | ||
{ | ||
return $text; | ||
} | ||
|
||
$text .= ' '; | ||
} | ||
|
||
if ($number < 10) | ||
{ | ||
$text .= $this->spellSingle($number, $isDecimalPart, $currency); | ||
} | ||
else if (($number > 10) && ($number < 20)) | ||
{ | ||
$text .= $teens[$number]; | ||
} | ||
else | ||
{ | ||
$text .= $tens[intval(substr($number, 0, 1))]; | ||
|
||
if ($number % 10 > 0) // whole tens | ||
{ | ||
$text .= ' ' . $this->spellSingle($number % 10, $isDecimalPart, $currency); | ||
} | ||
} | ||
|
||
return $text; | ||
} | ||
|
||
private function spellSingle($digit, $isDecimalPart, $currency) | ||
{ | ||
static $singlesMasculine = array( | ||
0 => 'nulle', | ||
1 => 'viens', | ||
2 => 'divi', | ||
3 => 'trīs', | ||
4 => 'četri', | ||
5 => 'pieci', | ||
6 => 'seši', | ||
7 => 'septiņi', | ||
8 => 'astoņi', | ||
9 => 'deviņi', | ||
); | ||
static $singlesFeminine = array( | ||
1 => 'viena', | ||
2 => 'divas', | ||
3 => 'trīs', | ||
4 => 'četras', | ||
5 => 'piecas', | ||
6 => 'sešas', | ||
7 => 'septiņas', | ||
8 => 'astoņas', | ||
9 => 'deviņas', | ||
); | ||
|
||
if ($isDecimalPart && ($currency === 'RUR')) | ||
{ | ||
// russian kopek nouns are feminine gender in Latvian | ||
return $singlesFeminine[intval($digit)]; | ||
} | ||
|
||
return $singlesMasculine[intval($digit)]; | ||
} | ||
|
||
protected function getName($type, $number, $currency) | ||
{ | ||
$tens = $number % 100; | ||
$singles = $number % 10; | ||
|
||
if ($type === 'million') | ||
{ | ||
if (($singles === 1) && ($tens !== 11)) | ||
{ | ||
return 'miljons'; | ||
} | ||
|
||
return 'miljoni'; | ||
} | ||
|
||
if ($type === 'thousand') | ||
{ | ||
if (($singles === 1) && ($tens !== 11)) | ||
{ | ||
return 'tūkstotis'; | ||
} | ||
|
||
return 'tūkstoši'; | ||
} | ||
|
||
static $names = array( | ||
'EUR' => array( | ||
'whole' => array('eiro', 'eiro', 'eiro'), | ||
'decimal' => array('cents', 'centi', 'centu'), | ||
), | ||
'LTL' => array( | ||
'whole' => array('lits', 'liti', 'litu'), | ||
'decimal' => array('cents', 'centi', 'centu'), | ||
), | ||
'LVL' => array( | ||
'whole' => array('lats', 'lati', 'latu'), | ||
'decimal' => array('santīms', 'santīmi', 'santīmu'), | ||
), | ||
'RUR' => array( | ||
'whole' => array('rublis', 'rubļi', 'rubļu'), | ||
'decimal' => array('kapeika', 'kapeikas', 'kapeiku'), | ||
), | ||
'USD' => array( | ||
'whole' => array('dolārs', 'dolāri', 'dolāru'), | ||
'decimal' => array('cents', 'centi', 'centu'), | ||
), | ||
); | ||
|
||
if (!isset($names[$currency])) | ||
{ | ||
throw new \InvalidArgumentException('Unsupported currency'); | ||
} | ||
|
||
if (($singles === 1) && ($tens !== 11)) // 1, 21, 31, ... 91 | ||
{ | ||
$index = 0; | ||
} | ||
else if ((($singles > 1) && ($singles < 10)) // 2-9, 22-29, ... 92-99 | ||
&& (($tens - $singles) !== 10)) | ||
{ | ||
$index = 1; | ||
} | ||
else // 0, 10, 100, 1000 | ||
{ | ||
$index = 2; | ||
} | ||
|
||
return $names[$currency][$type][$index]; | ||
} | ||
} |
Oops, something went wrong.