Используйте PHP Gettext без установки локалей

Я искал варианты интернационализации проекта с открытым исходным кодом:

  • Gettext, который, кажется, все рекомендуют, очевидно, требует, чтобы локали были «установлены в вашей системе» для использования. См. Это примечание к руководству по PHP, которое точно отражает мою ситуацию . Этот вопрос SO также касается той же проблемы. Это не подходит для проекта с открытым исходным кодом, потому что я не могу доверять тому, что у конечных пользователей установлены соответствующие языковые стандарты в их системе. Кроме того, очень-очень странно, что вам нужно устанавливать локали только для того, чтобы использовать строки, которые вы перевели (IMO).

  • Zend_Translate иногда также рекомендуется в пользу gettext, но я не использую Zend framework, поэтому не думаю, что это вариант для меня. Некоторые люди говорят, что вы можете отделить его от фреймворка Zend, но я понятия не имел, как это сделать. Если кто-нибудь может сказать мне, какие файлы мне нужно выбрать (я загрузил архив с фреймворком Zend), я был бы открыт для использования Zend_Translate.

  • Массивы. Я сейчас этим и занимаюсь, но это не идеально, потому что:

    • It will be using up lots of memory to define every translation, when most won't be used by the current page.
    • У меня проблемы с копированием ключей в массиве, который уже превратился в 1000 строк кода, а я еще почти ничего не добавил ...
    • Это означает, что непрограммисты действительно не могут переводить, тогда как POedit - это стандарт, который все ожидают использовать.

Могу ли я каким-то образом читать .mo файлы без Gettext или Zend_Translate, или я должен использовать Gettext? Если да, как я могу заставить работать все языковые стандарты, как в вопросе, на который я ссылался выше?

РЕДАКТИРОВАТЬ: теперь я хочу использовать Zend_Translate. Мне просто нужно решить, какие файлы мне нужны (было бы здорово, если бы их можно было объединить в один файл) - мне не нужен весь Zend Framework в моем проекте.


Обновление: мне было интересно узнать, как большие проекты с открытым исходным кодом обрабатывают i18n:

Итак, насколько я могу судить, ни один из этих трех случайных проектов не использует ни Zend_Translate, ни напрямую gettext.

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


Итак, вот что у меня получилось:

$lang = 'de'; //debug
setlocale( LC_ALL, 'C' );
bindtextdomain( 'default', PATH . "/locale/$lang" );
bind_textdomain_codeset( 'default', 'UTF-8' );
textdomain( 'default' );

var_dump( file_exists( PATH . "/locale/$lang/C/LC_MESSAGES/default.mo" ) ); //bool(true)

Но я все еще получаю только английскую строку, хотя я использовал poedit, msgfmt и т. Д. Для создания соответствующих файлов. Я также пробовал перезапустить Apache.


person Community    schedule 21.03.2013    source источник
comment
Установить локали? Что ты имеешь в виду? Вы просто включаете определенные .mo файлы и устанавливаете соответствующий языковой стандарт. Это действительно не так страшно, как вы думаете.   -  person mishmash    schedule 21.03.2013
comment
Было бы здорово, если бы это было так, но я не думаю, что это так ... см. Ссылку вверху вопроса. В примечаниях для пользователей в руководстве по PHP также говорится то и то вам нужно запустить locale -a, чтобы увидеть, какие языковые стандарты доступны для использования (и запустить sudo apt-get install language-pack-langcode-base, чтобы установить дополнительные языковые пакеты). Мои собственные тесты также отражают это. Это не подходит для проекта с открытым исходным кодом, так как я не могу ожидать этого от пользователей.   -  person    schedule 21.03.2013
comment
Простых массивов ключ = ›значение вряд ли достаточно для полноценной системы перевода. Поддерживают ли они множественное число? Контекст? Категории? Домены? Комментарии? Это все функции, которые вы должны использовать, возможно, вы просто еще этого не знаете. Если вы не хотите получать текст, попробуйте Zend_Translate. Ваши доводы против этого на самом деле не являются причинами.   -  person deceze♦    schedule 21.03.2013
comment
Ага, поэтому я хочу переключиться с массивов на что-то другое. Думаю, я бы хотел использовать Zend_Translate, если бы мне нужно было, но как? Пользователи SO сказали, что могут разделить его от остальной части фреймворка Zend, но я не знаю, как это сделать.   -  person    schedule 21.03.2013
comment
Просто поместите где-нибудь Zend Framework и загрузите класс Zend_Translate, готово.   -  person deceze♦    schedule 21.03.2013
comment
Но могу ли я поместить в свой проект только Zend_Translate, а не весь фреймворк Zend? Я загрузил tarball и нашел папку Translator, но я не уверен, какие еще части Zend ей нужны.   -  person    schedule 22.03.2013
comment
@DuncanNZ то, что сказал @deceze, - самый простой путь. Это может показаться излишним, но на самом деле это приведет к потере некоторого места на жестком диске, но, поскольку остальная часть фреймворка не будет использоваться, не будет потреблять память или нагрузку для каждого запроса и т. Д. Zend_Translate работает, удалите классы / папки и посмотрите, работает ли он по-прежнему ... пока не закончите с достаточно небольшим (для вас) набором классов.   -  person Carlos Campderrós    schedule 22.03.2013
comment
@deceze извините за мою глупость, но я даже не могу понять, как загрузить Zend. Я просто получаю, что класс Zend_Translate не найден. У меня есть весь фреймворк Zend (для начала). Я не уверен, какой файл мне следует включить - это Zend/I18n/Translator/Translator.php, или Zend Loader, или что-то в этом роде ...?   -  person    schedule 22.03.2013


Ответы (3)


Попробуйте gettext-php. Это прямая замена для gettext, написанного на PHP. Я думаю, что изначально это было сделано для WordPress, потому что WP необходимо запускать на общих хостах, которые не всегда настраиваются для каждой локали. Мне кажется, это тоже ваша проблема.

Это немного снизило производительность, но для меня это не было проблемой.

person Matt    schedule 22.03.2013
comment
Спасибо за предложение. Теперь, когда у меня (наконец) есть Gettext, я думаю, что пока останусь с ним, но буду иметь это в виду, если у меня возникнут другие проблемы. - person ; 23.03.2013

Вот решение:

$lang = 'de'; //debug
setlocale( LC_ALL, 'C.UTF-8' );
bindtextdomain( 'default', PATH . "/locale/$lang" );
bind_textdomain_codeset( 'default', 'UTF-8' );
textdomain( 'default' );

Единственная разница между этим и примером, который я разместил внизу своего ответа, заключается в том, что он использует C.UTF-8, а не только C.

Я проведу дополнительное тестирование этого, и если он будет работать кросс-платформенным, и обновлю этот ответ, если узнаю что-нибудь еще.

person Community    schedule 22.03.2013
comment
Поздравляю, у меня вроде тоже работает. Но это кажется действительно хакерским, и я не могу поверить, что это обычный способ решить эту проблему. Я не понимаю, что это за язык C.UTF-8, но, похоже, он установлен в каждой среде. Поскольку ваш пост опубликован 2 года назад, я хотел бы спросить вас, нашли ли вы тем временем лучшее решение. - person steven; 10.10.2015
comment
Извините, @steven, с тех пор я практически не использовал PHP. Однако в настоящее время меня меньше беспокоят передовые методы и, вероятно, я сразу выберу решение на основе массивов, зная о разочарованиях, связанных с gettext. - person ; 11.10.2015
comment
Вы знаете, как установить локали на xampp для Windows? - person Gonzalo; 25.01.2018

Для тех, у кого все еще есть проблемы с этим, вы можете попробовать следующий код, который я получил отсюда: http://php.net/manual/en/function.gettext.php#58310

Он решил меня на сервере freebsd, без дополнительной установки локали (fr_FR и my_MY). Этот код также полезен, когда у вас есть проблемы с кешем gettext.

<?php
function initialize_i18n($locale) {
  $locales_root="/app/php/locale"; // change This to where you locale folder at
  putenv('LANG='.$locale);
  setlocale(LC_ALL,"");
  setlocale(LC_MESSAGES,$locale);
  setlocale(LC_CTYPE,$locale);
  $domains = glob($locales_root.'/'.$locale.'/LC_MESSAGES/*.mo');
  $current = basename($domains[0],'.mo');
  $timestamp = preg_replace('{messages-}i','',$current);
  bindtextdomain($current,$locales_root);
  textdomain($current);
}
?>
person maximran    schedule 01.08.2018