PHPackages                             goodcat/laravel-l10n - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. goodcat/laravel-l10n

ActiveLibrary[Localization &amp; i18n](/categories/localization)

goodcat/laravel-l10n
====================

An opinionated Laravel package for app localization

v0.4.2(1mo ago)722MITPHPPHP ^8.2CI passing

Since Aug 30Pushed 4w agoCompare

[ Source](https://github.com/goodcat-dev/laravel-l10n)[ Packagist](https://packagist.org/packages/goodcat/laravel-l10n)[ RSS](/packages/goodcat-laravel-l10n/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (28)Versions (15)Used By (0)

Laravel L10n
============

[](#laravel-l10n)

[![Latest Version on Packagist](https://camo.githubusercontent.com/7c3cf72f9a15000df3ccf506971ffd316c3e8f6979c9718f7fd68234292293b0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f676f6f646361742f6c61726176656c2d6c31306e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/goodcat/laravel-l10n)[![GitHub Tests Action Status](https://camo.githubusercontent.com/16e8d64eb2499e6efab490c31babfe4df99e502d3c98cde4896c79a02b3c2353/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f676f6f646361742d6465762f6c61726176656c2d6c31306e2f746573742e796d6c3f6272616e63683d6d61696e266c6162656c3d74657374267374796c653d666c61742d737175617265)](https://github.com/goodcat-dev/laravel-l10n/actions?query=workflow%3Atest+branch%3Amain)

An opinionated Laravel package for app localization.

Quickstart
----------

[](#quickstart)

Get started with `laravel-l10n` in three steps.

1. Download the package via Composer. ```
    composer require goodcat/laravel-l10n
    ```
2. Add the locale middlewares to your `bootstrap/app.php` file. ```
    return Application::configure(basePath: dirname(__DIR__))
        ->withMiddleware(function (Middleware $middleware): void {
            $middleware->web([
                \Goodcat\L10n\Middleware\SetLocale::class,
                \Goodcat\L10n\Middleware\SetPreferredLocale::class,
            ]);
        });
    ```
3. Define localized routes using the `lang()` method. ```
    Route::get('/example', Controller::class)
        ->lang(['fr', 'de', 'it', 'es']);
    ```

That's it. You're all set to start using `laravel-l10n`.

Localized Routes
----------------

[](#localized-routes)

### Defining Localized Routes

[](#defining-localized-routes)

Use the `lang()` method to define which locales a route should support:

```
Route::get('/example', Controller::class)
    ->lang(['es', 'fr', 'it']);
```

This will generate:

- `/example` (fallback locale)
- `/es/ejemplo` (Spanish, translated via language file)
- `/fr/example` (French, no translation defined)
- `/it/example` (Italian, no translation defined)

#### Route groups

[](#route-groups)

To avoid repetitive language definitions on every single route, you can use `Route::lang()->group()`:

```
Route::lang(['es', 'it'])->group(function () {
    Route::get('/example', fn () => 'Hello, World!');
    Route::get('/another', fn () => 'Another route');
});
```

All routes inside the group will inherit the locale definitions. A route can also extend the group's locales with its own `lang()` call — the locales are merged:

```
Route::lang(['es', 'it'])->group(function () {
    Route::get('/example', fn () => 'Hello, World!'); // es, it
    Route::get('/another', fn () => 'Another route')
        ->lang(['fr']); // es, it, fr
});
```

### Translating Route URIs

[](#translating-route-uris)

Manage route translations in dedicated language files. The expected file structure is as follows:

```
/lang
├── /es
│   └── routes.php
├── /fr
│   └── routes.php
├── /it
│   └── routes.php
```

Inside your `routes.php` file, map the original route URI to a translated slug:

```
// lang/es/routes.php
return [
    'example' => 'ejemplo',
];
```

If no translation is provided for a given locale, the original URI is used as-is.

Note

The key should be the route URI **without** the leading slash. For example, for `Route::get('/example')`, the key should be `example`.

### Domain Translations

[](#domain-translations)

If your application uses domain-based routing, you can translate domains in the same `routes.php` language files. The key is the original domain string:

```
// lang/es/routes.php
return [
    'example'     => 'ejemplo',
    'example.com' => 'es.example.com',
];
```

URL Generation
--------------

[](#url-generation)

The package automatically replaces Laravel's default URL generator with `LocalizedUrlGenerator`, ensuring that the `route()` helper generates the correct URLs for the current locale without any extra configuration.

Note

If you need to use a custom URL generator, you can override it in your `AppServiceProvider` by aliasing your own implementation to the `url` service.

### Using the `route()` and `action()` Helpers

[](#using-the-route-and-action-helpers)

Once the generator is registered, the `route()` helper will intelligently create URLs based on the current application locale.

- **For the current locale**: The helper automatically generates the correct URL based on the active language.
- **For a specific locale**: You can explicitly request a URL for a different language by passing the `lang` parameter to the `route()` helper.

```
// Assuming the current locale is 'en'
route('example'); // Returns "/example"

// To generate a URL for a different locale
route('example', ['lang' => 'fr']); // Returns "/fr/example"

// If a translation exists for 'es' in lang/es/routes.php, the translated slug is used
route('example', ['lang' => 'es']); // Returns "/es/ejemplo"
```

The `action()` helper works the same way:

```
action(Controller::class, ['lang' => 'es']); // Returns "/es/ejemplo"
```

Locale Preference
-----------------

[](#locale-preference)

This package provides a mechanism for automatically detecting a user's preferred language.

The `SetPreferredLocale` middleware is responsible for populating the preferred locale. It does this by checking a series of configurable **preferred locale resolvers**.

By default, the package checks the following sources in order:

1. **SessionLocale**: Checks if a locale was set in the session.
2. **UserLocale**: Checks if the authenticated user has a preferred locale (the user model must implement Laravel's `Illuminate\Contracts\Translation\HasLocalePreference` interface).
3. **BrowserLocale**: Falls back to the browser's `Accept-Language` header.

### Customizing Resolvers

[](#customizing-resolvers)

You can customize the resolvers by setting the static property on the `L10n` class:

```
use Goodcat\L10n\L10n;
use Goodcat\L10n\Resolvers\BrowserLocale;

L10n::$preferredLocaleResolvers = [
    new BrowserLocale,
];
```

### Creating a Custom Resolver

[](#creating-a-custom-resolver)

Implement the `LocaleResolver` interface to create your own resolver:

```
use Goodcat\L10n\Resolvers\LocaleResolver;
use Illuminate\Http\Request;

class CookieLocale implements LocaleResolver
{
    public function resolve(Request $request): ?string
    {
        return $request->cookie('locale');
    }
}
```

Then add it to the resolver chain:

```
L10n::$preferredLocaleResolvers = [
    new CookieLocale,
    new SessionLocale,
    new UserLocale,
    new BrowserLocale,
];
```

Helpers
-------

[](#helpers)

This package adds several helper methods to your Laravel application.

### Application Helpers

[](#application-helpers)

```
// Get the user's preferred locale
app()->getPreferredLocale(); // Returns ?string

// Set the user's preferred locale (dispatches PreferredLocaleUpdated event)
app()->setPreferredLocale('es');

// Check if a locale is the fallback locale
app()->isFallbackLocale('en'); // Returns bool
```

### Route Matching

[](#route-matching)

Use `L10n::is()` to check if the current route matches a given pattern, regardless of the locale:

```
L10n::is('dashboard');  // Matches /dashboard, /es/dashboard, /it/bacheca, etc.
L10n::is('admin.*');    // Wildcard patterns are supported, just like Route::is()
```

This is the localized equivalent of `Route::is()`. It resolves the canonical route behind any localized variant and delegates to `Route::named()`.

Components
----------

[](#components)

The package provides Blade components for common localization needs.

### Alternate Hreflang Links

[](#alternate-hreflang-links)

The package provides a Blade component that generates `` tags following [Google's guidelines for localized versions](https://developers.google.com/search/docs/specialty/international/localized-versions).

Add the component to the `` of your layout:

```

```

For a route with `es` and `it` translations, this will render:

```

```

The component includes all localized variants, the fallback locale, and an `x-default` entry pointing to the canonical route. It renders nothing for routes without translations.

### Locale Switcher

[](#locale-switcher)

The package provides a Blade component that renders a `` element for switching between available locales. When the user selects a different locale, the page reloads to the corresponding localized URL.

```

```

For a route with `es` and `it` translations, this will render:

```

    en
    es
    it

```

The current locale is automatically selected. The component renders nothing for routes without translations.

You can pass any HTML attribute to the component:

```

```

### Customizing the Templates

[](#customizing-the-templates)

To customize the HTML output of the Blade components, publish the views:

```
php artisan vendor:publish --tag=l10n-views
```

This copies the templates to `resources/views/vendor/l10n/components/`. Each template documents the available variables in a docblock at the top of the file.

Localized Views
---------------

[](#localized-views)

The application's view loader is configured to automatically search for a localized version of a view before falling back to the generic one.

When you render a view, the system follows a specific search order based on the current application locale.

- **Locale-specific path**: The application first tries to find the view within a folder that matches the current locale. For example, if the locale is set to `it`, it will look for the `example` view in `resources/views/it/example.blade.php`.
- **Generic path**: If the view is not found in the locale-specific folder, it will then fall back to the generic `resources/views/example.blade.php`.

This makes it straightforward to organize your views with a clean, language-based folder structure, like the one below.

```
/resources/views
├── example.blade.php
├── /it
│   └── example.blade.php
└── /es
    └── example.blade.php

```

The `example.blade.php` file in the root views folder can serve as your default template, while the localized versions (`it/example.blade.php`, `es/example.blade.php`) contain language-specific content or layouts.

JavaScript URL Generation
-------------------------

[](#javascript-url-generation)

This package provides helper functions for generating localized URLs in your JavaScript/TypeScript frontend. Two stubs are available: one for [Wayfinder](https://github.com/laravel/wayfinder) and one for [Ziggy](https://github.com/tightenco/ziggy). Given the following route definition:

```
Route::get('/foo/{id}', Controller::class)
    ->lang(['it', 'es'])
    ->name('foo');
```

### Wayfinder

[](#wayfinder)

If you're using Wayfinder, publish the TypeScript helper:

```
php artisan vendor:publish --tag=l10n-wayfinder
```

Note

The `route()` helper only works with named routes, actions are not supported.

This creates a `resources/js/l10n.ts` file with the following exports:

- `route(routes, args?)` - Selects the appropriate localized route based on the current locale.
- `setFallbackLocale(locale)` - Sets the fallback locale (defaults to `en`).

Import the `route` helper and pass Wayfinder's generated route functions:

```
import { route } from '@/l10n';
import foo from '@/routes/foo';

const esUrl = route(foo, { id: 1, lang: 'es' }).url;
```

The locale is resolved in the following order:

1. The `lang` parameter, if provided.
2. The `lang` attribute of the `` element.
3. The fallback locale.

### Ziggy

[](#ziggy)

If you're using Ziggy, publish the JavaScript helper:

```
php artisan vendor:publish --tag=l10n-ziggy
```

This creates a `resources/js/l10n.js` file with a `route` function.

Use `route()` as a drop-in replacement for Ziggy's `route()` function:

```
import { route } from '@/l10n';

route('foo', { id: 1, lang: 'it' });
```

The function automatically looks for a localized route by appending the locale to the route name (e.g., `foo.es`). If a localized route exists, it uses that; otherwise, it falls back to the original route name.

Configuration
-------------

[](#configuration)

To customize the package behavior, publish the configuration file:

```
php artisan vendor:publish --tag=l10n-config
```

### Add Locale Prefix

[](#add-locale-prefix)

By default, this package **adds the locale prefix** to every route generated via `->lang()` (e.g. `/es/ejemplo`, `/it/esempio`). The original route (e.g. `/example`) always remains available as the canonical URL.

To disable prefixes, set `add_locale_prefix` to `false` in `config/l10n.php`. Routes will then use translated URIs without locale prefixes (e.g. `/ejemplo` instead of `/es/ejemplo`).

### Route Caching

[](#route-caching)

Localized routes are fully compatible with Laravel's route caching. When routes are cached, the package skips route generation at runtime (the localized variants are already included in the cache).

```
php artisan route:cache
```

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance93

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 90.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~24 days

Recently: every ~37 days

Total

12

Last Release

37d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6ca068e1dd24801f83c4c4802af654bdb2db4025499aa94d0575898a4a5d5c8f?d=identicon)[OutlawPlz](/maintainers/OutlawPlz)

---

Top Contributors

[![OutlawPlz](https://avatars.githubusercontent.com/u/14197383?v=4)](https://github.com/OutlawPlz "OutlawPlz (130 commits)")[![matteo-palazzo](https://avatars.githubusercontent.com/u/83695398?v=4)](https://github.com/matteo-palazzo "matteo-palazzo (14 commits)")

---

Tags

laravellocalizationl10ngoodcat

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/goodcat-laravel-l10n/health.svg)

```
[![Health](https://phpackages.com/badges/goodcat-laravel-l10n/health.svg)](https://phpackages.com/packages/goodcat-laravel-l10n)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77022.3M151](/packages/laravel-mcp)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k29.9M146](/packages/laravel-cashier)[api-platform/laravel

API Platform support for Laravel

58171.6k14](/packages/api-platform-laravel)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M132](/packages/laravel-pulse)[intervention/image-laravel

Laravel Integration of Intervention Image

1588.9M183](/packages/intervention-image-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
