Library / SDK
rmariuzzo/Laravel-JS-Localization avatar
rmariuzzo/Laravel-JS-Localization

Laravel-JS-Localization: shipping Laravel's language files to the browser

🌐 Convert your Laravel messages and consume them in the front-end!

606 stars168 forksPHPMIT

At a glance

What is it?
Laravel-JS-Localization converts your Laravel application messages into a JavaScript file that ships with the front end, paired with Lang.js, a thin browser library that mirrors the Laravel Translator API. It suits a Laravel team that wants one set of translation files for both server and client, and it is a package whose last push was in May 2026.
Who is it for?
This package fits a Laravel application whose front end needs the same strings the back end uses, and it does not fit a team that has already standardised on a different way of shipping translations or that needs per-request locale negotiation the generated file cannot express.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 171 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: one set of strings, two runtimes

Laravel-JS-Localization converts all your localization messages from your Laravel app to JavaScript, with a small library to interact with those messages using a syntax you are already familiar with.

The duplication this solves is easy to underestimate until you have shipped it. A Laravel application keeps its translations in language files, and the Blade templates read them through the Translator. The moment the front end needs a string, the same key has to exist in JavaScript too, and the two copies drift. This package makes the JavaScript file a build artefact derived from the Laravel files, so there is one source of truth and the browser gets the strings that the server already has.

The design bet is in the second half of that sentence. The package includes Lang.js, described as a thin library highly inspired by Laravel's Translator class, and the readme is explicit that the Lang.js API is based on the Translator class with no need to learn a whole API. The familiarity is the feature. A frontend developer who has used trans('messages.home') in a template can use Lang.get('messages.home') in JavaScript without reading a manual.

The audience is a Laravel team with a server-rendered back end and a JavaScript front end that needs strings, and the repository is by Rubens Mariuzzo with an MIT licence.

How the build works: an artisan command that reads the language files

The mechanism is a single Artisan command, and the readme is clear about where it reads from and what it writes.

The command generates the JavaScript version of all your messages found in the app/lang directory for Laravel 4, or the resources/lang directory for Laravel 5. The resulting JavaScript file contains all your messages plus Lang.js.

The command has a small set of options, and each one solves a real problem in a real project. The default invocation is:

shell
php artisan lang:js

A custom target path, for projects with a specific asset pipeline layout:

shell
php artisan lang:js public/assets/dist/lang.dist.js

Compression, which matters because the file contains every message for every locale:

shell
php artisan lang:js -c

A custom source folder, for a theme or module that keeps its own language files:

shell
php artisan lang:js public/assets/dist/lang.dist.js -s themes/default/lang

And a JSON output mode:

shell
php artisan lang:js --json

The order of the arguments is a small thing that trips people up, since the source option is a trailing flag rather than a separate argument, and the readme shows the source path as the last item. The repository has both a lib/ and a src/ directory alongside the Lang.js/ directory, which is where the JavaScript library that gets copied into the output lives.

The important consequence of this design is that the language files are read at build time. A string added to a Laravel language file appears in the JavaScript file only after the command runs, which means the command belongs in your deploy or asset pipeline step rather than in a request.

Configuration: the messages array decides what ships

The configuration is published as a normal Laravel package config file, and the key in it is the one decision that has a real cost attached.

You publish it with the standard vendor:publish command:

shell
php artisan vendor:publish --provider="Mariuzzo\LaravelJsLocalization\LaravelJsLocalizationServiceProvider"

which writes the file to config/localization-js.php. You may edit this file to define the messages you need in your JavaScript code, by editing the messages array. The readme states the rule in one line: an empty messages array will include all the language files in the build.

That default is the thing to think about. Including everything means every string in every locale is shipped to the browser, which for a multilingual application is a large file containing translations the visitor will never see. The alternative is to list the files you actually need, and the readme gives the shape:

php
<?php

return [
    'messages' => [
        'pagination',
        'validation',
    ],
];

With that in place, only pagination.php and validation.php are included in the build. For a typical application the JavaScript-visible surface is small, a handful of validation messages and the pagination strings, and the rest of the translation files stay on the server where they belong.

So the package has a sensible default that is wrong for production and a configuration that fixes it in two lines. Knowing to change it is the difference between a 40 kilobyte asset and a 400 kilobyte one.

Lang.js in the browser, and the API it mirrors

The JavaScript side is a thin library, and the readme lists the operations with a short example for each.

Getting a message is Lang.get('messages.home'). Getting one with replacements is Lang.get('messages.welcome', { name: 'Joe' }). Changing the locale is Lang.setLocale('es'), and checking whether a key exists is Lang.has('messages.foo').

The plural handling is the part with a little more going on, and it is worth knowing the shape of it. Support for singular and plural messages based on a count is Lang.choice('messages.apples', 10), and the same call can carry replacements as a third argument, Lang.choice('messages.apples', 10, { name: 'Joe' }). That mirrors Laravel's trans_choice, where the count selects between the singular and plural branch of a message and the replacements are interpolated afterwards.

The library is a separate project, Lang.js, and the readme directs readers to its own documentation for the full set of available methods. The deliberate choice here is to keep the surface small and Laravel-shaped rather than to design a general purpose i18n client, which means anything Laravel's Translator can do that this library cannot is a gap you will feel, and the documentation is the place to check.

The repository structure reflects the split: a Lang.js/ directory for the client library, lib/ and src/ for the PHP side, a scripts/ directory, and tests/ alongside a phpunit.xml.

Wiring it into the build: gulp, Elixir and Mix

The readme covers three optional integrations, all of which do the same thing, run the artisan command at the right moment in the asset build.

The first is gulp, using the gulp-shell plugin, with a task defined in your gulpfile.js:

js
var shell = require('gulp-shell');

gulp.task('langjs', shell.task('php artisan lang:js -c public/js/messages.js'));

The second is Laravel's Elixir, with two different forms depending on the version. Before Elixir 4.0 the task is registered with elixir.extend and a gulp.src pipeline, and from Elixir 4.0 the same task is registered through the Elixir.Task API. The readme notes the two cases separately, which is a small sign of the package's age.

The third is Laravel's Mix for Laravel 5.4 and later, which needs the webpack-shell-plugin-next package added to the devDependencies section of package.json, and a webpack-shell-plugin-next instance in the mix.webpackConfig plugins array:

js
const WebpackShellPluginNext = require('webpack-shell-plugin-next');

// Add shell command plugin configured to create JavaScript language file
mix.webpackConfig({
    plugins:
    [
        new WebpackShellPluginNext({onBuildStart:['php artisan lang:js --quiet'], onBuildEnd:[]})
    ]
});

The Mix integration runs the command on build start with the --quiet flag, so the artisan output does not pollute the build log. The gulp and Elixir examples do the same thing with an explicit target file, which is the older style of integration and still works.

The readme also points Webpack users at a separate project, the Laravel localization loader, described as the new and shiny option for Webpack specifically, which is a reasonable signal that the older integrations are the legacy path and that a new project is where the author is putting the effort.

Where it stops working, and what to check before adopting it

There are three practical limits, and none of them is a bug.

The first is that the whole design is build-time. The strings are read from the language files when the artisan command runs, so anything dynamic, a string that depends on the database, on the user, or on the request, cannot be expressed by this mechanism. The generated file is a static snapshot of the locale files at build time.

The second is the per-locale file size, which connects back to the configuration. The generated file contains every message for every locale you include, and the readme's default of an empty messages array means every language file in the application. On an application with twenty locales and a large message catalogue, that is a significant asset, and the fix is to list the files you need in config/localization-js.php.

The third is the version surface. The readme advertises support for Laravel 4.2, 5.0 through 5.5, 6.x, 7.x and 8.x, which is an impressive range, and also an indication of how old the package's target is. The most recent releases are v2.1.0 from 2026-03-26, v2.0.0 from 2025-04-21 and a v2.0.0-beta from 2025-03-10, and the repository was last pushed on 2026-05-05.

The development setup is documented in the same readme, and it is old-school: fork and clone, create a feature branch from develop, and push your commits and create a pull request. The prerequisites are Composer and PHP 5.5 or above, the dependencies are installed with composer install, the test dependencies with composer test-install, and the suite runs with composer test on PHPUnit with the tests stored in the tests directory. There is a .travis.yml in the repository root, which is the older continuous integration service, and a .gitmodules file.

The natural alternative to all of this is a modern bundler plugin that imports the language files at compile time, which is what the laravel-localization-loader project in the same organisation is for. The difference in approach is that the loader integrates with the bundler and emits the strings as part of the JavaScript bundle, while this package emits a standalone file you reference, configure and deploy yourself.

Editorial conclusion

This package fits a Laravel application whose front end needs the same strings the back end uses, and it does not fit a team that has already standardised on a different way of shipping translations or that needs per-request locale negotiation the generated file cannot express. Before adopting it, run php artisan lang:js and look at the generated file, because the messages array in config/localization-js.php decides what is included, and an empty array includes every language file in the build.

Frequently asked questions

What does Laravel-JS-Localization do?

It converts all your Laravel application messages into JavaScript, using a small library to interact with those messages in a syntax similar to the Laravel Translator. The resulting file contains your messages plus Lang.js, a thin library inspired by Laravel's Translator class.

How do I install Laravel-JS-Localization?

Run composer require mariuzzo/laravel-js-localization, then in your Laravel app go to config/app.php and add the service provider Mariuzzo\LaravelJsLocalization\LaravelJsLocalizationServiceProvider::class. The package supports Laravel 4.2, 5.x, 6.x, 7.x and 8.x.

How do I generate the JavaScript language file?

Run php artisan lang:js, which reads the messages from app/lang for Laravel 4 or resources/lang for Laravel 5. You can pass a target path such as php artisan lang:js public/assets/dist/lang.dist.js, add -c to compress the file, add -s with a path to use a custom source folder, and add --json to output a JSON file instead.

How do I control which translation files are included in the build?

Publish the configuration with php artisan vendor:publish using the LaravelJsLocalizationServiceProvider, then edit the messages array in config/localization-js.php. An empty messages array includes all the language files in the build, so listing the files you need, such as pagination and validation, keeps the generated file small.

How do I use the messages from JavaScript?

With the Lang.js library included in the generated file: Lang.get('messages.home') reads a message, Lang.get('messages.welcome', { name: 'Joe' }) interpolates replacements, Lang.setLocale('es') changes the locale, Lang.has('messages.foo') checks a key, and Lang.choice('messages.apples', 10, { name: 'Joe' }) handles singular and plural messages based on a count.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. rmariuzzo/Laravel-JS-Localization on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rmariuzzo-laravel-js-localization.svg)](https://hysenlabs.com/projects/rmariuzzo-laravel-js-localization)

Was this useful?