Хабрахабр

Анализ механизмов локализации интерфейса приложений в Splunk


В данной статье мы рассмотрим основной механизм локализации интерфейса приложений Splunk (в т.ч. стандартных элементов приложения Search) — gettext internationalization and localization (i18n).
Возможности для перевода:

  • интерфейс Splunk;
  • дашборды (заголовки панелей и полей ввода);
  • выбор статических ресурсов (картинки, CSS и т.д.) на основе текущей локали, например: logo-ru_RU.gif или logo-en_GB.gif.

Для локализации необходимо проделать несколько шагов:

  1. Создать новую локаль в Splunk (при необходимости).
  2. Сформировать файлы-словари перевода.
  3. При помощи JavaScript подгрузить переведённые поля.

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

Итак, перейдём к практике.

Создание новой локали в Splunk

Напомню, по умолчанию в Splunk используется en-US локаль, в этом можно убедиться в строке браузера: MYSERVER:8000/en-US/app/search (hint: если вручную поменять en-US на en-GB, то время и дата будут отображаться в более привычном виде).

Копируем существующую локаль: Для начала сделаем новую локаль для России.

sudo cp /opt/splunk/lib/python2.7/site-packages/splunk/appserver/mrsparkle/locale/en_GB /opt/splunk/lib/python2.7/site-packages/splunk/appserver/mrsparkle/locale/ru_RU -ru

Перезапускаем Splunk:

sudo /opt/splunk/bin/splunk restart

И проверяем:

MYSERVER:8000/ru-RU/app/launcher/home

Создание нового приложения

Создаём новое приложение с названием testapp (Name\Folder name: testapp):

MYSERVER:8000/ru-RU/manager/launcher/apps/local/_new?action=edit&ns=launcher

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

Теперь перейдём непосредственно к формированию файлов перевода.

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

sudo /opt/splunk/bin/splunk extract i18n -app testapp

После этого у нас появляется файл /opt/splunk/etc/apps/testapp/locale/messages.pot, который содержит в себе все поля, которые используются в приложении, т.к. у нас приложение новое, там будет только один элемент — ссылка на имя приложения.

Регистрируемся на сайте poeditor.com.

Добавляем русский язык (Add Language):

Создаём новый проект и импортируем (import terms) наш файл /opt/splunk/etc/apps/testapp/locale/messages.pot:

Добавим несколько полей при помощи кнопки Add Term:

Справа от каждого из них есть кнопка добавления перевода:

Воспользуемся и переведём наши поля:

Переходим в проект, выбираем русский язык и экспортируем в ДВА формата: .po и .mo:

Создаём папку с соответствующей локалью и копируем туда наши файлы, переименовав их в messages.po и messages.mo соответственно:

sudo mkdir /opt/splunk/etc/apps/testapp/locale/ru_RU/LC_MESSAGES
suco cp messages.* /opt/splunk/etc/apps/testapp/locale/ru_RU/LC_MESSAGES

Перезагружаем Splunk:

sudo /opt/splunk/bin/splunk restart.

Заходим в наше приложение и убеждаемся, что отображаемое имя приложения переведено:
localhost:8000/ru-RU/app/testapp/search

JS скрипт

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

Создаём папку, откуда будет загружаться скрипт:

sudo mkdir /opt/splunk/etc/apps/testapp/appserver
sudo mkdir /opt/splunk/etc/apps/testapp/appserver/static

Пишем сам скрипт в /opt/splunk/etc/apps/testapp/appserver/static/dashTranslate.js:

require([ 'jquery', 'underscore', 'splunk.i18n', 'splunkjs/mvc', 'splunkjs/mvc/simplexml/ready!' ], function ($, _, i18n, mvc) else { defaultTokens.set("form.t_locale", envTokenModel.get("locale")); // set locale token } // если перевода для текущей локали нет, то будем использовать стандартное значение if (i18n._("openvasTitle") == "openvasTitle") { defaultTokens.set("form.t_openvasTitle", "OpenVAS Events"); // default value } else { defaultTokens.set("form.t_openvasTitle", i18n._("openvasTitle")); // translated value } //перевод названий столбцов. значение в виде имени переменной нас вполне устроит как стандартное значение, поэтому не будем задавать его отдельно defaultTokens.set("form.t_signature", i18n._("signature")); defaultTokens.set("form.t_description", i18n._("description")); defaultTokens.set("form.t_count", i18n._("count")); });

Делаем дашборд

Создаём новый дашборд и добавляем в него (исходники дашборда для ленивых в конце):

  • Input text – Name: count, Token: t_count
  • Input text – Name: openvasTitle, Token: t_openvasTitle
  • Input text – Name: signature, Token: t_signature
  • Input text – Name: description, Token: t_description

Без инпутов не будут работать form.* токены, что не позволит передавать полноценное состояние дашборда в URL. Чтобы они не мозолили глаза, добавляем «depends="$nothing$"» в каждый из них.

Panel, statistic table – Title: $t_openvasTitle$

index=openvas
| stats count by "NVT Name" Summary
| rename "NVT Name" AS $form.t_signature$ Summary AS $form.t_description$ count AS $form.t_count$

Panel, pie chart – Title: $t_openvasTitle$

index=openvas
| stats count by "NVT Name"
| rename "NVT Name" AS $form.t_signature$ count AS $form.t_count$

Добавляем наш скрипт на дашборд – меняем первую строку на:

<form script="dashTranslate.js">

Тут есть небольшая особенность – Splunk переводит известные ему поля (count, signature в нашем случае) в текстовых полях инпутов или заголовках.

Режим редактирования:

Обычный режим:

Плюс при редактировании не ясно, что это, на самом деле, перевод, поэтому лучше использовать токены ($form.t_openvasTitle$ и $form.t_description$ в нашем примере). Однако надо держать в голове то, что при повторном редактировании панели выводиться будет перевод, и если случайно, например, поставить пробел, то в исходниках вместо переменной (openvasTitle или description в нашем примере) будет сохранён текст («События OpenVAS_» или «Описание_» в нашем примере).

В режиме повторного редактирования: верхний заголовок – токен $form.t_openvasTitle$, нижний – текст openvasTitle.

Как итог, у нас получился дашборд

Ограничения

Есть два ограничения, о которых стоит знать:

  1. Нельзя переводить заголовки дашбордов.
  2. Нельзя задавать начальные значения токенов в init\set, т.к. выполняются после скрипта-перевода (можно вынести JS на более позднюю загрузку, но тогда придётся конвертировать в HTML).

Перевод результатов поиска

Для вывода конечным пользователям текстовых данных предлагается использовать lookup с переводом на любое количество языков. В этом примере мы как раз используем глобальный токен Splunk $env::local$. Идентификатором уязвимости является хеш, по которому мы подключаем перевод. Также отмечу, что если перевод будет пустой, то будет использовано начальное значение. Добавим новый static table в наш дашборд:

index="openvas"
| eval signature=replace(signature, "[\n\r]", " ")
| eval description=replace(description, "[\n\r]", " ")
| eval hash=md5(signature.description)
| stats count by signature description hash
| lookup OpenVAS_translate hash AS hash OUTPUT signature_$env:locale$ AS signature_$env:locale$ description_$env:locale$ AS description_$env:locale$
| eval signature=coalesce('signature_$env:locale$', signature) | eval description=coalesce('description_$env:locale$', description)
| fields - signature_$env:locale$ description_$env:locale$ count hash
| rename signature AS $form.t_signature$ description AS $form.t_description$

Файл OpenVAS_translate.csv выглядит следующим образом (для работы с лукапами советую использовать приложение Lookup Editor):

Таким образом, при наличии перевода он будет произведён исходя из текущей локали.
ru-RU:

de-DE:

Перевод стандартного интерфейса Splunk

Перевод интерфейса Splunk осуществляется аналогичным образом -необходимо перевести в poeditor файл $SPLUNK_HOME/lib/python2.7/site-packages/splunk/appserver/mrsparkle/locale/messages.pot и скопировать два получившихся файла (messages.mo и messages.po) в папку:$SPLUNK_HOME/lib/python2.7/site-packages/splunk/appserver/mrsparkle/locale/ru_RU/LC_MESSAGES/

Все, кого интересуют актуальные вопросы по Splunk, мы приглашаем присоединиться к нашему каналу в Telegram.

Список используемых источников:

4. docs.splunk.com/Documentation/Splunk/6. 2. 1/AdvancedDev/TranslateSplunk
docs.splunk.com/Documentation/Splunk/7. 6/Viz/tokens
splunkonbigdata.com/2018/11/01/creating-a-splunk-locale
answers.splunk.com

Итоговый код дашборда:

<form script="d.js"> <label>i18n description</label> <description>description</description> <fieldset submitButton="false" autoRun="false"> <input type="text" token="t_count" depends="$nothing$"> <label>count</label> </input> <input type="text" token="t_openvasTitle" depends="$nothing$"> <label>openvasTitle</label> </input> <input type="text" token="t_signature" depends="$nothing$"> <label>signature</label> </input> <input type="text" token="t_description" depends="$nothing$"> <label>description</label> </input> </fieldset> <row> <panel> <title>$form.t_openvasTitle$</title> <table> <title>openvasTitle</title> <search> <query>index=openvas
| stats count by "NVT Name" Summary
| rename "NVT Name" AS $form.t_signature$ Summary AS $form.t_description$ count AS $form.t_count$</query> <earliest>0</earliest> <latest></latest> </search> <option name="drilldown">none</option> <option name="refresh.display">progressbar</option> </table> </panel> </row> <row> <panel> <chart> <title>$form.t_openvasTitle$</title> <search> <query>index=openvas
| stats count by "NVT Name"
| rename "NVT Name" AS $form.t_signature$ count AS $form.t_count$</query> <earliest>0</earliest> <latest></latest> </search> <option name="charting.chart">pie</option> <option name="charting.drilldown">none</option> <option name="refresh.display">progressbar</option> </chart> </panel> </row> <row> <panel> <table> <search> <query>index="openvas"
| eval signature=replace(signature, "[\n\r]", " ")
| eval description=replace(description, "[\n\r]", " ")
| eval hash=md5(signature.description)
| stats count by signature description hash
| lookup OpenVAS_translate hash AS hash OUTPUT signature_$env:locale$ AS signature_$env:locale$ description_$env:locale$ AS description_$env:locale$
| eval signature=coalesce('signature_$env:locale$', signature) | eval description=coalesce('description_$env:locale$', description)
| fields - signature_$env:locale$ description_$env:locale$ count hash
| rename signature AS $form.t_signature$ description AS $form.t_description$</query> <earliest>0</earliest> <latest></latest> </search> <option name="count">10</option> <option name="drilldown">none</option> <option name="refresh.display">progressbar</option> </table> </panel> </row>
</form>

Теги
Показать больше

Похожие статьи

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Проверьте также

Закрыть
Кнопка «Наверх»
Закрыть