Better I18NBetter I18N
Vite

Client-Side Features

Components and hooks for locale switching in Vite + React applications

Client-side features in @better-i18n/use-intl are built for CSR apps. Locale switching happens entirely in React state — no server round-trips, no page navigation required.

useLocale

Access and switch the current locale from anywhere inside BetterI18nProvider:

import { useLocale } from '@better-i18n/use-intl'

function LocaleToggle() {
  const { locale, setLocale, isLoading } = useLocale()

  return (
    <button
      onClick={() => setLocale(locale === 'en' ? 'tr' : 'en')}
      disabled={isLoading}
    >
      {isLoading ? 'Switching...' : `Current: ${locale}`}
    </button>
  )
}

Return Value

PropertyTypeDescription
localestringCurrent active locale (e.g., "en", "tr")
setLocale(locale: string) => voidSwitch locale — triggers CDN fetch + re-render
isLoadingbooleantrue while new messages are loading

Locale Switching Flow

Calling setLocale() triggers:

  1. CDN fetch for the new locale's messages
  2. React context update with new translations
  3. Full re-render of the component tree
  4. onLocaleChange callback (from BetterI18nProvider) fired with the new locale

LanguageSwitcher

A drop-in <select>-based language switcher. Handles loading state and locale changes automatically.

import { LanguageSwitcher } from '@better-i18n/use-intl'

function Header() {
  return (
    <header className="flex justify-between items-center p-4">
      <Logo />
      <LanguageSwitcher className="border rounded px-3 py-2" />
    </header>
  )
}

Props

PropTypeDefaultDescription
classNamestringCSS class for the <select> element
loadingLabelstring"Loading..."Label shown while fetching languages
renderOption(lang) => ReactNodeCustom option renderer

LocaleDropdown

A fully-featured accessible dropdown with flag icons, keyboard navigation, and CSS theming.

import { LocaleDropdown } from '@better-i18n/use-intl'

function Header() {
  return (
    <header>
      <LocaleDropdown />
    </header>
  )
}

Selecting a locale calls setLocale() internally — no props needed inside BetterI18nProvider.

Quick Theming

Override CSS custom properties on any parent element:

.my-header {
  --better-locale-text: #374151;
  --better-locale-trigger-bg: transparent;
  --better-locale-border: #e5e7eb;
  --better-locale-menu-bg: #ffffff;
  --better-locale-hover-bg: #f3f4f6;
  --better-locale-active-bg: #f9fafb;
  --better-locale-code-text: #9ca3af;
}

Unstyled Mode

Use variant="unstyled" with Tailwind or any CSS framework:

<LocaleDropdown
  variant="unstyled"
  className="relative"
  triggerClassName="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-100"
  menuClassName="absolute right-0 mt-1 w-52 bg-white border rounded-xl shadow-lg z-50"
/>

For the full API — props, CSS custom properties, data attributes, renderTrigger, renderItem, and keyboard shortcuts — see Locale Management.


Persisting the Locale

The localeCookie prop handles both reading and writing the locale cookie automatically:

src/App.tsx
import { BetterI18nProvider, LocaleDropdown } from '@better-i18n/use-intl'

function App() {
  return (
    <BetterI18nProvider localeCookie> {}
      <LocaleDropdown />
      <Router />
    </BetterI18nProvider>
  )
}

This writes a locale cookie on every locale change, and reads it back on page refresh. No manual document.cookie or localStorage needed.

With Vite Plugin (SSR)

When using @better-i18n/vite, set the same cookie name on both the plugin and provider:

vite.config.ts
betterI18n({
  project: "your-org/your-project",
  localeCookie: "locale", 
})
src/App.tsx
<BetterI18nProvider localeCookie> {/* matches "locale" by default */}
  <App />
</BetterI18nProvider>

The Vite plugin reads the cookie server-side during SSR, and the provider reads it client-side for SPA navigation.

Use a string value to set a custom cookie name:

<BetterI18nProvider localeCookie="preferred-locale">
  <App />
</BetterI18nProvider>

The cookie name must match across client, server, and Vite plugin. See Provider docs for the full server-side pairing pattern.

Next Steps

On this page