Skip to main content

Internationalization

The SDK bundles English (en) and Spanish (es) tables. Override individual strings via <RiftProvider strings={{...}}> for one-off copy tweaks, or contribute a full locale by extending the bundled tables.

Resolution order

useLocale().t(key, params?) resolves each key in this order:

  1. Consumer override on <RiftProvider strings={…}>.
  2. Bundled table for the resolved locale's primary subtag ("es-MX""es").
  3. English bundled table.
  4. The literal key itself (a visible "missing string" indicator during development).

The active locale is negotiated by useLocale():

  1. <RiftProvider locale="…"> if it matches a config.locales.supported.
  2. The primary subtag of that locale ("es-MX""es") if present in supported.
  3. config.locales.default.
  4. "en" as the final fallback.

Overriding individual strings

Most consumers only need to tweak a handful of labels — pass them on the provider:

<RiftProvider
locale="es-MX"
strings={{
"reservation.reserve": "Apartar boletos",
"checkout.confirm": "Pagar ahora",
"captcha.actionVerify": "Verifica que no eres un bot",
}}
>
{children}
</RiftProvider>

Overrides apply globally to the subtree. Per-component overrides remain available via the component's own label props (e.g. <ReserveButton label="…">, <CheckoutForm submitLabel="…">).

Placeholder interpolation

Keys with {placeholder} segments receive substitutions through the params arg of t():

t("ticketRow.increment", { name: "VIP" });
// → "Add one VIP ticket"

When overriding a key that takes placeholders, keep the same placeholder names — the SDK matches by exact name.

Adding a new locale

For a third-party locale, ship per-key overrides via the strings prop. The table must implement every key in StringKey (the SDK's canonical key set) — TypeScript enforces this at the source.

import { type StringsTable } from "@feelrift/react";

const fr: StringsTable = {
"event.hostedBy": "Organisé par {name}",
"event.dateRangeLabel": "Quand",
"event.locationLabel": "Où",
"event.organizerLabel": "Organisateur",
"reservation.reserve": "Réserver",
// …every other key in StringKey
};

<RiftProvider locale="fr-FR" strings={fr}>
{children}
</RiftProvider>;

When you use a locale beyond the bundled en / es, the SDK falls back to English for any unsupplied keys. Type-check the overrides as StringsTable to catch missing keys at compile time.

Key catalog

Every key the SDK exposes. Placeholders shown in {braces}.

Event header

KeyEnglish defaultNotes
event.hostedByHosted by {name}Organizer-row prefix.
event.dateRangeLabelWhenVisually-hidden <dt> label.
event.locationLabelWhereVisually-hidden <dt> label.
event.organizerLabelOrganizerVisually-hidden <dt> label.

Reservation

KeyEnglish default
reservation.reserveReserve
reservation.reservingReserving…
reservation.expiresInExpires in {remaining}
reservation.expiredReservation expired
reservation.priceChangedTitlePrice has changed
reservation.priceChangedDetailThe total updated from {oldTotal} to {newTotal} between reservation and checkout.
reservation.priceChangedAcceptAccept new price
reservation.priceChangedCancelCancel

Ticket row

KeyEnglish defaultNotes
ticketRow.fromPriceFrom {price}Cheapest-tier display.
ticketRow.remaining{count} leftShown when showRemaining is enabled.
ticketRow.soldOutSold out
ticketRow.incrementAdd one {name} ticketStepper button aria-label.
ticketRow.decrementRemove one {name} ticketStepper button aria-label.

Estimate / breakdown

KeyEnglish default
estimate.subtotalSubtotal
estimate.grandSubtotalSubtotal
estimate.totalTotal
estimate.colQuantityQty
estimate.colItemItem
estimate.colPricePrice
estimate.disclaimerWe pick the cheapest available tier first. Final price (including any fees) is confirmed when you reserve.
estimate.emptyPick tickets to see the breakdown.

Checkout

KeyEnglish default
checkout.emailLabelEmail address
checkout.emailPlaceholderyou@example.com
checkout.confirmConfirm and pay
checkout.confirmFreeConfirm
checkout.confirmingConfirming…
checkout.resumingResuming checkout…
checkout.windowClosedThe checkout window for this reservation has closed.
checkout.missingReturnUrlThis checkout requires a return URL but none was configured. Contact the organizer if this persists.

Captcha

KeyEnglish default
captcha.statusIdleCaptcha required
captcha.statusSolvingSolving captcha…
captcha.statusSolvedCaptcha solved
captcha.statusErrorCaptcha failed
captcha.actionVerifyVerify you're human
captcha.actionRetryTry again

Auth

KeyEnglish default
auth.signInSign in
auth.signOutSign out
auth.signingInSigning in…
auth.alreadySignedInAlready signed in.

Orders

KeyEnglish default
orders.titleYour orders
orders.emptyYou don't have any orders yet.
orders.loadingLoading your orders…
orders.errorCouldn't load your orders.

Errors

KeyEnglish default
error.genericSomething went wrong. Please try again.
error.rateLimitedToo many requests. Try again in {seconds} seconds.
error.insufficientInventoryThese tickets are no longer available.