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

в 12:20, , рубрики: splunk, Блог компании Акрибия, информационная безопасность

Анализ механизмов локализации интерфейса приложений в Splunk - 1
В данной статье мы рассмотрим основной механизм локализации интерфейса приложений 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 (NameFolder 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):

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

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

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

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

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

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

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

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

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

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

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

Создаём папку с соответствующей локалью и копируем туда наши файлы, переименовав их в 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

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

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) {      
      var defaultTokens = mvc.Components.get("default");
      var envTokenModel = mvc.Components.getInstance("env");
      
      	   if (envTokenModel.get("locale") != "ru-RU" || envTokenModel.get("locale") != "de-DE") {
    	      defaultTokens.set("form.t_locale", "ru-RU"); // если текущая локаль не из поддерживаемого списка, будем переводить на стандартный язык (русский), это сделано только для перевода результатов поиска (забегая вперёд, скажу, что это будет сделано при помощи lookup полей, которые будут иметь суффикс в виде локали, в противном случае можно напрямую использовать $env::locale$ токен)
    } 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 в нашем случае) в текстовых полях инпутов или заголовках.

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

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

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

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

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

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

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

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

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

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

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

Ограничения

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

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

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

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

index="openvas"
| eval signature=replace(signature, "[nr]", " ")
| eval description=replace(description, "[nr]", " ")
| 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):

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

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

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

de-DE:

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

Перевод стандартного интерфейса 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.

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

docs.splunk.com/Documentation/Splunk/6.4.1/AdvancedDev/TranslateSplunk
docs.splunk.com/Documentation/Splunk/7.2.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, "[nr]", " ")
| eval description=replace(description, "[nr]", " ")
| 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>

Автор: Acribia

Источник


* - обязательные к заполнению поля