ФорумПрограммированиеPHP для идиотов → Локализация - кто будет говорить?

Локализация - кто будет говорить?

  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 10 мая 2010 г. 20:37

    Предлагаю взглянуть на задачу локализации веб-приложения с такой точки зрения: надо ли объявлять язык свойством приложения? Может быть это атрибут объекта Пользователь? В системе всегда присутствует "текущий пользователь" и у него есть языковые предпочтения.

    $app->t('Say cheese')
    или
    $user->t('Say cheese')

    Казалось бы, какая разница если и Пользователь и Приложение всегда присутствуют. А разница есть.

    Пример: мы взялись за рассылку писем. Если язык - свойство приложения, то все письма будут на языке по-умолчанию или на языке инициатора рассылки. Или нам придется использовать какие-то хаки, чтобы постоянно переключать "текущий язык приложения".
    Но если сделаем так, что класс пользователь "умеет говорить на своем языке", то достаточно просто перебирать пользователей по списку и подставлять объект в шаблонизатор.
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 10 мая 2010 г. 22:42, спустя 2 часа 4 минуты 41 секунду

    о, ахуеть какая клевая тема, сам сейчас занят подобной проблемой. Ща расскажу о своем видении ситуации. Приготовьтесь господа, текста будет много


    Есть файл application/languages формата

    <?php

    return array(
     'avalible' => array('ru_RU', 'en_UK', 'et_EE'),
     'default'  => 'ru_RU'
    );


    И ежу понятно: мы теперь знаем, какие языки доступны в приложении и какой язык по умолчанию.

    У каждого пользователя есть поле lang_code (или locale?). Именно в базе: id, name, passhash, locale, … . Когда пользователь залогинен под своей учеткой - в сессии хранится информация об его языковых предпочтениях. Ессно когда делаем рассылку ему, то берем язык из этого поля.

    Теперь самое интересное: а на каком же языке показывать пользователю сайт? на том же, который прописан в базе для него? а вот хуй! Ниже представлена цепочка:

    1) если указан GET-параметр (или субдомен с языком) ?lang_code и значение этого параметра есть в languages.avalible - показываем сайт на этом языке. Опционально можно записать в сессию данные о языке. В противном случае - идем дальше.

    2) если в сессии есть данные о языке - показываем сайт на этом языке. В противном случае - идем дальше.

    3) получаем request-параметр HTTP_ACCET_LANGUAGES, парсим его. Берем первый язык из него. Он есть в languages.avalible? отлично, записываем эту информацию в сессию, показываем сайт на этом языке. Если нету - берем следующий язык, проверяем. И так далее. Если ни один язык не подошел - идем дальше.

    4) а что тут думать? берем язык, который прописан в languages.default. Записываем эти данные в сессию. И покажем пользователю список доступных языков



    по поводу "свойств" приложения и пользователя. Есть объект Locale, который сам занимается вышеописанным дрочем. Объект Translate имеет доступ к Locale и все переводы делаются на том языке, который в Locale. А когда мы делаем рассылку - язык будет принудительно перегружен.

    public function tr($string, $args = array(), $escape = NULL, $namespace = NULL, $locale = NULL)
    // вот когда здесь принудительно указываем $locale - это и есть перегрузка
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 10 мая 2010 г. 23:00, спустя 18 минут 5 секунд

    кстати, $tr->tr('переведи меня') - это i18n а не l10n. l10n - это форматирование даты, чисел, валюты.

    Что вы посоветуете для этого? Я пока колеблюсь в выборе между sfCulture и Zend_Locale. Может что-то полегче есть?
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 10 мая 2010 г. 23:15, спустя 14 минут 46 секунд

    ну пусть "интернационализация", согласен.

    то есть в твоих В.Б. для рассылки «придется использовать какие-то хаки, чтобы постоянно переключать "текущий язык приложения""»

    рассуждения о выборе предпочтительного языка понравились.
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 10 мая 2010 г. 23:22, спустя 7 минут 29 секунд

    кое что про оптимизацию

    public function tr($string, $args = array(), $escape = NULL, $namespace = NULL, $locale = NULL)

    функция-супермаркет :)
    по твоим значениям-по-умолчанию видно, что как правило нужен только первый параметр. на сотню вызовов будет 95 вызовов с одним параметром.
    не лучше ли сделать отдельные методы для множественного числа, экранирование выкинуть нахуй, потому, что это отдельная задача, а локаль настраивать один раз отдельным свойством/методом???
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 10 мая 2010 г. 23:46, спустя 23 минуты 16 секунд


    то есть в твоих В.Б. для рассылки «придется использовать какие-то хаки, чтобы постоянно переключать "текущий язык приложения""»


    это не совсем хак, да и текущий язык по сути не переключается

    $tr = BL_Translate::instance('modules.backend.news') // указали неймспейс
    ->setLanguage('en'); // и язык (вообще он сам из Locale укажется). Метод может принять как экземпляр BL_Locale так и строку (ru, ru_RU)

    $tr->tr('apple'); // apple

    $tr->tr('apple', false, false, false, 'ru'); // яблоко

    $tr->tr('apple'); // apple. То есть язык остался прежним


    не лучше ли сделать отдельные методы для множественного числа

    так и есть
    public function ntr($string, $count, $args = array(), $escape = NULL, $namespace = NULL, $locale = NULL)


    экранирование выкинуть нахуй, потому, что это отдельная задача

    я подумаю над этим.

    а локаль настраивать один раз отдельным свойством/методом???

    так и есть
    Спустя 117 сек.
    экранирование может быть выкину когда сделаю интеграцию с Twig и там будет Twig'овское экранирование использоваться
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 10 мая 2010 г. 23:55, спустя 8 минут 57 секунд

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

    Сообщения: 5210 Репутация: N Группа: Джедаи

    Spritz 11 мая 2010 г. 4:25, спустя 4 часа 30 минут 10 секунд

    я у себя устанавливаю язык приблизительно в том порядке что и уАбырвалг
    но вроде у меня заполняется сперва по умолчанию, а потом ищется, не помню порядок но если очень интересно кому, могу вечером позырять.
    Еще такая штука, допустим пользователь оставил коммент в статье, я сразу отправляю всем пользователям, подписанным на рассылку в статье уведомления (то что это не отложено сейчас не обсуждается), но уведомление мне надо отправить на языке пользователя, которому оно отправляется. При этом с помощью обычной фабрики я получаю инстанс языка обрабатываемого пользователя - Translate::SetLanguage($user->lang) - фактически переключая язык в синглтоне Translate. Причём я немного лукавлю и не перключаю язык к исходному состоянию, так как после этих действий идёт переадресация.
    Я категорически против языка у приложения, потому что язык это свойство пользователя, раз уж приложение многоязычное!
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 13 мая 2010 г. 15:00, спустя 2 дня 10 часов 35 минут

    Я для себя решил все-таки держать переводы вне User. При необходимости делать типа

    $old = Qb::setLanguage($user->language);
    // …
    Qb::setLanguage($old);

    Небольшая фишка: при переключении на другой язык не потребуется "руками" подгружать все необходимые разделы. Список нужных разделов у нас уже есть. setLanguage() подгрузит всё, что надо для нового языка.

    Переводы буду хранить в структуре:

    'languageA' => array(
     'domain1' => array(…),
     'domain2' => array(…),
    ),
    'languageB' => array(
     'domain1' => array(…),
     'domain2' => array(…),
    ),

    На диске храню отдельные файлы для каждой секции (domain) перевода в сериализованном виде. Для каждого языка отдельная папочка.

    Типично при инициализации приложения будет грузиться секция 'common'

    $user = new User() // загрузка пользователя, в т.ч. его предпочтительного языка
    Qb::set('user', $user); // сохраним в реестр на будущее
    Qb::setLanguage($user->language);
    Qb::useTranslation('common');


    В контроллере подгружаются разделы перевода по необходимости

    class XyzController
    {
    public function __construct()
    {
     Qb::useTranslation('forum');
     Qb::useTranslation('topic');
    }

    public function actionFoo()
    {
     echo Qb::t('Listen to me, banderlogies');
     echo Qb::t('Fuck you all', 'topic');
    }
     

    Кто будет грузить файл с примером, сначала запустите lang/revive.php чтобы создать serialized переводы
    1. i18n.zip (18)
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 12 мая 2010 г. 1:16, спустя 10 часов 16 минут 7 секунд

    ох ты наш любитель статики) А где plural forms?

    Qb::setLanguage('Russian'); // мне западло писать имя полостью, лучше ru, et, ua


    сериализацию можно б сделать опциональной. Мне кажется, что если на сервере будет APC то инклюд файла с переводом будет быстро работать.
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 12 мая 2010 г. 2:54, спустя 1 час 37 минут 38 секунд

    1. пример хорош пока он прост. это — пример. он иллюстрирует ОДНУ вещь: переключение языков
    2. конечно статика. она доступна отовсюду без онанизма вроде $this->$a->$b->t()
    3. непринципиально какие имена. абсолютно!
    4. хуй там. даже с байт-код кешерами сериализованные данные читаются быстрее
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 12 мая 2010 г. 1:37, спустя 22 часа 43 минуты 24 секунды

    кстати, блин, нашел у себя кучу проблем
    1)
    BL_Translate::instance('modules.backend.news', 'array'); // драйвер массива

    BL_Translate::instance('modules.backend.news', 'database'); // а вот хуй! опять драйвер массива. Так как в self::$instances['modules.backend.news'] уже есть данные


    2) местами у меня может быть двойной расход памяти
    3) и еще я в instance могу передать настройки драйвера, но не могу передать настройки всего Translate (они через BL_Settings получаются)
    Спустя 73 сек.
    зато в статике нельзя
    one:two:thre::four
    Спустя 32 сек.
    если даже с опкод кешерами сериализация быстрее - надо б и мне ее сделать тогда
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz 12 мая 2010 г. 3:46, спустя 2 часа 8 минут 19 секунд

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

    offtopic: Д. Котеров в известном примере показал, что эффективность кешеров сильно падает, когда php-файлов много.
    конечно редактировать сериализованный массив нереально. поэтому в моем примере (в архиве) исходные переводы даются как php, но есть "транслятор-сериализатор"

    в статике можно делать one::too()->three() и т.д. есть статический глобально видимый корень, дальше танцуешь как хочешь.
    и лучше, если не one, two, three, four, а только one, two ))) — юзабельнее )))
    ιιlllιlllι унц-унц
  • Абырвалг

    Сообщения: 6480 Репутация: N Группа: Джедаи

    Spritz 22 мая 2010 г. 2:36, спустя 9 дней 22 часа 50 минут

    Теперь самое интересное: а на каком же языке показывать пользователю сайт? на том же, который прописан в базе для него? а вот хуй! Ниже представлена цепочка:

    в этой цепочке я забыл про определение языка на основе geoip…
  • Givi

    Сообщения: 2284 Репутация: N Группа: Адекваты

    Spritz 22 мая 2010 г. 7:09, спустя 4 часа 33 минуты 8 секунд

    Абырвалг, считаю для себя такой подход (язык по геоАйПи) одним из говенных методов (кроме исключений для очень редких проектов).
    Причины: если у нас сайт русский, то для того же Гугля по сути "главный" сайт будет инглишем, а русский только вариацией. А нам нужно чтоб русский сайт был "русским". Но это так, образно.
    В целом считаю что дефолтным (если у юзера не указано иного) нужно показывать тот язык, по которому "географически" находится сайт. Тот, которым имеет наибольшую аудиторию. А дальше юзер сам себе выберет "свой" язык если это ему понадобится.
    Все ИМХО.

Пожалуйста, авторизуйтесь, чтобы написать комментарий!