Перейти к содержимому

Релизы и OTA

Экспорт — это файл, который вы коммитите. Релиз — снимок, который скачивает ваше приложение. Релизы нужны, чтобы поменять перевод, не выпуская новую сборку.

Со вкладки Релизы проекта или мутацией GraphQL createRelease. Релиз берёт утверждённые переводы проекта в том виде, в каком они прямо сейчас, и замораживает их.

ПолеЧто значит
versionПрисваивается автоматически, растёт в пределах проекта
name, descriptionВаши, чтобы сказать, что изменилось
splitByFilesГруппировать ли бандл по файлам — см. ниже
languagesКакие языки попали в бандл
segmentCountСколько ключей несёт самый полный язык

Внутрь попадают только переводы в статусе approved. Язык, который никто не дописал, окажется в релизе с готовыми ключами и без остальных, поэтому незаконченный язык релиз не блокирует — но прогресс перед выпуском посмотреть стоит.

По умолчанию бандл — плоское отображение ключа в значение, по отображению на язык, причём в исходном языке лежат исходные тексты:

json
{
"en": { "home.title": "Hello" },
"ru": { "home.title": "Привет" }
}

С splitByFiles ключи сгруппированы по файлу, из которого пришли:

json
{
"en": { "5f1c…": { "home.title": "Hello" } },
"ru": { "5f1c…": { "home.title": "Привет" } }
}

Плоская форма подходит, когда приложение грузит по словарю на язык, а разбитая — когда оно грузит по одному пространству имён за раз.

Сегмент с формами множественного числа несёт весь набор форм как значение, поэтому в релизе множественное число сохраняется целиком.

Ключ уникален в пределах своего файла, а не проекта, поэтому title может быть в двух файлах. В плоском бандле такой ключ может оказаться только один раз, так что он берётся из файла, последнего в порядке пути и имени, и все языки берутся из этого же файла: если в нём нет утверждённого перевода на какой-то язык, ключа в этом языке не будет, даже если в другом файле перевод есть. Релиз фиксирует это в duplicateKeys: ключ, файлы, в которых он есть, и usedFrom, то есть последний файл, из которого взято значение. Список возвращается вместе с релизом и показывается в интерфейсе.

Этот отчёт стоит прочитать при первом релизе проекта, разложенного по многим файлам. Либо переименуйте конфликтующие ключи, либо переключите релиз в splitByFiles: в бандле, разбитом по файлам, у каждого файла своё значение, а duplicateKeys пуст.

У каждого проекта одна раздача: постоянный ключ доступа, который отдаёт его релизы по HTTP без авторизации.

Найти его можно в разделе Релизы → Раздача или запросом GraphQL releaseDistribution. Если ключ утёк, перевыпустите его — старый перестанет работать немедленно, и всем клиентам понадобится новый.

GET https://api.ownlate.com/public/v1/ota/{accessKey}/manifest
GET https://api.ownlate.com/public/v1/ota/{accessKey}/bundles
GET https://api.ownlate.com/public/v1/ota/{accessKey}/bundles/{language}

Манифест маленький, его дёшево опрашивать:

json
{ "version": 7, "languages": ["en", "ru", "de"], "publishedAt": "2026-08-20T09:31:00Z" }

Ручки бандлов отдают переводы — по всем языкам или по одному:

json
{
"version": 7,
"language": "ru",
"splitByFiles": false,
"publishedAt": "2026-08-20T09:31:00Z",
"translations": { "home.title": "Привет" }
}

Все три по умолчанию отдают последний релиз. Добавьте ?version=5, чтобы закрепиться на более раннем, — пригодится, когда старая сборка приложения ждёт ключи, которых в текущем релизе уже нет.

Ответы несут ETag, собранный из версии и времени публикации. Пришлите If-None-Match — и неизменившийся бандл ответит 304 Not Modified без тела. Бандлы сжимаются, если клиент сообщил, что принимает сжатие, и сжатая форма тоже кешируется.

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