SDK
Resolvers
Locale helpers and the navigation resolver.
import {
pickLocale,
localizePath,
stripLocalePrefix,
isLocale,
resolveNavigation,
} from '@brandfine/client/resolvers'All pure functions — no I/O, no side effects, no module-level state. Each takes the consumer's locale config as an option.
Locale helpers
const opts = { locales: ['en', 'pt'], defaultLocale: 'en' } as const
// Coerce unknown input to a known locale, fallback to default.
pickLocale(Astro.currentLocale, opts) // → 'en' | 'pt'
// Add the locale prefix to a path.
localizePath('/services/uk-eta', 'pt', opts) // → '/pt/services/uk-eta'
localizePath('/services/uk-eta', 'en', opts) // → '/services/uk-eta' (default = bare)
// Strip a non-default locale prefix.
stripLocalePrefix('/pt/about', opts) // → '/about'
stripLocalePrefix('/about', opts) // → '/about'
// Type guard.
if (isLocale(value, opts.locales)) { /* value: string */ }Navigation resolver
Turns the API's locale-agnostic shape into a per-locale render-ready tree:
const nav = await bf.navigations.get('header')
if (!nav) {/* render hardcoded fallback */}
const hydrated = resolveNavigation(nav, 'pt', {
defaultLocale: 'en',
})
// hydrated.items: HydratedNavItem[]
// Each item: { href: string | null, label: string, type, children }What the resolver does
- POST items — picks the sibling for the active locale,
builds
/<postTypeSlug>/<slug>vialocalizePath. Falls back to the default-locale URL when no translation exists. - CUSTOM_URL items — runs paths through
localizePath; external URLs (http://,mailto:) pass through unchanged. - HEADING items —
href: null, label-only. - Labels — picks the active-locale label, falls back to default-locale, then to any populated label (last resort).
- Hidden locales — items with the active locale in
hiddenLocalesare dropped from the tree.
Custom URL conventions
Override urlForPost when your consumer doesn't use the
default /<postTypeSlug>/<slug> URL shape:
const hydrated = resolveNavigation(nav, 'pt', {
defaultLocale: 'en',
urlForPost: ({ post, sibling }) =>
`/blog/${sibling.slug}`, // ignore post type, always under /blog
})Most consumers won't need this — the default convention matches
what localizePath expects.