/** * A string, or the same string per locale. * * A plain string is the single-language case and keeps working unchanged — which * is most configs, most of the time. A map opts into more: * * name: "Pro" * name: { en: "Pro", it: "Pro" } * tagline: { en: "Search, analyse, organise", fr: "Cherchez, analysez, organisez" } */ export type Localized = string | Readonly>; /** A list of strings, or one list per locale. A separate type because translated * lists legitimately differ in LENGTH — a language may merge two bullets. */ export type LocalizedList = readonly string[] | Readonly>; export interface LocaleOptions { /** BCP 47 tag the surface is rendering in, e.g. "fr" or "fr-CA". */ locale?: string; /** Fallback when a locale has no entry. Default "en". */ defaultLocale?: string; } /** * Pick the best entry for `locale`. * * Exact tag → language subtag ("fr-CA" → "fr") → the default locale and ITS * language → the first entry. The last step is deliberate: a config with one * language under an unexpected key should still render, rather than showing a * customer nothing at all. */ export declare function resolveLocalized(value: Localized | undefined, opts?: LocaleOptions): string | undefined; /** {@link resolveLocalized} for a list. */ export declare function resolveLocalizedList(value: LocalizedList | undefined, opts?: LocaleOptions): readonly string[]; /** * Minor units → a currency string via Intl — THE formatter `derivePlanViews` defaults to, * exported so an app's other screens format identically to its pricing cards. * * One consumer kept seven local copies of this, two of which hardcoded EUR next to a * config that declares the currency. `formatMoney` on the pricing derivations stays the * override for a house style Intl won't reproduce ("€18" where it-IT writes "18,00 €"). */ export declare function formatMinor(minor: number, currency: string, locale?: string): string; export interface Messages { /** A limit that isn't one — a members column, a usage row. */ unlimited: string; /** Billing intervals, for a derived "billing cycle" row. */ monthly: string; yearly: string; /** Joins a list of seat types or intervals. */ separator: string; /** A plan whose price is quoted rather than listed. */ contactUs: string; /** A plan that costs nothing. */ free: string; /** Column headers for a generated markdown plan table. */ columnPlan: string; columnSeats: string; columnIncluded: string; columnMonthly: string; columnYearly: string; columnSeatTypes: string; columnTool: string; columnCost: string; /** Heading for rate-card entries the caller didn't group. */ otherGroup: string; /** Refusals a customer sees. `{n}`-style placeholders are substituted. */ seatMinimum: string; seatMaximum: string; seatTypeMaximum: string; memberMaximum: string; unknownPlan: string; notPurchasable: string; unknownSeatType: string; intervalUnavailable: string; poolExhausted: string; seatAllowanceReached: string; insufficientBalance: string; /** The two refusals that had no key at all, so `describeDenial` could not be * translated even in part. `{name}` is the window's own label or its `every`; * `{size}` its ceiling; `{resets}` an ISO instant, already formatted or "". */ rateLimitReached: string; spendLimitReached: string; /** Payment-form fallbacks, used only when Stripe returns an error with no * message of its own (Stripe's own messages are already localized by the * Elements locale, so these are the rare path, not the usual one). */ paymentDetailsInvalid: string; cardNotSaved: string; paymentFailed: string; /** * The structured refusal reasons tool results carry (`{ ok: false, reason }`), * one key per distinct meaning — see `describeReason`. They exist because a * consumer selling in one language mapped these codes to sentences in ten * different components, which is ten chances for the same refusal to be * explained two ways. */ reasonNotCapped: string; reasonNotBlocked: string; reasonSeatsFixed: string; reasonUnknownSeat: string; reasonSeatUnavailable: string; reasonAlreadyPending: string; reasonLimitReached: string; reasonMemberLimitReached: string; reasonInvalidAmount: string; reasonDuplicate: string; reasonNotFound: string; reasonLastAdmin: string; reasonNotAMember: string; reasonUnsupported: string; reasonAlreadyOnIt: string; reasonNoUpgrade: string; reasonQueueFull: string; reasonAtMax: string; reasonNotPurchased: string; reasonNoCard: string; reasonNoEmail: string; reasonChargeFailed: string; reasonMultipleSubscriptions: string; reasonInvalidBasket: string; reasonNeedsReturnUrl: string; reasonNoCustomer: string; reasonNotPurchasable: string; } /** * English, and the only language this package ships. * * A consumer overrides what it needs; anything not overridden stays English * rather than becoming a missing string. */ export declare const DEFAULT_MESSAGES: Messages; export type PartialMessages = Partial; /** Fill the gaps in a consumer's bundle with the English defaults. */ export declare const resolveMessages: (messages?: PartialMessages) => Messages; /** * The sentence for a structured refusal reason (`{ ok: false, reason }`), in the * caller's own bundle. * * The engine's tool results carry these codes so a caller can branch; what a HUMAN * reads was left to each screen, and the consumer that sells in Italian translated * them in ten separate components. This is the one map, on the dependency-free leaf, * so a client component passes its bundle while the API keeps answering English. * * `limit_reached` is the one code with two meanings — a member's top-up ceiling * (topup.ts) and no seat left for another member (members.ts) — genuinely different * sentences in any language, so `opts.of: "members"` picks the second. An unknown * code echoes itself rather than returning blank, the `formatMessage` rule: a typo * should be visible. */ export declare function describeReason(reason: string, messages?: PartialMessages, opts?: { of?: "members"; }): string; /** Substitute `{name}` placeholders. Unknown names are left as-is, so a typo is * visible rather than silently blank. */ export declare function formatMessage(template: string, values: Record): string; //# sourceMappingURL=i18n.d.ts.map