6

Question

I have a fairly static website with just a few basic PHP usage. Now the customer would like to have this website translated. I do have a solution, but it's cumbersome and I was wondering how others are doing it and what is the standard (in frameworks, etc.).

My Way

My way (I have simplified it a bit for the sake of easier understanding): I generate a PHP array for each language from the database and store this array in a language file, like es.php for Spanish.

I then translate a string in HTML using a tr function like this:
Before:<h1>Hello World</h1>
After: <h1><?php echo tr('Hello World'); ?></h1> which gives <h1>Hola Mundo</h1> for Spanish.

The Problem

This is cumbersome and error prone. I have to go through each .php file and replace all the hardcoded strings with this PHP tag with echo.
Is there a better way? How are others doing it? If needed, I can elaborate on my implementation.

duality_
  • 17,738
  • 23
  • 77
  • 95
  • possible duplicate of [PHP - how to translate a website into multiple languages?](http://stackoverflow.com/questions/954160/php-how-to-translate-a-website-into-multiple-languages) – David Z Feb 02 '12 at 23:32

6 Answers6

5

You should look into the PHP GETTEXT extension, it is very fast and will scan your PHP files for strings to translate with .MO and .PO files

You then can simply do something like __('Hello World'); or if you already have all the strings with tr('Hello World'); then you could just modify the tr function to pass it through __(string) or gettext(string) like..

function tr($string){
    __($string)
}
JasonDavis
  • 48,204
  • 100
  • 318
  • 537
  • 3
    How does that solve my problem? This does not change how I use the translation in the HTML and since I already have a backend implemented, I don't see a benefit. – duality_ Feb 02 '12 at 23:55
  • Well first of all your question said that you do use PHP, this is the standard and best way of doing Language translations, far better then using a PHP array. A basic search will back up those statements, but if you know a better solution, go with it. – JasonDavis Feb 03 '12 at 22:26
  • Like I said, your solution is not better than mine and does not offer any benefit to my problem. – duality_ Feb 04 '12 at 10:58
  • That's how translations are done. You either provide a string/key to perform a straight look up from a resource file that will retrieve the correct value dependent on whatever language your app state is currently in. OR you create a copy of the specified pages and simply place the translated text in place of the English text and route the user to a subdomain (e.g. es.mySite.com). Those are *essentially* the ONLY two methods of i18n - lookup, or copied code. – MunkiPhD Feb 14 '12 at 14:00
3

A little late for you, I suppose but in case someone like me stumbles across this thread... Because I currently have the same problem you do. Unfortunately, there doesn't appear to be a "non-cumbersome way" to do this with PHP. Everything seems to involve lots of function-calls (if you have a lot of text).

Well... there is ONE convenient way. Not exactly safe though. Manipulating the output buffer before it's sent to the user: => http://dev-tips.com/featured/output-buffering-for-web-developers-a-beginners-guide

So you could depending on the language chosen just define an array filled with "from->to"-data and replace all the readable text in your buffer by looping through that.

But of course... if you e.g. replace "send" (English) with "senden" (German) and you link to a "send.html", it would break that link.

So if one has to translate not only long, definitely unique strings but also shorter ones, one would have to manipulate only the text that is readable to the user. There is a solution for that too - however, that is JavaScript based: => http://www.isogenicengine.com/documentation/jquery-multi-language-site-plugin/

edwardh
  • 50
  • 6
  • 1
    Both links you suggested are unavailable. – Roko C. Buljan Dec 10 '20 at 15:27
  • You can still read it in webarchive: http://web.archive.org/web/20120229123740/http://www.isogenicengine.com/documentation/jquery-multi-language-site-plugin/ and http://web.archive.org/web/20120120203850/http://dev-tips.com/featured/output-buffering-for-web-developers-a-beginners-guide – MetropolisCZ Jul 23 '21 at 17:20
2

Try this solution. It works for me. It has french and english translation.

Index.php

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>How to Translate your Site in Runtime using Jquery - demo</title>
<link rel="stylesheet" href="css/main.css" type="text/css" />
<script src="js/jquery.min.js"></script>
<script src="js/main.js"></script>
</head>
<body>
<div class="example">
<h3><a href="#">How to Translate your Site in Runtime using Jquery - demo</a></h3>
<div id="content">
<div class="lang_switcher">
<button id="en" class="lang">EN</button>
<button id="fr" class="lang">FR</button>
</div>
<div style="clear:both;"></div>
<!-- nav menu start -->
<ul id="nav">
<li><a href="#nogo" key="home" class="tr">Home</a></li>
<li><a href="#nogo" key="peoples" class="tr">Peoples >></a>
<ul>
<li><a href="#nogo" key="all_list" class="tr">All list</a></li>
<li><a href="#nogo" key="online" class="tr">Online</a></li>
</ul>
</li>
<li><a href="#nogo" key="articles" class="tr">Articles >></a>
<ul>
<li><a href="#nogo" key="js" class="tr">JavaScript</a></li>
<li><a href="#nogo" key="php" class="tr">PHP</a></li>
<li><a href="#nogo" key="html" class="tr">HTML</a></li>
<li><a href="#nogo" key="css" class="tr">CSS</a></li>
</ul>
</li>
<li><a href="#nogo" key="contact_us" class="tr">Contact us</a></li>
</ul>
<!-- nav menu end -->
<div style="clear:both;"></div>
<h2 key="welcome" class="tr">Welcome guests</h2>
<hr />
<div key="a_man" class="tr">A man bribes a rabbit with wicked dentures to run away with him in a sailboat via an ambulance. Bribing Koalas to remain illegally in one place. Trees anchor me in place. / Your mom drives the ambulance, but the city is farther than it appears.</div>
</div>
</div>
</body>
</html>

main.js

// preparing language file
var aLangKeys=new Array();
aLangKeys['en']=new Array();
aLangKeys['fr']=new Array();
aLangKeys['en']['home']='Home';
aLangKeys['en']['peoples']='Peoples >>';
aLangKeys['en']['all_list']='All list';
aLangKeys['en']['online']='Online';
aLangKeys['en']['articles']='Articles >>';
aLangKeys['en']['js']='JavaScript';
aLangKeys['en']['php']='PHP';
aLangKeys['en']['html']='HTML';
aLangKeys['en']['css']='CSS';
aLangKeys['en']['contact_us']='Contact us';
aLangKeys['en']['welcome']='Welcome guests';
aLangKeys['en']['a_man']='A man bribes a rabbit with wicked dentures to run away with him in a sailboat via an ambulance. Bribing Koalas to remain illegally in one place. Trees anchor me in place. / Your mom drives the ambulance, but the city is farther than it appears.';

aLangKeys['fr']['home']='Accueil';
aLangKeys['fr']['peoples']='Peuples >>';
aLangKeys['fr']['all_list']='Toutes les listes';
aLangKeys['fr']['online']='En ligne';
aLangKeys['fr']['articles']='Articles >>';
aLangKeys['fr']['js']='JavaScript';
aLangKeys['fr']['php']='Php';
aLangKeys['fr']['html']='Html';
aLangKeys['fr']['css']='Css';
aLangKeys['fr']['contact_us']='Contactez nous';
aLangKeys['fr']['welcome']='Bienvenue aux invites';
aLangKeys['fr']['a_man']="Un homme soudoie un lapin avec des prothèses méchantes pour s'enfuir avec lui dans un voilier via une ambulance. Corruption des Koalas pour qu'ils restent illégalement à un endroit. Les arbres m'ancrent en place. / Votre mère conduit l'ambulance, mais la ville est plus loin qu'il n'y paraît.";
$(document).ready(function() {
// onclick behavior
$('.lang').click( function() {
var lang = $(this).attr('id'); // obtain language id
// translate all translatable elements
$('.tr').each(function(i){
$(this).text(aLangKeys[lang][ $(this).attr('key') ]);
});
} );
});

And some css- main.css

body{background:#eee;font-family:Verdana, Helvetica, Arial, sans-serif;margin:0;padding:0}
.example{background:#FFF;width:500px;height:500px;font-size:80%;border:1px #000 solid;margin:0.5em 10% 0.5em;padding:1em 2em 2em;-moz-border-radius:3px;-webkit-border-radius:3px}
.lang_switcher{float:right;overflow:hidden;}
/* nav menu styles */
#nav,#nav ul{list-style:none;font:10px verdana, sans-serif;border:1px solid #000;background:#fff;position:relative;z-index:200;border-color:#eca #b97 #a86 #edb;border-width:1px 2px 2px 1px;margin:0;padding:0 0 5px}
#nav{height:25px;padding:0}
#nav table{border-collapse:collapse}
#nav li{float:left;padding:0 20px 0 10px}
#nav li li{float:none}
#nav li a li{float:left}
#nav li a{display:block;float:left;color:#888;height:25px;padding-right:5px;line-height:25px;text-decoration:none;white-space:nowrap}
#nav li li a{height:20px;line-height:20px;float:none}
#nav li:hover{position:relative;z-index:300;background:#fff}
#nav a:hover{position:relative;z-index:300;text-decoration:underline;color:#b75}
#nav :hover ul{left:0;top:22px}
#nav a:hover ul{left:-10px}
#nav li:hover li:hover > ul{left:-15px;margin-left:100%;top:-1px}
#nav li:hover > ul ul{position:absolute;left:-9999px;top:-9999px;width:auto}
#nav li:hover > a{text-decoration:underline;color:#b75}
#nav a:hover a:hover ul,#nav a:hover a:hover a:hover ul,#nav a:hover a:hover a:hover a:hover ul,#nav a:hover a:hover a:hover a:hover a:hover ul{left:100%;top:-1px}
#nav ul,#nav a:hover ul ul,#nav a:hover a:hover ul ul,#nav a:hover a:hover a:hover ul ul,#nav a:hover a:hover a:hover a:hover ul ul{position:absolute;left:-9999px;top:-9999px}
Salman Riyaz
  • 808
  • 2
  • 14
  • 37
2

You could always punt and translate your site using Google's Tools and Resources.

Generally, I consider a multilingual site no longer to be "static". I use Drupal to implement sites. It has some excellent internationalization options.

ghoti
  • 45,319
  • 8
  • 65
  • 104
  • 1
    No, this is not an option, because the translations have to be professional and the design of the site also has to be professional, i.e. without some ugly Google translate – duality_ Feb 02 '12 at 23:52
  • 1
    @MetropolisCZ, after eleven years, I'm not surprised; Google expires products on a pretty regular basis and should never be relied on for anything long term. The Drupal solution, however, is still actively supported, and is the better of the two anyway. – ghoti Jul 24 '21 at 11:18
1

Do way i translate my website is Under doctype have lang then your selected lang, eg below,

Then create a php function to get this by $_POST['get'], and have have that function load up the selected language file/db etc,

1

I made a class to do mine

class WILang

{

    function __construct() 
{
     $this->WIdb = WIdb::getInstance();

}

public static function all($jsonEncode = true) {
    // determine lanuage
    $language = self::getLanguage();
    //echo $language;

    $WIdb = WIdb::getInstance();
        //$file = WILang::getFile($language);
        //echo $file;
        //echo $language;
    if ( ! self::isValidLanguage($language) )
    die('Language file doesn\'t exist!');
    else {

        $sql = "SELECT * FROM `wi_trans` WHERE `lang` = :file";
        $query = $WIdb->prepare($sql);
        $query->bindParam(':file', $language, PDO::PARAM_STR);
        $query->execute();
        //$result = array();
        while ($result = $query->fetchAll(PDO::FETCH_ASSOC)) {
            echo "{";
            foreach ($result as $res) {
            echo '"' .$res['keyword'] .'":"' . $res['translation'] . '",';
             //return array($res['keyword'] => $res['translation'] ,);  
        }

        echo "}";
        }

        }
}

public static function get($key ) //, $bindings = array()
{
    // determine language
    $language = self::getLanguage();

    $WIdb = WIdb::getInstance();

    $sql = "SELECT * FROM `wi_trans` WHERE `keyword`=:key AND lang=:lang";
    $query = $WIdb->prepare($sql);
    $query->bindParam(':key', $key, PDO::PARAM_STR);
    $query->bindParam(':lang', $language, PDO::PARAM_STR);
    $query->execute();

    $res = $query->fetch(PDO::FETCH_ASSOC);
    if($res > 0)
        return $res['translation'];
    else
        return '';
}

 public static function setLanguage($language) 
 {

    // check if language is valid
    if ( self::isValidLanguage($language) ) {
        //set language cookie to 1 year
        setcookie('wi_lang', $language, time() + 60 * 60 * 24 * 365, '/');

        // update session
        WISession::set('wi_lang', $language);

        //refresh the page
        header('Location: ' . $_SERVER['PHP_SELF']);
    }
}

     public static function getLanguage() 
     {
    // check if cookie exist and language value in cookie is valid
    if ( isset ( $_COOKIE['wi_lang'] ) && self::isValidLanguage ( $_COOKIE['wi_lang'] ) )
        return $_COOKIE['wi_lang']; // return lang from cookie
    else
        return WISession::get('wi_lang', DEFAULT_LANGUAGE);
}


    private static function getTrans($language) 
    {
        $WIdb = WIdb::getInstance();
        //$file = WILang::getFile($language);
        //echo $file;
        //echo $language;
    if ( ! self::isValidLanguage($language) )
    die('Language file doesn\'t exist!');
    else {
        //$language = include $file;
        //return $language;

        $sql = "SELECT * FROM `wi_trans` WHERE `lang` = :file";
        $query = $WIdb->prepare($sql);
        $query->bindParam(':file', $language, PDO::PARAM_STR);
        $query->execute();
        //$result = array();
        while ($result = $query->fetchAll(PDO::FETCH_ASSOC)) {
            echo "{";
            foreach ($result as $res) {
            echo '"' .$res['keyword'] .'":"' . $res['translation'] . '",';
             //return array($res['keyword'] => $res['translation'] ,);  
        }

        echo "}";
        }

        }

}



 private static  function getFile($language) 
 {
    $WIdb = WIdb::getInstance();
    $sql = "SELECT * FROM `wi_lang` WHERE `lang` = :file";
    $query = $WIdb->prepare($sql);
    $query->bindParam(':file', $language, PDO::PARAM_STR);
    $query->execute();

    $res = $query->fetch(PDO::FETCH_ASSOC);
    //echo $res['lang'];
    if ($res > 0)
        return $res['lang'];
    else
        return '';


}

    private static function isValidLanguage($lang) 
    {
    $file = self::getFile($lang);
    //echo $file;

    if($file == "")
    //if ( ! file_exists( $file ) )
        return false;
    else
        return true;
}

}