Полное руководство по интернационализации Rails (i18n)

1656554907 polnoe rukovodstvo po internaczionalizaczii rails i18n

от Анастасии

U-JBkqIqeKtNuw7-Nex4WlA-tpf2lQ1HC8Rf

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

Подготовка приложения Rails

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

rails new SampleApp

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

Теперь давайте сгенерируем a StaticPagesController какой будет иметь index действие (наша главная страница):

rails g controller StaticPages index

Настройте views/static_pages/index.html.erb просмотреть, добавив некоторый образец содержимого:

<h1>Welcome!</h1> <p>We provide some fancy services to <em>good people</em>.</p>

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

rails g scaffold Feedback author message

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

Настройте new действие, чтобы получить все отзывы из базы данных и упорядочить их по дате создания:

# feedbacks_controller.rb # ... def new @feedback = Feedback.new @feedbacks = Feedback.order created_at: :desc end

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

# feedbacks_controller.rb # ... def create @feedback = Feedback.new(feedback_params) if @feedback.save redirect_to new_feedback_path else @feedbacks = Feedback.order created_at: :desc render :new end end

Отобразить коллекцию отзывов на new страница:

<!-- views/feedbacks/new.html.erb --> <!-- other code goes here... --> <%= render @feedbacks %>

Наконец, создайте частичный для личного отклика:

<!-- views/feedbacks/_feedback.html.erb --> <article> <em> <%= tag.time feedback.created_at, datetime: feedback.created_at %><br> Posted by <%= feedback.author %> </em> <p> <%= feedback.message %> </p> <hr> </article>

Позаботьтесь о маршрутах:

# config/routes.rb Rails.application.routes.draw do resources :feedbacks root 'static_pages#index' end

Наконец добавьте глобальное меню к макету:

<!-- views/layouts/application.html.erb --> <!-- other code goes here... --> <nav> <ul> <li><%= link_to 'Home', root_path %></li> <li><%= link_to 'Feedback', new_feedback_path %></li> </ul> </nav>

Теперь запустите миграцию и загрузите сервер:

rails db:migrate rails s

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

Немного конфигурации

Прежде чем выполнять переводы, мы должны решить, какие языки будут поддерживаться. Вы можете выбрать любой, но я буду использовать русский и английский, причем последняя установлена ​​по умолчанию. Отразите это внутри config/application.rb файл:

# ... config.i18n.available_locales = [:en, :ru] config.i18n.default_locale = :en

Также подключите драгоценный камень rails-i18n, содержащий данные о локале для разных языков. К примеру, он переводил названия месяцев, правила множественного числа и другие полезные вещи.

# Gemfile # ... gem 'rails-i18n'

Просто установите этот драгоценный камень, и все готово:

bundle install

Хранение переводов

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

Самый простой способ сделать это – использовать локализованные просмотры. Все, что вам нужно сделать, это создать представление с именем index.LANG_CODE.html.erbгде LANG_CODE отвечает одному из поддерживаемых языков. Итак, в этой демонстрации мы должны создать два представления: index.en.html.erb и index.ru.html.erb. Внутри просто разместите содержимое для английской и русской версий сайта, и Rails автоматически выберет правильный вид на основе текущей установленной локали. Удобно, а?

Однако такой подход не всегда возможен. Другим способом было бы сохранить переведенные строки в отдельном файле и воспроизвести правильную версию строки на основе выбранного языка. По умолчанию Rails использует файлы YAML, хранящиеся под файлом. config/locales каталог. Переводы для разных языков хранятся в отдельных файлах, и каждый файл имеет имя этого языка.

Откройте config/locales папку и обратите внимание, что файл уже есть en.yml файл, внутри которого есть некоторые образцы данных:

en: hello: "Hello world"

Поэтому, en это ключ верхнего уровня, представляющий язык, для которого предназначены эти переводы. Далее есть вложенная пара ключ-значения, где hello есть ключ переводаи Hello world является фактически переведенной строкой. Давайте заменим эту пару таким содержимым:

en: welcome: "Welcome!"

Это только поздравительное сообщение с нашей домашней страницы. Теперь создайте a ru.yml файл в config/locales папку и предоставите туда переведенное поздравительное сообщение:

ru: welcome: "Добро пожаловать!"

Мы только что создали перевод для нашей первой строки, которая действительно великолепна.

Выполнение простых переводов

Теперь, когда мы заполнили файлы YAML некоторыми данными, посмотрим, как использовать переведенные строки в представлениях. На самом деле это так же просто, как и использовать translate метод, который называется псевдонимом t. Этот метод имеет один обязательный довод: имя ключа перевода:

<!-- views/static_pages/index.html.erb --> <h1><%= t 'welcome' %></h1>

Когда запрашивается страница, Rails ищет строку, соответствующую предоставленному ключу, и воспроизводит ее. Если нужный перевод не найден, Rails просто отобразит ключ на экране (и превратит его в более понятную форму).

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

Давайте позаботимся о втором сообщении:

en: welcome: "Welcome!" services_html: "We provide some fancy services to <em>good people</em>."
ru: welcome: "Добро пожаловать!" services_html: "Мы предоставляем различные услуги для <em>хороших людей</em>."

Зачем нам это _html постфикс? Ну, как вы видите, наша строчка имеет некоторую HTML-разметку, и по умолчанию Rails воспроизведет em тег в виде обычного текста. Пока мы не хотим, чтобы это произошло, мы обозначаем строчку как «безопасный HTML».

Теперь просто используйте t метод снова:

<!-- views/static_pages/index.html.erb --> <!-- ... ---> <p><%= t 'services_html' %></p>

Подробнее о ключах перевода

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

Если все наши пары ключ-значения сохраняются прямо под файлом en (или ru) без дальнейшего группирования, это приводит к двум основным проблемам:

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

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

en: main_page: header: welcome: "Welcoming message goes here"

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

Однако выгодно следить за структурой папок ваших просмотров (за мгновение мы увидим почему). Поэтому настройте файлы YAML таким образом:

en: static_pages: index: welcome: "Welcome!" services_html: "We provide some fancy services to <em>good people</em>."
ru: static_pages: index: welcome: "Добро пожаловать!" services_html: "Мы предоставляем различные услуги для <em>хороших людей</em>."

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

<!-- views/static_pages/index.html.erb --> <h1><%= t 'static_pages.index.welcome' %></h1> <p><%= t 'static_pages.index.services_html' %></p>

Однако есть также доступный «ленивый» поиск. Если вы выполняете перевод в представлении или контроллере, а ключи перевода размещены должным образом в соответствии со структурой папок, вы можете пропустить все пространства имен вместе. Таким образом, приведенный выше код преобразуется в:

<!-- views/static_pages/index.html.erb --> <h1><%= t '.welcome' %></h1> <p><%= t '.services_html' %></p>

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

Давайте также правильно переведем наше глобальное меню и пространство имен:

en: global: menu: home: "Home" feedback: "Feedback"
ru: global: menu: home: "Главная" feedback: "Отзывы"

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

<!-- views/layouts/application.html.erb --> <!-- ... ---> <nav> <ul> <li><%= link_to t('global.menu.home'), root_path %></li> <li><%= link_to t('global.menu.feedback'), new_feedback_path %></li> </ul> </nav>

Перевод моделей

Теперь перейдем к странице «Обратная связь» и позаботимся о форме. Первое, что нам нужно перевести, это метки для введенных данных. Кажется, что Rails позволяет нам предоставлять переводы атрибутов модели, и они будут автоматически использоваться при необходимости. Все, что вам нужно сделать, это правильно объединить эти переводы:

en: activerecord: attributes: feedback: author: "Your name" message: "Message"
ru: activerecord: attributes: feedback: author: "Ваше имя" message: "Сообщение"

Теперь этикетки будут переведены автоматически. Что касается кнопки «Отправить», вы можете предоставить перевод для самой модели, сказав:

en: activerecord: models: feedback: "Feedback"

Но, честно говоря, мне не нравится текст «Создать отзыв» на этой кнопке, поэтому давайте остановимся на общем слове «Отправить»:

en: global: forms: submit: Submit
ru: global: forms: submit: Отправить

Теперь воспользуйтесь этим переводом:

<!-- views/feedbacks/_form.html.erb --> <!-- ... ---> <%= form.submit t('global.forms.submit') %>

Сообщение об ошибках

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

# models/feedback.rb # ... validates :author, presence: true validates :message, presence: true, length: {minimum: 5}

Но как насчет соответствующих сообщений об ошибках? Как мы их переводим? Кажется, нам не нужно вообще ничего делать, поскольку rails-i18n gem уже знает, как локализовать распространенные ошибки. К примеру, этот файл содержит сообщение об ошибках для русского языка. Если вы на самом деле делать хотите настроить сообщение об ошибках по умолчанию, затем просмотрите официальный документ, который объясняет, как этого достичь.

Одна из проблем с формой, однако, заключается в том, что подзаголовок сообщения об ошибке (говорящий «Н ошибки запретили сохранить этот отзыв:”) не переведено. Давайте сейчас это поправим, а также поговорим о множественности.

Правила множества

Пока возможно одно или несколько сообщений об ошибке, слово «ошибка» в подзаголовке должно быть соответственно во множестве. В английском языке слова обычно во множестве, добавляя постфикс «s», но для русского языка правила несколько сложнее.

Я уже упоминал, что драгоценный камень rails-i18n содержит правила множественного числа для всех поддерживаемых языков, поэтому нам не нужно писать их с нуля. Все, что вам нужно сделать, это предоставить подходящий ключ для каждого возможного случая. Итак, для английского языка возможны только два случая: одна ошибка или много ошибок (конечно, ошибок быть не может, но в этом случае сообщение вообще не будет отображаться).

en: global: forms: submit: Submit messages: errors: one: "One error prohibited this feedback from being saved" other: "%{count} errors prohibited this feedback from being saved"

The %{count} вот интерполяция – мы берём переданное значение и размещаем его прямо в строке.

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

ru: global: forms: submit: Отправить messages: errors: one: "Не удалось сохранить отзыв! Найдена одна ошибка:" few: "Не удалось сохранить отзыв! Найдены %{count} ошибки:" many: "Не удалось сохранить отзыв! Найдено %{count} ошибок:" other: "Не удалось сохранить отзыв! Найдена %{count} ошибка:"

Имея это на месте, просто воспользуйтесь этим переводом:

<!-- views/feedbacks/_form.html.erb --> <!-- ... ---> <%= form_with(model: feedback, local: true) do |form| %> <% if feedback.errors.any? %> <div id="error_explanation"> <h2><%= t 'global.forms.messages.errors', count: feedback.errors.count %></h2> <!-- errors... --> </ul> </div> <% end %> <!-- form fields --> <% end %>

Обратите внимание, что в этом случае мы передаем ключ перевода, а также значение для count переменный. Rails выберет подходящий вариант перевода на основе этого числа. Также значение count будет вставлен в каждую %{count} заполнитель.

Наша следующая остановка – ст _feedback.html.erb частичный. Здесь нам нужно локализовать две строки: «Опубликовано…» и datetime (created_at поле). Что касается «Опубликовано…», давайте просто снова воспользуемся интерполяцией:

en: global: feedback: posted_by: "Posted by %{author}"
ru: global: feedback: posted_by: "Автор: %{author}"
<!-- views/feedbacks/_feedback.html.erb --> <article> <em> <%= tag.time feedback.created_at, datetime: feedback.created_at %><br> <%= t 'global.feedback.posted_by', author: feedback.author %> </em> <p> <%= feedback.message %> </p> <hr> </article>

Но как насчет created_at? Чтобы позаботиться об этом, мы можем воспользоваться преимуществами localize метод псевдонимом как справедливый l. Он очень похож на Ruby’s strftime, но создает переведенную версию даты (в частности, названия месяцев переведены должным образом). Давайте используем предварительно определенный формат под названием :long:

<!-- views/feedbacks/_feedback.html.erb --> <article> <em> <%= tag.time l(feedback.created_at, format: :long), datetime: feedback.created_at %><br> <%= t 'global.feedback.posted_by', author: feedback.author %> </em> <!--... --> </article>

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

Переключение между локалями

Итак, наше приложение теперь полностью переведено… но очень незначительная вещь: мы не можем изменить местность! Если подумать, это действительно серьезная проблема, поэтому давайте исправим ее сейчас.

Существует несколько способов установки и сохранения выбранной локали для запросов. Мы будем придерживаться следующего подхода:

  • Наши URL-адреса будут иметь необязательный :locale параметр, и так они будут выглядеть http://localhost:3000/en/some_page
  • Если этот параметр установлен и поддерживается указанный языковой стандарт, мы переводим программу на соответствующий язык
  • Если этот параметр не установлен или язык не поддерживается, установите стандартный язык по умолчанию.

Звучит просто? Тогда давайте погрузимся в код!

Прежде всего, настройте routes.rb включив а scope:

# config/routes.rb scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do # your routes here... end

Здесь мы проверяем указанный параметр с помощью регулярного выражения, чтобы убедиться, что язык поддерживается (обратите внимание, что символы привязки, как \A здесь запрещено).

Далее установите а before_action в ApplicationController чтобы проверить и установить локаль для каждого запроса:

# application_controller.rb # ... before_action :set_locale private def set_locale I18n.locale = extract_locale || I18n.default_locale end def extract_locale parsed_locale = params[:locale] I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil end

Кроме того, чтобы сохранить выбранный язык для запросов, установите параметр default_url_options:

# application_controller.rb # ... private def default_url_options { locale: I18n.locale } end

В состав входит locale параметр в каждой ссылке, созданной с помощью помощников Rails.

Последним шагом является предоставление двух ссылок для переключения между локалями:

<!-- views/layouts/application.html.erb --> <!-- ... --> <nav> <ul> <li><%= link_to t('global.menu.home'), root_path %></li> <li><%= link_to t('global.menu.feedback'), new_feedback_path %></li> </ul> <ul> <li><%= link_to 'English', root_path(locale: :en) %></li> <li><%= link_to 'Русский', root_path(locale: :ru) %></li> </ul> </nav>

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

Упростите свою жизнь с помощью Lokalise

Теперь вы, вероятно, думаете, что поддержка нескольких языков на большом веб-сайте, вероятно, проблема. И, честно, вы правы. Конечно, переводы можно разместить в пространстве имен и даже разделить на несколько файлов YAML, если это необходимо, но все равно вы должны убедиться, что все ключи переведены для каждой локали.

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

  • Чтобы начать, воспользуйтесь бесплатной пробной версией
  • Установите Lokalise CLI, который будет использоваться для загрузки и загрузки файлов перевода
  • Откройте страницу личного профиля, перейдите в раздел «Маркеры API» и сгенерируйте маркер чтения/записи
  • Создайте новый проект, дайте ему название и установите английский как базовый язык
  • На странице проекта нажмите кнопку «Больше» и выберите пункт «Настройки». На этой странице вы должны увидеть идентификатор проекта
  • Теперь с командной строки просто запустите lokalise --token <token> import <project_id> --lang_iso en --file config/locales/en.yml, предоставляя сгенерированный маркер и идентификатор проекта (в Windows также может потребоваться указать полный путь к файлу). Это должно скачать перевод на английский язык на Lokalise. Проделайте ту же команду для русского языка.
  • Вернитесь на страницу обзора проекта. Там вы должны просмотреть все ключи и значения перевода. Конечно, их можно редактировать, удалять, а также прибавлять новые. Здесь можно также отфильтровать ключи и, например, найти непереведенные, что очень удобно.
  • После того как вы закончите редактировать переводы, загрузите их обратно, запустив lokalise --token <token> export <project_id> --type yaml --bundle_structure %LANG_ISO%.yml --unzip_to E:/Supreme/docs/work/lokalise/rails/SampleApp/config/locales/. Прекрасно!

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

Вывод

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

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

Первоначально опубликовано на blog.lokalise.co 23 августа 2018 года.

Добавить комментарий

Ваш адрес email не будет опубликован.