Most efficient way to do language file in PHP?

夙愿已清 提交于 2019-11-27 18:01:28

Don't reinvent the wheel. Use for example gettext or Zend_Translate.

It'd probably be best to define a function that handles your language mapping. That way, if you do want to change how it works later, you're not forced to scour hundreds of scripts for cases where you used $lang[...] and replace them with something else.

Something like this would work and would be nice & fast:

function lang($phrase){
    static $lang = array(
        'NO_PHOTO' => 'No photo\'s available',
        'NEW_MEMBER' => 'This user is new'
    );
    return $lang[$phrase];
}

Make sure the array is declared static inside the function so it doesn't get reallocated each time the function is called. This is especially important when $lang is really large.

To use it:

echo lang('NO_PHOTO');

For handling multiple languages, just have this function defined in multiple files (like en.php, fr.php, etc) and require() the appropriate one for the user.

This might work better:

function _L($phrase){
static $_L = array(
    'NO_PHOTO' => 'No photo\'s available',
    'NEW_MEMBER' => 'This user is new'
);

     return (!array_key_exists($phrase,$_L)) ? $phrase : $_L[$phrase];
}

Thats what i use for now. If the language is not found, it will return the phrase, instead of an error.

You should note that an array can contain no more than ~65500 items. Should be enough but well, just saying.

Here's some code that i use to check for the user's language:

<?php
function setSessionLanguageToDefault() {
    $ip=$_SERVER['REMOTE_ADDR'];
    $url='http://api.hostip.info/get_html.php?ip='.$ip;
    $data=file_get_contents($url);
    $s=explode (':',$data);
    $s2=explode('(',$s[1]);

    $country=str_replace(')','',substr($s2[1], 0, 3));

    if ($country=='us') {
        $country='en';
    }

    $country=strtolower(ereg_replace("[^A-Za-z0-9]", "", $country ));
    $_SESSION["_LANGUAGE"]=$country;
}

if (!isset($_SESSION["_LANGUAGE"])) {
    setSessionLanguageToDefault();
}

if (file_exists(APP_DIR.'/language/'.$_SESSION["_LANGUAGE"].'.php')) {
    include(APP_DIR.'/language/'.$_SESSION["_LANGUAGE"].'.php');
} else {
    include(APP_DIR.'/language/'.DEFAULT_LANG.'.php');
}

?>

Its not done yet, but well i think this might help a lot.

Don't write your own language framework. Use gettext. PHP has standard bindings that you can install.

As the other answers don't really answer all the questions, I will go for that in my answer plus offering a sensible alternative.

1) I18n is short for Internationalization and has some similarities to I-eighteen-n.

2) In my honest opinion gettext is a waste of time.

3) Your approach looks good. What you should look for are language variables. The WoltLab Community Framework 2.0 implements a two-way language system. For once there are language variables that are saved in database and inside a template one only uses the name of the variable which will then be replaced with the content of the variable in the current language (if available). The second part of the system provides a way to save user generated content in multiple languages (input in multiple languages required).

Basically you have the interface text that is defined by the developer and the content that is defined by the user. The multilingual text of the content is saved in language variables and the name of the language variable is then used as value for the text field in the specific content table (as single-language contents are also possible).

The structure of the WCF is sadly in a way that reusing code outside of the framework is very difficult but you can use it as inspiration. The scope of the system depends solely on what you want to achieve with your site. If it is going to be big than you should definitely take a look at the WCF system. If it's small a few dedicated language files (de.php, en.php, etc), from which the correct one for the current language is included, will do.

Unfortunately gettext not work good and have problems in various situation like on different OS (Windows or Linux) and make it work is very difficult.

In addition it require you set lot's of environment variables and domains and this not have any sense.

If a developer want simply get the translation of a text he should only set the .mo file path and get the translation with one function like translate("hello","en_EN"); With gettext this is not possible.

why not you just make it as multi-dimesional array...such as this

<?php

$lang = array(
    'EN'=> array(
        'NO_PHOTO'=>'No photo\'s avaiable',
        'NEW_MEMBER'=>'This user is new',
    ),
    'MY'=> array(
        'NO_PHOTO'=>'Tiada gambar',
        'NEW_MEMBER'=>'Ini adalah pengguna baru',
    )
);

?>

You can do this:

class T {
const language = "English";
const home = "Home";
const blog = "Blog";
const forum = "Forum";
const contact = "Support";
}

You would have a file like this for each language. To use the text:

There is no place like <?=T::home?>.

The downside is that if you add a new constant, you have to do it for every langauge file. If you forget one, your page breaks for that language. That is a bit nasty, but it is efficient since it doesn't need to create a large associative array and possibly the values even get inlined.

Maybe access could be improved, eg:

class T {
    const home = "home";

    public static function _ ($name) {
        $value = @constant("self::$name");
        return $value ? $value : $name;
    }

    // Or maybe through an instance:
    public function __get ($name) {
        $value = @constant("self::$name");
        return $value ? $value : $name;
    }
}
echo "There is no " . T::_("place") . " like " . T::_("home");
$T = new T();
echo "There is no " . $T->place . " like " . $T->home;

We still avoid the array and rely on constant to do the lookup, which I assume is more expensive than using the constants directly. The up side is the lookup can use a fallback when the key is not found.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!