menu

はじめに

この前、サーバーのPHPフレームワークはlaravelを使い、クライアントのjavascriptはriot.jsを使って開発をしていて 多言語化する必要が出ました。laravelを使っている部分はtrans()を使って簡単に多言語化できたのですが、riot.jsを使っている部分が laravelのtrans()が使えずに、JSONで英語、日本語を用意して、mixinで共有し言語ごとに使い分けるようにしようとしましたが、これだと 管理が煩雑になりあまり良くありませんでした。

そこで、riot.jsを使っている部分もlaravelのtrans()を使って多言語化できないかと考え工夫をしたところ、実装することができました。 この記事ではそのやり方を説明します。

laravelの多言語化

laravelの多言語化の方法を簡単に説明します。公式ドキュメントは以下になります。

まずは、言語の文字列を定義するファイルを言語の数だけ用意します。英語と日本語を用意する場合は以下のようになります。

/resources
  /lang
    /en
      messages.php
    /ja
      messages.php

/en/messages.php、/ja/messages.phpに以下のように記述します

/en/messages.php
		<?php 
			return [
				'welcome' => 'Welcome to our application'	
			];
		
/ja/messages.php
		<?php 
			return [
				'welcome' => '私たちのアプリケーションへようこそ'
			];
		

これで多言語化の準備はできました。あとは表示したいところに以下のように記述します。

			//Welcome to our application(英語)
			//私たちのアプリケーションへようこそ(日本語)
			{{ trans('messages.welcome') }}
		

riot.jsでlaravelの多言語化が使えない理由

laravelの{{ }}やPHPの<?php echo "";?>はそれぞれ拡張子が blade.php、phpのファイルでないと機能しません。それなら、riot.jsのタグファイルは拡張子を自由に決められるので、 blade.phpにしてしまえばいいんじゃないかと思いますが、jsファイルなどを置くpublicフォルダの下にblade.phpの拡張子の riot.jsタグファイルを置いてみましたが、publicの下では正しくコンパイルされずうまくいきませんでした。

いろいろ試すうちに、どうやらroutes.phpでルーティングした先のblade.phpファイルでないと{{ }}が機能しないことが わかりました。routes.phpでルーティングしつつriot.jsファイルを読み込むようにします。

riot.jsのタグの中で{{ }}を機能させる

routes.phpでルーティングできるのは「/resources/views」フォルダの下になります。そこで以下のようにファイルを配置します。

/resources
  /views
    /tags
      test.blade.php

ここで、test.blade.phpは拡張子はlaravelのBladeテンプレートですが、中身はriotのカスタムタグです。 このタグを読み込むために、読み込みたいファイルの中で以下のように記述します。

			<script src="tags/test.tag" type="riot/tag"></script>
		

ポイントはsrcに実際のファイル名を指定するのではなく、test.blade.phpのフォルダ配置と同じでなおかつ、拡張子を「tag」と書くことです。 その後、routes.phpに次のように記述します。

			Route::get('/tags/{filename}.tag', function($filename){
				return view('tags/'. $filename);
			});
		

このように書くことで$filenameに「test」の文字列が入り、return view('tags/test');と書いたのと同じことになります。 この書き方はまさに/resources/views/tags/test.blade.phpを読み込む書き方です。読み込まれた結果、test.blade.phpファイルに 以下のように記述があれば、それが評価されて多言語化ができます。

			//Welcome to our application(英語)
			//私たちのアプリケーションへようこそ(日本語)
			{{ trans('messages.welcome') }}
		

追記-2016年4月6日

上記の記述は簡単に書かれていてわかりづらいところがあるかもしれませんので、説明を追記します。

用意するファイルを整理します。
1.hoge.blade.php --- riot.jsタグを読み込む、サイトに表示するページ。laravelのbladeファイルです
2.tags/test.tag --- 存在しないですが、読み込もうとするファイル。ここにriotの記述をするわけでありません
3.routes.php --- laravelのルーティングをするファイル。laravelのプロジェクトであれば必ず存在します
4.tags/test.blade.php --- blade.phpの拡張子ですが、中身はriot.jsです。ここにriot.jsの記述をします

それぞれのファイルの中身を抜粋します。

//hoge.blade.php
<!DOCTYPE html>
<html>
    <head>
        <title>@yield('title')</title>
        <meta name="description" content="@yield('description')">
        <meta name="keywords" content="@yield('keywords')">
		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
		//riotタグの読み込み
		<script src={{ URL::to('tags/test.tag') }} type="riot/tag"></script>
        
    </head>
    <body>
    	//riot.jsのtest.blade.phpで定義されているタグです
    	<test></test>
    	・・・省略・・・
    </body>
</html>
		
//tags/test.tag
//このファイルは存在しません。一応、public/tags/test.tagの場所にあることを想定していますが、
//用意する必要はありません。
		
//routes.php
<?php
Route::get('/', function () {
    return view('indexView');
});

Route::get('/multi-language', function(){
	return view('laravel/multiLanguageView');
});
//書くべきポイントはここです
//resources/views/tags/test.blade.phpを読み込みます
//$filenameにtestが入ります
Route::get('/tags/{filename}.tag', function($filename){
	return view('tags/'. $filename);
});
		
//tags/test.blade.php
<test>
	<div name="welcome-message">
		//多言語化したい文言を出力します。
		//riotタグの中でlaravelのtrans()を使っています。
		{{ trans('messages.welcome') }}
	</div>
	<style>
		・・・省略・・・
	</style>
	<script>
		var self = this;
		self.on('mount', function(){
			console.log('hoge');
		});
	</script>
</test>
		

詳しく説明すると、hoge.blade.phpで
<script src={{ URL::to('tags/test.tag') }} type="riot/tag">
が読み込まれるときにroutes.phpの
Route::get('/tags/{filename}.tag', function($filename){});
に処理が遷移します。ここで
return view('tags/'. $filename)
によって、test.blade.phpが返されます。
このときに返されるtest.blade.phpは、laravelの記述の 部分がサーバー側で解釈された後のファイルになります。
つまり、{{ trans('messages.welcome') }}が   解釈された後になっているということです。
解釈後は普通のriotファイルと同じなのでriotタグが読み込まれたのと同じことになります。

追記2 - tags/hoge/test.blade.phpの場合

読み込みたいriotファイルのフォルダ階層が/tags/test.blade.phpだけではなく、
/tags/hoge/test.blade.phpのように深い階層になることもあります。
この場合はroutes.phpに記述を増やせばうまくいきます。

//route1
Route::get('/tags/{filename}.tag', function($filename){
	return view('tags/'. $filename);
});
//追記。/tags/hoge用のroute定義
Route::get('/tags/hoge/{filename}.tag', function($filename){
	return view('tags/hoge/'. $filename);
});
		

フォルダ階層が変わったらその分だけroutes.phpに上記のように追記していきます。
鋭い人はあることに気づくかもしれません。route1だけでfilenameにhoge/test.tagが入って読み込むことができるのではないかと。
しかし、その通りにはなりません。filenameに「/」が入っていると正しく読み込まれないのです。404が返ってきます。
フォルダ階層が増えたらその分だけrouteを追加しましょう。