There’s quite a number of ways to approach localization (L10N) in PHP. Typing in “simple localization php” in Google yields an impressive amount of results. I won’t go into a heavy theoretical approach in what the best way is or that you need to use gettext or any such approach. I just want to present the function(s) I’m using and leave it up to you to decide whether you like the approach.
First some constants that I use. You can rip them out if you don’t like them, they’re not essential, I just like using constants for this type of work.
/**
* Define the url path for the resources
*/
defined('INCLUDE_PATH') or define('INCLUDE_PATH', '/include');
/**
* Define the language using language code based on BCP 47 + RFC 4644,
* http://www.rfc-editor.org/rfc/bcp/bcp47.txt
*
* The language files can be found in directory 'lang'
*/
defined('LANGUAGE') or define('LANGUAGE', 'en-us');
The constants are used in the code below, replace them with your own values or approach where necessary. What happens is that a language file is loaded based on the configured language. A static array $translations is used to ensure that the language file is loaded once and every other subsequent call is handled through the $translations array in memory rather than reloading the language file. The language file is constructed in JSON format and when the language file is loaded into the $translations array the PHP json_decode function is used to convert from JSON to PHP associative array format. When a call is made to the function a language phrase is passed to the function and the matching value is found in the $translations array by using the language phrase as a key for the associative array.
Please ensure the .txt files are utf-8 encoded (without BOM), otherwise the json PHP functions will not operate correctly (see comment DanyBoy below).
/**
* Load the proper language file and return the translated phrase
*
* The language file is JSON encoded and returns an associative array
* Language filename is determined by BCP 47 + RFC 4646
* http://www.rfc-editor.org/rfc/bcp/bcp47.txt
*
* @param string $phrase The phrase that needs to be translated
* @return string
*/
function localize($phrase) {
/* Static keyword is used to ensure the file is loaded only once */
static $translations = NULL;
/* If no instance of $translations has occured load the language file */
if (is_null($translations)) {
$lang_file = INCLUDE_PATH . '/lang/' . LANGUAGE . '.txt';
if (!file_exists($lang_file)) {
$lang_file = INCLUDE_PATH . '/lang/' . 'en-us.txt';
}
$lang_file_content = file_get_contents($lang_file);
/* Load the language file as a JSON object and transform it into an associative array */
$translations = json_decode($lang_file_content, true);
}
return $translations[$phrase];
}
An excerpt of the US English language file (in JSON format):
{
"lang":"en-us",
"No":"No",
"Yes":"Yes",
"or":"or",
"Do you require help":"Do you require help"
}
An excerpt of the German language file:
{
"lang":"de",
"No":"Nein",
"Yes":"Ja",
"or":"oder",
"Do you require help":"Brauchen Sie Hilfe"
}
Edit : Please make sure the language files are saved in UTF-8 format as this is the default encoding for the json_decode function used in the code above.
An example of it’s usage:
print localize('Do you require help') . localize('Yes') . localize('or') . localize('No');
An example of usage in some of my own code:
$create_page_array = array(
'status_message' => $status_message,
'table_caption' => localize('Delete Operation'),
'table_explanation' => localize('This command deletes an operation'),
'table_content' => $table_content,
'checkbox' => 'operation_name',
'table_sort' => '[[1,0]]'
);
The advantages to me are:
- Very easy integration into your code
- The language phrases remain recognizable in your own code
- The language files can be easily customised because the original phrase is part of the translation
- Language file needs to be loaded only once
- The language file is coded in an open standard (JSON) and can be processed in other ways that you currently don’t foresee