How to make a multilingual website?

10

I have a site made in PHP, now it has come to me that it is obligatory to make the site multilingual. I need to translate titles, menus and error messages. Texts added a posteriori by the user do not need to be translated.

I have seen several types of approaches like:

Definition of constants:

It consists of defining constants in different PHP files, for example pt_PT.php and then adding include 'pt_PT.php'; of translations before page loading.

Example: define( 'USER' , 'UTILIZADOR' );

Definition of arrays :

Consists of defining arrays also including include 'pt_PT.php'; .

Example: $lang['USER'] = 'UTILIZADOR';

Example in this answer .

Gettext:

After viewing this question I discovered it might be by function gettext .

For those who need it here a mini tutorial to use gettext and poEdit

Database:

There is also the possibility of saving the translations in a table of translations.

+-------+------------+--------+-----
|sigla  | pt_PT      | en     | ...
+-------+------------+--------+-----
| usr   | utilizador | user   | ...
+-------+------------+--------+-----

Different pages for each language:

I've also seen having replicated pages for different languages:

www.myhost.pt/en/index.php
www.myhost.pt/en/index.php

In my case that I do not need to have content translation, what is the best option?

Advantages / Disadvantages?

Is there any better option? What?

PS: the most consensual solution I've seen is through gettext.

    
asked by anonymous 18.06.2014 / 16:57

3 answers

9

The solution I use:

I created a file with a translation array for each language, and I made the language setting on the page.

languages.php

<?php
/*
#
# Translations system
# (C)2014 - MyEnterprise
#
*/

// Criar a array de todas as linguas
$translationsArray = array();

// Criar a array para cada lingua
$translationsArray["pt_BR"] = array();
$translationsArray["en_US"] = array();

# PT-BR            $lang     $string
$translationsArray["pt_BR"]["HelloWorld"] = "Olá mundo!";
$translationsArray["pt_BR"]["Title"]      = "Título";
$translationsArray["pt_BR"]["Welcome"]    = "Seja bem-vindo a %s";

# EN-US            $lang     $string
$translationsArray["en_US"]["HelloWorld"] = "hello World!";
$translationsArray["en_US"]["Title"]      = "Title";
$translationsArray["en_US"]["Welcome"]    = "Welcome to %s";

index.php

    <?php
// função para pegar string do arquivo languages.php
function getLanguageString($string, $lang="pt_BR", $parameters=null) {
    /*
    / levando em conta como exemplo: 
    / $translationsArray["pt_BR"]["Welcome"]    = "Seja bem-vindo a %s";
    /
    / $string = "ID" da string, seria o "Welcome"
    / $lang = A lingua para pegar a string, no caso pt_BR ou en_US
    / $parameters = uma array de valores para substituir os %s se tiver algum(s)
    */

// incluir o arquivo languages.php ou abortar o script
if (!require("languages.php")) {
    die("ERRO ao carregar arquivo de linguas");
}

    $actualTranslatedString = $translationsArray[$lang][$string];

    if (!empty($parameters)) {
        return vsprintf($actualTranslatedString, $parameters);
    }
    else {
        return $actualTranslatedString;
    }
}

// Exemplo:
$siteLang = "pt_BR";
$siteName = "GitHub";
$parameters = array(
    0 => $siteName
);

$bemVindo = getLanguageString("Welcome", $siteLang, $parameters); 
echo $bemVindo;

Here it worked. \ o

    
18.06.2014 / 18:59
6

The above forms are valid and functional, but I see a problem in using constants and arrays for this order, you may forget to set any of these for a given language and you will have problems.

One suggestion would be to use an interface and classes with methods that return text, eg:

interface Language {
    public function getLabelNome();
}

class ptBR implements Language {

    public function getLabelNome(){
       return "Nome";
   }

}

class enUS implements Language {
    public function getLabelNome() {
        return "Name";
    }
}

class esES implements Language{
    public function getLabelNome() {
        return "Nombre";
    }

}

When the user chooses the language, you instantiate the language class, so with the help of the interface you ensure that you have all the translations available.

Another advantage using methods is that you can handle the return form of the text, example

public function getLabelNome($uper = false){
    return $uper ? "NOME" : "Nome";
}

$lang = new ptBR();
echo $lang->getLabelNome(true); // retorna em maiúsculo

Edited

As mentioned by @Kazzkiq in the comments below, another advantage would be to not allow the user to change the value of the words out of the file where they are created.     

18.06.2014 / 21:03
4

Well the solution I adopted, after much study and conversation here in the office, was gettext with poEdit .

Here's a tutorial I've been guided by: PHP and Javascript Internationalization using Gettext and Poedit

It's simple and effective,

1 - Install poEdit and gettext as in the tutorial above *;

2 - Replace in PHP code our messages / Menus names by _("mensagem") ;

3 - Open the editor poEditor * and update, load the messages to translate as id's;

4 - Just translate, save the file .po to the correct place and this floor.

* I know it's in English, but I will not translate, because that's not the idea of the answer.

To translate my user types that are in the DB I created a class that prints the result from the DB into a translate.php file and from there I can do the translation with the poEdit is the example:

public function createArrayTipo()
{
    $filePHP   = fopen("translate.php", "a");
    $inicial = true;

    if (!is_resource($filePHP))
        return false;

    $sql_activity     = "SELECT id, name FROM user_type";
    $result_activity  = mysqli_query( $this->mysqli , $sql_activity  );

    fwrite($filePHP, "\n  \$tipos_user = array(");
    while($row = mysqli_fetch_array($result_activity))
        {
        if(!$inicial)
        fwrite($filePHP, ",");

        fwrite($filePHP, "'".$row['id']."' => _('".$row['name']."')" );

        $inicial = false;
    }
    fwrite($filePHP, "); \n");
    fclose($filePHP);
}

My question remains unanswered, but here is one more option.

    
01.07.2014 / 17:53