React integration for Laravel Localizer with Vite plugin, useLocalizer hook, and automatic TypeScript generation
npm install @devwizard/laravel-localizer-react


React integration for Laravel Localizer - seamlessly use Laravel translations in your React/Inertia.js applications with full TypeScript support.
- 🎣 React Hook - useLocalizer() hook for easy translation access
- 🔌 Vite Plugin - Auto-regenerates TypeScript translations on file changes
- 🎯 TypeScript - Full type safety with TypeScript support
- ⚡ Inertia.js - Native integration with Inertia.js page props
- 🌐 Pluralization - Built-in pluralization support
- 🔄 Replacements - Dynamic placeholder replacement
- 🌍 RTL Support - Automatic text direction detection
- 📦 Tree-shakeable - Modern ESM build
- React 18 or 19
- Inertia.js v1 or v2
- Laravel Localizer backend package
``bash`
npm install @devwizard/laravel-localizer-react
First, install and configure the Laravel Localizer package:
`bash`
composer require devwizardhq/laravel-localizer
php artisan localizer:install
See the Laravel Localizer documentation for complete backend setup.
First, generate TypeScript translation files from your Laravel app:
`bash`
php artisan localizer:generate --all
This creates files like resources/js/lang/en.ts, resources/js/lang/fr.ts, etc.
Add the Vite plugin to auto-regenerate translations when language files change.
File: 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({
// Watch patterns for language file changes
patterns: ['lang/', 'resources/lang/'],
// Command to run when files change
command: 'php artisan localizer:generate --all',
// Enable debug logging (optional)
debug: false,
}),
],
});
`
What it does:
- Watches for changes in lang/ and resources/lang/php artisan localizer:generate --all
- Automatically runs when files change
- Triggers HMR to reload your frontend with updated translations
Set up the global window.localizer object in your app entry point.
File: resources/js/app.tsx
`typescript
import './bootstrap';
import '../css/app.css';
import { createRoot } from 'react-dom/client';
import { createInertiaApp } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
// Import all generated translation files
import * as translations from './lang';
const appName = import.meta.env.VITE_APP_NAME || 'Laravel';
createInertiaApp({
title: (title) => ${title} - ${appName},./Pages/${name}.tsx
resolve: (name) =>
resolvePageComponent(
,
import.meta.glob('./Pages/*/.tsx')
),
setup({ el, App, props }) {
// Initialize window.localizer with translations
if (typeof window !== 'undefined') {
window.localizer = {
translations,
};
}
createRoot(el).render(
},
progress: {
color: '#4B5563',
},
});
`
TypeScript Declaration
To ensure type safety when accessing window.localizer, add this global declaration to your project:
`typescript`
declare global {
interface Window {
localizer: {
translations: typeof translations;
};
}
}
Alternative: Create a separate file
File: resources/js/lang/index.ts
`typescript`
// Export all generated translations
export * from './en';
export * from './fr';
export * from './ar';
// ... add other locales as needed
File: resources/js/app.tsx
`typescript
import * as translations from './lang';
// ... in setup()
window.localizer = { translations };
`
Add types to your tsconfig.json:
`json`
{
"compilerOptions": {
"types": ["@devwizard/laravel-localizer-react"]
}
}
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';
function WelcomeComponent() {
const { __ } = useLocalizer();
return (
{__('validation.required')}
$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function GreetingComponent() {
const { __ } = useLocalizer();
return (
{/ Supports :placeholder format /}
{__('greeting', { name: 'John' })}
{/ "Hello :name!" → "Hello John!" /} {/ Also supports {placeholder} format /}
{__('items', { count: 5 })}
{/ "You have {count} items" → "You have 5 items" /}
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function ItemCounter({ count }: { count: number }) {
const { choice } = useLocalizer();
return (
{/ Define in your translation file: /}
{/ "apples": "no apples|one apple|many apples" /}
{choice('apples', count)}
{/ count = 0: "no apples" /}
{/ count = 1: "one apple" /}
{/ count = 5: "many apples" /} {/ With replacements /}
{choice('apples', count, { count })}
{/ "You have {count} apples" → "You have 5 apples" /}
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function ConditionalTranslation() {
const { __, has } = useLocalizer();
return (
{has('welcome') && {__('welcome')}
}
{has('custom.message') ? {__('custom.message')}
: Default message
}
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function SafeTranslation() {
const { __ } = useLocalizer();
return (
{/ Use fallback for missing keys /}
{__('might.not.exist', {}, 'Default Text')}
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function LocaleInfo() {
const { locale, dir, availableLocales } = useLocalizer();
return (
Current Locale: {locale}
Text Direction: {dir}
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function RTLAwareComponent() {
const { __, dir } = useLocalizer();
return (
{__('welcome')}
{__('description')}
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function TranslationDebugger() {
const { translations } = useLocalizer();
return (
All Translations:
{JSON.stringify(translations, null, 2)}
);
}
`API Reference
$3
Returns an object with the following properties and methods:
| Property | Type | Description |
| ------------------ | ------------------------------------------------------------------------- | ----------------------------------- |
|
__ | (key: string, replacements?: Replacements, fallback?: string) => string | Main translation function |
| trans | (key: string, replacements?: Replacements, fallback?: string) => string | Alias for __() |
| lang | (key: string, replacements?: Replacements, fallback?: string) => string | Alias for __() |
| has | (key: string) => boolean | Check if translation key exists |
| choice | (key: string, count: number, replacements?: Replacements) => string | Pluralization support |
| locale | string | Current locale code (e.g., 'en') |
| dir | 'ltr' \| 'rtl' | Text direction |
| availableLocales | Record | Available locales with metadata |
| translations | Record | All translations for current locale |$3
`typescript
interface LocalizerOptions {
// Watch patterns for language file changes
patterns?: string[]; // default: ['lang/', 'resources/lang/'] // Command to run when files change
command?: string; // default: 'php artisan localizer:generate --all'
// Enable debug logging
debug?: boolean; // default: false
}
`TypeScript Support
The package is written in TypeScript and provides full type definitions:
`typescript
import {
useLocalizer,
UseLocalizerReturn,
Replacements,
LocaleData,
PageProps,
} from '@devwizard/laravel-localizer-react';// All types are available for import
`Testing
The package includes comprehensive tests using Jest and React Testing Library:
`bash
Run tests
npm testRun tests in watch mode
npm run test:watchGenerate coverage report
npm run test:coverage
`Examples
$3
`tsx
import { router } from '@inertiajs/react';
import { useLocalizer } from '@devwizard/laravel-localizer-react';function LanguageSwitcher() {
const { locale, availableLocales } = useLocalizer();
const changeLocale = (newLocale: string) => {
router.visit(route('locale.switch', { locale: newLocale }), {
preserveScroll: true,
preserveState: true,
});
};
return (
);
}
`$3
`tsx
import { useLocalizer } from '@devwizard/laravel-localizer-react';function LoginForm() {
const { __ } = useLocalizer();
return (
);
}
`Complete Working Example
Here's a full example of a multilingual user dashboard:
Backend:
lang/en.json`json
{
"welcome": "Welcome",
"dashboard": "Dashboard",
"greeting": "Hello, :name!",
"notifications": "You have :count notifications"
}
`Backend:
lang/en/dashboard.php`php
return [
'title' => 'User Dashboard',
'stats' => [
'users' => '{0} No users|{1} One user|[2,*] :count users',
'posts' => 'You have :count posts',
],
];
`Generate translations:
`bash
php artisan localizer:generate --all
`Frontend:
resources/js/Pages/Dashboard.tsx`tsx
import { Head } from '@inertiajs/react';
import { useLocalizer } from '@devwizard/laravel-localizer-react';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import { PageProps } from '@/types';interface DashboardProps extends PageProps {
stats: {
users: number;
posts: number;
notifications: number;
};
}
export default function Dashboard({ auth, stats }: DashboardProps) {
const { __, choice, locale, dir } = useLocalizer();
return (
user={auth.user}
header={
{__('dashboard.title')}
}
>
{/ Notification count /}
{__('notifications', { count: stats.notifications })}
{/ Statistics with pluralization /}
{choice('dashboard.stats.users', stats.users, { count: stats.users })}
{__('dashboard.stats.posts', { count: stats.posts })}
{/ Locale info /}
Current locale: {locale}
Text direction: {dir}
Development
`bash
Install dependencies
npm installRun tests
npm testBuild the package
npm run buildRun linter
npm run lintFormat code
npm run format
``Contributions are welcome! Please see CONTRIBUTING for details.
Please see CHANGELOG for recent changes.
The MIT License (MIT). Please see License File for more information.
- Laravel Localizer - Backend package
- @devwizard/laravel-localizer-vue - Vue integration