Yesod: и17я

Приветствую!

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

Ключи и переводы

Итак, давайте чуток расширим содержимое файла messages/en.msg и напишем в нём следующее:

Hello:      Hello
Welcome:    Welcome to Yesod!

ну и в файл messages/ru.msg напишем, соответственно, это:

Hello:      Привет
Welcome:    Добро пожаловать в Yesod!

Теперь у нас есть два i18n-ключа, Hello и Welcome, с каждым из которых ассоциировано по два перевода. Это избавляет нас от дубляжа кода в наших виджетах. Не знаю как вы, но я не очень люблю веб-решения, многоязычность которых реализуется дубляжом (и, соответственно, отражается языковой меткой в URL страниц). А ведь это канонический подход многих веб-систем: для каждой страницы создаются N экземпляров, где N соответствует числу языков. И когда я обращаюсь, скажем, к http://site.com/ru/page, получаю русский вариант страницы page, а когда вместо ru пишется en - тогда английский вариант.

В Yesod всё элегантнее и проще. Никакого дубляжа страниц здесь нет, ведь в коде страниц используются только ключи, а конкретный перевод подставляется на место ключа динамически, в зависимости от текущего языка. Поэтому при переключении языка URL страницы не меняется, а текстовое содержимое просто переписывается. Выглядит изящно.

Использование

Теперь давайте, наконец, поймём, как же использовать ключи в нашем коде. Основное правило: ключ используется с обязательным префиксом Msg. То есть ключ Hello будет фигурировать в коде как MsgHello, а ключ Welcome - как MsgWelcome. Запомнить легко: все ключи, заданные в каталоге messages, предваряются префиксом Msg.

Теперь к делу.

Заголовки

Откроем файл Handler/Home.hs и найдём нашу функцию getHomeR:

getHomeR :: Handler Html
getHomeR = defaultLayout $ do
    setTitle "Welcome To Yesod!"
    $(widgetFile "homepage")

Уже известная нам функция setTitle устанавливает заголовок страницы. Но здесь заголовок прописан явно, на английском языке. Давайте же исправим это:

getHomeR :: Handler Html
getHomeR = defaultLayout $ do
    setTitleI MsgWelcome
    $(widgetFile "homepage")

Предельно просто. Функция setTitleI - это i18n-аналог функции setTitle (отсюда и суффикс I). Мы передаём ей уже не явный текст, а имеющийся ключ. Таким образом, когда текущим языком страницы будет английский, заголовок будет отображён как “Welcome to Yesod!”, а если русский - тогда как “Добро пожаловать в Yesod!”.

Hamlet

Перейдём к HTML-скелету. Откроем файл templates/homepage.hamlet:

<div .centered>
    <h1>Я - единственный виджет этой страницы!

Единственный контент этого виджета задан по-русски, и это опять-таки не то, чего мы хотим. Добавим новый ключ. В файле messages/en.msg пропишем это:

Hello:      Hello
Welcome:    Welcome to Yesod!
HomeMainH:  I'm a single widget of this page!

а в файле messages/ru.msg - это:

Hello:      Привет
Welcome:    Добро пожаловать в Yesod!
HomeMainH:  Я - единственный виджет этой страницы!

Теперь возвращаемся к templates/homepage.hamlet и пишем:

<div .centered>
    <h1>_{MsgHomeMainH}

Как видите, тут тоже всё очень просто. Снова наш ключ с префиксом Msg, только на этот раз он заключён между символами _{ и }.

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

Но внимательный читатель обязательно спросит меня: “В заметке несколько раз был упомянут текущий язык страницы. А как же нам установить этот текущий язык?” Прекрасный вопрос, но это мы обсудим в одной из будущих заметок.