translocale_delivery 0.1.0
translocale_delivery: ^0.1.0 copied to clipboard
Read-only approved translation delivery with offline fallback for Dart and Flutter apps.
TransLocale delivery for Dart and Flutter #
Read-only delivery of approved translations, with bundled fallback and an optional native file cache. Requires Dart 3.12 or later.
This package is separate from translocale_flutter, which provides build-time tooling. It does not restore the legacy 0.0.1 OTA API or accept old credentials.
For Flutter apps, the Flutter runtime integration supplies native cache storage and installed-app version detection. Use this lower-level client when providing those values yourself. Both implement DeliveryRuntime and work with the generated localization wrapper.
Initialize #
Generate the app's catalog schema from local sources with translocale release-schema. An owner then publishes an approved release and creates a read-only credential for that project, channel, and schema. See release management.
import 'package:translocale_delivery/translocale_delivery.dart';
final delivery = DeliveryClient(
projectId: projectId,
channel: 'production',
schemaHash: schemaHash,
appVersion: '1.0.0',
token: deliveryToken,
);
final removeListener = delivery.addListener(refreshTranslations);
delivery.start(); // Do not wait for delivery before rendering built-in wording.
final raw = delivery.resolve('app.arb', 'fr', 'hello', 'Hello {name}');
// Format raw with the app's message renderer before displaying it.
// When the app removes this client:
removeListener();
delivery.dispose();
resolve uses exact file, locale, and key identities. getCatalog returns an immutable raw message map. Both return unformatted messages. Use the generated adapter below to retain Flutter's typed localization methods, parameter formatting, and built-in wording.
Use Flutter's generated API #
Run flutter gen-l10n, then use the Flutter tooling to generate an adapter:
dart run translocale_flutter:translocale ota-adapter --catalog app.arb
The command reads paths and class names from l10n.yaml and the source language from the template ARB. It writes translocale_localizations.dart beside the generated base. --catalog is its catalog identity in TransLocale. Regional sources select the correct generated subclass and inherit missing implementations. Explicit --base, --reference, --reference-class, --out, and --class options remain available. Generation is offline, preserves positional/named signatures and number/date formatting, and refuses to overwrite an existing file. Schema and delivery configuration remain separate for this lower-level command.
Add --check to verify an existing adapter in CI. It checks source fingerprints and generated behavior while allowing dart format changes. Regenerate after changing the generated inputs; remove the previous generated adapter before writing its replacement.
Wrap the app with the generated builder:
TransLocaleAppLocalizationsBuilder(
delivery: delivery,
builder: (context, delegates) => MaterialApp(
localizationsDelegates: delegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const HomePage(),
),
)
The builder starts delivery after the first frame, pauses automatic checks while inactive, and refreshes the delegates when delivery changes. It owns the supplied client and disposes it when removed or replaced; give each client one owner. Passing null uses the generated bundled translations. Set automaticUpdates: false for manual-only updates through delivery.check().
Existing calls such as AppLocalizations.of(context).welcome(name) keep their generated types and fallback behavior. Keep your app's existing locale-data initialization for date formatting. Advanced integrations can use TransLocaleAppLocalizationsDelegate(delivery) directly and manage listeners, lifecycle and disposal themselves.
The adapter selects the exact language of Flutter's loaded fallback implementation. If that release lacks the language or key, it uses the generated method. Unsupported or malformed delivered messages also use generated wording.
Message formatting #
FlutterMessageFormatter supports plain text, arguments, ICU apostrophe escaping, selects, nested branches, and cardinal plurals using the same Intl.pluralLogic behavior as gen-l10n. It accepts =0, =1, and =2 as Flutter's explicit cases. Date and number display strings come from the generated adapter, while selectors receive the original values.
Plural offsets, selectordinal, plural #, inline number/date formats, rich-text tags, overlapping exact/category selectors, and malformed syntax fall back to generated wording. This matches the supported dialect of translocale flutter-export; use explicit count placeholders and ARB format metadata. Parsing is limited to 100,000 characters and 32 nested branches, with a bounded cache of parsed messages. Custom renderers can still use the raw delivery API.
Use setActive(false) when the app is backgrounded and setActive(true) on resume. This pauses automatic polling. check() performs a manual refresh, sharing an in-flight request and respecting server cooldowns.
Only tld_ delivery credentials are accepted. App credentials are extractable and grant no editing or publishing access. Never include authoring credentials in a consumer. Production origins require HTTPS; HTTP is allowed on loopback for local verification.
Native cache #
import 'dart:io';
import 'package:translocale_delivery/translocale_delivery_io.dart';
final cache = FileDeliveryCache(Directory(privateCacheDirectory));
// Pass cache: cache to DeliveryClient.
Supply a dedicated directory inside the app's private application-support storage. The file cache writes a temporary file, flushes it, and renames it over the previous entry. Entries contain release wording without credentials and are scoped by origin, project, channel, and schema. translocale_delivery_io.dart requires native file access; it is not a Flutter web cache.
Custom DeliveryCache adapters must provide atomic writes. The runtime serializes writes and keeps only the latest queued release, so a slow earlier write cannot overwrite a later one. state.cache reports writing until the queued snapshot is stored. A write that takes more than five seconds reports a cache error without delaying translation use. A storage operation already started may finish after disposal; disposal prevents further queued writes and UI updates.
Runtime behavior #
- Built-in lookups return immediately. Startup validates the cached release before its first request, allowing an unchanged release to return
304. - Invalid responses, network failures, unsupported app versions, and revoked credentials retain the last valid wording. Missing messages use the caller's fallback.
- Rollback uses a newer channel revision pointing to an earlier compatible release. Older or conflicting revisions are rejected.
- Cache reads and network checks each have a five-second deadline.
start()can take up to ten seconds to settle; synchronous JSON/hash work remains on the calling isolate. Responses are bounded to 1,510,000 bytes. - Polling defaults to five minutes, configurable between 30 seconds and one hour. Numeric and HTTP-date
Retry-Aftervalues delay retries. Authentication failure stops automatic polling; a manual successful check can resume it. - Requests reject redirects. Disposing cancels requests and timers, clears in-memory wording, and ignores late responses. The persisted cache remains available for the next start.
state reports the active release, channel revision, wording source, delivery status, and cache status without credentials. A delivery error does not imply that the app has lost its current wording.
Verify #
In this package:
dart pub get
dart analyze
dart test
From the repository root, after building the JavaScript client and CLI:
npm run test:delivery:dart
Set DART_BIN if Dart is not on PATH. The verifier installs this package into an isolated consumer outside the workspace and exercises real HTTP delivery against ephemeral D1. It checks promotion/rollback, native cache writes, offline restart, incompatible app fallback, and conditional refresh. No paid translation jobs run.
Service-generated ARB fixtures verify shared schema and checksum rules using payloads with Arabic plural messages, Unicode, and escaped characters. npm run test:delivery:flutter separately generates reference output with Flutter, compares formatting in English/French/Arabic, and tests typed overrides, delegate reload, fallback, and RTL in Flutter widget tests. The Flutter journal example adds application lifecycle handling and private native storage. Verify it with npm run test:delivery:flutter-app. Set FLUTTER_BIN if needed. Device and installed-app verification remain separate gates.
License #
MIT. The hosted service remains private and cloud-only.