
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、昨今の話題はコロナウィルスの影響を受けた制限ばかりでしたが、先日のニュースで「2022年6月から入国検査がさらに緩和される」と聞き、以前のインバウンド旅行客が少しずつ帰ってくるのでは、感じています。
そして、この流れもあって「Laravel + DeepL で自動翻訳機能をつくる」という記事を公開したのですが、実はもうひとつ多言語化に必要なのものがあります。
それが・・・・・・
言語の切り替え
です。
そして、同じURLで言語ごとに内容を切り替えてもいいのですが、「うーん、それって SEO 的に OK なのかな…」という疑問があったので、今回は、
サブドメインごとに言語を割り振る
という実装をしてみます。
つまり、以下のような形ですね。
- example.com: メイン(日本語)
- en.example.com: 英語
- zh.example.com: 中国語
- ko.example.com: 韓国語
- vi.example.com: ベトナム語
ぜひ何かのお役に立てたら嬉しいです。
「姪っ子の英語力に感動
」
開発環境: Laravel 9.x、nginx 1.18.0、Ubuntu 20.04
目次 [非表示]
前提として
今回は便宜上、l9x.test
というドメインを使って開発を進めていきます。
皆さんはご自身のお好きなドメインに置き換えてくださいね。
nginx の設定
では、まずはウェブサーバーのnginx
の設定です。
server_name
を正規表現で以下すべてのドメインに対応させます。
- l9x.test
- en.l9x.test
- zh.l9x.test
- ko.l9x.test
- vi.l9x.test
server {
listen 80;
listen [::]:80;
server_name "~^((en|zh|ko|vi)\.)?l9x\.test$";
# 省略
}
※ テストなので「HTTP」接続のみをご紹介していますが、本来は443
ポートの「HTTPS」バージョンも設定してください。
※ もしLet's encrypt
(certbot
)でHTTPS
対応させる場合、正規表現には対応できていないようでした。その際はめんどうですが、ひとつずつサブドメインをセットしてください。
そして、設定を保存したら以下のコマンドでnginx
を再起動します。
sudo systemctl restart nginx
ドメイン名とIPアドレスを一致させる(hosts)
次に、(開発環境の場合)ブラウザで「l9x.test」などのドメインにアクセスできるようドメイン名を一致させる必要があります。これは、OSごとに設定方法が違うので以下の「Google検索」を参照してください。
- Windows: windows hosts 設定
- MacOS: mac hosts 設定
※ 本番環境の場合はドメインのDNS
設定になります。
なお、私が使っている(少数派の)Ubuntu
の場合は、以下のコマンドでhosts
ファイルを開きます。
sudo gedit /etc/hosts
そして、中身を以下のようにして保存します。
127.0.1.1 l9x.test
127.0.1.1 en.l9x.test
127.0.1.1 zh.l9x.test
127.0.1.1 ko.l9x.test
127.0.1.1 vi.l9x.test
これで、ブラウザから「l9x.test」などのドメインにアクセスができるようになりました。
ドメイン名で言語を自動的に切り替える
では、ここからはLaravel
側の実装になります。
アクセスしてきたドメインごとに言語をセットできるようにしていきましょう。
app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Arr;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
// 省略
public function boot()
{
$host_name = request()->getHost();
$locales = [
'l9x.test' => 'ja',
'en.l9x.test' => 'en',
'zh.l9x.test' => 'zh',
'ko.l9x.test' => 'ko',
'vi.l9x.test' => 'vi',
];
$locale = Arr::get($locales, $host_name, 'ja'); //
見つからないときは日本語
app()->setLocale($locale);
}
}
※ なお、本来は今後のことを考えて$locales
はどこか別の場所(Enum
やモデルの定数として一元管理しておいた方がいいでしょう)
コードを見ていただくと分かるとおり、ドメイン名を使って2文字の言語コードを取得し、それをセットしているだけです。
なお、もし言語が見つからない場合は日本語(ja)になるようにしています。
では、これでドメインごとに言語設定ができるようになりました!
各言語ファイルをつくる
続いて、各言語の翻訳ファイルの作成です。
Laravel
に標準で搭載されている言語機能を使ってlang
フォルダ以下にそれぞれファイルを作成しましょう。
lang/ja/message.php
<?php
return [
'greeting' => 'こんにちは!',
];
lang/en/message.php
<?php
return [
'greeting' => 'Hello!',
];
lang/zh/message.php
<?php
return [
'greeting' => '你好!',
];
lang/ko/message.php
<?php
return [
'greeting' => '안녕하세요!',
];
lang/vi/message.php
<?php
return [
'greeting' => 'xin chào!',
];
はい
これで設定はすべて完了です。
お疲れ様でした。
テストしてみる
では、実際にうまくいっているかPHPUnit
を使ってテストしていきましょう!
まずは次のルートを追加してください。
routes/web.php
Route::get('locale_via_domain', fn() => trans('message.greeting'));
これは、例えば「http://l9x.test/locale_via_domain」へアクセスすると、「こんにちは!」と表示されるものです。
もちろん、ドメインごとに以下のように表示が切り替わります。
- l9x.test: こんにちは!
- en.l9x.test: Hello!
- zh.l9x.test: 你好!
- ko.l9x.test: 안녕하세요!
- vi.l9x.test: xin chào!
続いて、以下のコマンドでPHPUnit
のテストファイルを作成してください。
php artisan make:test LocaleTest
すると、ファイルが作成されるので中身を次のように変更します。
tests/Feature/LocaleTest.php
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class LocaleTest extends TestCase
{
public function test_can_see_greetings()
{
$locales = [
'l9x.test' => 'ja',
'en.l9x.test' => 'en',
'zh.l9x.test' => 'zh',
'ko.l9x.test' => 'ko',
'vi.l9x.test' => 'vi',
];
foreach ($locales as $domain => $locale) {
$url = 'http://'. $domain .'/locale_via_domain';
$content = file_get_contents($url);
$greeting = trans('message.greeting', [], $locale);
$this->assertEquals($content, $greeting);
}
}
}
※ ちなみにLaravel
が用意してくれている$response = $this->get($url);
というコードを使ってしまうと、実行側の言語の影響を受けてしまうようだったので、file_get_contents()
を使っています。
では、実際にチェックしてみましょう
php artisan test --filter LocaleTest
どうなったでしょうか・・・・・・
はい
うまくテストが通りました。
成功です
実際の使用例
私が個人的に運営している「街角コレクション」を「英語」「中国語」に対応させました。
興味のある方はぜひご覧ください
ちなみに:日本語だけにしたいページがあるとき
ちなみに、「このページだけは日本語だけにしたいな(翻訳を提供できないな)」という場合は、ミドルウェアで対応できます。
例えば、「en.example.com」や「zh.example.com」でアクセスしてきたときは、通常の「example.com」へ強制的にリダイレクトするわけですね。
このような場合の手順は次のとおりです。
まず以下のコマンドでミドルウェアを作成します。
php artisan make:middleware OnlyJapaneseMiddleware
するとファイルが作成されるので中身を次のように変更します。
app/Http/Middleware/OnlyJapaneseMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class OnlyJapaneseMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$locale = app()->getLocale();
if($locale !== 'ja') {
$baseUrl = config('app.url');
$uri = $request->getRequestUri();
$url = $baseUrl . $uri;
return redirect($url);
}
return $next($request);
}
}
そして、ミドルウェアをLaravel
へ登録します。
app/Http/Kernel.php
// 省略
protected $routeMiddleware = [
// 省略
'only_japanese' => OnlyJapaneseMiddleware::class, //
ここ
];
そして、ルートやコントローラーで「only_japanese」をセットしてやればOKです。
routes/web.php
Route::get('test', [TestController::class, 'index'])
->middleware('only_japanese') //
ここ
->name('test.index');
企業様へのご提案
今回の機能を使うと、「サイトはひとつで言語ごとにサイトを用意する」ことができるようになります。
さらにサブドメインを使って言語の切り替えをしているので、閲覧する側にも分かりやすく、Laravel
側での対応コードを極力減らすことができます(つまり、開発スピードを上げることができます)
また、サブドメインを作成するだけで言語の増減をさせることもでき、よりフレキシブルな体制を準備することもできます。
もしサブドメインを利用した多言語化をご希望でしたら、いつでもお問い合わせからご連絡ください。
お待ちしております。
おわりに
ということで、今回は「サブドメインを使って多言語化」を実装してみました。
近年は、私の地元にも中国や韓国料理だけでなくベトナム料理のお店を目にすることも増えました。つまり、よりグローバル化が進んでいるのは間違いないので、サイトの多言語化はより重要になっていくんじゃないかと感じています。(スーパー翻訳機ができたら話は別ですが…まだ完璧とまではいかないですよね)
さらに、日本は人口減少時代を迎えていますので、徐々に「モノを売るのは海外しかない」という状況にもなってきていると思います。
ぜひ皆さんのサイトも多言語化を考えてみてくださいね。
ではでは〜
「久しぶりにチャプチェが
食べたい!
あまりおいてないんですよね…」