Skip to content

Suprnova v1.0.0

Choose a tag to compare

@eas4ai eas4ai released this 02 Aug 14:32
· 21 commits to main since this release

Added

  • Localization. Message catalogs in lang/<locale>/*.ftl
    (Fluent), a Lang facade with the
    __!("key", name: value) macro, per-request locale detection
    (LocaleMiddleware: session → cookie → Accept-Language
    APP_LOCALE), and locale-aware formatting for numbers, currency,
    dates, times, lists, and relative times over ICU4X. manual/localization.md
    is the chapter.

    The built-in validation rules stop hardcoding English. Each returns a
    keyed message (validation-min plus its arguments and an English
    fallback), translated once at the serialization boundary — so a Spanish
    app gets Spanish validation errors by dropping in
    lang/es/validation.ftl, with no rule wrapping and no forked copy of
    the framework's messages. Field names humanize through a field-<name>
    lookup. Rule::passes (and ContextualRule / AsyncRule) now return
    Result<(), ValidationMessage>; a custom rule's Err("…".into()) body
    still compiles and still renders verbatim, but the signature in your
    impl needs the new type.

    The browser gets the same bytes the server resolved: the merged catalog
    is served at /_suprnova/lang/<locale>.ftl with an ETag and an
    immutable ?v=<hash> form, the three starter kits parse it with
    @fluent/bundle, and suprnova generate-types emits a MessageKey
    union so renaming a message points the TypeScript compiler at every
    call site.

    Fluent rather than Laravel-style PHP arrays because one format has to
    serve both the server and the browser, and because CLDR plural
    categories are what gets Russian, Polish, and Arabic right —
    trans_choice's integer ranges cannot, which is why there is no
    trans_choice here. Behind a default-on localization feature;
    --no-default-features still compiles and still validates, using the
    embedded English fallbacks.

  • IntoInertiaScroll for Paginator. The trait was implemented for
    LengthAwarePaginator and CursorPaginator but not for the simple
    paginator, so simple_paginate results could not feed
    Inertia::paginate at all — despite simple.rs's own module docs
    pointing at it as the URL-generation path. That left offset-paginated
    Inertia collections with a choice between a COUNT(*) per request and
    hand-rolling the scroll metadata. next_page comes from the
    LIMIT n+1 overflow probe rather than a computed last page, there
    being no total to compute one from.

Fixed

  • suprnova generate-types emitted a different file on every run.
    The topological sort seeded its work queue by iterating a HashMap,
    and Rust randomises hash iteration order per process, so consecutive
    runs ordered the same interfaces differently. The output is a
    checked-in artifact, so every run produced a diff — and a generated
    file that churns for no reason is one people stop regenerating, after
    which it quietly stops describing the Rust it claims to. The directory
    walk is sorted too, so the output no longer depends on filesystem
    order either. Two runs of the same source are now byte-identical.

  • topological_sort did the opposite of its doc comment, emitting
    dependents before dependencies. Harmless — a TypeScript interface may
    reference one declared later in the same file — so the comment is
    corrected rather than the order, which would have reshuffled a tracked
    file for no benefit.