PHP framework CodeIgniter. Создание многоязычных сайтов

Владимир | | CodeIgniter, PHP.

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

Разберемся, как реализована поддержка языков.

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

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

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

Примечание. В этой статье речь идет о локализации фрэймворка и сайта, а не контента. Т.к. контент (текстовый) обычно находится в базе данных, то для размещения переводов вам, скорее всего, придется создать дополнительные таблицы и изменять запросы в зависимости от выбранного языка.

Создание файлов переводов

Т.к. CodeIgniter это PHP фрэймворк, то и файлы с переводами представляют собой обычные PHP скрипты, в которых объявлены массивы строк. Имена этих файлов должны обязательно содержать окончание «_lang.php».

Формат строк должен быть такой:

$lang['ключ'] = "Текст, который будет показан на сайте";

с помощью «ключа» осуществляется выбор нужной строки.

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

Размещение файлов

CodeIgniter имеет две папки, предназначенных для размещения файлов переводов.

1) \system\language\ — общая папка;
2) \system\application\language\ — это папка с переводами конкретного сайта.

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

При загрузке переводов поиск осуществляется в следующем порядке. Сначала – в папке приложения (\system\application\language\), а затем – в общей папке (\system\language\).

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

Например, мы создали два файла переводов для русского и английского языка, в которых разместили текст главной страницы сайта.

Что-то вроде:

<?php
$lang['title'] = "Hello";
?>

и

<?php
$lang['title'] = "Привет";
?>

Оба файла будут иметь одно и тоже имя main_lang.php, но размещены будут в разных папках:
\language\russian\main_lang.php – русский вариант;
\language\english\main_lang.php – английский вариант.

Загрузка файлов переводов

Теперь можно загружать файлы. Для этого используется метод load() объекта lang.

$this->lang->load('main', 'english');

В первом параметре мы указываем имя файла (без окончания «_lang.php»), а во втором – названия языка (это название должно совпадать с именем папки, в которой находится файл перевода).

Кроме того, можно настроить CodeIgniter так, чтобы он автоматически загружал файлы выбранного языка. Для этого в файле \application\config\autoload.php находим переменную $autoload['language'] и добавляем нужный язык.

$autoload['language'] = array('russian');

Для получения нужной строки используется метод line

$pageData['t'] = $this->lang->line('title');

которому в первом параметре передается ключ строки.

Собираем все вместе

Допустим, посетитель выбрал язык, а вы сохранили его выбор в сессии.

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

class Welcome extends Controller {
	function Welcome()
	{
		parent::Controller();
		$userLang = $this->session->userdata('userlang');
		$this->lang->load('main', $userLang);
	}
	function index()
	{
		$pageData['t'] = $this->lang->line('title');
		$this->load->view('welcome_message', $pageData);
	}
}

Как видите, в конструкторе мы загрузили выбранный язык (строки 5, 6), а в методе index (формирует главную страницу сайта) – получили текстовую строку с ключом 'title', которую теперь можно использовать для формирования страницы.

Примечание. Это максимально упрощенный пример. В реальной ситуации вы должны будете, как минимум проверить установлен ли параметр 'userlang' и если нет – выбрать язык по-умолчанию.

Локализация стандартных библиотек

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

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

Кстати, убедитесь, что кодировка файлов с переводами совпадает с кодировкой сайта.

Удачи!

  • Sam

    Прелестно… просто прелестно 🙂

    Спасибо за заметку. Читать мануал CI — радость, но читать ещё более понятные заметки на родном языке — ещё большая радость.

    • Спасибо за отзыв!
      Мануал в CI прекрасный (наверное один из лучших), но хотелось бы еще хорошую книжку (хотя бы на английском) 🙂

      • насчёт книжки могу поделится
        Packt Publishing — CodeIgniter for Rapid PHP Application Development 2007
        по моему единственная книга о CI правда 1.6 в ней нету 😉

        • Если не сложно, вышлите.
          Заранее спасибо.

        • выслал на gala.net 😉

  • Sam

    Прелестно… просто прелестно 🙂

    Спасибо за заметку. Читать мануал CI — радость, но читать ещё более понятные заметки на родном языке — ещё большая радость.

    • Спасибо за отзыв!
      Мануал в CI прекрасный (наверное один из лучших), но хотелось бы еще хорошую книжку (хотя бы на английском) 🙂

      • насчёт книжки могу поделится
        Packt Publishing — CodeIgniter for Rapid PHP Application Development 2007
        по моему единственная книга о CI правда 1.6 в ней нету 😉

        • Если не сложно, вышлите.
          Заранее спасибо.

        • выслал на gala.net 😉

  • мне не очень нравится этот способ потому как

    $this->lang->line(‘title’)

    гораздо менее удобней на мой взгляд, чем

    _TITLE_

    то есть просто константы, на мой взгляд гораздо лучше — принцип такой-же, а кода меньше.

    • В вашем варианте возможны две проблемы.

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

      Во-вторых, вам все равно придется написать код для загрузке нужной строки _TITLE_.
      Ведь $this->lang->line(‘title’) возвращает текст из заданного файла с переводом.

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

      P.S. В принципе ничто не мешает написать альтернативный вариант библиотеки и использовать его. Было бы интересно потестировать и сравнить.

      • система с константами на самом деле такая же как и родная CI — писать почти нифига не нужно.

        стандартный вариант:

        $lang = $this->uri->segment(1);

        switch($lang):

        case 'lv':
        $this->lang->load('main', 'latvian');
        break;

        case 'en':
        $this->lang->load('main', 'english');
        break;

        case 'ru':
        $this->lang->load('main', 'russian');
        break;

        default:
        $this->lang->load('main', 'english');
        break;

        endswitch;

        }

        вариант с константами:

        $lang = $this->uri->segment(1);

        switch($lang):

        case 'lv':
        include_once('/lang/main_latvian.php');
        break;

        case 'en':
        include_once('/lang/main_english.php');
        break;

        case 'ru':
        include_once('/lang/main_russian.php');
        break;

        default:
        include_once('/lang/main_english.php');
        break;

        endswitch;

        }

        и соответственно в языковом файле вместо
        $lang['title'] = 'Hello';
        получается
        define('title','Hello');

        вот и получается ваше во-вторых, по объёму, такое-же как и в оригинале

        ах да

        segment(1) потому что я обычно пишу route


        $route['(en|lv|ru)'] = $route['default_controller'];
        $route['(en|lv|ru)/(.+)'] = "$2";

        а как вы поступаете с роутером ?

        • Да, получается довольно компактно. Вы не тестировали быстродействие? По-идее ваш вариант должен быть быстрее. Все-таки работа идет с константами, а не ассоциативным массивом.

          По поводу роутинга…
          Дело в том, что я старался обойти этот вопрос в статье, но, похоже, не получилось 🙂 .
          Проблема в том, что я для себя не определился какой метод лучше, а точнее не протестировал все идеи. У меня есть три варианта.

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

          Второй. Это ваш вариант. Т.е. используются адреса вроде
          http://www.site.com/ru/controller/function/...
          http://www.site.com/en/controller/function/...
          Тут решение вы показали в своем примере. У меня получалось практически тоже самое. Разве что использовал «:any» вместо «(.+)», но это не важно. Главное, что в этом варианте посетитель может сохранить ссылку на версию сайта с нужным языком и можно не использовать сессии.

          Третий. Использовать субдомены.
          ru.site.com/….
          en.site.com/….
          Вот это вариант я как раз и не доделал. Идея простая. Раз есть три домена, то есть и три папки DOCUMENT_ROOT, в каждую их которых помещаем свой index.php, причем все они будут ссылаться на одну папку application. Но тут возникает проблема. Что делать с $config['base_url'] (из файла config.php)? Можно, конечно, ее проигнорировать и установить глобальные переменные для каждого домена в index.php. Но тогда придется игнорировать и функции типа anchor 🙁

          В общем, похоже ваш вариант самый подходящий.

        • Насчёт быстродействия:
          нет, не тестил как то не было необходимости.

          Насчёт роутинга

          Первый вариант я не рассматриваю, минусов слишком много как вы и сказали

          второй вариант — штатное использование роутинга, в принципе дающий всё что нужно.

          Третий вариант — даже не знаю зачем такое надо, но если вдруг надо, то насчёт $config[’base_url’]
          вот вам линк в помощь:
          http://codeigniter.com/wiki/Automatic_configbase_url/

          для удобства приведу код и здесь:
          $config['base_url'] = "http://".$_SERVER['HTTP_HOST'] . str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);

          и всё же я считаю что Codeigniter'ский роутер самое лучшее решение.

          P.S. не забывайте кстати о mod_rewrite и его возможностях 🙂

        • За ссылку спасибо! Попробую.

          mod_rewrite… Я о нем не забываю, но постоянно не хватает времени научиться нормально его использовать. Т.е. переделать готовые правила под свои задачи не проблема, а вот написать правила с нуля — гораздо сложнее.
          Честно говоря, я сильно сомневаюсь, что кто-то полностью представляет все его возможности и варианты использования 🙂

        • Sam

          Я представляю, хоть и не все… Поэтому мне не нравится ни один роутер в существующих фреймворках 🙁

        • а чем собственно не нравятся? чего не хватает?

  • мне не очень нравится этот способ потому как

    $this->lang->line(‘title’)

    гораздо менее удобней на мой взгляд, чем

    _TITLE_

    то есть просто константы, на мой взгляд гораздо лучше — принцип такой-же, а кода меньше.

    • В вашем варианте возможны две проблемы.

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

      Во-вторых, вам все равно придется написать код для загрузке нужной строки _TITLE_.
      Ведь $this->lang->line(‘title’) возвращает текст из заданного файла с переводом.

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

      P.S. В принципе ничто не мешает написать альтернативный вариант библиотеки и использовать его. Было бы интересно потестировать и сравнить.

      • система с константами на самом деле такая же как и родная CI — писать почти нифига не нужно.

        стандартный вариант:

        $lang = $this->uri->segment(1);

        switch($lang):

        case 'lv':
        $this->lang->load('main', 'latvian');
        break;

        case 'en':
        $this->lang->load('main', 'english');
        break;

        case 'ru':
        $this->lang->load('main', 'russian');
        break;

        default:
        $this->lang->load('main', 'english');
        break;

        endswitch;

        }

        вариант с константами:

        $lang = $this->uri->segment(1);

        switch($lang):

        case 'lv':
        include_once('/lang/main_latvian.php');
        break;

        case 'en':
        include_once('/lang/main_english.php');
        break;

        case 'ru':
        include_once('/lang/main_russian.php');
        break;

        default:
        include_once('/lang/main_english.php');
        break;

        endswitch;

        }

        и соответственно в языковом файле вместо
        $lang['title'] = 'Hello';
        получается
        define('title','Hello');

        вот и получается ваше во-вторых, по объёму, такое-же как и в оригинале

        ах да

        segment(1) потому что я обычно пишу route


        $route['(en|lv|ru)'] = $route['default_controller'];
        $route['(en|lv|ru)/(.+)'] = "$2";

        а как вы поступаете с роутером ?

        • Да, получается довольно компактно. Вы не тестировали быстродействие? По-идее ваш вариант должен быть быстрее. Все-таки работа идет с константами, а не ассоциативным массивом.

          По поводу роутинга…
          Дело в том, что я старался обойти этот вопрос в статье, но, похоже, не получилось 🙂 .
          Проблема в том, что я для себя не определился какой метод лучше, а точнее не протестировал все идеи. У меня есть три варианта.

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

          Второй. Это ваш вариант. Т.е. используются адреса вроде
          http://www.site.com/ru/controller/function/...
          http://www.site.com/en/controller/function/...
          Тут решение вы показали в своем примере. У меня получалось практически тоже самое. Разве что использовал «:any» вместо «(.+)», но это не важно. Главное, что в этом варианте посетитель может сохранить ссылку на версию сайта с нужным языком и можно не использовать сессии.

          Третий. Использовать субдомены.
          ru.site.com/….
          en.site.com/….
          Вот это вариант я как раз и не доделал. Идея простая. Раз есть три домена, то есть и три папки DOCUMENT_ROOT, в каждую их которых помещаем свой index.php, причем все они будут ссылаться на одну папку application. Но тут возникает проблема. Что делать с $config['base_url'] (из файла config.php)? Можно, конечно, ее проигнорировать и установить глобальные переменные для каждого домена в index.php. Но тогда придется игнорировать и функции типа anchor 🙁

          В общем, похоже ваш вариант самый подходящий.

        • Насчёт быстродействия:
          нет, не тестил как то не было необходимости.

          Насчёт роутинга

          Первый вариант я не рассматриваю, минусов слишком много как вы и сказали

          второй вариант — штатное использование роутинга, в принципе дающий всё что нужно.

          Третий вариант — даже не знаю зачем такое надо, но если вдруг надо, то насчёт $config[’base_url’]
          вот вам линк в помощь:
          http://codeigniter.com/wiki/Automatic_configbase_url/

          для удобства приведу код и здесь:
          $config['base_url'] = "http://".$_SERVER['HTTP_HOST'] . str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);

          и всё же я считаю что Codeigniter'ский роутер самое лучшее решение.

          P.S. не забывайте кстати о mod_rewrite и его возможностях 🙂

        • За ссылку спасибо! Попробую.

          mod_rewrite… Я о нем не забываю, но постоянно не хватает времени научиться нормально его использовать. Т.е. переделать готовые правила под свои задачи не проблема, а вот написать правила с нуля — гораздо сложнее.
          Честно говоря, я сильно сомневаюсь, что кто-то полностью представляет все его возможности и варианты использования 🙂

        • Sam

          Я представляю, хоть и не все… Поэтому мне не нравится ни один роутер в существующих фреймворках 🙁

        • а чем собственно не нравятся? чего не хватает?

  • MAX

    Согласен с mihailt. Сам подход довольно тяжеловат с точки зрения синтаксиса. Поэтому, на мой взгляд оптимальным будет использование дополнительной функции, по аналогии с WordPress _e('ключ'), которая и будет возвращать переведенную фразу. 🙂

    • Да, хороший вариант. Я столкнулся с этой этой функцией когда переводил на русский один из плагинов к WP. Всего два символа, очень удобно.
      Напоминает функции типа $() в Prototype 🙂

  • MAX

    Согласен с mihailt. Сам подход довольно тяжеловат с точки зрения синтаксиса. Поэтому, на мой взгляд оптимальным будет использование дополнительной функции, по аналогии с WordPress _e('ключ'), которая и будет возвращать переведенную фразу. 🙂

    • Да, хороший вариант. Я столкнулся с этой этой функцией когда переводил на русский один из плагинов к WP. Всего два символа, очень удобно.
      Напоминает функции типа $() в Prototype 🙂

  • Спасибо за полезную информацию.

  • Спасибо за полезную информацию.

  • MAX

    Спасибо за Automatic_configbase_url — нужная вещь. 😉

    Уж коли пошла такая «пьянка» 🙂 спрошу, может подскажете. В CodeIgniter происходит адресация на основе контролеров/методов. Когда контролера/метод, указанного в url нет, происходит переброс на страницу error_404.php. Можно ли сделать так, чтобы при всех несуществующих методах происходил вызов своего метода (внутри своего контролера), например page_404()?

    Сам на данным момент решил эту проблему путем модицикации CodeIgniter.php — где перед вызовом show_404() проверяется метод page_404.

    Есть более элегантное решение?

    • да как и сказал Sam решается при помощи _remap() ты же вроде у меня читал пост где это упомянуто?

  • MAX

    Спасибо за Automatic_configbase_url — нужная вещь. 😉

    Уж коли пошла такая «пьянка» 🙂 спрошу, может подскажете. В CodeIgniter происходит адресация на основе контролеров/методов. Когда контролера/метод, указанного в url нет, происходит переброс на страницу error_404.php. Можно ли сделать так, чтобы при всех несуществующих методах происходил вызов своего метода (внутри своего контролера), например page_404()?

    Сам на данным момент решил эту проблему путем модицикации CodeIgniter.php — где перед вызовом show_404() проверяется метод page_404.

    Есть более элегантное решение?

    • да как и сказал Sam решается при помощи _remap() ты же вроде у меня читал пост где это упомянуто?

  • Sam
  • Sam
  • MAX

    Супер! Так сразу и не догадался. Вот код, если вдруг кому понадобится.


    function _remap($method)
    {
    if ( method_exists($this, $method) ) $this->$method();
    else $this->page_404();
    }

    Спасибо! 🙂

  • MAX

    Супер! Так сразу и не догадался. Вот код, если вдруг кому понадобится.


    function _remap($method)
    {
    if ( method_exists($this, $method) ) $this->$method();
    else $this->page_404();
    }

    Спасибо! 🙂

  • Отдельный риспект за ссылочку на файлы с переводами 😉

  • Отдельный риспект за ссылочку на файлы с переводами 😉

  • Есть еще вариант использования _remap(). Для авторизации.

    Принцип такой:
    1) в контроллере создаем массив с перечнем методов которые можно вызывать без входа на сайт.
    $freeAccess = array('index','login','about');

    2) в методе _remap() что-то вроде
    function _remap($method) {
    if (in_array($method, $freeAccess)) {
    $this->$method();
    }
    else if (//проверка авторизации) {
    $this->$method();
    }
    else {
    $this->login();
    }
    }

    P.S. Вообще-то собирался написать пост на эту тему 🙂 .

  • Есть еще вариант использования _remap(). Для авторизации.

    Принцип такой:
    1) в контроллере создаем массив с перечнем методов которые можно вызывать без входа на сайт.
    $freeAccess = array('index','login','about');

    2) в методе _remap() что-то вроде

    function _remap($method) {
        if (in_array($method, $freeAccess)) {
            $this->$method();
        }
        else if (//проверка авторизации) {
                $this->$method();
        }
        else {
                $this->login();
        }
    }

    P.S. Вообще-то собирался написать пост на эту тему 🙂 .

  • LANKO

    только начинаю изучать CI, в тему вопроса многоязычности:

    иногда, в целях улучщения CEO, есть необходимость держать основной язык на верхнем уровне:

    1. основной язык(lang0): http://www.host.com/
    2. дополнительный язык (lang1): http://www.host.com/lang1/
    3. дополнительный язык (lanh2): http://www.host.com/lang2/

    если ли возможность сделать переадресацию с помощю routes или другим методом так, что бы при вызове $this->uri->segment(1); получать значение `lang0|lang1|lang2`.

    • Да, можно. В принципе метод описал mihailt (в комментариях выше).
      Просто нужно установить язык по-умолчанию (lang0) и если $this->uri->segment(1) не содержит названия языка, то использовать lang0.

      • LANKO

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

        — основной язык: http://www.host.com/articles/ $this->uri->segment(1) будет `articles`

        — дополнительный язык: http://www.host.com/lang1/articles/ $this->uri->segment(1) будет `lang1`, а $this->uri->segment(2) будет `articles`

        а нужно что бы значение $this->uri->segment(1) было одинаковым во всех языках.

        • именно для этого и нужна проверка

          Создаем массив со всеми поддерживаемыми языками
          $langs = array(«ru»,»en»,»ua»);

          выполняем проверку есть ли название языка в адресе

          if (in_array($this->uri->segment(1), $langs)) {
          $curLang = $this->uri->segment(1);
          }
          else {
          $curLang = «en»; //значение по-умолчанию
          }

  • LANKO

    только начинаю изучать CI, в тему вопроса многоязычности:

    иногда, в целях улучщения CEO, есть необходимость держать основной язык на верхнем уровне:

    1. основной язык(lang0): http://www.host.com/
    2. дополнительный язык (lang1): http://www.host.com/lang1/
    3. дополнительный язык (lanh2): http://www.host.com/lang2/

    если ли возможность сделать переадресацию с помощю routes или другим методом так, что бы при вызове $this->uri->segment(1); получать значение `lang0|lang1|lang2`.

    • Да, можно. В принципе метод описал mihailt (в комментариях выше).
      Просто нужно установить язык по-умолчанию (lang0) и если $this->uri->segment(1) не содержит названия языка, то использовать lang0.

      • LANKO

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

        — основной язык: http://www.host.com/articles/ $this->uri->segment(1) будет `articles`

        — дополнительный язык: http://www.host.com/lang1/articles/ $this->uri->segment(1) будет `lang1`, а $this->uri->segment(2) будет `articles`

        а нужно что бы значение $this->uri->segment(1) было одинаковым во всех языках.

        • именно для этого и нужна проверка

          Создаем массив со всеми поддерживаемыми языками
          $langs = array(«ru»,»en»,»ua»);

          выполняем проверку есть ли название языка в адресе

          if (in_array($this->uri->segment(1), $langs)) {
          $curLang = $this->uri->segment(1);
          }
          else {
          $curLang = «en»; //значение по-умолчанию
          }

  • a.koposov

    Шикарная статейка. Спасибо!
    Простите, а не могли бы Вы и мне выслать книжку?
    a.koposov(собака)reneissance.org

    • у меня на блоге, в последнем посте лежит ссылка.

    • Уже отправил.
      А пост mihailt обязательно посмотрите. Там выложено 17 очень интересных книг.

  • a.koposov

    Шикарная статейка. Спасибо!
    Простите, а не могли бы Вы и мне выслать книжку?
    a.koposov(собака)reneissance.org

    • у меня на блоге, в последнем посте лежит ссылка.

    • Уже отправил.
      А пост mihailt обязательно посмотрите. Там выложено 17 очень интересных книг.

  • Большое Вам спасибо!

  • Большое Вам спасибо!

  • a.koposov

    Огромное спасибо! Не ожидал тако доброты =) Респект вам Люди.

  • a.koposov

    Огромное спасибо! Не ожидал тако доброты =) Респект вам Люди.

  • Luiza

    да уж, мир не без добрых людей!

  • Luiza

    да уж, мир не без добрых людей!

  • Alex

    Огромное спасибо за статью, а можно ссылочку на исходник готового решения? дело в том что я новичек. И не совсем понятно следующее:
    #
    {
    #
    parent::Controller();
    #
    $userLang = $this->session->userdata(‘userlang’);
    #
    $this->lang->load(‘main’, $userLang);
    #
    }

    Это надо писать в каждом контроллере и для каждой необходимой строки?? Заранее благодарен за ответ.

  • Alex

    Огромное спасибо за статью, а можно ссылочку на исходник готового решения? дело в том что я новичек. И не совсем понятно следующее:
    #
    {
    #
    parent::Controller();
    #
    $userLang = $this->session->userdata(‘userlang’);
    #
    $this->lang->load(‘main’, $userLang);
    #
    }

    Это надо писать в каждом контроллере и для каждой необходимой строки?? Заранее благодарен за ответ.

  • Alex

    Прошу прощения, не то вставил…

    $pageData[‘t’] = $this->lang->line(‘title’);
    $this->load->view(‘welcome_message’, $pageData);

    • Пример отправил на email (если честно, он не сильно отличается от приведенного в статье).

      $pageData[‘t’] = $this->lang->line(‘title’);

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

      $this->load->view(‘welcome_message’, $pageData);

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

  • Alex

    Прошу прощения, не то вставил…

    $pageData[‘t’] = $this->lang->line(‘title’);
    $this->load->view(‘welcome_message’, $pageData);

    • Пример отправил на email (если честно, он не сильно отличается от приведенного в статье).

      $pageData[‘t’] = $this->lang->line(‘title’);

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

      $this->load->view(‘welcome_message’, $pageData);

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

  • SHAMAN

    Всем привет. Друг наконец-то меня убедил начать изучать веб.
    Скинул вот эту книженцию CodeIgniter for Rapid PHP Application Development и сказал что не прочитав её — ничё не выйдет. Большая просьба к людям посещающим сей ресурс — скиньте плз на мыло shaman_13@rambler.ru где можно взять эту книжку на русском или что-то подобное (главное на русском), ибо в английском слаб для чтения таких вещей

    • У меня есть две книги о CodeIgniter (в т.ч. и эта), но обе на английском.

      И я не соглашусь с вашим другом. Если вы только начали изучать веб разработку, то нужно начинать не с библиотек и фреймворков, а с самых базовых вещей.
      Т.е. вам подойдет практически любой учебник по PHP и MySQL. Что-нибудь вроде «Освой PHP за 24 часа…»

  • SHAMAN

    Всем привет. Друг наконец-то меня убедил начать изучать веб.
    Скинул вот эту книженцию CodeIgniter for Rapid PHP Application Development и сказал что не прочитав её — ничё не выйдет. Большая просьба к людям посещающим сей ресурс — скиньте плз на мыло shaman_13@rambler.ru где можно взять эту книжку на русском или что-то подобное (главное на русском), ибо в английском слаб для чтения таких вещей

    • У меня есть две книги о CodeIgniter (в т.ч. и эта), но обе на английском.

      И я не соглашусь с вашим другом. Если вы только начали изучать веб разработку, то нужно начинать не с библиотек и фреймворков, а с самых базовых вещей.
      Т.е. вам подойдет практически любой учебник по PHP и MySQL. Что-нибудь вроде «Освой PHP за 24 часа…»

  • Есть ли в CI зарезервированные имена контроллеров?
    include(U:home1020bandwww/system/application/controllers/../modules/news/frontend/controllers/news.php) нивкакую не хочет инклудицца, хотя и лежит там, и все прописано верно. Меняю имя контроллера, все грузится нормально. Я вареный….

    • Нигде в документации не встречал зарезервированных имен. И, честно говоря, не понял зачем вам подключать его вручную. Контроллер будет автоматически подключен если в строке адреса вы укажите его имя (первый параметр).

      • я не подключаю контроллер вручную. Это ошибка в CodeIgniter.php
        (155 строчка).
        if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().EXT))
        {
        //show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.');
        }

        include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().EXT);

        Материться только на имя news
        http://mysite/news

        • Думал посоветовать отправить bug report, но попробовал сам создать контроллер news и он нормально заработал.
          Проверял на последней версии.
          Какая версия у вас?

  • Есть ли в CI зарезервированные имена контроллеров?
    include(U:\home\1020band\www/system/application/controllers/../modules/news/frontend/controllers/news.php) нивкакую не хочет инклудицца, хотя и лежит там, и все прописано верно. Меняю имя контроллера, все грузится нормально. Я вареный….

    • Нигде в документации не встречал зарезервированных имен. И, честно говоря, не понял зачем вам подключать его вручную. Контроллер будет автоматически подключен если в строке адреса вы укажите его имя (первый параметр).

      • я не подключаю контроллер вручную. Это ошибка в CodeIgniter.php
        (155 строчка).
        if ( ! file_exists(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().EXT))
        {
        //show_error('Unable to load your default controller. Please make sure the controller specified in your Routes.php file is valid.');
        }

        include(APPPATH.'controllers/'.$RTR->fetch_directory().$RTR->fetch_class().EXT);

        Материться только на имя news
        http://mysite/news

        • Думал посоветовать отправить bug report, но попробовал сам создать контроллер news и он нормально заработал.
          Проверял на последней версии.
          Какая версия у вас?

  • Иван

    Здравствуйте , Уважаемые специалисты . Хотел у вас спросить насколько это хорошо , перекрывать нормальное поведение контроллера , создавая локальный роутинг с помощью ремапа (_remap($method)).
    Смотрел контроллер maxsite там используется этот подход .
    Для не которых же приложение под загрузку определённых отображений , выделяется отдельный метод к примеру …

    function category(){
    $this->load->view(«category»);
    }

    function razdel(){
    $this->load->view(«razdel»);
    }

    с помощью remap

    function _remap($method){
    if($method==»category»){
    $this->load->view(«category»);
    }
    elseif($method==»razdel»){
    $this->load->view(«razdel»);
    }

    }

    Скажите пожалуйста в каких случаях грамотней будет использовать такой подход ?

    • На мой взляд, _remap имеет смысл использовать если нужно выполнить какие-то действия до загрузки метода контроллера.

      В вашем примере в методе _remap сразу загружается представление. Я бы так не делал.

      function _remap($method){
          if($method=="category"){
              //какие-то действия, которые нужно
              //нужно отделить от метода category
              $this->category();
          }
      }

      Переносить всю логику в _remap не самое удачное решение.

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

      • Иван

        Большое спасибо ,Владимир.

  • Иван

    Здравствуйте , Уважаемые специалисты . Хотел у вас спросить насколько это хорошо , перекрывать нормальное поведение контроллера , создавая локальный роутинг с помощью ремапа (_remap($method)).
    Смотрел контроллер maxsite там используется этот подход .
    Для не которых же приложение под загрузку определённых отображений , выделяется отдельный метод к примеру …

    function category(){
    $this->load->view(«category»);
    }

    function razdel(){
    $this->load->view(«razdel»);
    }

    с помощью remap

    function _remap($method){
    if($method==»category»){
    $this->load->view(«category»);
    }
    elseif($method==»razdel»){
    $this->load->view(«razdel»);
    }

    }

    Скажите пожалуйста в каких случаях грамотней будет использовать такой подход ?

    • На мой взляд, _remap имеет смысл использовать если нужно выполнить какие-то действия до загрузки метода контроллера.

      В вашем примере в методе _remap сразу загружается представление. Я бы так не делал.

      function _remap($method){
      if($method==»category»){
      //какие-то действия, которые нужно
      //нужно отделить от метода category
      $this->category();
      }
      }

      Переносить всю логику в _remap не самое удачное решение.

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

      • Иван

        Большое спасибо ,Владимир.

  • D@RK_DIE$EL

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

    создал два файла, для меню, один на русском, другой на польском. Есть главный контроллер main, он грузиться автоматом. Ссылка соответственно названиесайта/index.php/main как мне переделать контроллеры и настройки фрэймворка чтобы ссылка выглядела
    названиесайта/языкСтраницы/index.php/main а потом проверять с каким языком ссылка и грузить соответсвующий файлик?

    А еще, что означает надпись uri->segment(1), нигде пока в уроках не видел описание.

    И можно ли убрать из названия ссылки index.php? Спасибо.

    • Смотрите комментарий mihailt. Он привел практически готовую реализацию.
      Только адрес будет выглядеть не
      названиесайта/языкСтраницы/index.php/main
      а
      названиесайта/index.php/языкСтраницы/main
      Убрать index.php из названия можно с помощь .htaccess. Пример здесь. Чтобы убрать index.php из названия ссылок измените параметр $config['index_page'] в config.php.
      uri->segment(1) — возвращает первый сегмент адреса. Подробнее здесь.

      • D@RK_DIE$EL

        Да, я читал mihailt, только я не понял, куда мне добавить

        $route['(en|lv|ru)'] = $route['default_controller'];
        $route['(en|lv|ru)/(.+)'] = «$2»;

        чтобы название ссылок всегда шло с языками. Помогите, очень надо.

        • Эти правила нужно добавить в роутер (файл config/routes.php).
          Подробнее на эту тему читайте здесь.

          А формирование ссылок выполняется методом anchor(). В его первом параметре нужно указать все сегменты адреса, и первым должен идти язык.
          Т.е. код будет примерно такой
          $lang = $this->uri->segment(1);
          echo anchor($lang.'/остальные_сегменты_адреса', 'Текст ссылки');

  • D@RK_DIE$EL

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

    создал два файла, для меню, один на русском, другой на польском. Есть главный контроллер main, он грузиться автоматом. Ссылка соответственно названиесайта/index.php/main как мне переделать контроллеры и настройки фрэймворка чтобы ссылка выглядела
    названиесайта/языкСтраницы/index.php/main а потом проверять с каким языком ссылка и грузить соответсвующий файлик?

    А еще, что означает надпись uri->segment(1), нигде пока в уроках не видел описание.

    И можно ли убрать из названия ссылки index.php? Спасибо.

    • Смотрите комментарий mihailt. Он привел практически готовую реализацию.
      Только адрес будет выглядеть не
      названиесайта/языкСтраницы/index.php/main
      а
      названиесайта/index.php/языкСтраницы/main
      Убрать index.php из названия можно с помощь .htaccess. Пример здесь. Чтобы убрать index.php из названия ссылок измените параметр $config['index_page'] в config.php.
      uri->segment(1) — возвращает первый сегмент адреса. Подробнее здесь.

      • D@RK_DIE$EL

        Да, я читал mihailt, только я не понял, куда мне добавить

        $route['(en|lv|ru)'] = $route['default_controller'];
        $route['(en|lv|ru)/(.+)'] = «$2»;

        чтобы название ссылок всегда шло с языками. Помогите, очень надо.

        • Эти правила нужно добавить в роутер (файл config/routes.php).
          Подробнее на эту тему читайте здесь.

          А формирование ссылок выполняется методом anchor(). В его первом параметре нужно указать все сегменты адреса, и первым должен идти язык.
          Т.е. код будет примерно такой
          $lang = $this->uri->segment(1);
          echo anchor($lang.'/остальные_сегменты_адреса', 'Текст ссылки');

  • D@RK_DIE$EL

    Спасибо, все получилось, очень вам благодарен.

    А можно ли адрес по умолчанию загрузить в виде названиеСайта/текущийязык/?

    • Проверьте uri->segment(1) и если он пуст, поставьте редирект на
      названиеСайта/текущийязык/

      • Zirali

        Всем привет

  • D@RK_DIE$EL

    Спасибо, все получилось, очень вам благодарен.

    А можно ли адрес по умолчанию загрузить в виде названиеСайта/текущийязык/?

    • Проверьте uri->segment(1) и если он пуст, поставьте редирект на
      названиеСайта/текущийязык/

  • D@RK_DIE$EL

    У меня на сайте два языка, автозагрузка не работает:
    $autoload['language'] = array('ru');
    выдает:
    An Error Was Encountered

    Unable to load the requested language file: language/ru/ru_lang.php ижет не в самом файле, а почему-то в папке языка, который у меня сейчас установлен.

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

    Контроллер с сылками на языки выглядит так:
    $langs = array("ru","pl");
    if (in_array($this->uri->segment(1), $langs)){
    $pageData['lang'] = $this->uri->segment(1);
    }
    else
    $pageData['lang'] = "ru";
    $pageData['fulluri'] = $this->uri->uri_string();

    • CI требует чтобы все файлы переводов находились в папке
      /application/название_языка/имя_файла_lang.php
      После того как определили язык нужно загрузить файл переводов.

      if (in_array($this->uri->segment(1), $langs)){
      $pageData['lang'] = $this->uri->segment(1);
      $this->lang->load('имя_файла', 'название_языка');
      }

      • D@RK_DIE$EL

        К сожалению то что вы мне посоветовали мне не работает. Такой способ я опробовал еще до того как задать вопрос.

        Я по умолчания гружу русский язык указав в aplicaion/config/config.php :
        $config['language'] = «ru»;

        В контролере я делал так:
        $this->load->helper('form');
        $langs = array(«ru»,»pl»);
        if (in_array($this->uri->segment(1), $langs)){
        $pageData['lang'] = $this->uri->segment(1);
        }
        else
        $pageData['lang'] = «ru»;
        $this->lang->load('validation', $pageData['lang']);

        но ошибки валидации мне все равно выводит на русском языке, если меня в конфиге язык, то все работает. Помогите, как можно загрузить язык валидации.

        • А если убрать автозагрузку из конфига?
          Т.е. так
          $autoload['language'] = array();

  • D@RK_DIE$EL

    У меня на сайте два языка, автозагрузка не работает:
    $autoload['language'] = array('ru');
    выдает:
    An Error Was Encountered

    Unable to load the requested language file: language/ru/ru_lang.php ижет не в самом файле, а почему-то в папке языка, который у меня сейчас установлен.

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

    Контроллер с сылками на языки выглядит так:
    $langs = array("ru","pl");
    if (in_array($this->uri->segment(1), $langs)){
    $pageData['lang'] = $this->uri->segment(1);
    }
    else
    $pageData['lang'] = "ru";
    $pageData['fulluri'] = $this->uri->uri_string();

    • CI требует чтобы все файлы переводов находились в папке
      /application/название_языка/имя_файла_lang.php
      После того как определили язык нужно загрузить файл переводов.

      if (in_array($this->uri->segment(1), $langs)){
      $pageData['lang'] = $this->uri->segment(1);
      $this->lang->load('имя_файла', 'название_языка');
      }

      • D@RK_DIE$EL

        К сожалению то что вы мне посоветовали мне не работает. Такой способ я опробовал еще до того как задать вопрос.

        Я по умолчания гружу русский язык указав в aplicaion/config/config.php :
        $config['language'] = «ru»;

        В контролере я делал так:
        $this->load->helper('form');
        $langs = array(«ru»,»pl»);
        if (in_array($this->uri->segment(1), $langs)){
        $pageData['lang'] = $this->uri->segment(1);
        }
        else
        $pageData['lang'] = «ru»;
        $this->lang->load('validation', $pageData['lang']);

        но ошибки валидации мне все равно выводит на русском языке, если меня в конфиге язык, то все работает. Помогите, как можно загрузить язык валидации.

        • А если убрать автозагрузку из конфига?
          Т.е. так
          $autoload['language'] = array();

  • Zirali

    Всем привет! В программировании не очень. Хочу освоить реализацию многоязычности. Уже бьюсь несколько дней, безрезультатно. Не хватает знаний в программировании. Не могу понять, как интегрировать на страницу сайта тексты переводов. Помогите! Разжуйте профану….

    • Тексты переводов находятся в базе? Если да, то просто выводите их также как и любые другие записи.
      Вообще задача сводится к определению нужного языка.

  • Frogggi

    замутно…

  • Yuri Dejurin

    а как реализовать поддержку языков вида
    _www.mysite.com/ru/main.html ?

  • Аноним

    Все похлопали в ладоши, но

    $autoload['language'] = array('russian');

    это ж не правильно! Будет ошибка Unable to load the requested language file: language/english/russian_lang.php

    А как правильно и почему загрузчик ищет файл в папке english?

    • Проверьте, существует ли у вас папка
      system/language/russian

  • Tiger30

    Вопрос? все сделано как описано, работает на ура, но есть большая проблема.

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

    Как сделать чтобы индексировались все языки?

    пример сайта: http://csdownload.pm/

    • Я не вижу на Вашем каких-либо ограничений, которые бы мешали поисковику.

      В такой ситуации можно сделать следующее:
      1) подключить сайт к google webmaster tools, в их админке отображаются ошибки сканирования.
      2) добавить robots.txt
      3) добавить карту сайта (как обычную страницу и sitemap.xml).

  • Alenko Verzina

    $autoload['language'] = array('russian');

    из рекомендация Кодигнайтера:

    /*

    | ——————————————————————-

    | Auto-load Language files

    | ——————————————————————-

    | Prototype:

    |

    | $autoload['language'] = array('lang1', 'lang2');

    |

    | NOTE: Do not include the «_lang» part of your file. For example

    | «codeigniter_lang.php» would be referenced as array('codeigniter');

    |

    */

    Вместо «russian» должно быть «main»

  • Alenko Verzina

    Делаю сейчас сайт многоязычным, пока только сайт, контент пока останется единым и не делимым)
    И вот немного запуталась, в каком месте пользователь меняет язык?)
    Т.е. он его меняет и в УРЛе добавляется префикс языка, мы это ловим и запоминает, далее этот префикс больше не нужен? Мы из сессии для остальных страниц берем нужный язык?

    • Обычно сессии для этого не используют, т.к. тогда получается, что для одного и того же URL существует несколько языковых версий страницы.
      Чаще используют либо субдомены (ru.sitename.com, en.sitename.com, …), либо подпапки (sitename.com/ru/…, sitename.com/en/…).

      И посмотрите эту ветку комментариев http://www.simplecoding.org/sozdanie-mnogoyazychnyx-sajtov-s-pomoshhyu-codeigniter.html#comment-49355162, там есть пример с получением префикса языка.

      • Alenko Verzina

        Да, спасибо, читала.
        Но все равно вопросов ещё много), при переходе на другую страницу как сохранить индефикатор языка на месте segment(1)?…

        • Смысл в том, чтобы префикс языка добавить в URL. Т.е. если посетитель выбрал, например, английский язык, то дальше он «ходит» только по ссылкам вида site.com/en/…
          И $this->uri->segment(1) у вас всегда будет содержать префикс языка.

        • Alenko Verzina

          А как префикс языка оставить на том же месте? Его как-то дописать в base_url()?

        • Нет, в base_url дописывать не нужно. Код языка нужно добавить при формировании ссылок на страницах, т.е. использовать переменную
          $lang = $this->uri->segment(1);

        • Alenko Verzina

          Уточню:
          «www.site.com/ru/controller/fun……
          http://www.site.com/en/controller/fun…...» (с)
          Вот есть вот такие вот ссылки, при их формировании как префикс оставлять на позиции segment(1) и при смене языка как изменить часть url ?

          PS: по моему я окончательно запуталась 🙁

        • Технически, смена языка — это переход на другую страницу.
          site.com/ru -> site.com/en
          Вам нужно только правильно сформировать ссылку, т.е. вставить код языка.

        • Alenko Verzina

          Допустим, есть у меня view главной страницы в котором есть ссылки для выбора языка:
          Рус |
          Eng

          и далее есть ссылки для перехода на другие страницы, вида:
          <*a href="examples/index/1">Пример_1
          <*a href="examples»>Все примеры

          При выборе языка, в данном примере (роуты настроены, вроде бы)) на главной странице все хорошо выходит получается ссылка вида:
          site/en
          я читаю segment(1) и в зависимости от содержания вывожу наполнение страницы на нужном языке.
          При выборе языка на другой странице, попустим:
          site/examples/index/1
          мой вариант кода меняет язык, при этом выбрасывая на стартовую страницу, т.е. получается ссылка:
          site/ru
          К тому же, при переходе на другие страницы (язык я запоминаю, так что страницы выводятся на выбранном языке) url меняется без сохранения сегмента с выбранным языком…

        • Alenko Verzina

          Как префикс языка оставить на месте, в base_url() дописать?

        • Alenko Verzina

          Наша в коментариях вроде то что нужно 🙂

          «Проверьте uri->segment(1) и если он пуст, поставьте редирект на
          названиеСайта/текущийязык/» (с)
          А потом:
          «$lang = $this->uri->segment(1);
          echo anchor($lang.'/остальные_сегменты_адреса', 'Текст ссылки');» (с)

          Логику уловила, сейчас попробую применить на практике)) У меня тут ещё и Twig замешан…

        • Alenko Verzina

          Но при выборе языка как поступить со ссылкой до сих пор не понимаю…
          Может убрать из вьюшки и поставить форму, допустим, а сам URL сформировать уже кодом в контроллере?…

        • Этот код выполнит редирект если запрос не содержит кода языка. В противном случае, запрос будет обрабатываться как обычно.

          Но чтобы не было лишних редиректов, нужно чтобы все ссылки на сайте были с кодом языка, т.е. сформированы так, как вы написали:

          echo anchor($lang.'/остальные_сегменты_адреса', 'Текст ссылки');