Building a Laravel Translation Package – Wiring Up The Frontend

Published on by

Building a Laravel Translation Package – Wiring Up The Frontend image

In the last installment of this series, we talked through the process of manipulating the translations in our application’s language files into a format where we are now in a position to start interacting with them. In this article, we’ll be wiring up the frontend ready to start building out the user interface which will aid users with the process of translation management.

The UI will be developed using the community favorites, Tailwind CSS and Vue.js.

The Approach

Like it or loathe it, I’m taking a leaf straight out of the Caleb Porzio book of embracing the backend for this package. In his talk, Caleb presents the notion of taking the emphasis away from using Javascript to build single page applications including making it responsible for retrieving all of its data as well as things like routing and form submissions. Instead, he suggests using strengths of Laravel to produce a more hybrid approach. Taking inspiration from this, we’ll be leveraging our controllers and blade views to pass the data required by our Vue.js components to add the necessary dynamic functionality. Laravel Mix will be utilized to build and compile the package assets.


To start, we’ll need to tell Laravel where to load our routes from. One way to do this is by using the loadRoutesFrom method inside of our package’s TranslationServiceProvider. This method is inherited from the parent Illuminate\Support\ServiceProvider class.


This allows us to define all the package routes in one file in the same way you would in your Laravel application.

Route::group(config('translation.route_group_config') + ['namespace' => 'JoeDixon\\Translation\\Http\\Controllers'], function ($router) {
$router->get(config('translation.ui_url'), 'LanguageController@index')
$router->get(config('translation.ui_url').'/{language}/translations', 'LanguageTranslationController@index')

In this file, we use the Route::group() method to pull in any custom group configuration which is merged with the namespace from where the package controllers reside.

The only other thing to note is that the configuration is again used to dynamically register the routes where the user wants them. If left to the default configuration options, the ui_url is set to languages. As such, the above routes will be registered as follows:


In this file, routes are defined to list, create and store languages and list, create, store and update translations.


There is no wiring in the service provider required for controllers. As long as they are found at the namespace defined in the routes file, everything will work as expected.

In each of the controllers, access to the translation drivers we created in the previous article in this series, is required from just about every method. As such, we’ll resolve it from the container in the constructor.

public function __construct(Translation $translation)
$this->translation = $translation;

Now, regardless of the driver, it’s trivial to use the functionality we have already built to interact with the project’s translations from within the controller.

public function index(Request $request)
$languages = $this->translation->allLanguages();
return view('translation::languages.index', compact('languages'));

The only thing which may look a little alien here is the way the view is loaded. translation:: simply tells Laravel to load the view from the translation package namespace which Laravel is made aware of in the service provider. More on that to follow.


First, we need to tell Laravel where the routes for the package should be loaded from.

$this->loadViewsFrom(__DIR__.'/../resources/views', 'translation');

By using the loadViewsFrom method in the boot method of the package service provider, Laravel knows that our routes should be loaded from /package/root/resources/views using the translation namespace. Using a namespace mitigates the risk of views conflicting between packages or even the main application.

__DIR__.'/../resources/views' => resource_path('views/vendor/translation'),

The above line tells Laravel where the views can be found and where they should be copied to should the package consumer wish to pull them into their application.

In this case, they would be copied from /package/root/resources/views to views/vendor/translation within the resource path of the application.

Typically, this is done so the consumer is able to edit them to suit their own requirements.


For my own sanity, I like to use Laravel Mix to build assets for my packages. It offers a great developer experience and is quick and easy to get up and running.

I start by running npm init from the root of the project and following the instructions to setup the environment.

Now it’s possible to install Laravel Mix by running npm install laravel-mix --save-dev. This will install all the required dependencies as well as add Laravel Mix as a development dependency to the package.json file.

Next, we need to copy the webpack.mix.js file which ships with Mix to the root of the project so we can start configuring the build.

cp node_modules/laravel-mix/setup/webpack.mix.js ./


Next, we will install and configure the CSS framework, Tailwind, into our package. To do this, pull in the dependency by running npm install tailwindcss --save-dev.

With the dependencies available, we can now start to configure the installation. First, we’ll generate the Tailwind configuration file. This can be achieved by running ./node_modules/.bin/tailwind init tailwind.js where tailwind.js is the name the configuration file will be generated as. This file allows you to tweak the base color settings, fonts and font sizes, widths and heights and much, much more. It’s worth taking a look at this or reading the Tailwind documentation for further information. However, for the purposes of this tutorial, we will continue with the excellent default values.

Finally, we need to tell Laravel Mix to run PostCSS using the Tailwind configuration as part of the build.

To do this, we first need to require the Tailwind PostCSS plugin in the webpack.mix.js file.

var tailwindcss = require('tailwindcss');

Then as part of the build pipeline, we can use Mix’s postCss method, passing in the exported function stored in the tailwindcss variable above to configure this step of the build.

mix.postCss('resources/assets/css/main.css', 'css', [

This method is saying, take the file at resources/assets/css/main.css, apply the tailwind PostCSS plugin and output to the css directory.

Now when we run npm run dev|production|watch, this process will run automagically.


We will develop the UI using Vue.js, so this will need to be pulled in as a dependency. We will also require a little bit of ajax functionality so let’s also install the popular axios package to do the heavy lifting for us.

npm install vue axios


Above, we have asked Mix to build the assets into the css and js directories, but we need to tell it where to find them in relation to the webpack.mix.js file. The can be done using the following method.


In a standard Laravel application, this would be used to publish the built assets to a publicly available location. However, in our package scope, we need to publish them to a location where they can easily be published using the php artisan publish command. This allows an end user to publish the files to their application where they are free to modify them and keep them within their own version control.

Finally, we need to tell Laravel where to find the files for publishing. This is, again, carried out in the Service Provider.

__DIR__.'/../public/assets' => public_path('vendor/translation'),
], 'assets');

The first argument is an array where the key represents the path to the assets within the package, and the value represents the location where they should be published within the app. The second argument is a tag defining the type of files being published. This provides the user the flexibility to choose the types of file they wish to publish as an option to the publish command.


In development, you will likely not want to have to run the publish artisan command every time you want to test your changes. To mitigate this, update the mix.setPublicPath method to the path you wish to load the assets from in testing. However, don’t forget to change it back when you are ready to commit! An excellent way to manage this state is by using environment variables.

We now have the groundwork in place to start fleshing out the routes, controllers, views, and assets needed to bring the user interface to life, which we’ll cover in the next installment.

Joe Dixon photo

Founder and CTO of ubisend. Proud Father to two tiny heroes, Husband, developer, occasional globetrotter.


Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.


Manage your Laravel app as if it was a CMS – edit any text on any page or in any email without touching Blade or language files.

Visit Paragraph
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo


The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo


Providing innovation and stability to ensure your web application succeeds.

Shift logo


Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

LoadForge logo


Easy, affordable load testing and stress tests for websites, APIs and databases.

Paragraph logo


Manage your Laravel app as if it was a CMS – edit any text on any page or in any email without touching Blade or language files.

Lucky Media logo

Lucky Media

Bespoke software solutions built for your business. We ♥ Laravel

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
Bacancy - Staff Augmentation logo

Bacancy - Staff Augmentation

Leave your web app development hustles to the leading IT Staff Augmentation Service Providers. Choose from an extensive pool of 1050+ developers and give yourself the sigh of success you deserve with Bacancy. Get In Touch Today!

Bacancy - Staff Augmentation logo

Save hours of manually writing Code Documentation, Comments & DocBlocks, Test suites and Refactoring.
Rector logo


Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies


The latest

View all →
Add Architecture Tests to Saloon API Integrations with Lawman image

Add Architecture Tests to Saloon API Integrations with Lawman

Read article
Protect Routes with JWT Tokens Using This Package for Laravel image

Protect Routes with JWT Tokens Using This Package for Laravel

Read article
Increment a Rate Limiter by a Custom Amount in Laravel 10.46 image

Increment a Rate Limiter by a Custom Amount in Laravel 10.46

Read article
Add Kanban Boards to Your Laravel App in Seconds image

Add Kanban Boards to Your Laravel App in Seconds

Read article
October CMS v3.6 Ships Today, Full of New Features image

October CMS v3.6 Ships Today, Full of New Features

Read article
Laracon EU Videos are now out image

Laracon EU Videos are now out

Read article