[ACCEPTED]-Most efficient way to do language file in PHP?-multiple-languages
It'd probably be best to define a function 14 that handles your language mapping. That 13 way, if you do want to change how it works 12 later, you're not forced to scour hundreds 11 of scripts for cases where you used $lang[...]
and 10 replace them with something else.
Something 9 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 8 sure the array is declared static
inside the function 7 so it doesn't get reallocated each time 6 the function is called. This is especially 5 important when $lang
is really large.
To use it:
echo lang('NO_PHOTO');
For 4 handling multiple languages, just have this 3 function defined in multiple files (like 2 en.php
, fr.php
, etc) and require()
the appropriate one for the 1 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 8 for now. If the language is not found, it 7 will return the phrase, instead of an error.
You 6 should note that an array can contain no 5 more than ~65500 items. Should be enough 4 but well, just saying.
Here's some code that 3 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 2 not done yet, but well i think this might 1 help a lot.
Don't write your own language framework. Use 1 gettext. PHP has standard bindings that you can install.
As the other answers don't really answer 35 all the questions, I will go for that in 34 my answer plus offering a sensible alternative.
1) I18n 33 is short for Internationalization and has 32 some similarities to I-eighteen-n.
2) In 31 my honest opinion gettext is a waste of 30 time.
3) Your approach looks good. What 29 you should look for are language variables. The 28 WoltLab Community Framework 2.0 implements a two-way language system. For 27 once there are language variables that are 26 saved in database and inside a template 25 one only uses the name of the variable which 24 will then be replaced with the content of 23 the variable in the current language (if 22 available). The second part of the system 21 provides a way to save user generated content 20 in multiple languages (input in multiple 19 languages required).
Basically you have the 18 interface text that is defined by the developer 17 and the content that is defined by the user. The 16 multilingual text of the content is saved 15 in language variables and the name of the 14 language variable is then used as value 13 for the text field in the specific content 12 table (as single-language contents are also 11 possible).
The structure of the WCF is sadly 10 in a way that reusing code outside of the 9 framework is very difficult but you can 8 use it as inspiration. The scope of the 7 system depends solely on what you want to 6 achieve with your site. If it is going to 5 be big than you should definitely take a 4 look at the WCF system. If it's small a 3 few dedicated language files (de.php, en.php, etc), from 2 which the correct one for the current language 1 is included, will do.
why not you just make it as multi-dimesional 1 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 12 this for each language. To use the text:
There is no place like <?=T::home?>.
The 11 downside is that if you add a new constant, you 10 have to do it for every langauge file. If you forget one, your 9 page breaks for that language. That is a 8 bit nasty, but it is efficient since it 7 doesn't need to create a large associative 6 array and possibly the values even get inlined.
Maybe 5 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 4 the array and rely on constant to do the lookup, which 3 I assume is more expensive than using the 2 constants directly. The up side is the lookup 1 can use a fallback when the key is not found.
An extension to the answers above whom deserve 12 the credit - I'm just posting as maybe this 11 will also be useful to someone else who 10 ends up here.
I personally prefer the key 9 to the array to be the actual phrase in 8 my mother tongue (in my case English) rather 7 than a CONSTANT_VALUE because:
- I find it easier to read the code when the text is in my native language rather than having to remember what a CONSTANT_VALUE actually outputs
- It means no lookup is needed to return the phrase for visitors who also use my naitive language (giving marginally better performance)
- It's one less list of values to maintain
The downside 6 is that it's harder to spot missing values 5 in other languages as you don't necessarily 4 have a master list anymore - I also log 3 a warning from the abstract method so that 2 I spot any missing values.
I implemented 1 as:
- An abstract class with static methods for outputting the text value (using late static binding)
- A concrete class for each language: English overriding the method to return the phrase without translation, other languages overriding the list of phrases so that a translated phrase is returned
<?php
namespace Language;
abstract class _Language
{
protected static $displayText = array();
public static function output($phrase){
return static::$displayText[$phrase] ?? $phrase;
}
}
<?php
namespace Language;
class English extends _Language
{
public static function output($phrase){
return $phrase;
}
}
<?php
namespace Language;
class Spanish extends _Language
{
protected static $displayText = array(
'Forename' => 'Nombre',
'Registered Email' => 'Correo electrónico registrado',
'Surname' => 'Apellido'
);
}
Usage:
$language = new \Language\Spanish();
echo $language::output('Forename'); // Outputs: Nombre
$language = new \Language\English();
echo $language::output('Registered Email'); // Outputs: Registered Email
Unfortunately gettext not work good and have problems 10 in various situation like on different OS 9 (Windows or Linux) and make it work is very 8 difficult.
In addition it require you set 7 lot's of environment variables and domains 6 and this not have any sense.
If a developer 5 want simply get the translation of a text 4 he should only set the .mo file path and 3 get the translation with one function like 2 translate("hello","en_EN"); With gettext 1 this is not possible.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.