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:
- Consumer override on
<RiftProvider strings={…}>. - Bundled table for the resolved locale's primary subtag
(
"es-MX"→"es"). - English bundled table.
- The literal key itself (a visible "missing string" indicator during development).
The active locale is negotiated by useLocale():
<RiftProvider locale="…">if it matches aconfig.locales.supported.- The primary subtag of that locale (
"es-MX"→"es") if present insupported. config.locales.default."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
| Key | English default | Notes |
|---|---|---|
event.hostedBy | Hosted by {name} | Organizer-row prefix. |
event.dateRangeLabel | When | Visually-hidden <dt> label. |
event.locationLabel | Where | Visually-hidden <dt> label. |
event.organizerLabel | Organizer | Visually-hidden <dt> label. |
Reservation
| Key | English default |
|---|---|
reservation.reserve | Reserve |
reservation.reserving | Reserving… |
reservation.expiresIn | Expires in {remaining} |
reservation.expired | Reservation expired |
reservation.priceChangedTitle | Price has changed |
reservation.priceChangedDetail | The total updated from {oldTotal} to {newTotal} between reservation and checkout. |
reservation.priceChangedAccept | Accept new price |
reservation.priceChangedCancel | Cancel |
Ticket row
| Key | English default | Notes |
|---|---|---|
ticketRow.fromPrice | From {price} | Cheapest-tier display. |
ticketRow.remaining | {count} left | Shown when showRemaining is enabled. |
ticketRow.soldOut | Sold out | |
ticketRow.increment | Add one {name} ticket | Stepper button aria-label. |
ticketRow.decrement | Remove one {name} ticket | Stepper button aria-label. |
Estimate / breakdown
| Key | English default |
|---|---|
estimate.subtotal | Subtotal |
estimate.grandSubtotal | Subtotal |
estimate.total | Total |
estimate.colQuantity | Qty |
estimate.colItem | Item |
estimate.colPrice | Price |
estimate.disclaimer | We pick the cheapest available tier first. Final price (including any fees) is confirmed when you reserve. |
estimate.empty | Pick tickets to see the breakdown. |
Checkout
| Key | English default |
|---|---|
checkout.emailLabel | Email address |
checkout.emailPlaceholder | you@example.com |
checkout.confirm | Confirm and pay |
checkout.confirmFree | Confirm |
checkout.confirming | Confirming… |
checkout.resuming | Resuming checkout… |
checkout.windowClosed | The checkout window for this reservation has closed. |
checkout.missingReturnUrl | This checkout requires a return URL but none was configured. Contact the organizer if this persists. |
Captcha
| Key | English default |
|---|---|
captcha.statusIdle | Captcha required |
captcha.statusSolving | Solving captcha… |
captcha.statusSolved | Captcha solved |
captcha.statusError | Captcha failed |
captcha.actionVerify | Verify you're human |
captcha.actionRetry | Try again |
Auth
| Key | English default |
|---|---|
auth.signIn | Sign in |
auth.signOut | Sign out |
auth.signingIn | Signing in… |
auth.alreadySignedIn | Already signed in. |
Orders
| Key | English default |
|---|---|
orders.title | Your orders |
orders.empty | You don't have any orders yet. |
orders.loading | Loading your orders… |
orders.error | Couldn't load your orders. |
Errors
| Key | English default |
|---|---|
error.generic | Something went wrong. Please try again. |
error.rateLimited | Too many requests. Try again in {seconds} seconds. |
error.insufficientInventory | These tickets are no longer available. |
Related
<RiftProvider>→strings— the prop that takes the overrides.useLocale— the hook that resolves locale + translates keys.