rerune 1.9.0
rerune: ^1.9.0 copied to clipboard
OTA localization for Flutter: update translations and add languages without an app release while keeping generated AppLocalizations APIs.
1.9.0 #
- Behavior change: lookups follow Flutter's own fallback order. Flutter
resolves a message through the requested locale, such as
de_AT, its language,de, then the template ARB file, whose text it fills in for a message another ARB file lacks. ReRune now takes the same steps and shows the dashboard text before your bundled text at each step. A key that the ARB file of a bundled language lacks now shows the dashboard text of the template language instead of the bundled template text, and a bundled regional text now wins over the dashboard text of its language. A language that the app does not bundle now ends at the template language instead of the manifestmain_language. Flutter's own controls, which ReRune loads in a fallback language for a language Flutter has no translations for, now load in the template language when Flutter has it. Like Flutter's generated lookup, ReRune now compares locale subtags as written, soLocale('de', 'at')does not use the bundledde_ATtexts. For a locale with both a script and a region, such aszh-Hant-TW, Flutter uses only the first class that exists of the exact locale, its script and its region; ReRune now also uses only the first of them that is saved, so azh-Hant-TWlookup no longer reaches dashboardzh-TWwhen dashboardzh-Hantis saved. Regenerate withdart run reruneor build_runner: the generated config now passestemplateLocale,untranslatedKeysandregionalKeystoReRuneLocalizationsConfig, which the generator reads from Flutter's generated files and the ARB files underlib. A translation equal to the template text counts as translated when the ARB files show it; without ARB files underlib, the generator warns and counts it as missing. A config generated by an earlier version keeps the previous order. - The generated config now escapes message names in its string literals.
Flutter allows
$in a message name, which made the generated code fail to compile. An ARB file underlibthat cannot be read no longer stopsdart run rerune. ReRune.setup(...)no longer reads and decodes every saved language. It reads a small saved state per language and the texts of the language that Flutter picks from the device languages; the texts of another language load when Flutter loads the app's localizations for it, before it shows that language. Only the languages the app shows and the steps of their fallback order stay in memory, and a language the app stops showing is unloaded once Flutter releases its localizations. Update checks still download and save every published language. A production check reads the saved texts of a language only when its version, name or URL changed; a staging check reads every snapshot it checks, as before. Localizations that load while setup still reads the saved state do not wait for the store: setup loads their texts as it finishes and notifies listeners. In a debug build benchmark with 10000 keys in 40 languages, setup took 63 ms instead of 2011 ms, showing one language 46 ms, and memory grew by 32 MB instead of 200 MB.- Behavior change:
ReRune.resolveText(locale: ...)called directly for a language whose saved texts are not loaded skips them, loads them in the background, and notifiesReRune.localizationsRevisionListenableonce they are loaded. GeneratedAppLocalizationsgetters read localizations whose texts Flutter waited for, apart from localizations that load while setup still reads the saved state. ReRuneCacheStore.readLocaleBundleInfo(...)returns the saved state of a locale without its texts as the newReRuneCachedLocaleInfo, andReRuneCachedLocaleBundle.inforeturns it from a bundle. The default reads the whole bundle, so custom stores keep working; override it to make setup faster. The built-in stores save that state next to each language, inlocale_<locale>.info.jsonon IO platforms and in the_locale_<locale>.infokey on the web. They derive it from the bundle again when it is missing, as for a bundle an earlier version saved, or cannot be read, and ignore it when its bundle is gone.- Saved texts that cannot be read when their language loads are logged, the
language leaves
ReRune.supportedLocales, and the next update check downloads it completely and reports the failure, as it did when checks read every saved language.
1.8.0 #
- Failures that ReRune causes at runtime no longer reach your app. ReRune
logs them at the configured
logLeveland answers with a safe value: the bundled text, an update result that carries the error, or no change. A check that fails in a way none of its steps handles reportsparsefor invalid data andstorageotherwise, and notifies listeners so the app shows what the check already saved; a check thatReRune.setStaging(...)interrupted reports nothing. Mistakes in how the app uses ReRune still throw as before, so they show up during development: calling aReRuneAPI beforeReRune.setup(...), an emptyotaPublishId, a config without locales, setup without the Flutter binding while checks on start are on, and persisting a variant with a cache store that does not support settings. Failures in your own bundledAppLocalizationscode also still reach your app, because they would happen without ReRune too, and so does an error of your own listener that yourFlutterError.onErrorrethrows: it fails the ReRune call that notified the listener, as before. When that call is a setup, the new setup stays active without its automatic checks, as in 1.7.0. - Behavior change:
ReRune.setup(...)now throws when the localizations config lists shipped parameters that cannot be read. Previously the failure appeared only later, inside update checks. - Behavior change:
ReRune.setup(...)called while widgets build, such as frominitStateorbuild, is not supported. Its texts apply, butReRune.localizationsRevisionListenableandReRuneBuilderdo not update for that setup, and debug builds report a Flutter error. Release and profile builds cannot detect a setup during the first mount afterrunApp, so there such a setup updates as usual. - A remote text that cannot be rendered for any reason now shows the bundled
text. Previously a remote plural threw while the widget was built when the
bundled text shows the count without a plural and the count is not
finite, such as
double.nan. - Behavior change:
ReRune.setVariant(persist: true)andReRune.resetVariant()no longer complete with an error when saving the selection fails, for example because the disk is full. The failure is logged, and the selection applies until the next setup or until the app restarts. A store whosewriteSettingthrows anUnsupportedError, such as a custom store that keeps the default, still completes them with that error, because it cannot save at all. AnUnimplementedError, which platform plugins throw at runtime, is logged like any other failed save. - Behavior change:
ReRuneVariant.namedno longer throws anArgumentErrorfor an invalid slug, because slugs often arrive at runtime. Such a slug cannot name a published variant, so the selection equalsReRuneVariant.main, andReRune.setup(...)orReRune.setVariant(...)logs the invalid slug at theerrorlevel. - Behavior change: a
periodicIntervalInHoursorperiodicIntervalInDaysvalue that is zero or negative now counts as not set, and setup logs it. The other value still applies, so-1hours with2days refreshes every two days; when no valid value remains, setup also logs that periodic refresh is off. PreviouslyReRuneUpdatePolicyfailed an assertion in debug builds and setup threw anArgumentError. - A very large refresh interval no longer overflows into a timer that fires continuously. Outside the web the combined interval is capped at 100000 days.
ReRune.localizationsRevisionListenableandReRune.onFetchedTextsAppliednow return one listenable and one stream for the lifetime of the app, so listeners and subscriptions keep receiving changes after a later setup. Each setup notifies the listenable once it has read its saved variant and texts, and the event revisions keep counting up across setups. A setup that a listener of a ReRune notification starts, also after an await or from a timer, sends no notification of its own while it starts, so a listener that calls setup on every notification cannot set up endlessly. An event is no longer lost when a listener replaces the setup while it is notified.onFetchedTextsAppliedemits nothing for a check that fails in a way none of its steps handles, even for texts it applied before. Previously a replacing setup disposed the listenable that existing listeners held and closed the stream, so a pendingonFetchedTextsApplied.firstfailed withStateError.- Behavior change:
ReRune.setup(...)with the same settings as the active setup now changes nothing and returns once the active setup is ready. Previously it replaced the setup, read the saved state again and started a new check; callReRune.checkForUpdates()for that. AfterReRune.setStaging(...)orReRune.setVariant(...)changed the selection, such a setup still replaces the active one and restores its settings, and a setup that an error of your own listener failed runs again. - A language that leaves the manifest while the app shows it now keeps your
AppLocalizationsfor the rest of that app run, loaded in the bundled fallback language, together with Flutter's own labels, and ReRune logs a warning once per language. Previously the app lost its localizations for that language. A language that left before the app started, and any locale that neither your bundled texts nor ReRune offered during the run, stays unsupported, as it is without ReRune. - A cache store that returns an unreadable manifest, or a manifest built in code with a locale code that ReRune cannot read, now counts as a failed cache read. Previously setup or later lookups could fail.
- Calling
ReRune.setup(...)from a listener of a ReRune notification, or from another app lifecycle observer, no longer breaks the update check that is running or reports a Flutter error. - Behavior change: on the web, the default cache store no longer creates
the
SharedPreferencesinstance that the whole app shares, so the app can still callSharedPreferences.setPrefixafterReRune.setup(...). Previously that call threw. State saved under the defaultflutter.prefix stays readable. If the app calledSharedPreferences.setPrefixbefore setup, ReRune saved its state under that prefix: ReRune then loses that state once, so it downloads the texts again, forgets a saved variant and the locale versions it rejected, and the old keys stay in local storage until the app removes them. For such an app, its ownSharedPreferences.clear()no longer clears ReRune state; with the default prefix it still does. - Flutter web apps compiled to WebAssembly now use the browser cache store. Previously they used a store that could not save anything, so fetched texts were never applied.
- A manifest version that is not a finite number is rejected as an invalid manifest.
1.7.0 #
- With
ReRuneUpdatePolicy.checkOnStartenabled, ReRune now also checks for updates whenever the app is shown again after being hidden, such as when the user returns from another app or the home screen, switches back to the browser tab, or restores a minimized window. A notification shade or system dialog that only covers the app does not start a check, and a check that is already running is shared. Previously, text published while the app was open appeared only after a restart,ReRune.checkForUpdates(), or a periodic refresh. - Behavior change:
checkOnStartistrueby default, so apps with the default policy now check on every return to the foreground. SetcheckOnStart: falseto turn off both automatic checks. - Behavior change: with
checkOnStartenabled,ReRune.setup(...)needs the Flutter binding and throwsBinding has not yet been initializedwithout it, keeping any earlier setup. CallWidgetsFlutterBinding.ensureInitialized()beforeReRune.setup(...), as the README setup already does.
1.6.1 #
- Remote plural messages in a language that
package:intlhas no plural rules for, such as Hausa (ha), now select the CLDR plural form. Previously every count selectedother, so a count of one showed the plural text. The SDK carries the rules for such languages, currently Hausa. Languages that intl covers keep intl's rules. - A
#in remote plural text now shows the count when intl has no number symbols for the language, formatted as English formats it. Previously the text silently fell back to the bundled text. - A remote text that cannot be rendered now logs one warning per key and locale when logging is enabled, and the bundled text is shown as before. Verbose logging adds the error.
ReRune.localizationsDelegatesnow loads the translations of Flutter's own controls, such as Material and Cupertino labels, for a supported language that Flutter does not translate. They load in the manifestmain_languagewhen Flutter has it, otherwise in the first compiled locale, and otherwise in English. Previously a screen with Material widgets failed withNo MaterialLocalizations foundin such a language. Your own texts stay in the requested language, and the text direction still follows Flutter's default.- Manifests and locale files are now always read as UTF-8, whatever
Content-Typethe server sends. Previously a response withoutapplication/json, or with another charset, was read as Latin-1, so letters such asü,ë,Ƙ, and all Cyrillic or Arabic text showed as garbled text and stayed in the cache. A response that is not valid UTF-8 is now rejected and never cached: a manifest reportsinvalidManifestand a locale file reportsnetworkand keeps the current text. - Behavior change: for a language Flutter does not translate, a delegate that
an app lists after
...ReRune.localizationsDelegatesfor one of Flutter's localization types no longer takes effect, because the fallback comes first. List such a delegate before ReRune's delegates.
1.6.0 #
- A locale update is now accepted only when every text fits the app. Code
generation records the parameters of every generated getter and method,
with their kinds, and passes them to the SDK through the new optional
ReRuneLocalizationsConfig(shippedParameters: ...). When a value of a key the app ships reads an unknown parameter, a parameter declared with an incompatible kind, or a plural or choice count the app does not pass as a number, the whole locale document is rejected, from a fetch, a delta, the cache, or a staging snapshot. The app keeps the last accepted texts for that locale, or falls back to the main language and then to the shipped text when there are none, and the update result reports aparseerror. Reading fewer parameters than the app passes is still accepted, so "Save 50% today" keeps working after a placeholder is removed. Keys the app does not ship are not checked. - Behavior change: a value with a
{{name}}token that its record does not declare now rejects the whole locale document. Previously only that key was skipped and the rest of the locale applied. - A production locale version rejected for its content is remembered in the cache store settings and not downloaded again until a new version is published, or until the SDK version or the app's generated parameters change. Staging snapshots are still downloaded on every check.
- After an app update, saved locale documents are checked again. A saved document that no longer fits the app is deleted, and the locale falls back until the dashboard publishes a fitting version.
- Behavior change: the fallback order now prefers the app's own bundled translation of the requested language. When the app bundles that language, a key falls back from the OTA locale to the bundled text of the same language, no longer to the OTA main language. When the app does not bundle it, a key falls back to the OTA main language and then to the bundled text of the main language. Previously the last step used the first compiled locale, which is the alphabetically first language in generated Flutter code.
- Added the
ReRuneParameterKindenum used by generated code. - Each rejection logs one warning at
ReRuneLogLevel.errorand above with the locale, the key, and the reason, without values or arguments. - Regenerate with
dart run build_runner buildordart run reruneto apply the parameter check. Generated code from earlier versions keeps working without it.
1.5.1 #
- Each controller now owns one long lived SDK client. It is created on the
first request, reused for every manifest, locale, and staging request, and
closed when the controller is disposed, including when a later
ReRune.setupcall replaces it. Requests keep connections alive instead of opening a new connection and TLS session each; idle connections close on their own after 15 seconds. A client passed toReRune.setup(testHttpClient: ...)is still used for every request. - A timed out request is now aborted instead of left running. Each request
has one 15 second limit, from connecting to reading the body, and on
Android, iOS, and desktop connecting is also bounded by the same limit.
Timeouts still report a
networkerror. - Native requests send the user agent
rerune-flutter/<version>. Browsers do not let pages set a user agent, so web requests are unchanged. - The minimum
httpversion is now1.5.0, which added request aborting.
1.5.0 #
- Fixed stale text after a refresh. Every manifest, locale, and staging
request now goes over the network to the ReRune CDN. The SDK creates its
own HTTP client with no response cache: a
dart:ioclient on Android, iOS, and desktop, and on the web afetchclient that sendscache: "no-store". Previously, Flutter web used the default browser fetch cache mode, so the browser could answer a request from its HTTP cache for up to 5 minutes for the manifest (max-age=300) and up to 30 days for locale files. The stored translations and the manifestIf-None-Matchcheck are unchanged; the CDN still answers304when nothing changed. - The SDK no longer uses a client installed with
http.runWithClient. A host app client such as aCupertinoClientbacked byNSURLCache, or a client with a response cache, can no longer serve SDK requests. Tests that faked the CDN that way must pass the fake toReRune.setup(testHttpClient: ...)instead. - Added
ReRune.setup(testHttpClient: ...), marked@visibleForTesting, for replacing the CDN transport in tests, such as with aMockClient. The SDK does not close a supplied client. Production code must omit it.
1.4.0 #
- BREAKING: changed the manifest transport. The SDK now requests
https://cdn.rerune.io/api/ota/{publishId}/manifest.json, with the trimmed publish ID encoded as one path segment, and no longer sends theX-OTA-Publish-Idheader on manifest or locale requests. Staging mode still appendsstaging=trueto the manifest URL. - BREAKING: changed locale requests. Production requests no longer add
versionortarget_versionquery parameters. A full fetch requests the manifest locale URL unchanged, such assq/88.json. A delta prefixes the final path segment with the applied cache version and.., such assq/86..88.json. Staging requests are unchanged. - The publish ID is not a secret. Info level logs print request URLs, which
now include it, and the
ReRuneLogLeveldocumentation says so. ReRune.setup(otaPublishId: ...)and every other public API are unchanged.
1.3.0 #
- Added opt-in OTA staging mode.
ReRune.setup(staging: true)previews enabled draft translations while project staging is enabled in the ReRune project. The manifest and locale endpoints then receive exactly onestaging=true, locale responses are complete snapshots that replace the cached document, empty snapshots clear a locale, and draft ETags revalidate snapshots with conditional requests. - Added
ReRune.setStaging(bool)for switching between production and staging content after setup. A switch reads the selected mode's persisted namespace into the live session, rebuilds lookups, and immediately checks for updates in the selected mode. The selection is session scoped: later setup calls restore thestagingvalue passed there.ReRune.isStagingexposes the active selection to application controls. - Added the optional
ReRuneCacheStore.stagingNamespacegetter. The controller keeps one cache store per mode and works with them lazily: the staging namespace is derived on first use, the inactive store is never touched, and the live session is the working set, so steady-state synchronizations re-read nothing from storage. The bundled IO store persists staging state in a sibling cache directory and the web store under a suffixed key prefix, so each mode owns its own files or keys, and cache reads never create storage. Custom stores that keep the default getter keep staging mode working in memory for the current run. - Manifest versions do not track draft edits, so staging mode checks every locale on every synchronization even when published versions match, the cached version is newer, or the manifest returns 304.
- Every update check captures its mode and activation generation. Cache loads are serialized, and checks coalesce only within one generation, so a mode switch discards superseded work and a later return cannot revive it.
LocaleClientrequests support conditionalIf-None-Matchrevalidation. A 304 without a matching usable snapshot retries unconditionally. A replacement response ETag is persisted with the retained snapshot. Production behavior is unchanged.
1.2.1 #
- Updated the package and README issue tracker links to GitHub Issues.
- Runtime behavior and public APIs are unchanged.
1.2.0 #
- Added
dart run rerune prepare-arband the opt-inre_rune_arb_compatibilitybuilder. They derive Flutter catalogs inlib/l10n/flutterfrom unchangedlib/l10nsources, removing redundantoffset:0declarations. Nonzero bundled offsets fail with a diagnostic instead of being silently removed. - Corrected delivered JSON plural rendering to subtract nonnegative integer
offsets, match exact numeric selectors against the original argument, and
format
#using the adjusted count. Explicit arguments retain their value. - Plural categories now follow locale rules, including negative adjusted
counts. Use
=0,=1, or=2for exact numeric cases; category names no longer act as implicit exact selectors. Missing categories useother. - Offset changes now participate in message equality and update detection.
1.1.0 #
- Added typed translation variant selection through
ReRuneVariant.mainandReRuneVariant.named(...). - Added the optional
variantargument toReRune.setup(...). A selection restored from the cache takes precedence over this initial value. - Added
ReRune.setVariant(...)for immediate runtime changes and optional persistence, plusReRune.resetVariant()to select and persist main content.ReRune.variantexposes the active selection. - Added optional SDK setting methods to
ReRuneCacheStore. Existing custom stores remain source compatible, and stores can override these methods when persisted variant selection is required. - Locale decoding now selects plain or structured variant content before applying existing placeholder and plural rendering. Missing variant content falls back to the localized entry's main content.
- Named Variant payload errors use Variant terminology while retaining the
backend
variationsandvariationfield names. - Structured messages now retain recursive text, argument, and message
variantparts. Translationvariationsremain separate from plural, select, and choice message branches. - Plural control variables remain runtime arguments and do not require a matching placeholder declaration. Existing plural category selection is unchanged by structured message offset metadata.
- Persisted runtime Variant changes are serialized so overlapping setter calls store the most recently requested selection.
- The example Variant toggle persists Main and
vipselections and restores its visible state after setup. - The example welcome image overlays
publish_datewith a fixed demo date so Main andvipmethod translations remain visible while testing the toggle. - The example plural method now uses the delivered
plural_samplekey instead of the misspelledammount_of_keyskey.
1.0.0 #
- Declared the current ReRune Flutter SDK contract stable for its first major release.
- Kept runtime behavior and the public API unchanged from
0.14.6. - Added a compact published example for setup and manual update checks.
- Expanded code generation compatibility through Analyzer 14 and Build 4 while preserving the existing lower bounds.
- Removed the unused direct
source_gendependency. - Updated Build Runner commands for its current command line interface.
0.14.6 #
- Removed the product flow image from the pub.dev screenshot gallery.
- Added the ReRune for Flutter card to the top of the public README.
0.14.5 #
- Revised public package prose to avoid em dashes and optional compound hyphens.
- Added repository guidance and a release validation check that prevents em dash characters from returning.
0.14.4 #
- Added a synthetic pub.dev screenshot of the product flow and a reusable social preview image built from a dashboard crop that contains no private data.
0.14.3 #
- Reworked the public README to focus on Flutter localization outcomes that do not require app releases, and moved transport protocol details back to internal documentation.
- Added one local release validation script covering package and example generation, analysis, tests, code generation parity, and the pub.dev dry run.
0.14.2 #
- Improved pub.dev discovery metadata with a description focused on outcomes
and localization, translation, OTA, and
code-generationtopics.
0.14.1 #
- Changed the package license from proprietary terms to the MIT License.
0.14.0 #
- BREAKING: locale transport now consumes the backend's generic JSON array for
each locale instead of Flutter ARB documents. Plain
valuemessages and structured cardinal plural variants are decoded and rendered directly while generatedAppLocalizationsgetters and methods remain the consumer API. - BREAKING: the manifest request no longer sends
platform=flutter. The manifest response schema and full or delta request protocol with explicit locale versions remain unchanged. - BREAKING: replaced
ReRuneCachedArbwithReRuneCachedLocaleBundle. CustomReRuneCacheStoreimplementations must replacereadArb,writeArb, anddeleteArbwithreadLocaleBundle,writeLocaleBundle, anddeleteLocaleBundle. - BREAKING: default persistence moved to the
rerune_locale_cache_v1namespace and storeslocale_<locale>.jsonentries on IO platforms. Existingota_localizationsARB caches are ignored without migration or deletion. - Generic full responses are authoritative complete locale documents. Generic deltas replace complete records by translation key while retaining omitted cached records, then persist a deterministic complete canonical JSON snapshot.
- Locale records may contain
values: []to indicate that the key has no translation for the requested locale. ReRune keeps the opaque record in the canonical cache but omits its runtime message so existing locale, main language, and bundled fallback continues. In a delta, this also clears a previously cached runtime override for that locale. - Records whose visible
{{placeholder}}tokens do not match their declarations are also accepted and preserved in canonical cache but omitted from the runtime overlay. Other keys and synchronization metadata still commit; a delta mismatch clears any older runtime override for that key. - Locale payload validation is atomic. Invalid structures preserve the last committed locale, while missing or incompatible runtime plural/placeholder arguments fall back only the affected message to its bundled Flutter value.
- Structured plurals use the six lowercase cardinal categories and require
other. Rendering selects through the supplying locale'sIntl.pluralLogicrules before interpolating declared{{placeholder}}tokens.
0.13.0 #
- BREAKING: locale requests now use explicit version addressing. Full requests
send
target_version; delta requests send the successfully applied localeversionand manifesttarget_version. Theupdated_attimestamp protocol is removed. - BREAKING: removed
ReRuneCachedArb.updatedAtand the serializedupdated_atcache field.ReRuneCachedArbnow requires and persists completedataplus the successfully applied manifest localename,version,minimumDeltaBaseVersion, andurl. - Locale HTTP
409, or an applied locale version newer than its manifest target, stops the current locale pass and triggers one unconditional manifest refresh. A second stale signal stops the check and clears the cached manifest ETag; later checks receive their own single recovery attempt. - Successful locale commits survive a restart caused by a stale manifest. Final update lists are deduplicated, final manifest membership wins, and the check emits at most one fetched text update event.
- Manifest locale entries now store and expose
name. Applied locale caches retain the matching name and URL, andReRune.localeName(locale)resolves the successfully applied cached name through normalized locale fallbacks. ReRuneUpdateResult.updatedLocaleNamesreports changes to manifest names only. These changes count towardhasUpdatesand advance the general localization revision without emittingReRune.onFetchedTextsApplied.
0.12.0 #
- BREAKING: locale endpoints now support incremental updates through the
optional RFC 3339
updated_atquery parameter. ReRune tracks the cursor and successfully applied manifest version independently for every locale. - BREAKING:
ReRuneCachedArbnow requiresversionandupdatedAt; the previous locale cache format is invalidated and refetched in full. - BREAKING: every manifest locale and
ReRuneCachedArbnow requiresminimumDeltaBaseVersion. When its manifest value differs from the cached locale value, ReRune fetches withoutupdated_atand fully replaces the cached locale before committing the new metadata. - BREAKING: removed ETag support for locale responses,
ReRuneManifestLocale.sha256, andReRuneErrorType.checksum. Manifest ETags remain supported. - BREAKING: custom
ReRuneCacheStoreimplementations must implementdeleteArb(...)for cleanup of unpublished locales. - Newly fetched manifests are authoritative for published languages. ReRune removes cached locale bundles and their copies in memory when they are no longer listed.
- Locale requests are skipped when that locale's manifest version and minimum delta base version match its successfully applied cache metadata; a changed root manifest version alone does not download any language.
- Incremental locale responses are merged into the complete cached ARB, with incoming keys overriding cached values. Missing delta keys are retained; incremental deletion is not supported. Full locale responses replace the cache and remove keys absent from the response.
- Successful identical or empty deltas and identical full replacements advance the locale cursor, version, and minimum base metadata without emitting a text update event or localization rebuild.
- Manifest
304responses now require and reuse complete cached manifest state; a cacheless304reports a network error and stops the check. Unexpected locale304responses report a network error without changing locale state. - Ordinary manifest network and validation failures now report the error and stop the synchronization attempt even when cached manifest state exists. Cached translations remain available for offline lookup.
- Overlapping update checks now share one active operation.
- Valid cache envelopes containing invalid ARB data now report a parse error
and force a full request without
updated_at, allowing valid backend content to repair the cache even when stored metadata matches the manifest. - Existing cache envelopes that cannot be read or decoded report a storage error and force the same full repair request. Default IO and web stores now reject persisted envelopes that are not objects instead of silently treating them as missing.
ReRuneCacheStore.readManifest()andreadArb(...)must returnnullonly for absent entries and throw for existing unreadable or malformed state.- Locale request, ARB parse/merge, and cache commit failures now report
network,parse, andstorageerror types respectively. - Default IO cache writes now use flushed replacement through a temporary file. Web cache writes and deletions reject unsuccessful preferences operations and restore the last persistent cache view.
- Added regression coverage proving one failed language does not stop remaining published languages and covering manifest writes, locale writes, cleanup deletion failures, recovery from corrupt cache data, and default cache commits.
- Added
ReRuneLogLeveldiagnostics that consumers can configure throughReRune.setup(logLevel: ...). Logging defaults tooff;errorandinfoexclude request headers and response bodies. ReRuneLogLevel.verbosegives explicit access to sensitive data, including raw headers, response bodies, failure causes, and stack traces.- Fixed the CI drift guard to execute the standalone code generation parity
checks through
dart run. - BREAKING: removed the unreliable root element rebuild attempt. Consumers
that need immediate UI updates in the current app session must wrap the
relevant app subtree in
ReRuneBuilderor listen toReRune.localizationsRevisionListenable. Newly built widgets continue resolving generated localization getters against the latest loaded OTA bundles without that wrapper. - BREAKING:
ReRuneUpdateResultnow requiresremovedLocales.updatedLocalescontains only locales whose fetched OTA values changed, whileremovedLocalesreports locales removed from the published manifest.hasUpdatesis true when either list contains values. - Unpublishing no longer emits
ReRune.onFetchedTextsAppliedor advances the fetched text revision. It advances the general localization revision when loaded translations or runtime locale availability changed. - BREAKING: removed the obsolete
ReRuneLocalizationsOverlay, the generated infrastructureReRuneOverlayLocalizationsDelegateandReRuneOverlayFactory, and the accidentally publicReRune.composeLocalizationsDelegates(...). - BREAKING: generated
ReRuneLocalizationsConfigconstruction now suppliesbaseDelegateandoverlayFactorydirectly. Regenerate committed*.rerune.g.dartfiles before compiling against this release. - Localization delegate construction and delegate list composition are now
private SDK implementation details. The typed
ReRuneCacheStore,ReRuneCachedManifest,ReRuneCachedArb,ReRuneManifest, andReRuneManifestLocalecustom storage contract remains public. - Added deterministic web restart coverage that persists manifest and locale
records through
WebCacheStore, resets the SharedPreferences singleton, and verifies offline bootstrap, dashboard locales, main language fallback, and synchronization metadata for each locale. - Added deterministic native cache lifecycle coverage that recreates
IoCacheStoreagainst the same filesystem directory and verifies persisted replacement, idempotent locale deletion, offline controller bootstrap, main language fallback, and complete synchronization metadata for each locale. - Superseded or disposed controllers now finish pending initialization silently, do not start automatic refresh work, and ignore active manifest or locale responses before they can update persistent or runtime state.
ReRune.setup(...)now stages replacement delegates, compiled locales, and controller state before changing the global facade. A failed initial or replacement setup leaves the previous complete configuration untouched.- BREAKING: manifest locale identifiers and
main_languagenow accept only language identifiers compatible with Flutter. Supported shapes include a language alone, a language with region, a language with script, and a language with both script and region. Separators and subtag casing are canonicalized; malformed identifiers and canonical duplicates reject the complete manifest.
0.11.0 #
- BREAKING: backend manifests must include a
main_languagevalue that is not empty and resolves to an entry inlocales; legacy manifests without it are rejected. - BREAKING:
ReRuneManifest(...)now requiresmainLanguage. - Removed the legacy resolution path for a missing
main_language. OTA lookup always resolves requested locale variants, then main language variants, then the bundled Flutter fallback.
0.10.0 #
- Added OTA fallback for missing keys through the manifest's
main_language. Lookup checks requested OTA locale variants, then OTA main language variants, then bundled Flutter localization. - ICU placeholders, plurals, and selects resolved from the OTA main language now use that supplying locale's formatting rules.
- Manifest parsing and caching now preserve the normalized
main_language. - Excluded the repository's private test app from pub.dev release archives.
0.9.3 #
- Clarified that
MaterialApp.localeis optional and only needed for language picker overrides managed by the app. - Updated the README install snippet to the latest published version.
0.9.2 #
- Added a locale picker to the example app's current locale status row using
LocaleNotifierstate managed by the app.
0.9.1 #
- Clarified the recommended language picker docs with a
LocaleNotifierexample managed by the app and anulldevice default option.
0.9.0 #
- BREAKING: removed the SDK locale override APIs introduced in
0.8.4:ReRune.locale,ReRune.localeListenable,ReRune.setLocale(...), andReRune.clearLocale(). - ReRune now documents locale state managed by the app as the recommended
language picker integration. Build picker options from
ReRune.supportedLocales, store the selected locale in the app, and pass that value toMaterialApp.locale. ReRuneBuilderagain rebuilds only on localization bundle revisions.- The example welcome screen now displays the resolved locale tag instead of a localized hardcoded language name.
0.8.4 #
- Added locale override state owned by the SDK with
ReRune.locale,ReRune.localeListenable,ReRune.setLocale(...), andReRune.clearLocale(). ReRuneBuildernow rebuilds for changes to the selected locale as well as localization bundle revisions.- Documented the optional language picker flow using
ReRune.supportedLocalesplusMaterialApp.locale: ReRune.locale.
0.8.3 #
- Highlighted remote language delivery in the package documentation.
- Documented
ReRune.supportedLocalesas the source of truth for language pickers that include dashboard locales fetched from the network or loaded from cache.
0.8.2 #
- Added support for dashboard locale additions after a successful manifest and ARB fetch, allowing new languages to become available without an app store release.
ReRune.supportedLocalesnow includes compiled app locales plus dashboard locales fetched from the network or loaded from cache.- Generated localization overlays now preserve the requested locale name when falling back through a compiled base locale.
- Manifest locale keys are normalized to standard Flutter locale keys such as
pt_BR. - Added
ReRune.localizationsRevisionListenable;ReRuneBuildernow rebuilds on all localization revisions so rootMaterialAppwidgets can resolve newly available dashboard locales again. ReRune.setup(...)now returns aFuture<void>that completes after cached manifest/ARB bundles are loaded;checkOnStartrefreshes continue in the background instead of blocking setup.
0.8.1 #
- Clamp oversized periodic refresh intervals on web to the maximum supported timer delay instead of throwing.
- Document the web timer fallback limit in the public update policy API and README.
0.8.0 #
- BREAKING:
ReRuneUpdatePolicynow configures periodic refresh withperiodicIntervalInHoursand/orperiodicIntervalInDays; intervals in minutes or seconds are no longer accepted.
0.7.0 #
- BREAKING: runtime now requires manifest locale entries to provide absolute
urlvalues. - BREAKING: removed runtime ARB URL fallback synthesis; ARB fetch uses manifest
urlonly. - Tightened ARB parsing to enforce string message values for keys that do not contain metadata.
- Refactored OTA update workflow and network fetch internals to reduce cyclomatic complexity.
0.6.0 #
- BREAKING: renamed
ReRuneOverlayBuildertoReRuneBuilder.
0.5.0 #
- Added fast CLI codegen command:
dart run rerune. - Added parity guard coverage to ensure CLI and builder generation stay identical at the byte level.
0.4.1 #
- Excluded internal
docs/session notes from publish artifacts via.pubignore. - Excluded local
build/artifacts from publish artifacts via.pubignore.
0.4.0 #
- BREAKING: removed manual annotation anchor setup for code generation.
build_runnernow generates ReRune config directly fromapp_localizations.dart.
0.3.0 #
- BREAKING: collapsed repository back to a single package
rerune. - BREAKING: removed split packages (
rerune_core,rerune_gen) and workspace tooling. - Added build_runner codegen directly in
rerune(build.yaml,lib/builder.dart). - BREAKING: removed macro scaffolding APIs; generation now uses code generation only.
- BREAKING: setup now accepts generated localizations config via
ReRune.setup(..., localizations: reRuneAppLocalizationsConfig). - Removed the macro example and retained one example app based on code generation.
0.2.3 #
- Expanded README onboarding with full consumer integration steps and migration guidance.
0.2.2 #
- Changed the license to proprietary, all rights reserved (BasalBit GmbH).
- Added a commercial terms reference at
https://rerune.io/terms.
0.2.1 #
- Updated package metadata to use
https://rerune.io/issue-trackerand links that point to the website only.
0.2.0 #
- BREAKING: removed CLI wrapper generation workflow (
dart run rerune/flutter pub run rerune). - Added integration runtime APIs owned by the package:
ReRune,ReRuneOverlayLocalizationsDelegate<T>, andReRuneOverlayBuilder. - BREAKING:
ReRune.setup(...)now requires supported locales either viasupportedLocales:or by callingReRune.configureLocalizationsOverlay(...)first. - Added macro migration scaffolding APIs:
ReRuneLocalizationsOverlayandReRuneLocalizationsOverlayMacro. - Migrated the example app away from generated
rerune_app_localizations.dartto overlay wiring managed by the app. - Moved
reruneinto a monorepo layout; it now depends onrerune_core.
0.1.3 #
- Lowered package SDK constraints to
dart >=3.4.0 <4.0.0andflutter >=3.22.0to avoid unnecessarily requiring Dart 3.9+.
0.1.2 #
- BREAKING: removed generated
ReRune.fetchedRevisionListenable; useReRune.onFetchedTextsAppliedas the single event handle for fetched updates. - BREAKING: simplified generated
ReRuneBuilderto a singlebuilder:callback; removedReRuneRefreshModeand refresh mode options. - Updated generator output, example pages, and documentation to use the single event stream plus builder model.
0.1.1 #
- Added the generated
ReRuneBuilderwidget for application UI redraws after OTA changes. ReRuneBuildernow usesbuilder:(Flutter convention) instead ofchild:.ReRuneBuildersupportsReRuneRefreshMode.fetchedUpdatesOnly(default) andReRuneRefreshMode.anyControllerChange.- Updated generated wrapper template and example
BuilderPageto useReRuneBuilderinstead of manualValueListenableBuilderwiring.
0.1.0 #
- BREAKING: removed all
rerune.jsonruntime config support. - BREAKING: removed
projectId,apiKey, andmanifestUrlsetup/constructor inputs. - BREAKING:
ReRuneLocalizationControllernow requiresotaPublishIdand sends it asX-OTA-Publish-Id. - BREAKING:
ReRuneLocalizationControllerand typed builder APIs are no longer exported publicly; use generatedReRune.setup(...)andReRunestatic APIs. - Manifest endpoint is now fixed to the SDK translations manifest route with
platform=flutter. - An ARB fallback endpoint per locale is used when the manifest locale URL is omitted.
- The example app now uses integration through setup, with no direct controller construction.
0.0.4 #
- BREAKING: removed seed ARB support (
seedBundlesandtranslations_path). - Fallback now follows Flutter defaults only: OTA/cache first, then bundled
AppLocalizationsstrings. - BREAKING: runtime config now gives the
rerune.jsonasset precedence over constructor values forprojectIdandapiKey. - BREAKING: removed runtime
--dart-definefallback for config resolution. platformis fixed toflutterand is no longer configurable in controller/runtime config.- Added explicit
StateErrorwith debug log when required credentials are missing. - Docs/examples now use
ReRune.setup(...),ReRune.localizationsDelegates, andReRune.supportedLocales. - Clarified that
ReRuneUpdatePolicydefaults tocheckOnStart: true. - The generated
ReRune.setup(...)helper now wires supported locales automatically and initializes OTA. - BREAKING: removed deprecated generated compatibility aliases (
Rerune...Setup,createRerune...Controller). - BREAKING: removed CLI executable alias
generate; useflutter pub run reruneonly. - BREAKING: renamed
OtaLocalizationControllertoReRuneLocalizationController. - BREAKING: renamed
OtaUpdatePolicytoReRuneUpdatePolicy. - BREAKING: renamed
OtaUpdateResulttoReRuneUpdateResult. - BREAKING: renamed
OtaErrorType/OtaErrortoReRuneErrorType/ReRuneError. - BREAKING: renamed
Manifest/ManifestLocaletoReRuneManifest/ReRuneManifestLocale. - BREAKING: renamed
CachedManifest/CachedArbtoReRuneCachedManifest/ReRuneCachedArb. - BREAKING: renamed
CacheStoretoReRuneCacheStoreandcreateDefaultCacheStore()toreRuneCreateDefaultCacheStore(). - BREAKING: renamed
OtaTypedLocalizationBuildertoReRuneBuilder. - BREAKING: renamed typed builder typedefs to
ReRuneDelegateFactory<T>andReRuneLocalizationWidgetBuilder<T>. - Added
ReRuneTextUpdateEventand exported it frompackage:rerune/rerune.dart. - Added optional refresh APIs limited to fetched text for immediate UI updates
after applied OTA text changes:
reRuneFetchedRevision,reRuneFetchedRevisionListenable, andonReRuneFetchedTextsApplied. - Added
ReRuneLocalizationRefreshMode.fetchedUpdatesOnlytoReRuneBuilder. - Existing refresh behavior remains the default. Refresh limited to fetched text must be enabled explicitly.
- Updated generator output (
rerune_app_localizations.dart) to use renamedReRune*public APIs. - Expanded tests:
- controller tests for revision and event behavior limited to fetched text,
- new
test/ota_typed_localization_builder_test.dartfor builder refresh modes, - updated example widget test coverage for menu navigation.
- The example app now has a demo menu with three pages:
- manual refresh page,
- event listener (
onReRuneFetchedTextsApplied) page, ReRuneBuilderpage with a mode limited to fetched updates.
- The manual refresh flow in the example now separates update checks from UI
refresh and shows update results through
SnackBar. - Example pages are split into dedicated files under
example/lib/pages/. - Updated the README and example README for renamed APIs and refresh usage limited to fetched text.
- Updated
AGENTS.mdnaming rules and applied them across the codebase. - Updated license copyright holder to
BasalBit GmbH.
0.0.3 #
- BREAKING: package identity is now
rerune. - BREAKING: public import changed to
package:rerune/rerune.dart. - Added canonical CLI command
flutter pub run rerunefor localization wrapper generation. - Added automatic detection of standard Flutter localization settings from
l10n.yamland defaultgen-l10npaths. - Added
--dart-defineconfig fallback (RERUNE_PROJECT_ID,RERUNE_API_KEY,RERUNE_PLATFORM) sorerune.jsonasset setup is optional.
0.0.2 #
- BREAKING: removed legacy APIs based on keys (
OtaLocalizations,OtaLocalizationsDelegate,OtaLocalizationBuilder). - BREAKING:
OtaLocalizationControllerno longer acceptsbaseUrl; API host is fixed by the SDK. - Added typed
AppLocalizationsoverlay flow withOtaTypedLocalizationBuilder<T>. - Added generator entrypoint for producing typed OTA wrappers.
0.0.1 #
- Initial release of the OTA localization SDK.
- Manifest driven ARB updates with ETag support and local caching.
- Dynamic localization delegate with manifest URLs hosted by ReRune.