Skip to content
React package

Laravel Localizer React

Use Laravel translations in React and Inertia apps with a useLocalizer hook, placeholder replacement and a Vite plugin that regenerates types.

pnpm add @devwizard/laravel-localizer-react
View on GitHub
On this page

Overview

Laravel Localizer React is the React frontend for Laravel Localizer. The Laravel package turns your language files into generated TypeScript; this package reads them in components through a useLocalizer() hook and ships a Vite plugin that re-runs the generator whenever a language file changes.

The hook reads the current locale and text direction from Inertia’s shared locale prop, so switching language on the server updates the whole UI. If you build with Vue instead, use Laravel Localizer Vue. The package is MIT licensed and maintained by the DevWizard core team.

Features

  • useLocalizer() hook returning __, trans, lang, has, choice, locale, dir, availableLocales, translations and getLocales.
  • Placeholder replacement in both :name and {name} styles.
  • Optional fallback text for missing keys.
  • Locale and RTL direction taken from Inertia page props.
  • Vite plugin, exported from the /vite entry, that regenerates the TypeScript files on build start and when language files change.
  • Exported types: Replacements, LocaleData, PageProps and UseLocalizerReturn.
  • ESM build with sideEffects disabled.

Requirements

  • React 18 or 19.
  • @inertiajs/react 1 or 2.
  • Vite 5, 6, 7 or 8 for the plugin.
  • The Laravel Localizer backend package, with the middleware registered so the locale prop is shared.

Installation

Terminal
pnpm add @devwizard/laravel-localizer-react

Other package managers:

Terminal
npm install @devwizard/laravel-localizer-react
yarn add @devwizard/laravel-localizer-react

Install the backend first if you have not already:

Terminal
composer require devwizardhq/laravel-localizer
php artisan localizer:install --framework=react

Configuration

Generate the TypeScript files once, then wire up the Vite plugin and the global translations object.

Terminal
php artisan localizer:generate --all

Add the plugin to vite.config.ts:

TypeScript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import laravel from 'laravel-vite-plugin';
import { laravelLocalizer } from '@devwizard/laravel-localizer-react/vite';

export default defineConfig({
  plugins: [
    laravel({ input: ['resources/js/app.tsx'], refresh: true }),
    react(),
    laravelLocalizer(),
  ],
});

The plugin options, all optional:

Option Default Description
patterns ['lang/**', 'resources/lang/**'] Globs, relative to the project root, that trigger regeneration
command 'php artisan localizer:generate --all' Shell command to run
debug false Log extra messages about detected changes

The hook reads translations from window.localizer, so set it in your entry file before rendering:

TSX
import * as translations from './lang';

window.localizer = { translations };

Optionally declare the global type:

TypeScript
declare global {
  interface Window {
    localizer: {
      translations: typeof translations;
    };
  }
}

Usage

Call the hook in any component under an Inertia page:

TSX
import { useLocalizer } from '@devwizard/laravel-localizer-react';

export function Welcome() {
  const { __, dir } = useLocalizer();

  return (
    <section dir={dir}>
      <h1>{__('welcome')}</h1>
      <p>{__('greeting', { name: 'Sam' })}</p>
    </section>
  );
}

Replacements work with :name and {name} placeholders in the translation string. A missing key returns the fallback you pass as the third argument, or the key itself:

TSX
__('might.not.exist', {}, 'Default text');

Use has() to test for a key and choice() to pass a count into the string:

TSX
const { has, choice } = useLocalizer();

has('welcome');
choice('apples', 5, { unit: 'kg' });

API Reference

useLocalizer()

Member Type Description
__, trans, lang (key, replacements?, fallback?) => string Translate a key; the three are the same function
has (key) => boolean Whether the key exists for the current locale
choice (key, count, replacements?) => string Translate and substitute count
locale string Current locale, 'en' if the prop is missing
dir 'ltr' or 'rtl' Text direction, 'ltr' if missing
availableLocales Record of label, flag and dir Locales from the shared prop
translations Record<string, string> All strings for the current locale
getLocales () => string[] Locale codes

choice() adds count to the replacements and translates the key. It does not split pipe-separated plural forms, so the string itself must contain the wording you want, for example You have :count apples.

Vite plugin

laravelLocalizer(options) from @devwizard/laravel-localizer-react/vite, also its default export. It runs command on build start and on hot updates of files matching patterns. The command runs asynchronously and errors are reported through Vite.

Examples

A locale switcher built from the shared props. It assumes a route on your server that stores the chosen locale, such as a link with the locale query parameter that the backend middleware reads:

TSX
import { router } from '@inertiajs/react';
import { useLocalizer } from '@devwizard/laravel-localizer-react';

export function LocaleSwitcher() {
  const { locale, availableLocales } = useLocalizer();

  return (
    <select
      value={locale}
      onChange={(e) => router.get(window.location.pathname, { locale: e.target.value })}
    >
      {Object.entries(availableLocales).map(([code, meta]) => (
        <option key={code} value={code}>
          {meta.flag} {meta.label}
        </option>
      ))}
    </select>
  );
}

Handle a right-to-left layout by reading dir:

TSX
const { dir } = useLocalizer();

return <main dir={dir}>{children}</main>;

Point the plugin at a custom command, for example when PHP runs in a container:

TypeScript
laravelLocalizer({
  command: 'docker compose exec app php artisan localizer:generate --all',
  debug: true,
});

FAQ & Troubleshooting

The console warns that translations are not initialized. Set window.localizer = { translations } in your entry file before the app renders, using the index generated by localizer:generate.

Keys show instead of text. Check that the locale prop is shared (the Laravel middleware must be registered) and that a generated file exists for the current locale.

Does choice() handle singular and plural forms? No. It only substitutes count. Provide a string such as :count apples or choose the wording in your component.

Translations do not update during development. Confirm the plugin is in vite.config.ts and that php is on the path where Vite runs. Turn on debug to see the change detection messages.

Which Inertia version works? The peer range is @inertiajs/react 1.x or 2.x.

Changelog & Support

Release history is in the CHANGELOG and on the GitHub releases page. Open bugs and feature requests in GitHub issues. Source: DevWizardHQ/laravel-localizer-react. Using Vue instead? See Laravel Localizer Vue. For help with multilingual products, the DevWizard team takes project contracts and monthly retainers through the contact page.