Я работала над созданием модуля BI, в основе которого использование Apache Superset для расчета и демонстрации различных метрик. Планировалось использовать дашборды в общем интерфейсе приложения целиком, просто встроив их в интерфейс, а настройки для создания метрик и прочего спрятать в общую админку. Соответственно, появилась необходимость локализовать интерфейс Superset’а.

Готового решения найти не удалось, поэтому пришлось разбираться самостоятельно.

Сразу оговорюсь, речь пойдет о версии 6.1.0 с расширением dev, в которое включены библиотеки для работы с другими БД, помимо SQLite. В репозитории с исходным кодом есть ветка с информацией о релизах.

Для разворачивания я использую Docker.

Проблема частичной локализации

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

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

Таким образом, в файле pythonpath/superset_config.py мы указываем значения для двух переменных:

LANGUAGES = {
    'ru': {'flag': 'ru', 'name': 'Russian'},
    'en': {'flag': 'us', 'name': 'English'},
    
}

BABEL_DEFAULT_LOCALE = 'ru'

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

Частично переведенный интерфейс
Частично переведенный интерфейс

Причины и исправления

Дело в том, что в image по умолчанию не включены скомпилированные локализационные файлы для разных языков, хотя сами файлы с переводом представлены. Таким образом, первой задачей по исправлению будет компиляция файла.

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

  • Backend (Python, Babel, .mo файлы)

  • Frontend (JavaScript, JSON словари)

Выполним локализацию в два этапа:

  1. Подготовим скомпилированные файлы перевода для python

  2. Запустим скрипт, который составит словарь для JS

Далее будет необходимость добавлять файлы в image и выполнять команды над ними. Один из удобных вариантов решения в данном случае - создание собственного image на основе официального с добавлением необходимых файлов, библиотек и выполнением действий.

Компиляция файла перевода

Начнем с компиляции файлов локализации. Они располагаются в папке superset/translations

Проверьте состав папки:

  1. файл messages.pot является шаблоном для файлов локализации, он должен быть в корне папки. Его трогать нет необходимости.

  2. в папках с <язык>/LC_MESSAGES хранятся файлы с расширением .po, в каждом файле .po есть перевод строк интерфейса для соответствующего языка. Он представляет собой заполненный словарь.

Состав папки
Состав папки

Если чего-то из этого у вас недостает, советую заглянуть в официальный репозиторий superset: https://github.com/apache/superset

Итак, мы подобрались к первой причине нашей проблемы. В папке не хватает скомпилированного файла .mo, это наш словарь, но уже для машины. Мы получаем его из файла messages.po с помощью библиотеки Babel. Я выполняла эту компиляцию локально, не в docker-контейнере.

python -m babel.messages.frontend compile -d <Абсолютный путь к папке>/translations   

Теперь, когда мы располагаем .mo файлом, большая часть интерфейса для нас переведена.

Более переведенный
Более переведенный

На данном этапе Dockerfile будет выглядеть так, вам необходимо заново собрать image, чтобы проверить это:

FROM apache/superset:6.1.0rc1-dev

USER root

RUN apt-get update && apt-get install -y \
    curl \
    gnupg \
    ca-certificates \
    && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
    && apt-get install -y nodejs \
    && rm -rf /var/lib/apt/lists/*
COPY ./<Относительный путь к файлу>/superset_config.py /app/pythonpath/superset_config.py

COPY <Относительный путь к файлу>/ru /app/superset/translations/ru

USER superset

Создание словаря для перевода фронта

Часть интерфейса, которая переводится python, теперь располагает скомпилированным файлом локализации.

Другая же часть переводится JS. Для этого ей нужно составить собственный словарь так же на основе .po файла. Вам нужно запустить скрипт, который этот словарь составит superset/superset-frontend/scripts/po2json.sh. Для этого вам может понадобиться добавить скрипт в image, прежде чем его выполнить.

В Dockerfile добавляем следующие команды:

COPY ./<Относительный путь к папке scripts/po2json.sh> /app/superset-frontend

RUN cd /app/superset-frontend && \
    npm install --legacy-peer-deps && \
    npm run build-translation

Теперь переведен весь интерфейс:

Переведенный интерфейс
Переведенный интерфейс

Развертывание

В результате Dockerfile будет выглядеть следующим образом:

FROM apache/superset:6.1.0rc1-dev

USER root

RUN apt-get update && apt-get install -y \
    curl \
    gnupg \
    ca-certificates \
    && curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
    && apt-get install -y nodejs \
    && rm -rf /var/lib/apt/lists/*
COPY ./<Относительный путь к файлу>/superset_config.py /app/pythonpath/superset_config.py

COPY <Относительный путь к файлу>/ru /app/superset/translations/ru

COPY ./<Относительный путь к папке scripts/po2json.sh> /app/superset-frontend

RUN cd /app/superset-frontend && \
    npm install --legacy-peer-deps && \
    npm run build-translation

USER superset

Обратите внимание, сначала мы используем пользователя root, это дает нам право на установку утилит, а в конце снова переходим на пользователя superset.

Пояснение по установленным утилитам:

  • curl используется для загрузки внешних скриптов и файлов по HTTP. В данном случае — для скачивания установочного скрипта Node.js.

  • gnupg необходим для работы с GPG-ключами. Используется при добавлении внешних репозиториев (например, NodeSource), чтобы проверять их подлинность.

  • ca-certificates - набор корневых сертификатов, обеспечивающий корректную работу HTTPS. Без них curl не сможет безопасно скачивать файлы.

  • nodejs необходим для сборки фронтенда Apache Superset, включая компиляцию переводов (npm run build-translation).

После установки утилит мы копируем файл конфиг, затем папку со скомпилированным переводом, затем файл со скриптом, создающим словарь для JS.

После того, как мы все скопировали, запускаем скрипт, создающий словарь. Image готов!

Теперь переключим внимание на docker-compose.yml. По умолчанию Superset использует БД SQLite и внутренние инструменты кеширования. Подключим его вместо этого к PostgreSQL и Redis.

Для начала нам надо обозначить эти два сервиса в нашем docker-compose.yml.

  redis:
    image: redis:7
    container_name: redis
    restart: until-stopped
    networks:
      - app-network

Мы задаем сеть, внутри которой будут доступны контейнеры, и, поскольку нам не нужен доступ извне, не добавляем порты.

  db:
    image: postgres:15
    restart: always
    env_file: .env
    volumes:
      - pgdata:/var/lib/postgresql/data     
    networks:
      - app-network

При создании контейнера БД удобно добавить файл .env с основными настройами: название бд, пользователь, пароль

POSTGRES_USER=postgres
POSTGRES_PASSWORD=secret
POSTGRES_DB=superset

Для подключения superset к новым сервисам нам нужно всего лишь расширить superset_config.py, добавив туда следующие переменные:

REDIS_URL = "redis://redis:6379/0"
RATELIMIT_STORAGE_URI = REDIS_URL
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://postgres:secret@db:5432/superset"

Сам superset мы пробрасываем наружу, не забывая при этом, что контенер должен быть в той же сети, что и остальные два, чтобы он мог к ним обращаться. В файле ./superset/.env нам нужно сохранить всего лишь одну переменную SUPERSET_SECRET_KEY - это просто случайно сгенерированная строка. Ее можно создать любым удобным способом, например, через openssl.

  superset:
    build:
      context: .
      dockerfile: superset/Dockerfile
    depends_on:
      - db
      - redis
    env_file:
      - ./superset/.env
    ports:
      - "8088:8088"
    restart: always
    networks:
      - app-network

volumes:
  pgdata:

networks:
  app-network:
    driver: bridge

После того, как вы подготовили image в Dockerfile и контейнеры в docker-compose, надо выполнить две команды сборки и запуска:

docker-compose build
docker-compose up -d

Комментарии (0)