Files
suaveplan/packages/localization/i18n/i18n-backend-storage/README.md
2026-05-27 23:47:53 +01:00

7.3 KiB

@suaveplan/i18n-backend-storage - Universal translation backend backed by any AbstractStorage from @suaveplan/storage. Three wire layouts: single-key-per-namespace (default), single-key-per-locale, flat-keys. Pluggable codec, AbortSignal cancellation, OpenTelemetry instrumentation under i18n.backend.storage.*. Zero runtime dependencies on @suaveplan/i18n core.

Summary

Universal translation backend for the @suaveplan/i18n family, backed by any AbstractStorage implementation from @suaveplan/storage. Implements the full Backend contract (read, readMulti, save, lastModified) over three wire layouts: single-key-per-namespace (default), single-key-per-locale, and flat-keys. Pluggable codec, optional AbortSignal cancellation, OpenTelemetry instrumentation under the i18n.backend.storage.* prefix. Zero runtime dependencies on @suaveplan/i18n core.

Documentation tree

- [backend](./src/backend/backend.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_- [backend](./src/backend/backend.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_- [backend](./src/backend/backend.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_- [backend](./src/backend/backend.md) — _(no submodules)_- [factory](./src/factory/factory.md) — _(no submodules)_ - [factory](./src/factory/factory.md) — _(no submodules)_- [observability](./src/observability/observability.md) — _(no submodules)_ - [observability](./src/observability/observability.md) — _(no submodules)_

Why this exists

The Wave 5 modular split lifts each backend out of the @suaveplan/i18n monolith into its own sibling so consumers can install only the backends they need. The storage backend is the canonical persistence layer: pair it with MemoryStorage for tests, OpfsStorage / IndexedDBStorage for offline-first browser apps, or S3Storage / GarageStorage / NodeFsStorage / SqliteStorage for server-tier deployments. Splitting it out also isolates @suaveplan/storage as a transitive dep — consumers using only the HTTP or memory backends no longer pull it in.

Install

bun add @suaveplan/i18n-backend-storage @suaveplan/storage

Quick Start

import { storageBackend } from "@suaveplan/i18n-backend-storage";
import { MemoryStorage } from "@suaveplan/storage";

const backend = storageBackend({ storage: new MemoryStorage() });

await backend.save("en", "auth", { login: { title: "Sign in" } });
const record = await backend.read("en", "auth");
// → { login: { title: "Sign in" } }

Modules

Subpath Description
@suaveplan/i18n-backend-storage Root barrel — class + factory + types + schemas + observability
@suaveplan/i18n-backend-storage/backend StorageBackend class + defaultCodec
@suaveplan/i18n-backend-storage/factory storageBackend factory function only
@suaveplan/i18n-backend-storage/schemas Zod boundary schemas
@suaveplan/i18n-backend-storage/observability OTel instruments + in-memory state ring

Modules Documentation

Capabilities

Flag Value Notes
canRead true always
canReadMulti true per-layout dispatch
canSave true persists into the wrapped storage
canTrackModification true consults getMetadata().modifiedAt
canWatch false the storage contract has no change feed

Layouts

  • single-key-per-namespace (default) — one key per (locale, ns) at <prefix>/<locale>/<namespace>.json. Best for HTTP-CDN-style storages.
  • single-key-per-locale — one key per locale holding the whole namespace map. Best when namespaces are small and read together.
  • flat-keys — one key per leaf string at <prefix>:<locale>:<namespace>:<dotPath>. Best for content- addressed storages with cheap per-leaf delta shipping.

Testing

The package's own tests use the shared runBackendConformance harness from @suaveplan/i18n-shared/testing so the universal Backend contract is exercised against a fresh storage backend per assertion (against all three layouts):

import { runBackendConformance } from "@suaveplan/i18n-shared/testing";
import { StorageBackend } from "@suaveplan/i18n-backend-storage";
import { MemoryStorage } from "@suaveplan/storage";

runBackendConformance("StorageBackend", async () => {
    const backend = new StorageBackend({ storage: new MemoryStorage() });
    return {
        backend,
        async seed(locale, namespace, record) {
            await backend.save(locale, namespace, record as never);
        },
    };
});

Versioning

This package is part of the i18n modular-split rollout. Stays at 0.1.0 until the slim core (Wave 6) cuts the family 1.0.0 release. The metric names under i18n.backend.storage.* are part of the public API contract and will not change without a major bump.

Wave 5 Scope

This package is Wave 5b of the 14-package i18n modular split. It ships pure additions only — packages/i18n/i18n/src/core/backend/storage/ retains its copy of the backend until Wave 6 deletes it. Both copies coexist during Wave 5; downstream consumers continue to import from the monolith and observe no behaviour change.