Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
4
/**
5
 * Numbers_Words
6
 *
7
 * PHP version 5
8
 *
9
 * LICENSE: This source file is subject to version 3.01 of the PHP license
10
 * that is available through the world-wide-web at the following URI:
11
 * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
12
 * the PHP License and are unable to obtain it through the web, please
13
 * send a note to license@php.net so we can mail you a copy immediately.
14
 *
15
 * @category  Numbers
16
 * @package   Numbers_Words
17
 * @author    Igor Feghali <ifeghali@php.net>
18
 * @copyright 1997-2008 The PHP Group
19
 * @license   http://www.php.net/license/3_01.txt  PHP License 3.01
20
 * @version   CVS: $Id: lang.pt_BR.php 271694 2008-12-20 22:23:24Z ifeghali $
21
 * @link      http://pear.php.net/package/Numbers_Words
22
 */
23
 
24
/**
25
 * Include needed files
26
 */
27
require_once "Numbers/Words.php";
28
 
29
/**
30
 * Class for translating numbers into Brazilian Portuguese. This class complies
31
 * to Brazilian Academy of Letters rules as of 2008-12-12.
32
 *
33
 * @category Numbers
34
 * @package  Numbers_Words
35
 * @author   Igor Feghali <ifeghali@php.net>
36
 * @license  http://www.php.net/license/3_01.txt  PHP License 3.01
37
 * @link     http://pear.php.net/package/Numbers_Words
38
 */
39
class Numbers_Words_pt_BR extends Numbers_Words
40
{
41
    /**
42
     * Locale name
43
     * @var string
44
     * @access public
45
     */
46
    var $locale = 'pt_BR';
47
 
48
    /**
49
     * Language name in English
50
     * @var string
51
     * @access public
52
     */
53
    var $lang = 'Brazilian Portuguese';
54
 
55
    /**
56
     * Native language name
57
     * @var string
58
     * @access public
59
     */
60
    var $lang_native = 'Português Brasileiro';
61
 
62
    /**
63
     * The word for the minus sign
64
     * @var string
65
     * @access private
66
     */
67
    var $_minus = 'negativo';
68
 
69
    /**
70
     * The word separator for numerals
71
     * @var string
72
     * @access private
73
     */
74
    var $_sep = ' e ';
75
 
76
    /**
77
     * The special separator for numbers and currency names
78
     * @var string
79
     * @access private
80
     */
81
    var $_curr_sep = ' de ';
82
 
83
    /**
84
     * The array containing numbers 11-19.
85
     * In Brazilian Portuguese numbers in that range are contracted
86
     * in a single word.
87
     * @var array
88
     * @access private
89
     */
90
    var $_contractions = array(
91
        '',
92
        'onze',
93
        'doze',
94
        'treze',
95
        'quatorze',
96
        'quinze',
97
        'dezesseis',
98
        'dezessete',
99
        'dezoito',
100
        'dezenove'
101
    );
102
 
103
    var $_words = array(
104
        /**
105
         * The array containing the digits (indexed by the digits themselves).
106
         * @var array
107
         * @access private
108
         */
109
        array(
110
            '',         // 0: not displayed
111
            'um',
112
            'dois',
113
            'três',
114
            'quatro',
115
            'cinco',
116
            'seis',
117
            'sete',
118
            'oito',
119
            'nove'
120
        ),
121
 
122
        /**
123
         * The array containing numbers for 10,20,...,90.
124
         * @var array
125
         * @access private
126
         */
127
        array(
128
            '',         // 0: not displayed
129
            'dez',
130
            'vinte',
131
            'trinta',
132
            'quarenta',
133
            'cinqüenta',
134
            'sessenta',
135
            'setenta',
136
            'oitenta',
137
            'noventa'
138
        ),
139
 
140
        /**
141
         * The array containing numbers for hundreds.
142
         * @var array
143
         * @access private
144
         */
145
        array(
146
            '',         // 0: not displayed
147
            'cento',    // 'cem' is a special case handled in toWords()
148
            'duzentos',
149
            'trezentos',
150
            'quatrocentos',
151
            'quinhentos',
152
            'seiscentos',
153
            'setecentos',
154
            'oitocentos',
155
            'novecentos'
156
        ),
157
    );
158
 
159
    /**
160
     * The sufixes for exponents (singular)
161
     * @var array
162
     * @access private
163
     */
164
    var $_exponent = array(
165
        '',         // 0: not displayed
166
        'mil',
167
        'milhão',
168
        'bilhão',
169
        'trilhão',
170
        'quatrilhão',
171
        'quintilhão',
172
        'sextilhão',
173
        'septilhão',
174
        'octilhão',
175
        'nonilhão',
176
        'decilhão',
177
        'undecilhão',
178
        'dodecilhão',
179
        'tredecilhão',
180
        'quatuordecilhão',
181
        'quindecilhão',
182
        'sedecilhão',
183
        'septendecilhão'
184
    );
185
 
186
    /**
187
     * The currency names (based on Wikipedia) and plurals
188
     *
189
     * @var array
190
     * @link http://pt.wikipedia.org/wiki/ISO_4217
191
     * @access private
192
     */
193
    var $_currency_names = array(
194
        'BRL' => array(array('real', 'reais'), array('centavo', 'centavos')),
195
        'USD' => array(array('dólar', 'dólares'), array('centavo', 'centavos')),
196
        'EUR' => array(array('euro', 'euros'), array('centavo', 'centavos')),
197
        'GBP' => array(array('libra esterlina', 'libras esterlinas'), array('centavo', 'centavos')),
198
        'JPY' => array(array('iene', 'ienes'), array('centavo', 'centavos')),
199
        'ARS' => array(array('peso argentino', 'pesos argentinos'), array('centavo', 'centavos')),
200
        'MXN' => array(array('peso mexicano', 'pesos mexicanos'), array('centavo', 'centavos')),
201
        'UYU' => array(array('peso uruguaio', 'pesos uruguaios'), array('centavo', 'centavos')),
202
        'PYG' => array(array('guarani', 'guaranis'), array('centavo', 'centavos')),
203
        'BOB' => array(array('boliviano', 'bolivianos'), array('centavo', 'centavos')),
204
        'CLP' => array(array('peso chileno', 'pesos chilenos'), array('centavo', 'centavos')),
205
        'COP' => array(array('peso colombiano', 'pesos colombianos'), array('centavo', 'centavos')),
206
        'CUP' => array(array('peso cubano', 'pesos cubanos'), array('centavo', 'centavos')),
207
    );
208
 
209
    /**
210
     * The default currency name
211
     * @var string
212
     * @access public
213
     */
214
    var $def_currency = 'BRL'; // Real
215
 
216
    // {{{ toWords()
217
 
218
    /**
219
     * Converts a number to its word representation
220
     * in Brazilian Portuguese language
221
     *
222
     * @param integer $num An integer between -999E54 and 999E54
223
     *
224
     * @return string  The corresponding word representation
225
     *
226
     * @access public
227
     * @author Igor Feghali <ifeghali@php.net>
228
     * @since  Numbers_Words 0.11.0
229
     */
230
    function toWords($num)
231
    {
232
        $neg   = 0;
233
        $ret   = array();
234
        $words = array();
235
 
236
        /**
237
         * Negative ?
238
         */
239
        if ($num < 0) {
240
            $ret[] = $this->_minus;
241
            $num   = -$num;
242
            $neg   = 1;
243
        }
244
 
245
        /**
246
         * Removes leading zeros, spaces, decimals etc.
247
         * Adds thousands separator.
248
         */
249
        $num = number_format($num, 0, '.', '.');
250
 
251
        /**
252
         * Testing Zero
253
         */
254
        if ($num == 0) {
255
            return 'zero';
256
        }
257
 
258
        /**
259
         * Breaks into chunks of 3 digits.
260
         * Reversing array to process from right to left.
261
         */
262
        $chunks = array_reverse(explode(".", $num));
263
 
264
        /**
265
         * Looping through the chunks
266
         */
267
        foreach ($chunks as $index => $chunk) {
268
            /**
269
             * Testing Range
270
             */
271
            if (!array_key_exists($index, $this->_exponent)) {
272
                return Numbers_Words::raiseError('Number out of range.');
273
            }
274
 
275
            /**
276
             * Testing Zero
277
             */
278
            if ($chunk == 0) {
279
                continue;
280
            }
281
 
282
            /**
283
             * Testing plural of exponent
284
             */
285
            if ($chunk > 1) {
286
                $exponent = str_replace('ão', 'ões', $this->_exponent[$index]);
287
            } else {
288
                $exponent = $this->_exponent[$index];
289
            }
290
 
291
            /**
292
             * Adding exponent
293
             */
294
            $ret[] = $exponent;
295
 
296
            /**
297
             * Actual Number
298
             */
299
            $word  = array_filter($this->_parseChunk($chunk));
300
            $ret[] = implode($this->_sep, $word);
301
        }
302
 
303
        /**
304
         * In Brazilian Portuguese the last chunck must be separated under
305
         * special conditions.
306
         */
307
        if ((count($ret) > 2+$neg)
308
             && $this->_mustSeparate($chunks)) {
309
                $ret[1+$neg] = trim($this->_sep.$ret[1+$neg]);
310
        }
311
 
312
        $ret = array_reverse(array_filter($ret));
313
        return implode(' ', $ret);
314
    }
315
 
316
    // }}}
317
    // {{{ _parseChunck()
318
 
319
    /**
320
     * Recursive function that parses an indivial chunk
321
     *
322
     * @param string $chunk String representation of a 3-digit-max number
323
     *
324
     * @return array Words of parsed number
325
     *
326
     * @access private
327
     * @author Igor Feghali <ifeghali@php.net>
328
     * @since  Numbers_Words 0.15.1
329
     */
330
    function _parseChunk($chunk)
331
    {
332
        /**
333
         * Base Case
334
         */
335
        if (!$chunk) {
336
            return array();
337
        }
338
 
339
        /**
340
         * 100 is a special case
341
         */
342
        if ($chunk == 100) {
343
            return array('cem');
344
        }
345
 
346
        /**
347
         * Testing contractions (11~19)
348
         */
349
        if (($chunk < 20) && ($chunk > 10)) {
350
            return array($this->_contractions[$chunk % 10]);
351
        }
352
 
353
        $i    = strlen($chunk)-1;
354
        $n    = (int)$chunk[0];
355
        $word = $this->_words[$i][$n];
356
 
357
        return array_merge(array($word), $this->_parseChunk(substr($chunk, 1)));
358
    }
359
 
360
    // }}}
361
    // {{{ _mustSeparate()
362
 
363
    /**
364
     * In Brazilian Portuguese the last chunk must be separated from the others
365
     * when it is a hundred (100, 200, 300 etc.) or less than 100.
366
     *
367
     * @param array $chunks Array of integers that contains all the chunks of
368
     *                      the target number, in reverse order.
369
     *
370
     * @return boolean Returns true when last chunk must be separated
371
     *
372
     * @access private
373
     * @author Igor Feghali <ifeghali@php.net>
374
     * @since  Numbers_Words 0.15.1
375
     */
376
    function _mustSeparate($chunks)
377
    {
378
        $chunk = null;
379
 
380
        /**
381
         * Find first occurrence != 0.
382
         * (first chunk in array but last logical chunk)
383
         */
384
        reset($chunks);
385
        do {
386
            list(,$chunk) = each($chunks);
387
        } while ($chunk === '000');
388
 
389
        if (($chunk < 100) || !($chunk % 100)) {
390
            return true;
391
        }
392
        return false;
393
    }
394
 
395
    // }}}
396
    // {{{ toCurrencyWords()
397
 
398
    /**
399
     * Converts a currency value to its word representation
400
     * (with monetary units) in Portuguese Brazilian
401
     *
402
     * @param integer $int_curr         An international currency symbol
403
     *                                  as defined by the ISO 4217 standard (three characters)
404
     * @param integer $decimal          A money total amount without fraction part (e.g. amount of dollars)
405
     * @param integer $fraction         Fractional part of the money amount (e.g. amount of cents)
406
     *                                  Optional. Defaults to false.
407
     * @param integer $convert_fraction Convert fraction to words (left as numeric if set to false).
408
     *                                  Optional. Defaults to true.
409
     *
410
     * @return string  The corresponding word representation for the currency
411
     *
412
     * @access public
413
     * @author Igor Feghali <ifeghali@php.net>
414
     * @since  Numbers_Words 0.11.0
415
     */
416
    function toCurrencyWords($int_curr, $decimal, $fraction = false, $convert_fraction = true)
417
    {
418
        $neg   = 0;
419
        $ret   = array();
420
        $nodec = false;
421
 
422
        /**
423
         * Negative ?
424
         * We can lose the '-' sign if we do the
425
         * check after number_format() call (i.e. -0.01)
426
         */
427
        if (substr($decimal, 0, 1) == '-') {
428
            $decimal = -$decimal;
429
            $neg     = 1;
430
        }
431
 
432
        /**
433
         * Removes leading zeros, spaces, decimals etc.
434
         * Adds thousands separator.
435
         */
436
        $num = number_format($decimal, 0, '', '');
437
 
438
        /**
439
         * Checking if given currency exists in driver.
440
         * If not, use default currency
441
         */
442
        $int_curr = strtoupper($int_curr);
443
        if (!isset($this->_currency_name[$int_curr])) {
444
            $int_curr = $this->def_currency;
445
        }
446
 
447
        /**
448
         * Currency names and plural
449
         */
450
        $curr_names = $this->_currency_names[$int_curr];
451
 
452
        if ($num > 0) {
453
            /**
454
             * Word representation of decimal
455
             */
456
            $ret[] = $this->toWords($num);
457
 
458
            /**
459
             * Special case.
460
             */
461
            if (substr($num, -6) == '000000') {
462
                $ret[] = trim($this->_curr_sep);
463
            }
464
 
465
            /**
466
             * Testing plural. Adding currency name
467
             */
468
            if ($num > 1) {
469
                $ret[] = $curr_names[0][1];
470
            } else {
471
                $ret[] = $curr_names[0][0];
472
            }
473
        }
474
 
475
        /**
476
         * Test if fraction was given and != 0
477
         */
478
        $fraction = (int)$fraction;
479
        if ($fraction) {
480
 
481
            /**
482
             * Removes leading zeros, spaces, decimals etc.
483
             * Adds thousands separator.
484
             */
485
            $num = number_format($fraction, 0, '.', '.');
486
 
487
            /**
488
             * Testing Range
489
             */
490
            if ($num < 0 || $num > 99) {
491
                return Numbers_Words::raiseError('Fraction out of range.');
492
            }
493
 
494
            /**
495
             * Have we got decimal?
496
             */
497
            if (count($ret)) {
498
                $ret[] = trim($this->_sep);
499
            } else {
500
                $nodec = true;
501
            }
502
 
503
            /**
504
             * Word representation of fraction
505
             */
506
            if ($convert_fraction) {
507
                $ret[] = $this->toWords($num);
508
            } else {
509
                $ret[] = $num;
510
            }
511
 
512
            /**
513
             * Testing plural
514
             */
515
            if ($num > 1) {
516
                $ret[] = $curr_names[1][1];
517
            } else {
518
                $ret[] = $curr_names[1][0];
519
            }
520
 
521
            /**
522
             * Have we got decimal?
523
             * If not, include currency name after cents.
524
             */
525
            if ($nodec) {
526
                $ret[] = trim($this->_curr_sep);
527
                $ret[] = $curr_names[0][0];
528
            }
529
        }
530
 
531
        /**
532
         * Negative ?
533
         */
534
        if ($neg) {
535
            $ret[] = $this->_minus;
536
        }
537
 
538
        return implode(' ', $ret);
539
    }
540
    // }}}
541
}
542
 
543
?>