Laravel Multi-Language Travel Website with Filament Panel

Laravel Daily| 00:09:47|Apr 14, 2026
Chapters10
The presenter introduces a Laravel based method for a multilingual site with locale URLs and a Filament admin panel for managing language data.

A practical Laravel multi-language setup using Filament for admin management, with JSON translations via Spatie and a look at alternatives like Astrotomic translatable.

Summary

Laravel Daily’s tutorial walks through creating a multilingual travel site using Laravel, Filament, and a locale-based URL structure. The host demonstrates a 10-language example with language-switch tabs in the admin panel, highlighting how title, slug, and other fields are stored as JSON translations for each locale. He explains that static site text uses JSON translations, while dynamic model data (tours) leverage the Spatie Laravel Translatable package to save multilingual fields in a JSON column. A key demo shows enabling a new language (Lithuanian) in config locales.php and how the UI adapts without data for that language, automatically falling back to English. He also compares two translation approaches: Spatie’s JSON-based translatable fields versus Astrotomic’s separate translation tables, noting performance trade-offs for large datasets. The video adds a practical note about SEO-friendly locale-prefixed URLs, route handling, and middleware that sets the locale from the URL and cookie. Towards the end, he teases a full source project for premium members and promotes a free Upwork-focused Laravel jobs newsletter.

Key Takeaways

  • Locale-based routing is enforced via a route pattern and a setLocale middleware, ensuring every public URL is prefixed with the two-letter locale.
  • Spatie Laravel Translatable stores translatable fields (title, slug, description, highlights) as JSON and exposes getTranslation methods for each language.
  • In Filament, language tabs are generated dynamically from config locales.php, with fields named as title.code to map to the JSON structure.
  • Adding a new language (e.g., LT for Lithuanian) updates the UI to include the locale in the admin and on the homepage, though data remains empty until filled and defaults to English where translations are missing.
  • An alternative to JSON-based translations is Astrotomic Laravel Translatable, which uses separate translation tables for potentially better performance on large datasets.
  • Static site translations rely on JSON in resources/lang and can be auto-translated via AI tools, while dynamic model translations live in the translatable JSON columns.
  • The workflow includes SEO-conscious multilingual URLs with alternate links visible in the page source, aiding crawlability and language targeting.

Who Is This For?

Laravel developers building multilingual sites who want to use Filament for admin panels and are weighing JSON-based translations against table-based alternatives, plus anyone curious about locale-based routing and SEO implications.

Notable Quotes

""For example, with these set of countries flags and locales with filament admin panel with flags also here to manage the models.""
Intro showing Filament-based language tabs and locale-driven model management.
""The URL is ES, then this is Spanish and everything else is in Spanish language including menu items.""
Demonstrates how language affects the public UI and URLs.
""In the code base there are specific translations not translated for DE at the end and other languages like this here.""
Notes partial translations and fallback behavior for untranslated locales.
""The JSON structure is flexible to add another language and the Lithuanian example shows the system can expand easily.""
Shows how adding a new locale updates the admin and frontend without breaking."},{

Questions This Video Answers

  • How do I implement locale-prefixed URLs in Laravel with a setLocale middleware?
  • Should I use Spatie Laravel Translatable JSON fields or Astrotomic Translatable tables for my multilingual Laravel app?
  • How can Filament dynamically render language tabs from a config file in Laravel?
  • How does Laravel handle SEO with multilingual pages and alternate links?
  • What are the best practices for falling back to English when a translation is missing in a non-English locale?
LaravelFilamentSpatie Laravel TranslatableAstrotomic Translatablemultilingual-sitelocale-routingJSON translationsSEO multilingual URLsUpwork Laravel jobsLaravel Daily project examples
Full Transcript
Hello guys. Today in this video I will show you one of the approaches for multi-language website in Laravel. For example, with these set of countries flags and locales with filament admin panel with flags also here to manage the models. This will be one of the approaches and we will discuss the alternatives also at the end of this video. And this is based on Upwork job, real Upwork job, Laravel developer for multilingual travel website. I simplified that website but basically the condition was exactly that. 10 languages with URLs here and so on. And lately I'm diving deeper into Upwork in general. Here's a tweet that I even upgraded to freelancer plus for $20 just to feel the pulse. What are the jobs for Laravel developers available? How are they priced and so on. So for that, I've started a separate newsletter where you can find about latest jobs that I handpicked for Laravel developers. And if you want to find out how to get to that newsletter, this is free absolutely. I'll talk about that at the end of this video. But for now, let's dive into multi-language example. So first visual demo and then we'll dive into the code. So here's a homepage and here we have 10 languages to choose from. If I switch to Español to Spanish, even Google translate then recognizes that it's Spanish language automatically translated with AI. I'm not a Spanish speaker, but as you can see the URL is ES, then this is Spanish and everything else is in Spanish language including menu items. And if we scroll down, the button is also in Spanish and this text. Then if we click on specific tour, we see everything in Spanish as well. Most of the text translated. But now if I click to any other language which is not translated, then it goes back to placeholders or English language translations. So in the code base there are specific translations not translated for DE at the end and other languages like this here. But for example, menu items fall back to English language because they are not translated to German. Also if I go back to Spanish and see the source of the page in the browser, you can see here that the title is in Spanish and then there are alternate URLs for all the other languages. So this is good for the SEO purposes for multi-language projects. And then there's a simple admin panel as well. So if you go to tours, we can click new tour and here we can choose the language and add title or slug. And by the way, title and slug are required only for the English language. For others, they are optional. This is kind of a filament trick and I will show you that a bit later. And also in the pages, we can go to edit the page and for example, switch between English and Spanish. And as you can see, this is placeholder for DE that I showed you earlier. So now let's dive into the code and discuss how it all works at least in my version. And at the end of this video, we will discuss the alternatives. First, how this list works on the top right. So this is configurable in file config locales.php with names and flag emojis. And then in the blade on top, there's blade layout with language switcher included into that. And here we have for each of locales with collection operations with links to change the route. Speaking of the routes, let's take a look at routes web. So if we visit the homepage, you will be redirected to some locale which is from cookie for example. Or maybe it comes from the URL and you will get redirected to home with specific locale. So this is route home and then that home is prefixed with this. And this is regular expression to have those two letters validated. Also you can see the middleware called set locale and this is how it works. We get the locale from route and if it doesn't exist, we show 404. Then we set that into the application and into the cookie as well. So with that mechanism, all the URLs of the public website are prefixed with locale by definition as a required parameter. And then as a result of that, we have underscore underscore functions in blade which work automatically because the locale is set within application. And then these translations are in JSON for example, Spanish JSON with these texts. But these are static translations for the text on the website. What about dynamic translations for models? And for that, we use a package. So in the package.json, you see Spatie Laravel translatable which is a very popular option. And then in the model of tour, we have has translations here and then translatable fields as array. In the database, all those fields are saved as JSON. So you can see in the database here in the table plus this is the result what happens in the database then. So we have title, slug, description and highlights all translatable and saved as JSON. But then that package Laravel translatable allows to retrieve the value from JSON something like this, get translations with the field or with the field for specific language. So you don't really work directly with JSON, you work translation, get translation and other operations from the package. And now let's see how those tours are managed in the filament admin panel with this form for example. So this is the tour form file for filament resource. And first we have tabs. So those flags are actually tabs with icons for flags. And we get those tabs dynamically collecting them from the config you saw a few minutes ago. So for each locale, each language, we have tab make with schema inside almost identical. Except for for example, as I mentioned earlier, title and slug are required only for English language for example. And the thing is that all those fields are referenced as title.code of the language. And this is exactly how Spatie Laravel translatable is referencing those fields. So that's why the values would be saved automatically into the same JSON structure in the database. But also in addition to that, not everything is translatable for tours. So there's another section details without any languages and without any locales. So if we scroll to the bottom, these things are global for every tour no matter the language. So these are then saved in the database as regular fields here. But as a result of this flexible approach, we can add 11th language pretty easily. Let's try to do exactly that. We go to the config and let's for example add another language my own for example Lithuanian for LT, Lithuanian native and then VS code even suggests the flag. Great. And now if I refresh that admin panel, we see Lithuanian here. Empty of course, no data, but it works already. The JSON structure is flexible to add another language. And if we go to the homepage of English language in the list, we should see Lithuanian language here at the bottom. And if we click, the URL works /lt. Of course, no data here but also no errors. It's a fallback to English language everywhere. Both from Laravel app language perspective for static text and from dynamic text from the database for tours here. And now we can talk about alternative approaches. For example, if you don't like JSONs in the database with Spatie package, there's another alternative package for translating the models, Astrotomic Laravel translatable, which in the docs we may find in the installation that it has different database tables for for example, main table posts and then post translations with locale here in the database separately. Then you don't need to transform anything from and to JSON. The values are directly in the database and of course package helps you to retrieve them. What is the syntax here? Yeah, so translate or title and then other syntax options. But basically it's querying the database with separate tables joined. This approach is probably better if you have a lot of SQL queries for translations. For example, for admin translations, the query from the database as relational structure will of course work faster than JSON. But also it depends on the size. tables, you probably wouldn't feel that much of a difference. But for bigger projects with a lot of translations and a lot of languages and a lot of queries for translations, then I would probably go for Laravel translatable in separate database tables. But of course, as usual, we can discuss in the comments below. And if you want a full source of that project to play around with it, I will put that in a project example section of Laravel daily. This is for premium members. So Laravel daily is not only just for courses, but about project example sources as well. So it's not here yet and I will put that here after shooting this video. And you see more of the projects here and you can get to the GitHub of those projects as well inside of the same membership. But also I want to show you a new thing with Upwork jobs that I started that I announced in the beginning of this video. So if you click newsletter, this is free, no membership required. On the right, I see a new section Upwork Laravel jobs. So this is a second separate free newsletter in addition to just newsletter I send every Thursday with industry news. So if you want to subscribe to that, you will get something like this every morning. For now, for this month, I'm experimenting with Upwork a lot and you will get the jobs that I handpicked from Upwork while browsing just on my mobile sometimes while I have downtime. I will pick the jobs worthy for Laravel developers or PHP or even agnostic to tech stack with Laravel being a good fit. And I will link this first issue of that newsletter in the description below so you may also click those jobs as well already. But if you want to get this every morning, this is the URL laravel-daily.com/newsletter and on the right, subscribe to the free form for newsletter. That's it for this time and see you guys in other videos.

Get daily recaps from
Laravel Daily

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.