Программирование многоязычных приложений PHP

Я разрабатываю приложение PHP, и мне интересно, как лучше всего включить многоязычную поддержку для пользователей в других странах.

Я хорошо владею PHP, но никогда не разрабатывал ничего с поддержкой других языков.

Я думал поместить язык в файл PHP с константами, например:

en.php может содержать:

define('HZ_DB_CONN_ERR', 'There was an error connecting to the database.');

а fr.php может содержать:

define('HZ_DB_CONN_ERR', 'whatever the french is for the above...');

Затем я мог вызвать функцию и автоматически передать нужный язык.

hz_die('HZ_DB_CONN_ERR', $this);

Это хороший способ сделать это?

- морристебир.


person morristhebear    schedule 16.01.2009    source источник


Ответы (9)


Странный. Кажется, что люди игнорируют очевидное решение. Ваше представление о файлах, зависящих от локали, в порядке. Есть en.php:

define('LOGIN_INCORRECT','Your login details are incorrect.');
...

Затем, если у вас есть глобальный файл конфигурации / констант (который я бы предложил по многим причинам), используйте такой код:

if ($language == 'en') {
  reqire_once 'en.php';
} else if ($language == 'de') {
  require_once 'de.php';
}

Вы можете определить функции для отображения числа и валюты, сравнения / сортировки (например, для немецкого, французского и английского языков используются разные методы сопоставления) и т. Д.

Люди часто забывают, что PHP - это динамический язык, поэтому вещи вроде этого:

if ($language == 'en') {
  function cmp($a, $b) { ... }
} else if ($language == 'de') {
  function cmp($a, $b) { ... }
}

на самом деле совершенно законны. Используй их.

person cletus    schedule 17.01.2009
comment
Хорошая мысль, я согласен с таким подходом - person Codex73; 02.10.2009
comment
Я бы использовал такие константы только в том случае, если языковые файлы были созданы из базы данных и получены из пользовательского контента. В противном случае он может стать недоступным при добавлении новых строк и т. Д. Он также имеет тенденцию заполняться заброшенными. - person DanMan; 20.12.2012

Вы можете использовать gettext или что-то, что поддерживает gettext, а также многое другое. как Zend_Translate.

Редактировать:

Ради точности Zend_Translate поддерживает gettext без модуля gettext. Здесь вы можете увидеть множество различных типов ввода, которые он поддерживает .

Если вы используете массивы, как было предложено, вы также можете использовать это с Zend_Translate. Дело в том, что если вы сегодня используете массивы, а завтра gettext, xml или что-то еще, вам нужно только изменить свою конфигурацию для Zend_Translate.

person OIS    schedule 16.01.2009

Мне очень нравится такой подход:

один файл - это сам переводчик:

class Translator{
    private static $strs = array();
    private static $currlang = 'en';

    public static function loadTranslation($lang, $strs){
        if (empty(self::$strs[$lang]))
            self::$strs[$lang] = array();

        self::$strs[$lang] = array_merge(self::$strs[$lang], $strs);        
    }

    public static function setDefaultLang($lang){
        self::$currlang = $lang;        
    }

    public static function translate($key, $lang=""){
        if ($lang == "") $lang = self::$currlang;
        $str = self::$strs[$lang][$key];
        if (empty($str)){
            $str = "$lang.$key";            
        } 
        return $str;       
    }    

    public static function freeUnused(){
        foreach(self::$strs as $lang => $data){
            if ($lang != self::$currlang){
                $lstr = self::$strs[$lang]['langname'];
                self::$strs[$lang] = array();
                self::$strs[$lang]['langname'] = $lstr;                
            }            
        }        
    }

    public static function getLangList(){
        $list = array();
        foreach(self::$strs as $lang => $data){
            $h['name'] = $lang;
            $h['desc'] = self::$strs[$lang]['langname'];
            $h['current'] = $lang == self::$currlang;
            $list[] = $h;
        }
        return $list;        
    }

    public static function &getAllStrings($lang){
        return self::$strs[$lang];
    }

}

function generateTemplateStrings($arr){
    $trans = array();
    foreach($arr as $totrans){
        $trans[$totrans] = Translator::translate($totrans);
    }
    return $trans;    
}

языковые файлы могут быть просто include()d и выглядеть так:

en.php:

Translator::loadTranslation('en', array(
  'textfield_1'          => 'This is some Textfield',
  'another_textfield '   => 'This is a longer Text showing how this is used',
));

de.php:

Translator::loadTranslation('de', array(
  'textfield_1'          => 'Dies ist ein Textfeld',
  'another_textfield '   => 'Dies ist ein längerer Text, welcher aufzeigt, wie das hier funktioniert.',
));

в вашем приложении вы можете перевести одну строку следующим образом:

$string = Translator::translate('textfield_1')

или даже связку строк:

$strings = generateTemplateStrings(array('textfield_1', 'another_textfield'));

Поскольку языковые файлы могут быть просто включены, вы можете очень легко сложить их и, скажем, сначала включить глобальный файл, а затем включить файлы из подмодулей, которые могут либо добавлять новые строки, либо заменять уже определенные (что не работает с define()-метод).

Поскольку это чистый PHP, его даже можно очень легко кэшировать с помощью кода операции.

У меня даже есть сценарии, на основе которых создаются CSV-файлы, содержащие непереведенные строки из файла, и даже лучше: конвертировать переведенный CSV-файл обратно в языковой файл.

Я продуктивно использую это решение с 2004 года, и я очень им доволен.

Конечно, вы можете даже расширить его, например, с помощью соглашений о множественном числе. Однако локализация числовых форматов - это то, что вам придется делать другими способами - на ум приходит intl-extension.

person pilif    schedule 19.01.2009
comment
Я пытаюсь реализовать ваш способ, описанный выше, но не могу понять, как и где определить второй язык. Translator.php, похоже, не включает другой язык (например, de), а также этот сценарий, похоже, не определяет автоматически изменение языка моего веб-сайта. Я получаю только английский перевод. Здесь будут очень благодарны за любые советы. - person otinanai; 16.04.2013

Спасибо всем за ваши подходы и решения. Я пришел сюда с такими же зарождающимися сомнениями, и я могу заключить, что использование «метода определения» более реалистично, поскольку даже с странной проблемой, которая не использует очень стильные методы с другими библиотеками или некоторыми, будучи реалистичными и при продуктивном мышлении, его так легко поддерживать и понимать, так что вы можете изучать другие языки, не обладая навыками программирования, парни.

Я считаю, что лучше использовать метод массивов, поскольку вам не нужно распространять этот большой многоязычный язык, чтобы получить некоторые переводы, кроме того, вы используете меньше памяти, поскольку вы загружаете только необходимые строки.

О том, что их нельзя переопределить; ну, как правило, если вы определяете константы, это потому, что они не нужны или не должны изменяться, поэтому при необходимости вы можете использовать раздел для определенных строк и переменных.

Я добавляю, что мне не нравится, как выглядят эти файлы определения, но учтите, что ваши посетители совсем не беспокоятся о том, как реализована идиома, это идеальная допустимая реализация, и вы легко можете получить некоторые выводы.

person Community    schedule 26.03.2009

Возможно, вы захотите взглянуть на фреймворк, такой как CakePHP или CodeIgniter, который значительно упрощает написание интернационализированных приложений. Вы должны учитывать не только строки, но и такие вещи, как числовые форматы и форматы даты.

person Rad    schedule 16.01.2009
comment
Я вообще не являюсь поклонником полных фреймворков MVC (хотя мне нравится использовать Smarty), я все еще нахожусь на ранних стадиях разработки и еще не думал о валюте и форматах даты, но учту это. .. Благодарность! - person morristhebear; 16.01.2009
comment
IMHO CakePHP - это полный перебор (и раздувание, как 99% фреймворков MVC). - person cletus; 17.01.2009

Ваше решение должно работать нормально, если оно предназначено исключительно для перевода. Как уже упоминалось, существует множество других переменных, зависящих от локали, таких как форматы валюты и даты.

Надежным подходом к обеспечению языкового стандарта вашего приложения было бы использование _1 _ в сочетании с Zend_Translate.

Zend_Locale позволяет легко определить языковой стандарт пользователя или установить его, если хотите. Этот класс полезен, например, для автоматической установки правильного денежного формата.

Zend_Translate позволяет легко переводить текст, используя несколько разных форматы:

  • Множество
  • CSV
  • Gettext
  • Ини
  • Tbx
  • Tmx
  • Qt
  • Xliff
  • XmlTm
person Aron Rotteveel    schedule 16.01.2009

Ваш подход работает, если вы включаете разные файлы констант в зависимости от того, какой язык выбрал пользователь.

Вы также можете пропустить постоянную часть и просто определить большую хеш-таблицу с постоянным => переводом, чтобы предотвратить сбои в пространстве имен.

файл: en.php

$constants = Array(
 'CONSTANT_KEY' => 'Translated string'
);

файл: functions.php

function getConstant($key, $fallback) {
   // ... return constant or fallback here.
}

Однако, когда дело касается большого количества данных, такой подход будет сложно поддерживать. Есть несколько других подходов, которые могут лучше служить вашей цели, например, идеальное решение - это когда все ваши константы хранятся в глобальном пространстве памяти для всего вашего сайта, чтобы избежать того, чтобы каждый запрос / поток сохранял все эти переведенные данные в объем памяти. Для этого требуется какой-то модульный подход к php. Gettext, как кто-то здесь предложил, может использовать этот подход.

Google для локализации PHP, чтобы найти полезные ресурсы.

person jishi    schedule 16.01.2009

Один совет для вас - создать функцию, которая возвращает переведенную строку, и, если ее нет в хэш-таблице, вернуть запрошенный хеш-ключ с чем-то вроде * позади него, чтобы уведомить вас о необходимости перевода.

person Ólafur Waage    schedule 16.01.2009

Вот как я это делаю:

parent_script.php:

$lang_pick = "EN";    //use your own method to set language choice

require_once('trans_index.php'); 

echo $txt['hello'];

trans_index.php:

    $text = array();

    $text['hello'] = array (
     "EN"=> "Hello",
     "FR"=> "Bonjour",
     "DE"=> "Guten Tag",
     "IT"=> "Ciao"
    );                          //as many as needed



foreach($text as $key => $val) {

$txt[$key] = $text[$key][$lang_pick];

}

Это может быть слишком просто для ваших нужд, но я считаю его вполне выполнимым. Это также позволяет очень легко поддерживать несколько версий текста.

person Community    schedule 18.01.2009