skip to Main Content

I am trying to set up localization on my Laravel Inerita (Vue.js). I know about https://github.com/mcamara/laravel-localization, but this does not support Inertia (at least I was not successful with running this on my Vue.js file) {{ __("text") }} does not work in inertia error: TypeError: _ctx.__ is not a function.

Anyway, I am using a different localization package called laravel-vue-i18n.

I am successful in using this on Vue.js, but I am having problems when setting the locale based on URL. How do I set my routes/middleware to use a nullable locale (en as default)?

File web.php

// Can be nullable locale?
Route::middleware(['setLocale'])->prefix('{locale?}')->group(function () {
  Route::resource('posts', PostController::class);
  Route::resource('comments', CommentController::class);

});

File SetLocaleMiddleware.php

class SetLocaleMiddleware
{
    public function handle($request, Closure $next, $locale = 'en')
    {
        Log::info($locale); // Always logs as 'en' even if I add 'ja' in the URL
        Log::info($request->route('locale')); // Locale or whatever is the text after localhost/ for some reason

        if (!in_array($locale, ['en', 'ja'])) {
            abort(400);
        }

        App::setLocale($locale);

        return $next($request);
    }
}

File app/Kernel.php

protected $middlewareAliases = [
    'setLocale' => AppHttpMiddlewareSetLocaleMiddleware::class,
];

Expected results:

// Set application language to Japanese
http://localhost/ja
http://localhost/ja/posts
http://localhost/ja/comments

// Set application language to English as default
http://localhost
http://localhost/posts
http://localhost/comments

Note: it does not have to be middleware.

2

Answers


  1. Chosen as BEST ANSWER

    So I found a solution that worked for me, though I am not able to use the ja in the url route, but instead use laravel's Session facade and update the locale in vue on the fly using createApp

    1. npm install laravel-vue-i18n
    2. publish the lang files: php artisan lang:publish
    3. copy the en directory and change to your desired new locale (mine was ja)
    4. optional (create a post.php or any other php file inside the directory)
    app
      lang
        en
          auth.php
          pagination.php
          password.php
          post.php
          validation.php
        ja
          auth.php
          pagination.php
          password.php
          post.php
          validation.php
    
    1. Add i18nVue from laravel-vue-i18n in app.ts file

    File app.ts

    // Format may be different for app.js (remove ':string') inside async
    import { createApp, h, DefineComponent } from "vue";
    import { createInertiaApp } from "@inertiajs/vue3";
    import { i18nVue } from "laravel-vue-i18n";
    
    createInertiaApp({
        ...
        setup({ el, App, props, plugin }) {
            createApp({ render: () => h(App, props) })
                ...
                .use(i18nVue, {
                    fallbackLang: "en",
                    resolve: async (lang: string) => {
                        const langs: any = import.meta.glob("../../lang/*.json");
                        return await langs[`../../lang/${lang}.json`]();
                    },
                })
                ...
        },
    });
    
    1. add i18n in vite.config.js

    vite.config.js

    import i18n from "laravel-vue-i18n/vite";
    
    export default defineConfig({
        plugins: [
            ...
            i18n(),
        ],
    });
    
    1. add lang/php_*.json in .gitignore
    2. add a Route::group in your web.php. Also include the controller@method to update the locale.

    File web.php

    Route::post('/locale', [SetLocaleController::class, 'locale'])->name('locale');
    
    Route::middleware(['setLocale'])->group(function () {
      Route::resource('posts', PostController::class);
      Route::resource('comments', CommentController::class);
    });
    
    1. create new middleware php artisan make:middleware SetLocaleMiddleware

    File SetLocaleMiddleware.php

    class SetLocaleMiddleware
    {
        public function handle($request, Closure $next)
        {
            // get locale from session or get default value 'en'
            $locale = Session::get('locale', 'en');
            App::setLocale($locale);
            return $next($request);
        }
    }
    
    1. create new controller php artisan make:controller SetLocaleController

    File SetLocaleController.php

    class SetLocaleController extends Controller
    {
        public function locale(Request $request)
        {
            // set locale to session
            Session::put('locale', $request->get('locale'));
            $data = ['locale' => $request->get('locale')];
            return response()->json($data);
        }
    }
    
    1. Update HandleInertiaRequests to return locale as props

    File HandleInertiaRequests.php

    class HandleInertiaRequests extends Middleware
    {
        ...
        public function share(Request $request): array
        {
            return [
                ...parent::share($request),
                ...
                'locale' => Session::get('locale', 'en'),
                ...
            ];
        }
    }
    
    1. In your VueJS File, there are multiple ways to toggle locale select, radio, etc. Use what you want and maybe use below how to switch the locale:
    import { createApp } from "vue";
    import { i18nVue } from "laravel-vue-i18n";
    import axios from "axios";
    
    const app = createApp({});
    
    // the method to update the locale. remote ':string` if in not using typescript.
    const toggleLocale = async (locale: string) => {
        await axios
            .post(route("locale"), { locale: locale })
            .then((response) => {
                app.use(i18nVue, {
                    lang: response.data.props.locale,
                });
            })
            .catch((error) => {
                console.log(error);
            });
    };
    

    Bonus, if you are experiencing error 419 (missing csrf token), do the following in your axios (preferably in app.ts/js)

    import axios from "axios";
    axios.defaults.withCredentials = true;
    axios.defaults.withXSRFToken = true;
    

    How to use

    lang/en/post.php

    <?php
    
    return [
        'add, :title' => 'Add :title',
    ];
    

    lang/ja/post.php

    <?php
    
    return [
        'add, :title' => ':titleを追加',
    ];
    

    any vuejs files

    <template>
        ...
        {{ trans("post.add, :title", { title: props.title,}) }}
        <!-- 'post' is from post.php while add is the key -->
        <!-- you can also add parameters here too. -->
        ...
    </template>
    
    <script setup lang="ts">
    import { trans } from "laravel-vue-i18n";
    </script>
    

    Routes stays as

    // Set application language to English as default
    http://localhost
    http://localhost/posts
    http://localhost/comments
    

  2. To achieve the expected results and set up a middleware to accept a nullable locale in Laravel for InertiaJS (Vue), you can modify the SetLocaleMiddleware.php as follows:

    <?php
    
    namespace AppHttpMiddleware;
    
    use Closure;
    use IlluminateSupportFacadesApp;
    
    class SetLocaleMiddleware
    {
        public function handle($request, Closure $next)
        {
            $locale = $request->route('locale') ?? 'en';
    
            Log::info($locale);
    
            if (!in_array($locale, ['en', 'ja'])) {
                abort(400);
            }
    
            App::setLocale($locale);
    
            return $next($request);
        }
    }
    

    This modification allows the SetLocaleMiddleware to accept a nullable locale from the URL. If a locale is present in the URL, it will be used; otherwise, the default locale will be set to ‘en’.

    Additionally, you need to update your web.php routes to ensure that the middleware is applied correctly:

    use AppHttpControllersPostController;
    use AppHttpControllersCommentController;
    
    Route::middleware(['setLocale'])->group(function () {
        Route::prefix('{locale?}')->group(function () {
            Route::resource('posts', PostController::class);
            Route::resource('comments', CommentController::class);
        });
    });
    

    With these changes, your routes should now correctly handle nullable locales, setting the application language accordingly.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search