Локализация angular-приложения

Введение

В данной статье пойдет речь про простую и удобную локализацию angular-приложений (для первой версии angularJS) под названием angular-gettext. На самом деле метод локализации с помощью данного плагина соответствует общей концепции по настройке нескольких языков и общим принципам локализации. Поэтому мы рассмотрим и общий порядок по интернационализации любого программного обеспечения.

Официальный сайт плагина — https://angular-gettext.rocketeer.be/, на котором можно найти все необходимое — последнюю версию angular-gettext и подробную документацию с примерами использования. В данной статье нет многих подробностей и тонкостей — лишь общий пример локализации angular-приложения. Можете задавать вопросы в комментариях.

Общие принципы локализации

Можно выделить общий порядок по локализации:

  1. Специальное выделение слов в шаблоне, которые необходимо перевести на разные языки.
  2. Сохранение перевода на определенный язык в отдельных файлах (может быть json, xml и другие).
  3. Подключение необходимого плагина или написание собственной функции локализации.
  4. Настройка конфигурации (где лежат переводы, язык по умолчанию и так далее).

Можно написать и свой плагин для локализации на любом языке — порядок останется почти таким же. Однако есть уже большое количество готовых решений как для JavaScript, так и для серверных языков, например, популярных php-фреймворков.

В JavaScript сохранение перевода в отдельных файлах осуществляется либо в формате json, так как он просто самый удобный для языка JS, либо в самом js с обычным объектом внутри. Но в серверных языках программирования часто встречается xml и xml-подобные форматы.

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

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

getText(‘Строка для поиска перевода или просто id’, ‘de’);

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

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

Локализация angular-приложения с помощью angular-gettext

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

В angularJS уже есть своя шаблонная система и angular-gettext использует ее возможности с помощью фильтров и специальных директив. Чтобы добавить строку к переводу необходимо написать строку на каком-то одном языке (рекомендуется английский) и пометить ее с помощью фильтра translate:

{{‘Some string’ | translate}}

Или же можно воспользоваться менее универсальным вариантом — добавить особый атрибут (директиву в AngularJS) к html тегу:

<span translate>Some string</span>

А также использовать особый тег:

<translate>Some string</translate>

В таком случае всё содержимое html элемента будет помечено как перевод. Данный метод менее универсальный чем фильтр, так как его конечно же нельзя использовать, например, в атрибутах, в тексте без оборачивания в элемент, а кроме того в перевод попадает все содержимое внутри тега, которое может содержать ненужные юникод символы, пробелы, отступы или иконки. Есть и другие нюансы перевода, которые можно узнать в документации —  https://angular-gettext.rocketeer.be/dev-guide/annotate.

Далее нам понадобятся дополнительные инструменты. Так как возможности фронтенд разработки ограничены и браузерный JS не умеет читать файлы, необходимо воспользоваться системами сборки проектов. Если вы опытный JavaScript разработчик вы должны знать, что это. Если нет — очень рекомендую изучить, что такое Gulp, Grunt, Webpack, Browserify или другие.

В документации angular-gettext рекомендуют grunt и приводится подробная инструкция как все сделать. Мы же воспользуемся другим очень популярным инструментом — gulp.

Для gulp есть плагин gulp-angular-gettext, установим его в проект через npm:

npm install gulp-angular-gettext

Далее в gulpfile.js подключим его и настроим:

var gulp = require('gulp');

var gettext = require('gulp-angular-gettext');

gulp.task('pot', function () {

    return gulp.src(['www/templates/*.html', 'www/js/controllers.js'])

        .pipe(gettext.extract('ru.pot', {

        }))

        .pipe(gulp.dest('po/'));

});

gulp.task('lang', function () {

    return gulp.src('po/*.po')

        .pipe(gettext.compile({

            format: 'javascript'

        }))

        .pipe(gulp.dest('www/js/translations/'));

});

Поясним код — gettext.extract обрабатывает переданный поток из указанных в gulp.src файлах, генерирует pot файл и бросает его в папку под названием po. Метод gettext.compile берет файлы перевода в po формате и делает из них js-файл, который умеет считывать плагин angular-gettext, так как внутри данного файла обычный js объект. Как сделать po-файлы мы еще посмотрим. После этого готовые файлы сохраняются в папке js/translations, в которой angular-gettext по умолчанию ищет файлы перевода.

То есть мы с помощью специального плагина для gulp собрали все наши помеченные строки в файл pot, который является основой для дальнейшего перевода. Как видите, отличие фронтенда и в частности angular-gettext от бэкендовских локализаций в том, что функция локализации не работает динамически, JS не умеет работать с файловой системой и сам не добавит новые файлы в перевод, нам необходимо самостоятельно запускать сборку pot файла каждый раз при обновлении локализации. Можно конечно сделать все переводы в json-файлах и потом загружать их самостоятельно через ajax, но angular-gettext берет на себя данный функционал и кроме того использует более универсальный метод о котором пойдет речь далее.

Теперь нам понадобится программа для удобного перевода. Можно воспользоваться любой которая умеет работать с файлами интернационализации — pot и po. Общий план работы все равно одинаковый:

  1. Использовать pot шаблон как основу для перевода.
  2. Сгенерировать новый po файл или обновить уже существующий.
  3. Перевести нужный текст в программе.
  4. Сохранить перевод в po файл.

Мы будем использовать программу Poedit, доступную для основных операционных систем. В ней нужно выбрать опцию — “Новый каталог из pot файла” или, если уже есть файл перевода, открыть po файл и выбрать — “Обновить из pot файла”.

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

Таким образом, данный способ, который предлагает angular-gettext позволяет использовать любые удобные универсальные программы-переводчики, что конечно дает больше свободы и удобнее чем составлять вручную json файлы.

Теперь у нас есть сгенерированные файлы с переводами и помеченные места куда определенный перевод вставлять. Не забываем запустить gulp, чтобы он собрал js из po файла. Для того чтобы angularJS умел работать с локализацией, необходимо совершить инъекцию модуля angular-gettext в ваше angular-приложение.

Для этого сначала устанавливаем модуль через npm или bower:

npm install --save angular-gettext

Или

bower install --save angular-gettext

Потом подключаем скрипт gettext на страницу:

<script src="node_modules/angular-gettext/dist/angular-gettext.min.js"></script>

Или

<script src="bower_components/angular-gettext/dist/angular-gettext.min.js"></script>

Также можно просто скачать файл angular-gettext.min.js и подключить на страницу откуда угодно.

И последний шаг — инъекция модуля в ваш Angular:

angular.module(''app'', ['gettext']);

Таким образом, функция локализации angular-приложения у нас есть. Осталось сконфигурировать angular-gettext.

Настроить angular-gettext просто, достаточно в блоке run, config или контроллере angular приложения сделать инъекцию объекта gettextCatalog и вызвать метод setCurrentLanguage с аргументом — названием файла локализации в папке translations:

angular.module('app').run(function (gettextCatalog) {

gettextCatalog.setCurrentLanguage(‘de’);

});

В дальнейшем можно динамически менять язык с помощью данного метода из любого контроллера:

angular.module('app').controller('MainCtrl', function ($scope, gettextCatalog) {

gettextCatalog.setCurrentLanguage(‘en’);

});

Выводы

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