I18N_Arabic

# Source for file Numbers.php

Documentation is available at Numbers.php

1. <?php
2. /**
3. * ----------------------------------------------------------------------
4. *
5. * Copyright (c) 2006-2016 Khaled Al-Sham'aa.
6. *
7. * http://www.ar-php.org
8. *
9. * PHP Version 5
10. *
11. * ----------------------------------------------------------------------
12. *
13. * LICENSE
14. *
15. * This program is open source product; you can redistribute it and/or
16. * modify it under the terms of the GNU Lesser General Public License (LGPL)
17. * as published by the Free Software Foundation; either version 3
18. * of the License, or (at your option) any later version.
19. *
20. * This program is distributed in the hope that it will be useful,
21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23. * GNU Lesser General Public License for more details.
24. *
25. * You should have received a copy of the GNU Lesser General Public License
26. * along with this program. If not, see <http://www.gnu.org/licenses/lgpl.txt>.
27. *
28. * ----------------------------------------------------------------------
29. *
30. * Class Name: Spell numbers in the Arabic idiom
31. *
32. * Filename: Numbers.php
33. *
34. * Original Author(s): Khaled Al-Sham'aa <khaled@ar-php.org>
35. *
36. * Purpose: Spell numbers in the Arabic idiom
37. *
38. * ----------------------------------------------------------------------
39. *
40. * Spell numbers in the Arabic idiom
41. *
42. * PHP class to spell numbers in the Arabic idiom. This function is very
43. * useful for financial applications in Arabic for example.
44. *
45. * If you ever have to create an Arabic PHP application built around invoicing or
46. * accounting, you might find this class useful. Its sole reason for existence is
47. * to help you translate integers into their spoken-word equivalents in Arabic
48. * language.
49. *
50. * How is this useful? Well, consider the typical invoice: In addition to a
51. * description of the work done, the date, and the hourly or project cost, it always
52. * includes a total cost at the end, the amount that the customer is expected
53. * to pay.
54. *
55. * To avoid any misinterpretation of the total amount, many organizations (mine
56. * included) put the amount in both words and figures; for example, $1,200 becomes
57. * "one thousand and two hundred dollars." You probably do the same thing every time
58. * you write a check.
59. *
60. * Now take this scenario to a Web-based invoicing system. The actual data used to
61. * generate the invoice will be stored in a database as integers, both to save space
62. * and to simplify calculations. So when a printable invoice is generated, your Web
63. * application will need to convert those integers into words, this is more clarity
64. * and more personality.
65. *
66. * This class will accept almost any numeric value and convert it into an equivalent
67. * string of words in written Arabic language (using Windows-1256 character set).
68. * The value can be any positive number up to 999,999,999 (users should not use
69. * commas). It will take care of feminine and Arabic grammar rules.
70. *
71. * Example:
72. * <code>
73. * include('./I18N/Arabic.php');
74. * $obj = new I18N_Arabic('Numbers');
75. *
76. * $obj->setFeminine(1);
77. * $obj->setFormat(1);
78. *
79. * $integer = 2147483647;
80. *
81. * $text = $obj->int2str($integer);
82. *
83. * echo "<p align=\"right\"><b class=hilight>$integer</b><br />$text</p>";
84. *
85. * $obj->setFeminine(2);
86. * $obj->setFormat(2);
87. *
88. * $integer = 2147483647;
89. *
90. * $text = $obj->int2str($integer);
91. *
92. * echo "<p align=\"right\"><b class=hilight>$integer</b><br />$text</p>";
93. * </code>
94. *
95. * @category I18N
96. * @package I18N_Arabic
97. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
98. * @copyright 2006-2016 Khaled Al-Sham'aa
99. *
100. * @license LGPL <http://www.gnu.org/licenses/lgpl.txt>
101. * @link http://www.ar-php.org
102. */
104. /**
105. * This PHP class spell numbers in the Arabic idiom
106. *
107. * @category I18N
108. * @package I18N_Arabic
109. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
110. * @copyright 2006-2016 Khaled Al-Sham'aa
111. *
112. * @license LGPL <http://www.gnu.org/licenses/lgpl.txt>
113. * @link http://www.ar-php.org
114. */
115. class I18N_Arabic_Numbers
116. {
117. private $_individual = array();
118. private $_complications = array();
119. private $_arabicIndic = array();
120. private $_ordering = array();
121. private $_currency = array();
122. private $_spell = array();
123. private $_feminine = 1;
124. private $_format = 1;
125. private $_order = 1;
127. /**
128. * Loads initialize values
129. *
130. * @ignore
131. */
132. public function __construct()
133. {
134. $xml = simplexml_load_file(dirname(__FILE__).'/data/ArNumbers.xml');
136. foreach ($xml->xpath("//individual/number[@gender='male']") as $num) {
137. if (isset($num['grammar'])) {
138. $grammar = $num['grammar'];
140. $this->_individual["{$num['value']}"][1]["$grammar"] = (string)$num;
141. } else {
142. $this->_individual["{$num['value']}"][1] = (string)$num;
143. }
144. }
146. foreach ($xml->xpath("//individual/number[@gender='female']") as $num) {
147. if (isset($num['grammar'])) {
148. $grammar = $num['grammar'];
150. $this->_individual["{$num['value']}"][2]["$grammar"] = (string)$num;
151. } else {
152. $this->_individual["{$num['value']}"][2] = (string)$num;
153. }
154. }
156. foreach ($xml->xpath("//individual/number[@value>19]") as $num) {
157. if (isset($num['grammar'])) {
158. $grammar = $num['grammar'];
160. $this->_individual["{$num['value']}"]["$grammar"] = (string)$num;
161. } else {
162. $this->_individual["{$num['value']}"] = (string)$num;
163. }
164. }
166. foreach ($xml->complications->number as $num) {
167. $scale = $num['scale'];
168. $format = $num['format'];
170. $this->_complications["$scale"]["$format"] = (string)$num;
171. }
173. foreach ($xml->arabicIndic->number as $html) {
174. $value = $html['value'];
176. $this->_arabicIndic["$value"] = $html;
177. }
179. foreach ($xml->xpath("//order/number[@gender='male']") as $num) {
180. $this->_ordering["{$num['value']}"][1] = (string)$num;
181. }
183. foreach ($xml->xpath("//order/number[@gender='female']") as $num) {
184. $this->_ordering["{$num['value']}"][2] = (string)$num;
185. }
187. $expression = "//individual/number[@value<11 or @value>19]";
188. foreach ($xml->xpath($expression) as $num) {
189. $str = str_replace(array('أ','إ','آ'), 'ا', (string)$num);
190. $this->_spell[$str] = (integer)$num['value'];
191. }
193. $xml = simplexml_load_file(dirname(__FILE__).'/data/arab_countries.xml');
195. foreach ($xml->xpath("//currency") as $info) {
196. $money_ar = $info->money->arabic;
197. $money_en = $info->money->english;
199. $this->_currency["{$info->iso}"]['ar']['basic'] = $money_ar->basic;
200. $this->_currency["{$info->iso}"]['ar']['fraction'] = $money_ar->fraction;
201. $this->_currency["{$info->iso}"]['en']['basic'] = $money_en->basic;
202. $this->_currency["{$info->iso}"]['en']['fraction'] = $money_en->fraction;
204. $this->_currency["{$info->iso}"]['decimals'] = $info->money->decimals;
205. }
206. }
208. /**
209. * Set feminine flag of the counted object
210. *
211. * @param integer $value Counted object feminine
212. * (1 for masculine & 2 for feminine)
213. *
214. * @return object $this to build a fluent interface
215. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
216. */
217. public function setFeminine($value)
218. {
219. if ($value == 1 || $value == 2) {
220. $this->_feminine = $value;
221. }
223. return $this;
224. }
226. /**
227. * Set the grammar position flag of the counted object
228. *
229. * @param integer $value Grammar position of counted object
230. * (1 if Marfoua & 2 if Mansoub or Majrour)
231. *
232. * @return object $this to build a fluent interface
233. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
234. */
235. public function setFormat($value)
236. {
237. if ($value == 1 || $value == 2) {
238. $this->_format = $value;
239. }
241. return $this;
242. }
244. /**
245. * Set the ordering flag, is it normal number or ordering number
246. *
247. * @param integer $value Is it an ordering number? default is 1
248. * (use 1 if no and 2 if yes)
249. *
250. * @return object $this to build a fluent interface
251. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
252. */
253. public function setOrder($value)
254. {
255. if ($value == 1 || $value == 2) {
256. $this->_order = $value;
257. }
259. return $this;
260. }
262. /**
263. * Get the feminine flag of counted object
264. *
265. * @return integer return current setting of counted object feminine flag
266. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
267. */
268. public function getFeminine()
269. {
270. return $this->_feminine;
271. }
273. /**
274. * Get the grammer position flag of counted object
275. *
276. * @return integer return current setting of counted object grammer
277. * position flag
278. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
279. */
280. public function getFormat()
281. {
282. return $this->_format;
283. }
285. /**
286. * Get the ordering flag value
287. *
288. * @return integer return current setting of ordering flag value
289. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
290. */
291. public function getOrder()
292. {
293. return $this->_format;
294. }
296. /**
297. * Spell integer number in Arabic idiom
298. *
299. * @param integer $number The number you want to spell in Arabic idiom
300. *
301. * @return string The Arabic idiom that spells inserted number
302. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
303. */
304. public function int2str($number)
305. {
306. if ($number == 1 && $this->_order == 2) {
307. if ($this->_feminine == 1) {
308. $string = 'الأول';
309. } else {
310. $string = 'الأولى';
311. }
312. } else {
313. if ($number < 0) {
314. $string = 'سالب ';
315. $number = (string) -1 * $number;
316. } else {
317. $string = '';
318. }
320. $temp = explode('.', $number);
322. $string .= $this->subInt2str($temp[0]);
324. if (!empty($temp[1])) {
325. $dec = $this->subInt2str($temp[1]);
326. $string .= ' فاصلة ' . $dec;
327. }
328. }
330. return $string;
331. }
333. /**
334. * Spell number in Arabic idiom as money
335. *
336. * @param integer $number The number you want to spell in Arabic idiom as money
337. * @param string $iso The three-letter Arabic country code defined in
338. * ISO 3166 standard
339. * @param string $lang The two-letter language code in ISO 639-1 standard
340. * [ar|en]
341. *
342. * @return string The Arabic idiom that spells inserted number as money
343. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
344. */
345. public function money2str($number, $iso='SYP', $lang='ar')
346. {
347. $iso = strtoupper($iso);
348. $lang = strtolower($lang);
350. $number = sprintf("%01.{$this->_currency[$iso]['decimals']}f", $number);
351. $temp = explode('.', $number);
352. $string = '';
354. if ($temp[0] != 0) {
355. $string .= $this->subInt2str($temp[0]);
356. $string .= ' ' . $this->_currency[$iso][$lang]['basic'];
357. }
359. if (!empty($temp[1]) && $temp[1] != 0) {
360. if ($string != '') {
361. if ($lang == 'ar') {
362. $string .= ' و ';
363. } else {
364. $string .= ' and ';
365. }
366. }
368. $string .= $this->subInt2str((int)$temp[1]);
369. $string .= ' ' . $this->_currency[$iso][$lang]['fraction'];
370. }
372. return $string;
373. }
375. /**
376. * Convert Arabic idiom number string into Integer
377. *
378. * @param string $str The Arabic idiom that spells input number
379. *
380. * @return integer The number you spell it in the Arabic idiom
381. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
382. */
383. public function str2int ($str)
384. {
385. // Normalization phase
386. $str = str_replace(array('أ','إ','آ'), 'ا', $str);
387. $str = str_replace('ه', 'ة', $str);
388. $str = preg_replace('/\s+/', ' ', $str);
389. $ptr = array('ـ', 'َ','ً','ُ','ٌ','ِ','ٍ','ْ','ّ');
390. $str = str_replace($ptr, '', $str);
391. $str = str_replace('مائة', 'مئة', $str);
392. $str = str_replace(array('احدى','احد'), 'واحد', $str);
393. $ptr = array('اثنا','اثني','اثنتا', 'اثنتي');
394. $str = str_replace($ptr, 'اثنان', $str);
395. $str = trim($str);
397. if (strpos($str, 'ناقص') === false
398. && strpos($str, 'سالب') === false
399. ) {
400. $negative = false;
401. } else {
402. $negative = true;
403. }
405. // Complications process
406. $segment = array();
407. $max = count($this->_complications);
409. for ($scale=$max; $scale>0; $scale--) {
410. $key = pow(1000, $scale);
412. $pattern = array('أ','إ','آ');
413. $format1 = str_replace($pattern, 'ا', $this->_complications[$scale][1]);
414. $format2 = str_replace($pattern, 'ا', $this->_complications[$scale][2]);
415. $format3 = str_replace($pattern, 'ا', $this->_complications[$scale][3]);
416. $format4 = str_replace($pattern, 'ا', $this->_complications[$scale][4]);
418. if (strpos($str, $format1) !== false) {
419. list($temp, $str) = explode($format1, $str);
420. $segment[$key] = 'اثنان';
421. } elseif (strpos($str, $format2) !== false) {
422. list($temp, $str) = explode($format2, $str);
423. $segment[$key] = 'اثنان';
424. } elseif (strpos($str, $format3) !== false) {
425. list($segment[$key], $str) = explode($format3, $str);
426. } elseif (strpos($str, $format4) !== false) {
427. list($segment[$key], $str) = explode($format4, $str);
428. if ($segment[$key] == '') {
429. $segment[$key] = 'واحد';
430. }
431. }
433. if ($segment[$key] != '') {
434. $segment[$key] = trim($segment[$key]);
435. }
436. }
438. $segment[1] = trim($str);
440. // Individual process
441. $total = 0;
442. $subTotal = 0;
444. foreach ($segment as $scale => $str) {
445. $str = " $str ";
446. foreach ($this->_spell as $word => $value) {
447. if (strpos($str, "$word ") !== false) {
448. $str = str_replace("$word ", ' ', $str);
449. $subTotal += $value;
450. }
451. }
453. $total += $subTotal * $scale;
454. $subTotal = 0;
455. }
457. if ($negative) {
458. $total = -1 * $total;
459. }
461. return $total;
462. }
464. /**
465. * Spell integer number in Arabic idiom
466. *
467. * @param integer $number The number you want to spell in Arabic idiom
468. * @param logical $zero Present leading zero if true [default is true]
469. *
470. * @return string The Arabic idiom that spells inserted number
471. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
472. */
473. protected function subInt2str($number, $zero = true)
474. {
475. $blocks = array();
476. $items = array();
477. $zeros = '';
478. $string = '';
479. $number = ($zero != false) ? trim($number) : trim((float)$number);
481. if ($number > 0) {
483. //--- by Jnom: handle left zero
484. // http://www.itkane.com
485. // jnom23@gmail.com
486. if ($zero != false) {
487. $fulnum = $number;
488. while (($fulnum[0]) == '0') {
489. $zeros = 'صفر '.$zeros;
490. $fulnum = substr($fulnum, 1, strlen($fulnum));
491. };
492. };
493. //---/
495. while (strlen($number) > 3) {
496. array_push($blocks, substr($number, -3));
497. $number = substr($number, 0, strlen($number) - 3);
498. }
499. array_push($blocks, $number);
501. $blocks_num = count($blocks) - 1;
503. for ($i = $blocks_num; $i >= 0; $i--) {
504. $number = floor($blocks[$i]);
506. $text = $this->writtenBlock($number);
507. if ($text) {
508. if ($number == 1 && $i != 0) {
509. $text = $this->_complications[$i][4];
510. if ($this->_order == 2) {
511. $text = 'ال' . $text;
512. }
513. } elseif ($number == 2 && $i != 0) {
514. $text = $this->_complications[$i][$this->_format];
515. if ($this->_order == 2) {
516. $text = 'ال' . $text;
517. }
518. } elseif ($number > 2 && $number < 11 && $i != 0) {
519. $text .= ' ' . $this->_complications[$i][3];
520. if ($this->_order == 2) {
521. $text = 'ال' . $text;
522. }
523. } elseif ($i != 0) {
524. $text .= ' ' . $this->_complications[$i][4];
525. if ($this->_order == 2) {
526. $text = 'ال' . $text;
527. }
528. }
530. //--- by Jnom: handle left zero
531. if ($text != '' && $zeros != '' && $zero != false) {
532. $text = $zeros.' '.$text;
533. $zeros = '';
534. };
535. //---/
537. array_push($items, $text);
538. }
539. }
541. $string = implode(' و ', $items);
542. } else {
543. $string = 'صفر';
544. }
545. return $string;
546. }
548. /**
549. * Spell sub block number of three digits max in Arabic idiom
550. *
551. * @param integer $number Sub block number of three digits max you want to
552. * spell in Arabic idiom
553. *
554. * @return string The Arabic idiom that spells inserted sub block
555. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
556. */
557. protected function writtenBlock($number)
558. {
559. $items = array();
560. $string = '';
562. if ($number > 99) {
563. $hundred = floor($number / 100) * 100;
564. $number = $number % 100;
566. if ($this->_order == 2) {
567. $pre = 'ال';
568. } else {
569. $pre = '';
570. }
572. if ($hundred == 200) {
573. array_push(
574. $items,
575. $pre.$this->_individual[$hundred][$this->_format]
576. );
577. } else {
578. array_push($items, $pre.$this->_individual[$hundred]);
579. }
580. }
582. if ($number != 0) {
583. if ($this->_order == 2) {
584. if ($number <= 10) {
585. array_push($items, $this->_ordering[$number][$this->_feminine]);
586. } elseif ($number < 20) {
587. $number -= 10;
588. $item = 'ال' . $this->_ordering[$number][$this->_feminine];
590. if ($this->_feminine == 1) {
591. $item .= ' عشر';
592. } else {
593. $item .= ' عشرة';
594. }
596. array_push($items, $item);
597. } else {
598. $ones = $number % 10;
599. $tens = floor($number / 10) * 10;
601. array_push(
602. $items,
603. 'ال' . $this->_ordering[$ones][$this->_feminine]
604. );
605. array_push(
606. $items,
607. 'ال' . $this->_individual[$tens][$this->_format]
608. );
609. }
610. } else {
611. if ($number == 2 || $number == 12) {
612. array_push(
613. $items,
614. $this->_individual[$number][$this->_feminine][$this->_format]
615. );
616. } elseif ($number < 20) {
617. array_push(
618. $items,
619. $this->_individual[$number][$this->_feminine]
620. );
621. } else {
622. $ones = $number % 10;
623. $tens = floor($number / 10) * 10;
625. if ($ones == 2) {
626. array_push(
627. $items,
628. $this->_individual[2][$this->_feminine][$this->_format]
629. );
630. } elseif ($ones > 0) {
631. array_push(
632. $items,
633. $this->_individual[$ones][$this->_feminine]
634. );
635. }
637. array_push($items, $this->_individual[$tens][$this->_format]);
638. }
639. }
640. }
642. $items = array_diff($items, array(''));
643. $string = implode(' و ', $items);
645. return $string;
646. }
649. /**
650. * Represent integer number in Arabic-Indic digits using HTML entities
651. *
652. * @param integer $number The number you want to present in Arabic-Indic digits
653. * using HTML entities
654. *
655. * @return string The Arabic-Indic digits represent inserted integer number
656. * using HTML entities
657. * @author Khaled Al-Sham'aa <khaled@ar-php.org>
658. */
659. public function int2indic($number)
660. {
661. $str = strtr("$number", $this->_arabicIndic);
663. return $str;
664. }
665. }

Documentation generated on Fri, 01 Jan 2016 10:26:16 +0200 by phpDocumentor 1.4.0