Квест → Как хакнуть форму
Прошли: 77
Одина из проблем, с которой вам придется столкнуться при создании мультиязычного сайта — это то, как держать в порядке ваши строки переводов для серверной стороны и для JavaScript компонентов. Я собираюсь продемонстрировать основные приёмы реализации этого, используя в моих примерах Laravel и Vue.js.
Сразу хочу уточнить, что приёмы показанные в этом посте полностью независимы от фреймворка и даже языка. Идея, лежащая в основе, будет работать также и в приложении на .Net с Ember.js на фронте.
Я опишу это с двух сторон, так что вы можете прочитать только про то, что вам нужно. Если вы просто ищите решение для вашего приложения на Laravel и Vue, пролистайте и посмотрите на примеры с кодом. Если вы прочитали выше абзац про .Net и находитесь в недоумении, то не переживайте мы погрузимся чуть глубже, рассказав что мы действительно делаем — в дополнение к работе с кодом самих библиотек.
Сначала давайте посмотрим на то, что мы пишем и почему. Целью является иметь единый источник строк перевода, которые могут быть использованы в шаблонах нашего backend-языка (Laravel blade), а также в наших frontend-компонентах (Vue). Несмотря на то, что может показаться проще просто иметь php-файлы для одного и json-файл для другого, поддерживая переводы в актуальном состоянии, всё же будет ещё намного проще, если у нас будет единый источник. Однако, эти два языка не могут свободно "общаться" друг с другом напрямую, поэтому мы должны написать своего рода мост между ними.
Это значит, нам понадобятся следующие компоненты:
Первый пункт этого списка поставляется с нашим фреймворком Laravel — компонент Localization или “lang”-файлы. Подробнее: https://laravel.ru/docs/v5/localization (на русском) или https://laravel.com/docs/5.5/localization (оригинальная документация). Я не буду тратить очень много времени на него, так как он довольно прост и хорошо документирован — по ссылке выше или в многочисленных руководствах/статьях. Я бы порекомендовал создавать директорию components
внутри каждой языковой директории (т.е. /resources/en/components
) по причинам, которые вы увидите далее.
Php-файлы удобны для интеграции с нашей системы, и, возможно, для использования стороннего API для поддержки самих переводов, но они всё же php-файлы и должны быть преобразованы во что-то, что сможет прочесть javascript для наших Vue-компонентов. Есть разные варианты: если у вас небольшой сайт, вы покажется проще создать Vue-prop и передать набор значений на соответствующих страницах — так же, как вы передаёте другие данные инициализации. Однако, это будет немного беспорядочно и не очень быстро.
Приём, который мы собираемся использовать, состоит в том, чтобы преобразовать их все в один файл javascript, который мы позже сможем импортировать во Vue. Есть много хороших библиотек для этого. Если вы работаете с Laravel, вам может понравится Laravel-JS-Localization, которая работает со всеми версиями Laravel. Это только конвертер php-файлов в js-файл, так что для нас по-прежнему не имеет значения что мы используем на клиентской стороне Vue, или Angular, или что-нибудь ещё. Кроме того, если вы не используете Laravel, вы можете найти (или создать) эквивалентную библиотеку для этого преобразования (например, «CakePHP-JS-Localization», которая будет понимать систему файлов перевода CakePHP).
Настройка этой библиотеки очень простая, но я просто отмечу пару вещей, которые я нашел, когда я её устанавливал. Файл config/localization-js.php
имеет две настройки. В messages
перечисляются файлы, которые вы хотите включить в этот файл перевода, т.е. просто список php-lang-файлов для ваших Vue-компонентов. В настройке path
указывается путь, где этот файл будет создан, т.е. скорее всего вы захотите расположить его в ваших assets, если вы используете для сборок фронтэнда gulp или что-то похожее. Я бы назвал его как-то более понятно, чем “translations” или “messages”, чтобы не путать его с другим кодом. Я назвал так:
/* * The default path to use for the generated javascript. */ 'path' => resource_path('assets/js/vue-translations.js'),
Для выполнения конвертации мы будем использовать команду artisan lang:js --quiet --no-lib
.
Каждый раз, когда вы добавляете или изменяете переводы в поддиректории components
вам потребуется переконвертировать их, т.к. Vue на самом деле использует файл vue-translations.js
, так что все изменения должны быть воссозданы в нём. В зависимости от того, как часто вы это делаете, вы можете захотеть добавить эту команду в свою сборку фронта (gulp, mix, что угодно). Переконвертация происходит очень быстро и не добавит много времени на сборку.
Если вы посмотрите внутрь файл vue-translations.js
, то вы увидите, что это большая json-свалка всех en/components/*.php
файлов. Так что следующее, что нам нужно — это какой-то парсер, который сможет прочитать этот json и выбрать одину конкретную строку перевода, которая нам нужна. Для этого мы будем использовать https://github.com/rmariuzzo/lang.js.
Итак, еще раз — чтобы было ясно, что мы делаем. Файл vue-translations.js
— это стандартный формат, который понимает Lang.js
. Неважно как мы получили наши переводы в этом формате, главное, что мы сделали так, чтобы Lang.js смог использовать свой функционал, чтобы прочитать его. Вот почему я сказал, что не важно, какой фреймворк или даже язык программирования используется. (Вы даже могли бы написать его вручную, если вы достаточно мазохистичны).
Сейчас мы на шаге 3 — импорт библиотеки Lang.js в наш фронтэнд (в данном случае, Vue). Библиотека имеет простой API и использует функции в стиле lang.get('greetings.hello')
, но мы хотим импортировать её во Vue чтобы можно было легко её использовать в наших компонентах.
Посмотрим на наш файл main.js
(или как вы называете ваш “глобальный” файл для всех компонентов). Мы можем создать пользовательский фильтр, как показано ниже:
// Если файл разрастается, вы можете вынести это в filters.js var Vue = require('vue'); var Lang = require('lang.js'); // получение данных import translations from './vue-translations.js'; // вот почему мы использовали --no-lib в командной строке var lang = new Lang(); lang.setLocale('en'); // @TODO вызвать когда мы создаём переключатель языков // по умолчанию 'en', но но если вам нужен другой язык, // в Lang.js есть такой функционал, который вы можете использовать: // if (lang.getLocale() === 'undefined'){ // lang.setLocale('en'); // } // передача данных в Lang.js lang.setMessages(translations); // Это наш обычный фильтр Vue. // '...args' позволяет нам использовать любое количество параметров в наших строках Vue.filter('trans', (...args) => { return lang.get(...args); });
Сама Lang.js имеет много хороших функций для таких вещей, как плюрализация и вы, возможно, захотите посмотреть на документацию, но этого будет достаточно для наших нужд.
Ну и в конце давайте заюзаем это на нашей странице!
Наш основной фильтр во Vue будет работать так:
// вызов без параметров: {{{ 'components/Faqs.question' | trans }}} // передача дополнительных параметров: // для Vue 1.* {{{ 'components/Faqs.question' | trans {'value' : 'Pass this value'} }}} // для Vue 2.* {{{ 'components/Faqs.question' | trans({'value' : 'Pass this value'}) }}}
Обратите внимание на синтаксис. Для этого примера в Laravel это будет файл с именем Faqs.php
в подкаталоге с названием components
внутри en
(или любой другой языковой группы). question
- это ключ в оригинальном массиве. Строка ‘components/Faqs.question’
передается в trans
-фильтр без параметров в этом случае, а trans()
говорит Lang.js найти этот ключ во vue-translations.js
.
Вот и весь процесс. Он кажется немного сложным на первый взгляд, но давайте взглянем ещё раз на то, что мы делаем:
/en/components/Faq.php
).vue-translations.js
).Итак! В итоге у нас остался один источник переводов, который мы можем импортировать в любой сторонний сервис для переводов.
Надеюсь, это поможет!