A simple approach to Localization in PHP

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:

  1. Very easy integration into your code
  2. The language phrases remain recognizable in your own code
  3. The language files can be easily customised because the original phrase is part of the translation
  4. Language file needs to be loaded only once
  5. The language file is coded in an open standard (JSON) and can be processed in other ways that you currently don’t foresee
  • MAB

    Hi

    I was looking for a way to localize my own phrases and found your post. Your idea perfectly fits my desires and quite simple. JSON files are easy to translate, even for people not familiar with programming. Thanks for telling us your idea :-)

    • postme

      MAB,

      happy to share and thank you for your kind words

      Meint

  • http://www.sur-plus.com bryan

    Super, very helpfull. Just one thin: in your example you declared ‘INCLUDE_PATH’ instead of ‘INCLUDE_FILE’.

    • postme

      oops, thanks, corrected

  • Pingback: A simple approach to Localization in PHP

  • Alain

    Hi,
    how do you make this work with utf8 or other encodings?
    Thanks

    • postme

      The method works with Unicode data because of the json_decode function. A quote from the PHP manual page: “This function only works with UTF-8 encoded data”.

  • shyam

    this is nice post.

  • Pingback: GeoLocalization « Alessioma’s Weblog

  • http://www.whitneyland.com Lee

    Great work on your code, thanks.

    The line numbers in the code listing are not fun though:
    http://remove-line-numbers.ruurtjan.com

    • postme

      @Lee, Hi I’ve removed the line numbers, thanks for your comment, regards Meint

  • Pingback: CarlosGuerra » Pues si, sinluz.tk ahora 2.0(.0.0.0.0.0)

  • DanyBoy

    Hi, thanks for the great tuto.

    However I want to point out that this is necessary to encode the .txt files in ‘utf-8 (without BOM)’. If not, the json decode returns null.
    (Spent 30 min with that problem xD )

    Thanks again

    • postme

      @DanyBoy, tnx I updated the blogpost with this info

  • Puresilence

    Hey, nice simple and easy approach! THX for this tip. Helped me a lot :o)

  • Pingback: Pues sí, sinluz.tk ahora 2.0(.0.0.0.0.0) | GuerraCarlos

  • http://www.limabean.co.za JP

    Thanks for sharing. I have to do something similar now for a multi-lingual site and I think this might just do the trick! :)

  • http://pantljika-online.info Zoran

    Thank you very much, it’s just what I needed.
    I also replaced return with:
    if (!array_key_exists($phrase, $translations)) {
    return $phrase;
    } else {
    return $translations[$phrase];
    }
    to avoid possible errors if there is no key in JSON file.