Accept-Languageを見て言語別に分けるApacheの多言語化をやってみたのでメモ
index.html.ja
とかindex.html.en
とかでApacheだけで多言語化出来る事は一応知ってたけど、phpとか使わないサイトだけど多言語化はするなんて、今までやった事無かった。たまたま、使えそうな機会があったので、やってみました。
ブラウザかのHTTP RequestにあるAccept-Language headerを見て、言語別に振り分けるんですが、複数の言語を優先度付きで設定できたりen-US
といったロケールのサブセットも指定できるので、ちょっと予想しにくい動きをします。
この辺も、色々設定してcurlで確認してみたので書いておきます。というか、こっちを書きたい。
多言語化のやり方
mod_negotiation + mod_mime + FileInfo + Multiviews Options ディレクティブを使った多言語化
いまいち、この方法の名前みたいなのが分からないけど、mod_negotiationが主となる方法っぽい。他のmod_mimeやディレクティブは無くてもやる方法もあるみたい*1だけど、今回は全部セットで使います。
今回は、基本的に日本語のロケールが指定してあれば日本語を、それ以外は英語になる様に設定しました。
コンテントネゴシエーション - Apache HTTP サーバ バージョン 2.2
この機能については、Apacheドキュメントではこのページが詳しい様子。すると、コンテンツネゴシエーションが、この方法の名前ってことになるのかな?なんかしっくりこないけど。
httpd.conf
AllowOverride FileInfo Options=MultiViews
今回は.htaccessに設定を出したので、httpd.confのAllowOverrideに設定します。
後述する.htaccessを、多言語化したいファイルのあるディレクトリに作るけどFileInfo
はAddLanguage
に、Options=MultiViews
は、そのままMultiViews Optionsディレクティブを使う為に。ちなみにAllowOverride All
だとMultiViewsは上書き可能にならないらしい。
.htaccess
AddLanguage ja-jp-mac .ja AddLanguage ja-jp .ja AddLanguage ja .ja Options +MultiViews
AddLanguageの3行は無くても、大抵はhttpd.confに基本的な設定があるので振り分けはされるけど、あった方が多分意図した振り分けになると思う。本当はen-US
やen-GB
とかも書いておいた方が良いのかもしれないけど、あまり深追いしたくなかったので、今回は無しにしました。
用意したファイル
- index.html.ja
- index.html.en
index.htmlは置いてません。あまりちゃんと確認してないけどindex.htmlも置いてあると、多言語化よりもindex.htmlが優先されているようでした。
挙動の確認
$ curl -v -H 'Accept-Language: ja-JP, en;q=0.8' -I http://example.com
基本的にcurlコマンドを使って挙動を確認しました。
Accept-Languageに複数のロケールがあり、優先度が不明な場合、LanguagePriorityによって決まる。
Accept-Language: ja, en
もっと下に、httpd.confのこれに関連する部分を抜粋してあります。そのhttpd.confと前述の.htaccessが設定してある状態で考えます。
ja
とen
が指定されているけど優先度が不明。LanguagePriority
ではen
が最優先なので、index.html.enが出力される。
AddLanguage ja .jaはAccept-Language: ja-JPとは合致しない
とても不便ですが、ロケール*2のサブセットはサブセット無しのものには合致しないようです。と書いても、かなり分かりにくいと思うので具体例を書きます。
AddLanguage ja .ja AddLanguage en .en Accept-Language: ja-JP, en;q=0.8
この例では、AddLanguageがこの2つだけの場合で考えます。AddLanguage ja-JP .jp
という設定が無いので、優先度が0.8のen
が選択されて、index.html.enが出力されます。前述のやり方でja-JP
やja-JP-mac
を設定してるのは、この為です。
サブセットのあるロケールだけを指定した場合は、希望した言語が選択される場合がある
AddLanguage ja .ja AddLanguage en .en Accept-Language: ja-JP
この例でも、AddLanguageがこの2つだけの場合で考えます。AddLanguage ja-JP .jp
という設定が無くLanguagePriority
ではenが最優先なのでen
が選択されると思いきや、ja
が選択されます。
AddLanguage ja .ja AddLanguage en .en Accept-Language: ja-Foo, ja-Bar
こんな、あり得ないロケールであっても、ロケールがja
系のみしか指定されてないなら、LanguagePriority
に関わらずja
が選択されるみたい。
前述の挙動はForceLanguagePriorityの設定による
ForceLanguagePriority Prefer Fallback #ForceLanguagePriority Prefer #ForceLanguagePriority Fallback
これはPrefer
とFallback
の、2つの場合でLanguagePriority
を使うかどうかを設定します。ForceLanguagePriority Prefer Fallback
の場合は、どちらの場合でもLanguagePriority
を使います。
Apacheドキュメントの挙動について書いてあるところ
httpd.confにある設定の抜粋
# # DefaultLanguage and AddLanguage allows you to specify the language of # a document. You can then use content negotiation to give a browser a # file in a language the user can understand. # # Specify a default language. This means that all data # going out without a specific language tag (see below) will # be marked with this one. You probably do NOT want to set # this unless you are sure it is correct for all cases. # # * It is generally better to not mark a page as # * being a certain language than marking it with the wrong # * language! # # DefaultLanguage nl # # Note 1: The suffix does not have to be the same as the language # keyword --- those with documents in Polish (whose net-standard # language code is pl) may wish to use "AddLanguage pl .po" to # avoid the ambiguity with the common suffix for perl scripts. # # Note 2: The example entries below illustrate that in some cases # the two character 'Language' abbreviation is not identical to # the two character 'Country' code for its country, # E.g. 'Danmark/dk' versus 'Danish/da'. # # Note 3: In the case of 'ltz' we violate the RFC by using a three char # specifier. There is 'work in progress' to fix this and get # the reference data for rfc1766 cleaned up. # # Catalan (ca) - Croatian (hr) - Czech (cs) - Danish (da) - Dutch (nl) # English (en) - Esperanto (eo) - Estonian (et) - French (fr) - German (de) # Greek-Modern (el) - Hebrew (he) - Italian (it) - Japanese (ja) # Korean (ko) - Luxembourgeois* (ltz) - Norwegian Nynorsk (nn) # Norwegian (no) - Polish (pl) - Portugese (pt) # Brazilian Portuguese (pt-BR) - Russian (ru) - Swedish (sv) # Simplified Chinese (zh-CN) - Spanish (es) - Traditional Chinese (zh-TW) # AddLanguage ca .ca AddLanguage cs .cz .cs AddLanguage da .dk AddLanguage de .de AddLanguage el .el AddLanguage en .en AddLanguage eo .eo AddLanguage es .es AddLanguage et .et AddLanguage fr .fr AddLanguage he .he AddLanguage hr .hr AddLanguage it .it AddLanguage ja .ja AddLanguage ko .ko AddLanguage ltz .ltz AddLanguage nl .nl AddLanguage nn .nn AddLanguage no .no AddLanguage pl .po AddLanguage pt .pt AddLanguage pt-BR .pt-br AddLanguage ru .ru AddLanguage sv .sv AddLanguage zh-CN .zh-cn AddLanguage zh-TW .zh-tw # # LanguagePriority allows you to give precedence to some languages # in case of a tie during content negotiation. # # Just list the languages in decreasing order of preference. We have # more or less alphabetized them here. You probably want to change this. # LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW # # ForceLanguagePriority allows you to serve a result page rather than # MULTIPLE CHOICES (Prefer) [in case of a tie] or NOT ACCEPTABLE (Fallback) # [in case no accepted languages matched the available variants] # ForceLanguagePriority Prefer Fallback
httpd.confはこんな感じで、たぶんCentOSでyumで入れたApacheのままになっていると思います。今気がついたけどDefaultLanguage
がコメントアウトされたままで、これをちゃんと設定したら、また挙動変わるのかも。