Helping ordinary people create extraordinary websites!
HOME TUTORIALS SCRIPTS WEB HOSTING BLOG FORUM
Get Our Newsletter
Email:

Internationalisation and my PHP Development Infrastructure

By Tony Marston
2005-07-17


My Implementation - Handling Numbers

Although the English notation for numbers is to use '.' (period) for the decimal separator and ',' (comma) for the thousands separator there are some countries which use a different notation. Some have the two separators completely reversed, and some use ' ' (space) as the thousands separator. Regardless of any national conventions all numbers are processed within the program code, and stored within the database, in a common format. That is, the decimal point is a '.' (period) and there are no thousands separators.

This means that all decimal values must be formatted before they can be output to the user, and any user input must be unformatted before it can be handled by the program.

Convert to external (user's) format

A very important step in this process is therefore to identify all the decimal format conventions expected by the user. Fortunately all the relevant information can be provided by the localeconv() function. Unfortunately this requires the user's actual locale to be identified first with the setlocale() function. I say 'unfortunately' because the input to this function is the user's current locale or location whereas the only information available at present is the user's preferred language as supplied in the HTTP variables. I have got round this minor annoyance by modifying the 'languages' array used to determine the user's language to include a locale in the full language string, as in the following examples:

  • English (United Kingdom) [ENG]
  • English (United States) [USA]
  • French (Canada) [CAN]
  • French (France) [FRA]
  • German (Germany) [DEU]
  • Spanish (Spain) [ESP]

This means that I can now set the user's locale using code similar to the following:

    // get full language string from first entry in user_language_array

$country = $_SESSION['user_language_array'][0][2];
// extract locale which is enclosed in '[' and ']'
if (!preg_match('?\[[^\[]+\]?', $country, $regs)) {
// 'Locale is not defined in string'
trigger_error(getLanguageText('sys0078', $country), E_USER_ERROR);
} // if
$locale = trim($regs[0], '[]');
// find out if this is a valid locale
if (!$locale = setLocale(LC_ALL, $locale)) {
// 'Cannot set locale'
trigger_error(getLanguageText('sys0079', $locale), E_USER_ERROR);
} // if

Having set the locale it is then a relatively simple exercise to convert any decimal number from internal to external format using code similar to the following:

    $decimal_places = $this->fieldspec[$fieldname]['scale'];

$locale = localeconv();
$decimal_point = $locale['decimal_point'];
$thousands_sep = $locale['thousands_sep'];
if ($thousands_sep == chr(160)) {
// change non-breaking space into ordinary space
$thousands_sep = chr(32);
} // if
$fieldvalue = number_format($fieldvalue,
$decimal_places,
$decimal_point,
$thousands_sep);

Convert to internal format

When the user presses the SUBMIT button any numbers that have been input will need to be converted back into internal format before they can be processed. This is done with code similar to the following:

function number_unformat ($input)

// convert input string into a number using settings from localeconv()
{
$locale = localeconv();
$decimal_point = $locale['decimal_point'];
$thousands_sep = $locale['thousands_sep'];
if ($thousands_sep == chr(160)) {
// change non-breaking space into ordinary space
$thousands_sep = chr(32);
} // if

$count = count_chars($input, 1);
if ($count[ord($decimal_point)] > 1) {
// too many decimal places
return $input;
} // if

// split number into 2 distinct parts
list($integer, $fraction) = explode($decimal_point, $input);

// remove thousands separator
$integer = str_replace($thousands_sep, NULL, $integer);

// join the two parts back together again
$number = $integer .'.' .$fraction;

return $number;

} // number_unformat


Tutorial Pages:
» Introduction
» Possible Methods
» Design Decisions
» My Implementation - Directory Structure
» My Implementation - File Names
» My Implementation - Determine User Language
» My Implementation - Locate Language Subdirectory
» My Implementation - Load Screen Structure file
» My Implementation - Get Language Text
» My Implementation - Get Language Array
» My Implementation - Handling Dates
» My Implementation - Handling Numbers
» Conclusion
» References


 | Bookmark
Related Tutorials:
» Zend Framework Tutorial
» Port Scanning and Service Status Checking in PHP
» Web Database Access from Desktop Applications
» CubeCart 3.0 Installation and Configuration
» PHP Site Search Made Easy
» Installing and Configuring Drupal 6.1