ResilientLang docsDeveloper documentation (draft, product name is a placeholder)

Bundle format

Everything a visitor's browser needs is static JSON: UTF-8, minified, served with Access-Control-Allow-Origin: *. This page summarises BUNDLE_FORMAT.md in the repository, which is the normative text.

URL layout#

<base>/v1/<siteKey>/manifest.json                      mutable, short cache
<base>/v1/<siteKey>/<version>/<lang>.<hash8>.json      immutable, cached for a year

<base> is a delivery origin: your own site, then the primary CDN, then the secondary CDN. <version> increases with every publish. <hash8> is the first 8 hex characters of the file's SHA-256.

FileCache-Control
manifest.jsonpublic, max-age=60, stale-while-revalidate=86400, stale-if-error=604800
language filespublic, max-age=31536000, immutable

manifest.json#

{
  "schema": 1,
  "siteKey": "rl_site_live_abcdefghijklmnopqrstuv",
  "version": 42,
  "generatedAt": "2026-10-28T12:00:00Z",
  "sourceLanguage": "en",
  "languages": [
    { "code": "fr", "name": "French", "nativeName": "Français", "dir": "ltr",
      "file": "42/fr.1a2b3c4d.json", "sha256": "<64 hex>", "bytes": 18234, "strings": 512, "urlPrefix": "/fr" }
  ],
  "cdns": ["https://cdn-a.example/", "https://cdn-b.example/"],
  "kid": "<signing key id>",
  "signature": "<base64url Ed25519>"
}

Language file#

{ "schema": 1, "lang": "fr", "version": 42,
  "strings": { "0e9408353c729c32": "Ajouter au panier" },
  "attrs":   { "<key>": "Rechercher" } }

strings are text nodes and text blocks; attrs are attribute values (alt, title, placeholder, aria-label, button value, selected meta content). The publisher puts attribute strings in attrs, never in strings. A missing key means "show the source text"; it is never an error.

What the loader checks in a manifest#

A manifest that fails any rule is refused as a whole (the page keeps the cached accepted version, else the source language):

How the signature and version are judged across key changes is on Signing and key epochs.

Versioning#

schema changes only additively within v1. A breaking change creates /v2/ paths.

Next: how keys are computed, in Strings and keys, and how the loader consumes all this, in The loader.