import type { I18nEngine } from "@stapel/core"; /** * categories-react's own translation KEYS (frontend-standard §4.2): headless * components never render literal strings — hosts resolve these via core's * i18n engine (`useT`). Backend error codes flow through the SAME contour: a * `StapelApiError.code` is already a key, so the default bundle below ships * English fallbacks for the 62 backend error codes (generated) plus the pair's * own UI keys. All UI keys live under the `categories.` namespace. * * ── WHAT IS DELIBERATELY NOT IN THIS FILE ────────────────────────────────── * * **A category name.** `category.electronics` is a key, and it is a key this * library must never carry a text for: the catalogue is a deployment's * content, not a library's chrome, and no two marketplaces have the same tree. * `catalog/labels.ts` explains the mechanism in full — names arrive as keys * because no serializer runs the module's `DISPLAY_TRANSLATOR` seam — and the * pair's answer is to hand the key to the HOST's engine, whose bundle is where * a deployment's catalogue copy belongs. When the key does not resolve the key * is shown, on purpose: a visible `category.electronics` gets fixed, while a * prettified "Electronics" ships for a year in the wrong language. * * The same goes for a feature's name and its option labels. * * **The twelve `error.400.feature_*` / `description_too_*` keys.** They are * owned by `stapel_attributes` and translated by `@stapel/attributes-react` * (`/i18n/ru`, `/i18n/es`) — the package that also draws and validates those * values. Restating them here would give one refusal two sentences, which is * the exact thing §13.2's note 3 closed. A host registers both bundles; the * suite proves the union covers the whole registry. */ export declare const CATEGORIES_I18N_KEYS: { readonly unknownError: "categories.error.unknown"; readonly catalogTitle: "categories.catalog.title"; readonly catalogLoading: "categories.catalog.loading"; readonly catalogLoadFailed: "categories.catalog.load_failed"; readonly catalogEmpty: "categories.catalog.empty"; readonly catalogRetry: "categories.catalog.retry"; /** The sync walk hit its page budget — the tree on screen is incomplete. */ readonly catalogTruncated: "categories.catalog.truncated"; readonly catalogRefreshing: "categories.catalog.refreshing"; readonly catalogAsOf: "categories.catalog.as_of"; readonly categoryTitle: "categories.category.title"; readonly categoryUnknownSlug: "categories.category.unknown_slug"; /** What to do about an address that resolves to nothing. */ readonly categoryUnknownSlugHint: "categories.category.unknown_slug_hint"; /** The way OUT of a dead address — the link the hint promises. */ readonly categoryBackToCatalog: "categories.category.back_to_catalog"; readonly categorySubcategories: "categories.category.subcategories"; /** * "N subcategories" beside a tree row. A PLURAL FAMILY: render with * `tPlural`, never `t` (see {@link CATEGORIES_I18N_PLURAL_KEYS}). It * replaces a hover `title=` on the count badge — a number whose meaning was * available only to a mouse. */ readonly categorySubcategoriesCount: "categories.category.subcategories_count"; /** A leaf: no sub-categories, and that is not an error. */ readonly categoryNoSubcategories: "categories.category.no_subcategories"; readonly categoryOpen: "categories.category.open"; readonly breadcrumbsRoot: "categories.breadcrumbs.root"; readonly breadcrumbsLabel: "categories.breadcrumbs.label"; readonly carouselTitle: "categories.carousel.title"; readonly carouselLoading: "categories.carousel.loading"; readonly carouselLoadFailed: "categories.carousel.load_failed"; readonly carouselEmpty: "categories.carousel.empty"; /** The leading tile, which links the catalogue root rather than a category. */ readonly tilesAll: "categories.tiles.all"; /** * "All categories" — the overflow tile past `maxVisible` (`overflow: * "modal"`), and the dialog it opens listing every child. One key for * both: the button says what it does and the dialog it opens is titled the * same thing. */ readonly tilesShowAll: "categories.tiles.show_all"; /** The overflow dialog's search box (shown past * `ALL_CATEGORIES_SEARCH_THRESHOLD` children in `CategoryTileGrid.tsx`). */ readonly tilesAllSearch: "categories.tiles.all_search"; /** The overflow dialog's search found nothing. */ readonly tilesAllNoMatches: "categories.tiles.all_no_matches"; /** The panel's accessible name — it is a menu of the whole catalogue, so it * says that rather than naming whichever root is highlighted. */ readonly megaMenuLabel: "categories.mega_menu.label"; /** The tail of a truncated third level, linking the second-level node that * holds the rest. NOT a plural family: it counts links, and the languages * this pair ships spell that with one invariable word plus a number. */ readonly megaMenuMore: "categories.mega_menu.more"; /** * The heading over the categories a search query reached. Carries `{query}`, * because a list of category links above somebody else's results has to say * WHY it is there — without the typed words it reads as a second menu that * appeared on its own. */ readonly searchHitsTitle: "categories.search.hits_title"; /** The button when the count is absent, in flight, refused, or a number the * engine declined to give — the sentence that is true under every arm. */ readonly quickSearchCta: "categories.quick_search.cta"; /** * "Show {count} listings" — an EXACT total. A PLURAL FAMILY: render with * `tPlural`, never `t` (see {@link CATEGORIES_I18N_PLURAL_KEYS}). */ readonly quickSearchCtaCount: "categories.quick_search.cta_count"; /** "Show {count}+ listings" — a LOWER BOUND, never spelled as a total. * A PLURAL FAMILY. */ readonly quickSearchCtaAtLeast: "categories.quick_search.cta_count_at_least"; readonly pickerTitle: "categories.picker.title"; readonly pickerSearch: "categories.picker.search"; readonly pickerLoading: "categories.picker.loading"; readonly pickerLoadFailed: "categories.picker.load_failed"; readonly pickerNoMatches: "categories.picker.no_matches"; readonly pickerUp: "categories.picker.up"; readonly pickerSelected: "categories.picker.selected"; /** The phone trigger that opens the drill-down as a bottom sheet. */ readonly pickerChoose: "categories.picker.choose"; /** Close the sheet, keeping whatever is chosen. */ readonly pickerDone: "categories.picker.done"; readonly pickerBlockedNothingSelected: "categories.picker.blocked.nothing_selected"; readonly pickerBlockedNotALeaf: "categories.picker.blocked.not_a_leaf"; /** The placeholder of one unanswered level. */ readonly cascadeChoose: "categories.cascade.choose"; /** * The ladder has not been started. A SEPARATE key from the picker's * equivalent on purpose: the picker's sentence tells a person to open a * chooser, and there is no chooser to open here — the control is already on * screen and it is asking. */ readonly cascadeBlockedNothingSelected: "categories.cascade.blocked.nothing_selected"; readonly featuresTitle: "categories.features.title"; readonly featuresLoading: "categories.features.loading"; readonly featuresLoadFailed: "categories.features.load_failed"; readonly featuresEmpty: "categories.features.empty"; readonly featuresMandatory: "categories.features.mandatory"; /** A feature's value TYPE as a word. `int`, `bool` and a host's own * `holo_signature` are this build's vocabulary, and they were reaching a * public category page as the badge's copy. Every known type has a word; * anything else says "another kind of detail" rather than its identifier. */ readonly featuresTypeString: "categories.features.type.string"; readonly featuresTypeInt: "categories.features.type.int"; readonly featuresTypeFloat: "categories.features.type.float"; readonly featuresTypeBool: "categories.features.type.bool"; readonly featuresTypeSelect: "categories.features.type.select"; readonly featuresTypeDate: "categories.features.type.date"; readonly featuresTypeHeader: "categories.features.type.header"; readonly featuresTypeColor: "categories.features.type.hex_color"; readonly featuresTypeNestedSelect: "categories.features.type.hierarchical_select"; readonly featuresTypeMeasurement: "categories.features.type.convertible_unit"; readonly featuresTypeOther: "categories.features.type.other"; /** A feature whose `config` carries no `type` at all. */ readonly featuresUntyped: "categories.features.untyped"; }; /** * Value type (as `config.type` spells it) → the key for its human word. * A type absent from this table is not a bug and not copy: it is a build the * catalogue is ahead of, and it renders {@link CATEGORIES_I18N_KEYS.featuresTypeOther}. */ export declare const FEATURE_TYPE_LABEL_KEYS: Readonly>; export type CategoriesI18nKey = (typeof CATEGORIES_I18N_KEYS)[keyof typeof CATEGORIES_I18N_KEYS]; /** * The keys above that are PLURAL FAMILIES rather than single messages. * * A family is catalogued as one flat key per CLDR category * (`.one`, `…few`, `…many`, `…other`) and rendered with core's * `tPlural(family, { count })`, which asks `Intl.PluralRules` for the current * locale's category. Which categories a bundle carries is a fact about the * language — `en` needs two, `ru` needs four — so `test/i18n.test.ts` asks * `Intl.PluralRules` which forms each locale can select and demands exactly * those, rather than checking a list somebody typed. */ export declare const CATEGORIES_I18N_PLURAL_KEYS: readonly CategoriesI18nKey[]; /** * English fallback bundle for categories-react UI keys + backend error codes. * The generated backend texts are spread FIRST so coverage of the error * registry is by construction; the pair's own copy follows. */ export declare const categoriesI18nBundleEn: Record; /** * Register the English bundle into a core i18n engine. Locale bundles ship as * opt-in subpaths (`@stapel/categories-react/i18n/ru`, `…/es`) so a host that * needs only English never carries them. * * A host that renders a category's feature schema also registers * `@stapel/attributes-react`'s bundles — that package owns the twelve * `stapel_attributes` error keys in every locale. */ export declare function registerCategoriesI18n(i18n: I18nEngine): void; //# sourceMappingURL=keys.d.ts.map