😎
Laravel+Next(Subpath locale)で多言語化対応
nextjsはすでに記事がいくつかあるように、かなり手軽に多言語化対応ができる。ドメインで指定したりサブパスを切って対応したり、Cookieでもできるらしい。
今回はサブパスでフロントエンドの多言語か対応したので、それに応じてバックエンドからのエラーやレスポンスの多言語か対応もしたので備忘録として残す。
前提
- ユーザーは任意の言語にいつでも切り替えられる
- ロケール判定はサブパス
- httpクライアントはaxios
- axiosはcreateしてから使ってる
方向性としては生成タイミングの問題で煩わしい思いをしたくないので、Interceptor使ってHttpヘッダーに選択されているロケールを入れてしまって、セッションごとにLaravel側でsetLocale
する形にする。
セッションが発生しない処理で多言語化対応が必要なのであればDB等にユーザーの選好言語を保存してあげないと通知、メールの多言語化ができなそうだが、現状そこは要件ではないのでスルー。
frontend
サブパスロケール判定処理
getCurrentClientLocale
import isClient from "@utils/isClient";
const getCurrentClientLocale = () => {
const path = isClient() ? window.location.pathname : "";
if (path.startsWith("/en")) {
return "en";
}
return "ja";
};
export default getCurrentClientLocale;
axiosの生成
Repository.ts
import axios from "axios";
import isClient from "@utils/isClient";
import getCurrentClientLocale from "@utils/getCurrentClientLocale";
import HttpRequestHeaderKeys from "@constants/HttpRequestHeaderKeys";
const Repository = axios.create({
baseURL: isClient()
? process.env.NEXT_PUBLIC_API_ENDPOINT
: process.env.API_ENDPOINT,
responseType: "json",
withCredentials: true,
headers: {
"Content-Type": "application/json",
},
});
Repository.interceptors.request.use((request) => {
request.headers = {
...request.headers,
[HttpRequestHeaderKeys.PREFERRED_LOCALE]: getCurrentClientLocale(),
};
return request;
});
export default Repository;
backend
Laravel Middlewar
SetPreferredLocale.php
<?php
namespace App\Http\Middleware;
use App\Constants\HttpRequestLocaleHeader;
use App\Constants\SelectableLocales;
use Closure;
use Illuminate\Http\Request;
class SetPreferredLocale
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$preferred_locale = $request->headers->get(HttpRequestLocaleHeader::PREFERRED_LOCALE->key());
if ($preferred_locale === SelectableLocales::EN->value) {
app()->setLocale(SelectableLocales::EN->value);
} else {
app()->setLocale(config('app.locale'));
}
return $next($request);
}
}
全てのルートに適応する必要があったのでそのように配置。
Kernel.php
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
//custom middleware
SetPreferredLocale::class
];
laravel側で例外メッセージとか、abortとかうっかりハードコーディングしてると、多言語化されないぞ?ってなってしまうのでお気をつけて。基本__()
で参照する。
Discussion