Top View


Author Daiki Urata

LaravelとVueで翻訳ファイルを共通化する

2023/05/09

はじめに

LaravelとVueのプロジェクトで多言語対応する場合に翻訳ファイルを共通で使いたい場合があります(とくにattributesなど重複することがあるので)。

Laravel標準機能として JSONファイルを翻訳ファイルとして扱うことができ、それをVue I18nで読み込むなど共通化できる方法はありますが、ファイル分割やネストした書き方ができないなど、若干不便な部分があります。

そこで Laravel Vue i18n というライブラリを使うことで通常のPHPの翻訳ファイルのまま、Vueでもその翻訳ファイルを使えるように。

基本的にドキュメント通りのやり方で問題ありませんでした。

環境

  • Laravel 10
  • Breeze (Vue3 + Vite + Inertia)
  • TypeScript

Laravelプロジェクトの作成はBreezeのtypescriptオプションを使って作成しました。

langディレクトリ作成

まずはlangディレクトリを用意します。

lang/en以下にauth.phpやvalidation.phpが作られると思います。

$ php artisan lang:publish

Laravel Vue i18nの導入

インストール

次にLaravel Vue i18nをインストールします。

$ npm install -D laravel-vue-i18n

Vite設定

まずはvite.config.jsにプラグインを追加します。

これによりビルド時や開発サーバー起動時にauth.phpやvalidation.phpから自動でJSONファイルに変換された翻訳ファイルが生成されます。

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import i18n from 'laravel-vue-i18n/vite'; // <- 追加

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.ts',
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
        i18n(), // <- 追加
    ],
});

Vue設定

次にresources/js/app.tsを編集します。

i18nVueをimportしてきてVueに追加してあげます。resolveの部分についてはドキュメント通りlang以下の*.jsonを読み込んであげる形になります。

import './bootstrap';
import '../css/app.css';

import { createApp, h, DefineComponent } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { i18nVue } from 'laravel-vue-i18n' // <- 追加

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue')),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            // ----- ここから追加 -----
            .use(i18nVue, {
                resolve: async (lang: string) => {
                    const langs = import.meta.glob('../../lang/*.json');
                    return await langs[`../../lang/${lang}.json`]();
                }
            })
            // ----- ここまで追加 -----
            .mount(el);
    },
    progress: {
        color: '#4B5563',
    },
});

lang オプションを指定しない限りは <html lang="en"> タグから自動で探してきて言語設定してくれるようですので、app.blade.phpで正しく指定してあればとくに問題はありません。

動かしてみる

設定が完了したのでViteサーバーを起動してみます。

$ npm run dev

するとlang/en以下にあるphpファイルを基にlang/php_en.jsonというファイルが出力されます。

これをVue側で読み込んで使用している仕組みのようです(php_en.jsonはViteサーバー終了後には削除されます)。

{
    "auth.failed": "These credentials do not match our records.",
    "auth.password": "The provided password is incorrect.",
    "auth.throttle": "Too many login attempts. Please try again in :seconds seconds.",
    "pagination.previous": "&laquo; Previous",
    "pagination.next": "Next &raquo;",
    "passwords.reset": "Your password has been reset.",
    ...
}

そしてVueのtemplateタグ内で以下のように書けるようになります。auth.phpで記述したテキストが表示されるようになります。

<template>
	<div>
     {{ $t('auth.failed')  }}
   </div>
</template>

これでLaravel側で利用している翻訳ファイルをそのままVueで利用できるようになりました。

おわりに

Laravel Vue i18nを使ってLaravelとVue間で翻訳ファイルを共通化することができました。

設定も簡単でスムーズに動かすことができました。

ただ、共通化することでLaravel側で使わない翻訳テキストもPHPファイルに書いて管理することになるので、運用方法やプロジェクト構成によっては利用を考える必要がありそうです。

Daiki Urata

Daiki Urata

Twitter X

フロントエンド/モバイルアプリなどを主に開発しています。