Skip to content

Commit

Permalink
Add Swahili Language Support (#181)
Browse files Browse the repository at this point in the history
* Added Swahili language

* Updated README to fit swahili

* Improved kiswahili grammar

* Added Swahili tests

* Added Swahili
  • Loading branch information
titustum authored Sep 18, 2024
1 parent 69354c0 commit 8fe5777
Show file tree
Hide file tree
Showing 10 changed files with 444 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
/build/
/composer.lock
*.cache
test.php
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ Note: The Currency Transformer within this library processes integers; ensure yo
| Ukrainian | ua | + | + |
| Uzbek | uz | + | + |
| Yoruba | yo | + | + |
| Swahili | sw | + | + |

## Contributors

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"php": ">=7.4"
},
"require-dev": {
"phpunit/phpunit": "^9.6.7",
"phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3.7.2"
},
"autoload": {
Expand Down
1 change: 1 addition & 0 deletions src/Concerns/ManagesCurrencyTransformers.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ trait ManagesCurrencyTransformers
'ua' => Transformer\UkrainianCurrencyTransformer::class,
'uz' => Transformer\UzbekCurrencyTransformer::class,
'yo' => Transformer\YorubaCurrencyTransformer::class,
'sw' => Transformer\SwahiliCurrencyTransformer::class,
];

/**
Expand Down
1 change: 1 addition & 0 deletions src/Concerns/ManagesNumberTransformers.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ trait ManagesNumberTransformers
'ua' => Transformer\UkrainianNumberTransformer::class,
'uz' => Transformer\UzbekNumberTransformer::class,
'yo' => Transformer\YorubaNumberTransformer::class,
'sw' => Transformer\SwahiliNumberTransformer::class,
];

/**
Expand Down
16 changes: 16 additions & 0 deletions src/CurrencyTransformer/SwahiliCurrencyTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace NumberToWords\CurrencyTransformer;

use NumberToWords\Legacy\Numbers\Words;
use NumberToWords\TransformerOptions\CurrencyTransformerOptions;

class SwahiliCurrencyTransformer implements CurrencyTransformer
{
public function toWords(int $amount, string $currency, ?CurrencyTransformerOptions $options = null): string
{
$converter = new Words($options);

return $converter->transformToCurrency($amount, 'sw', $currency);
}
}
248 changes: 248 additions & 0 deletions src/Legacy/Numbers/Words/Locale/Sw.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
<?php

namespace NumberToWords\Legacy\Numbers\Words\Locale;

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

class Sw extends Words
{
private static $miscNumbers = [
10 => 'kumi',
20 => 'ishirini',
30 => 'thelathini',
40 => 'arobaini',
50 => 'hamsini',
60 => 'sitini',
70 => 'sabini',
80 => 'themanini',
90 => 'tisini',
100 => 'mia'
];

private static $digits = [
1 => 'moja',
2 => 'mbili',
3 => 'tatu',
4 => 'nne',
5 => 'tano',
6 => 'sita',
7 => 'saba',
8 => 'nane',
9 => 'tisa'
];

private static $exponent = [
0 => '',
3 => 'elfu',
5 => 'laki',
6 => 'milioni',
9 => 'bilioni',
12 => 'trilioni',
];

private $zero = 'sifuri';
private $and = 'na';
private $wordSeparator = ' ';
private $minus = 'kasoro';

// Currency names
private static $currencyNames = [
'KES' => [['Shilingi ya Kenya', 'Shilingi za Kenya'], ['senti', 'senti']],
'USD' => [['Dola ya Marekani', 'Dola za Marekani'], ['senti', 'senti']],
'EUR' => [['Yuro', 'Yuro'], ['senti', 'senti']],
'GBP' => [['Pauni ya Uingereza', 'Pauni za Uingereza'], ['senti', 'senti']],
'TZS' => [['Shilingi ya Tanzania', 'Shilingi za Tanzania'], ['senti', 'senti']],
'UGX' => [['Shilingi ya Uganda', 'Shilingi za Uganda'], ['senti', 'senti']],
'ZAR' => [['Randi ya Afrika Kusini', 'Randi za Afrika Kusini'], ['senti', 'senti']],
'NGN' => [['Naira ya Nigeria', 'Naira za Nigeria'], ['kobo', 'kobo']],
'GHS' => [['Cedi ya Ghana', 'Cedi za Ghana'], ['Pesewa', 'Pesewa']],
'RWF' => [['Faranga ya Rwanda', 'Faranga za Rwanda'], ['senti', 'senti']],
'BWP' => [['Pula ya Botswana', 'Pula za Botswana'], ['thebe', 'thebe']],
'INR' => [['Rupia ya India', 'Rupia za India'], ['paise', 'paise']],
'JPY' => [['Yen ya Japani', 'Yen za Japani'], ['seni', 'seni']],
'CNY' => [['Yuan ya China', 'Yuan za China'], ['feni', 'feni']],
'CAD' => [['Dola ya Kanada', 'Dola za Kanada'], ['senti', 'senti']],
'AUD' => [['Dola ya Australia', 'Dola za Australia'], ['senti', 'senti']],
'CHF' => [['Faranga ya Uswisi', 'Faranga za Uswisi'], ['senti', 'senti']],
'BRL' => [['Reali ya Brazil', 'Reali za Brazil'], ['sentavo', 'sentavo']],
'MXN' => [['Peso ya Meksiko', 'Peso za Meksiko'], ['sentavo', 'sentavo']],
'SAR' => [['Riyal ya Saudi Arabia', 'Riyal za Saudi Arabia'], ['halala', 'halala']],
'AED' => [['Dirham ya Umoja wa Falme za Kiarabu', 'Dirham za Umoja wa Falme za Kiarabu'], ['fils', 'fils']],
'EGP' => [['Pauni ya Misri', 'Pauni za Misri'], ['piastiri', 'piastiri']],
];



protected function toWords($number)
{
if ($number == 0) {
return $this->zero;
}

$isNegative = $number < 0;
$number = abs($number);

// Handle decimal numbers
$integerPart = floor($number);
$decimalPart = $number - $integerPart;

$result = $this->convertIntegerPart($integerPart);

if ($decimalPart > 0) {
$result .= ' nukta ' . $this->convertDecimalPart($decimalPart);
}

if ($isNegative) {
$result = $this->minus . $this->wordSeparator . $result;
}

return trim($result);
}

private function convertIntegerPart($number)
{
$result = '';

if ($number >= 1000000000000) {
$trillions = floor($number / 1000000000000);
$result .= self::$exponent[12] . $this->wordSeparator . $this->numberToSwahiliLessThanThousand($trillions) . ', ';
$number %= 1000000000000;
}

if ($number >= 1000000000) {
$billions = floor($number / 1000000000);
$result .= self::$exponent[9] . $this->wordSeparator . $this->numberToSwahiliLessThanThousand($billions) . ', ';
$number %= 1000000000;
}

if ($number >= 1000000) {
$millions = floor($number / 1000000);
$result .= self::$exponent[6] . $this->wordSeparator . $this->numberToSwahiliLessThanThousand($millions) . ', ';
$number %= 1000000;
}

if ($number >= 100000) {
$lakhs = floor($number / 100000);
$result .= self::$exponent[5] . $this->wordSeparator . $this->numberToSwahiliLessThanHundredThousand($lakhs) . ', ';
$number %= 100000;
}

if ($number >= 1000) {
$thousands = floor($number / 1000);
$result .= self::$exponent[3] . $this->wordSeparator . $this->numberToSwahiliLessThanThousand($thousands) . ', ';
$number %= 1000;
}

if ($number > 0) {
$result .= $this->numberToSwahiliLessThanThousand($number);
}

return rtrim(rtrim($result), ',');
}

private function convertDecimalPart($decimal)
{
$decimalStr = substr(strval($decimal), 2); // Remove "0."
$result = '';
foreach (str_split($decimalStr) as $digit) {
$result .= $this->numberToSwahiliLessThanTen((int)$digit) . $this->wordSeparator;
}
return trim($result);
}

private function numberToSwahiliLessThanTen($number)
{
return self::$digits[$number];
}

private function numberToSwahiliLessThanHundred($number)
{
if ($number < 10) {
return $this->numberToSwahiliLessThanTen($number);
}

$tens = array_values(self::$miscNumbers);
$ten = floor($number / 10);
$one = $number % 10;

$result = $tens[$ten - 1];
if ($one > 0) {
$result .= $this->wordSeparator . $this->and . $this->wordSeparator . $this->numberToSwahiliLessThanTen($one);
}

return $result;
}

private function numberToSwahiliLessThanThousand($number)
{
if ($number < 100) {
return $this->numberToSwahiliLessThanHundred($number);
}

$hundred = floor($number / 100);
$remainder = $number % 100;

$result = ($hundred == 1) ? self::$miscNumbers[100] : self::$miscNumbers[100] . $this->wordSeparator . $this->numberToSwahiliLessThanTen($hundred);
if ($remainder > 0) {
$result .= $this->wordSeparator . $this->and . $this->wordSeparator . $this->numberToSwahiliLessThanHundred($remainder);
}

return $result;
}

private function numberToSwahiliLessThanHundredThousand($number)
{
if ($number < 1000) {
return $this->numberToSwahiliLessThanThousand($number);
}

$thousand = floor($number / 1000);
$remainder = $number % 1000;

$result = ($thousand == 1) ? self::$exponent[3] : self::$exponent[3] . $this->wordSeparator . $this->numberToSwahiliLessThanThousand($thousand);
if ($remainder > 0) {
$result .= $this->wordSeparator . $this->and . $this->wordSeparator . $this->numberToSwahiliLessThanThousand($remainder);
}

return $result;
}

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 Swahili language', $currency)
);
}

$currencyNames = static::$currencyNames[$currency];
$return = trim($this->toWords($decimal));

// Check if singular and plural forms are available
$level = ($decimal === 1) ? 0 : 1;
$currencySingularOrPlural = isset($currencyNames[0][$level]) ? $currencyNames[0][$level] : '';

$return = $currencySingularOrPlural. $this->wordSeparator.$return;

if (null !== $fraction) {

$level = $fraction === 1 ? 0 : 1;

// Check if singular and plural forms for fraction are available
$fractionSingularOrPlural = isset($currencyNames[1][$level]) ? $currencyNames[1][$level] : '';

$return .= sprintf(
'%1$s%2$s%1$s%3$s',
$this->wordSeparator,
$this->and.' '.$fractionSingularOrPlural,
trim($this->toWords($fraction))
);
}

return trim(ucfirst($return));
}

}
15 changes: 15 additions & 0 deletions src/NumberTransformer/SwahiliNumberTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace NumberToWords\NumberTransformer;

use NumberToWords\Legacy\Numbers\Words;

class SwahiliNumberTransformer implements NumberTransformer
{
public function toWords(int $number): string
{
$converter = new Words();

return $converter->transformToWords($number, 'sw');
}
}
37 changes: 37 additions & 0 deletions tests/CurrencyTransformer/SwahiliCurrencyTransformerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace NumberToWords\CurrencyTransformer;

class SwahiliCurrencyTransformerTest extends CurrencyTransformerTest
{
protected function setUp(): void
{
$this->currencyTransformer = new SwahiliCurrencyTransformer();
}

public function providerItConvertsMoneyAmountToWords(): array
{
return [
[6474, 'USD', 'Dola za Marekani sitini na nne na senti sabini na nne'],
[6574, 'USD', 'Dola za Marekani sitini na tano na senti sabini na nne'],
[8174, 'USD', 'Dola za Marekani themanini na moja na senti sabini na nne'],
[8255, 'KES', 'Shilingi za Kenya themanini na mbili na senti hamsini na tano'],
[72900, 'USD', 'Dola za Marekani mia saba na ishirini na tisa'],
[89400, 'USD', 'Dola za Marekani mia nane na tisini na nne'],
[99900, 'TZS', 'Shilingi za Tanzania mia tisa na tisini na tisa'],
[100000, 'USD', 'Dola za Marekani elfu moja'],
[100100, 'USD', 'Dola za Marekani elfu moja, moja'],
[109725, 'GBP', 'Pauni za Uingereza elfu moja, tisini na saba na senti ishirini na tano'],
[110400, 'USD', 'Dola za Marekani elfu moja, mia na nne'],
[124380, 'EUR', 'Yuro elfu moja, mia mbili na arobaini na tatu na senti themanini'],
[238500, 'USD', 'Dola za Marekani elfu mbili, mia tatu na themanini na tano'],
[376600, 'USD', 'Dola za Marekani elfu tatu, mia saba na sitini na sita'],
[584600, 'USD', 'Dola za Marekani elfu tano, mia nane na arobaini na sita'],
[645900, 'USD', 'Dola za Marekani elfu sita, mia nne na hamsini na tisa'],
[723200, 'USD', 'Dola za Marekani elfu saba, mia mbili na thelathini na mbili'],
[-72925, 'UGX', 'Shilingi za Uganda kasoro mia saba na ishirini na tisa na senti ishirini na tano'],
[-89425, 'USD', 'Dola za Marekani kasoro mia nane na tisini na nne na senti ishirini na tano'],
[-99925, 'USD', 'Dola za Marekani kasoro mia tisa na tisini na tisa na senti ishirini na tano'],
];
}
}
Loading

0 comments on commit 8fe5777

Please sign in to comment.