Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
543 lines (486 sloc) 14.1 KB
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Numbers_Words
*
* PHP version 5
*
* This source file is subject to version 3.01 of the PHP license,
* that is bundled with this package in the file LICENSE, and is
* available at through the world-wide-web at
* http://www.php.net/license/3_01.txt
* If you did not receive a copy of the PHP license and are unable to
* obtain it through the world-wide-web, please send a note to
* license@php.net so we can mail you a copy immediately.
*
* @category Numbers
* @package Numbers_Words
* @author Igor Feghali <ifeghali@php.net>
* @license PHP 3.01 http://www.php.net/license/3_01.txt
* @version SVN: $Id$
* @link http://pear.php.net/package/Numbers_Words
*/
/**
* Include needed files
*/
require_once "Numbers/Words.php";
/**
* Class for translating numbers into Brazilian Portuguese. This class complies
* to Brazilian Academy of Letters rules as of 2008-12-12.
*
* @category Numbers
* @package Numbers_Words
* @author Igor Feghali <ifeghali@php.net>
* @license PHP 3.01 http://www.php.net/license/3_01.txt
* @link http://pear.php.net/package/Numbers_Words
*/
class Numbers_Words_pt_BR extends Numbers_Words
{
/**
* Locale name
* @var string
* @access public
*/
var $locale = 'pt_BR';
/**
* Language name in English
* @var string
* @access public
*/
var $lang = 'Brazilian Portuguese';
/**
* Native language name
* @var string
* @access public
*/
var $lang_native = 'Português Brasileiro';
/**
* The word for the minus sign
* @var string
* @access private
*/
var $_minus = 'negativo';
/**
* The word separator for numerals
* @var string
* @access private
*/
var $_sep = ' e ';
/**
* The special separator for numbers and currency names
* @var string
* @access private
*/
var $_curr_sep = ' de ';
/**
* The array containing numbers 11-19.
* In Brazilian Portuguese numbers in that range are contracted
* in a single word.
* @var array
* @access private
*/
var $_contractions = array(
'',
'onze',
'doze',
'treze',
'quatorze',
'quinze',
'dezesseis',
'dezessete',
'dezoito',
'dezenove'
);
var $_words = array(
/**
* The array containing the digits (indexed by the digits themselves).
* @var array
* @access private
*/
array(
'', // 0: not displayed
'um',
'dois',
'três',
'quatro',
'cinco',
'seis',
'sete',
'oito',
'nove'
),
/**
* The array containing numbers for 10,20,...,90.
* @var array
* @access private
*/
array(
'', // 0: not displayed
'dez',
'vinte',
'trinta',
'quarenta',
'cinqüenta',
'sessenta',
'setenta',
'oitenta',
'noventa'
),
/**
* The array containing numbers for hundreds.
* @var array
* @access private
*/
array(
'', // 0: not displayed
'cento', // 'cem' is a special case handled in _toWords()
'duzentos',
'trezentos',
'quatrocentos',
'quinhentos',
'seiscentos',
'setecentos',
'oitocentos',
'novecentos'
),
);
/**
* The sufixes for exponents (singular)
* @var array
* @access private
*/
var $_exponent = array(
'', // 0: not displayed
'mil',
'milhão',
'bilhão',
'trilhão',
'quatrilhão',
'quintilhão',
'sextilhão',
'septilhão',
'octilhão',
'nonilhão',
'decilhão',
'undecilhão',
'dodecilhão',
'tredecilhão',
'quatuordecilhão',
'quindecilhão',
'sedecilhão',
'septendecilhão'
);
/**
* The currency names (based on Wikipedia) and plurals
*
* @var array
* @link http://pt.wikipedia.org/wiki/ISO_4217
* @access private
*/
var $_currency_names = array(
'BRL' => array(array('real', 'reais'), array('centavo', 'centavos')),
'USD' => array(array('dólar', 'dólares'), array('centavo', 'centavos')),
'EUR' => array(array('euro', 'euros'), array('centavo', 'centavos')),
'GBP' => array(array('libra esterlina', 'libras esterlinas'), array('centavo', 'centavos')),
'JPY' => array(array('iene', 'ienes'), array('centavo', 'centavos')),
'ARS' => array(array('peso argentino', 'pesos argentinos'), array('centavo', 'centavos')),
'MXN' => array(array('peso mexicano', 'pesos mexicanos'), array('centavo', 'centavos')),
'UYU' => array(array('peso uruguaio', 'pesos uruguaios'), array('centavo', 'centavos')),
'PYG' => array(array('guarani', 'guaranis'), array('centavo', 'centavos')),
'BOB' => array(array('boliviano', 'bolivianos'), array('centavo', 'centavos')),
'CLP' => array(array('peso chileno', 'pesos chilenos'), array('centavo', 'centavos')),
'COP' => array(array('peso colombiano', 'pesos colombianos'), array('centavo', 'centavos')),
'CUP' => array(array('peso cubano', 'pesos cubanos'), array('centavo', 'centavos')),
);
/**
* The default currency name
* @var string
* @access public
*/
var $def_currency = 'BRL'; // Real
// {{{ _toWords()
/**
* Converts a number to its word representation
* in Brazilian Portuguese language
*
* @param integer $num An integer between -999E54 and 999E54
*
* @return string The corresponding word representation
*
* @access protected
* @author Igor Feghali <ifeghali@php.net>
* @since Numbers_Words 0.16.3
*/
function _toWords($num)
{
$neg = 0;
$ret = array();
$words = array();
/**
* Negative ?
*/
if ($num < 0) {
$ret[] = $this->_minus;
$num = -$num;
$neg = 1;
}
/**
* Removes leading zeros, spaces, decimals etc.
* Adds thousands separator.
*/
$num = number_format($num, 0, '.', '.');
/**
* Testing Zero
*/
if ($num == 0) {
return 'zero';
}
/**
* Breaks into chunks of 3 digits.
* Reversing array to process from right to left.
*/
$chunks = array_reverse(explode(".", $num));
/**
* Looping through the chunks
*/
foreach ($chunks as $index => $chunk) {
/**
* Testing Range
*/
if (!array_key_exists($index, $this->_exponent)) {
return Numbers_Words::raiseError('Number out of range.');
}
/**
* Testing Zero
*/
if ($chunk == 0) {
continue;
}
/**
* Testing plural of exponent
*/
if ($chunk > 1) {
$exponent = str_replace('ão', 'ões', $this->_exponent[$index]);
} else {
$exponent = $this->_exponent[$index];
}
/**
* Adding exponent
*/
$ret[] = $exponent;
/**
* Actual Number
*/
$word = array_filter($this->_parseChunk($chunk));
$ret[] = implode($this->_sep, $word);
}
/**
* In Brazilian Portuguese the last chunck must be separated under
* special conditions.
*/
if ((count($ret) > 2+$neg)
&& $this->_mustSeparate($chunks)) {
$ret[1+$neg] = trim($this->_sep.$ret[1+$neg]);
}
$ret = array_reverse(array_filter($ret));
return implode(' ', $ret);
}
// }}}
// {{{ _parseChunck()
/**
* Recursive function that parses an indivial chunk
*
* @param string $chunk String representation of a 3-digit-max number
*
* @return array Words of parsed number
*
* @access private
* @author Igor Feghali <ifeghali@php.net>
* @since Numbers_Words 0.15.1
*/
function _parseChunk($chunk)
{
/**
* Base Case
*/
if (!$chunk) {
return array();
}
/**
* 100 is a special case
*/
if ($chunk == 100) {
return array('cem');
}
/**
* Testing contractions (11~19)
*/
if (($chunk < 20) && ($chunk > 10)) {
return array($this->_contractions[$chunk % 10]);
}
$i = strlen($chunk)-1;
$n = (int)$chunk[0];
$word = $this->_words[$i][$n];
return array_merge(array($word), $this->_parseChunk(substr($chunk, 1)));
}
// }}}
// {{{ _mustSeparate()
/**
* In Brazilian Portuguese the last chunk must be separated from the others
* when it is a hundred (100, 200, 300 etc.) or less than 100.
*
* @param array $chunks Array of integers that contains all the chunks of
* the target number, in reverse order.
*
* @return boolean Returns true when last chunk must be separated
*
* @access private
* @author Igor Feghali <ifeghali@php.net>
* @since Numbers_Words 0.15.1
*/
function _mustSeparate($chunks)
{
$chunk = null;
/**
* Find first occurrence != 0.
* (first chunk in array but last logical chunk)
*/
reset($chunks);
do {
list(,$chunk) = each($chunks);
} while ($chunk === '000');
if (($chunk < 100) || !($chunk % 100)) {
return true;
}
return false;
}
// }}}
// {{{ toCurrencyWords()
/**
* Converts a currency value to its word representation
* (with monetary units) in Portuguese Brazilian
*
* @param integer $int_curr An international currency symbol
* as defined by the ISO 4217 standard (three characters)
* @param integer $decimal A money total amount without fraction part (e.g. amount of dollars)
* @param integer $fraction Fractional part of the money amount (e.g. amount of cents)
* Optional. Defaults to false.
* @param integer $convert_fraction Convert fraction to words (left as numeric if set to false).
* Optional. Defaults to true.
*
* @return string The corresponding word representation for the currency
*
* @access public
* @author Igor Feghali <ifeghali@php.net>
* @since Numbers_Words 0.11.0
*/
function toCurrencyWords($int_curr, $decimal, $fraction = false, $convert_fraction = true)
{
$neg = 0;
$ret = array();
$nodec = false;
/**
* Negative ?
* We can lose the '-' sign if we do the
* check after number_format() call (i.e. -0.01)
*/
if (substr($decimal, 0, 1) == '-') {
$decimal = -$decimal;
$neg = 1;
}
/**
* Removes leading zeros, spaces, decimals etc.
* Adds thousands separator.
*/
$num = number_format($decimal, 0, '', '');
/**
* Checking if given currency exists in driver.
* If not, use default currency
*/
$int_curr = strtoupper($int_curr);
if (!isset($this->_currency_name[$int_curr])) {
$int_curr = $this->def_currency;
}
/**
* Currency names and plural
*/
$curr_names = $this->_currency_names[$int_curr];
if ($num > 0) {
/**
* Word representation of decimal
*/
$ret[] = $this->_toWords($num);
/**
* Special case.
*/
if (substr($num, -6) == '000000') {
$ret[] = trim($this->_curr_sep);
}
/**
* Testing plural. Adding currency name
*/
if ($num > 1) {
$ret[] = $curr_names[0][1];
} else {
$ret[] = $curr_names[0][0];
}
}
/**
* Test if fraction was given and != 0
*/
$fraction = (int)$fraction;
if ($fraction) {
/**
* Removes leading zeros, spaces, decimals etc.
* Adds thousands separator.
*/
$num = number_format($fraction, 0, '.', '.');
/**
* Testing Range
*/
if ($num < 0 || $num > 99) {
return Numbers_Words::raiseError('Fraction out of range.');
}
/**
* Have we got decimal?
*/
if (count($ret)) {
$ret[] = trim($this->_sep);
} else {
$nodec = true;
}
/**
* Word representation of fraction
*/
if ($convert_fraction) {
$ret[] = $this->_toWords($num);
} else {
$ret[] = $num;
}
/**
* Testing plural
*/
if ($num > 1) {
$ret[] = $curr_names[1][1];
} else {
$ret[] = $curr_names[1][0];
}
/**
* Have we got decimal?
* If not, include currency name after cents.
*/
if ($nodec) {
$ret[] = trim($this->_curr_sep);
$ret[] = $curr_names[0][0];
}
}
/**
* Negative ?
*/
if ($neg) {
$ret[] = $this->_minus;
}
return implode(' ', $ret);
}
// }}}
}
Jump to Line
Something went wrong with that request. Please try again.