多国対応ウェブアプリを開発する前に知っておきたかったこと

# はじめに

最近仕事で多国対応（主に英語圏）のアプリを初めて作った訳ですが、わからないなりにいろいろ事前準備をしたにもかかわらず、実装から運営まであらゆるフェーズでこけました。そんなわけで、あんな苦労は二度としたくないし、他の人にもして欲しくないので、気をつけたい点を共有します。


# プログラミング

- 日付のフォーマットは、国毎に表現が違う。Railsの場合、[I18n.l](http://guides.rubyonrails.org/i18n.html#adding-date-time-formats)で自動変換可能。
  - 【日】2015年3月10日
  - 【米】03/10/2015
  - 【独】10.3.2015
- 国によって小数点や千単位の区切り方が違う。バリエーションが多すぎるので、ライブラリ使っての対応が必須。Railsの場合、[number_with_delimiter](http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#method-i-number_with_delimiter)で実現可能。気になる人に→[バリエーションリスト](http://boards.straightdope.com/sdmb/showpost.php?p=2811033&postcount=23)。
+ 英語は単数形(Singular)、複数形(Plural)、所有格(Possessive)などで単語が変わる。これらはとにかく[ルールが多い](http://manapedia.jp/text/index?text_id=505)上に[例外も沢山](http://www.prdaily.com/Main/Articles/39_plural_forms_that_might_confuse_writers_10648.aspx)あるのでライブラリ必須。Rails の場合、[rails-i18n](https://github.com/svenfuchs/rails-i18n) で対応可能。(Possessive対応には[possessive gem](https://github.com/bclubb/possessive))
- 米国だけ[メートル法](http://ja.wikipedia.org/wiki/%E3%83%A1%E3%83%BC%E3%83%88%E3%83%AB%E6%B3%95)ではなく[ヤード・ポンド法](http://ja.wikipedia.org/wiki/%E3%83%A4%E3%83%BC%E3%83%89%E3%83%BB%E3%83%9D%E3%83%B3%E3%83%89%E6%B3%95)、摂氏ではなく華氏。Railsの場合、[rails-units](https://github.com/scpike/rails-units)で変換可能。
- 英語では例えば、「リンゴ１００個」を翻訳した場合、「100 Apples」となり、単位が主語の先頭にくる＋助数詞が無い。単位と主語を１つの翻訳データとして扱わないと英語で表現できなくなる。
  - 悪い例）コード: <code> t(".apple") + count + t(".amount")</code>
  - 良い例）コード: <code> t(".x_items", item: t(".apple"), count: count)</code> <br>　　　　翻訳の定義(英): <code>x_items: "%{count} %{item}"</code> <br>　　　　翻訳の定義(日): <code>x_items: "%{item}%{count}個"</code>　
- DBのデータは翻訳が必要な文字列カラムだけ切り出して別のテーブルを作る。国別にサーバーを持つなら、国毎に翻訳カラムを直接編集することもでるが、更新作業にかかるコストが高い上に作業ミスが発生しやすいのでお勧めしない。Railsの場合、[Globalize](https://github.com/globalize/globalize) がお勧。
- Javascriptを使う場合、翻訳用の文字列を直接Javascriptの文字列として出力してはいけない。[handlebars.js](http://handlebarsjs.com) や [underscore.js の_.template](http://underscorejs.org/#template)を使って、ロジックをHTML側に書く。
- どうしてもJavascript側で出力する場合、クオテーション（’）やダブルクオテーション（”）は、エスケープして出力させる必要がある。よく英語圏ユーザーの入力データーで使われているので、要注意。Railsの場合、[<%=j %>](http://api.rubyonrails.org/classes/ActionView/Helpers/JavaScriptHelper.html#method-i-escape_javascript)で簡単にエスケープ可能。
- 英語は基本日本語より文字が長くなる。ドイツ語はもっと長くなる。事前にこうなる事を想定してボタンなどの横幅に余裕を持ったデザインにしておく事が理想的。だが、完全に事前把握するのは困難なので、崩れたデザイン部分は後追いで、CSSでルールを上書いて対処する。例えば、<code>.title</code>というルールがあるとする。そして英語版でルールを上書きしたいとする。その場合、body などの要素のヒエラルキーのトップに、<code>.lang-[言語]</code> (例えば<code>.lang-en</code>)などのクラス名を追加して、<code>.lang-en .title</code>というルールを定義することで、英語版専用のプロパティを適応する事ができる。
- あまりに表現が苦しい時は、文字ではなく画像で対応するのもあり。画像にしたら、配置やフォントを自由に行えるので便利。これを実現する場合、言語専用パスを画像にも設ける必要有り。
- ユーザー入力に対するNGワードフィルタなどは、言語毎に特徴が異なるので、慎重に導入する必要がある。下手するとフィルタしたくない言葉まで大量にフィルタしてしまう事になる。


# インフラ・ミドルウェア
- サーバーのシステム設定で時刻設定にはUTCを使う。最低でもDST(サマータイム)を使わない地域に設定しておく。これがDST有りの地域だとcrontabがDSTの切り替わりのタイミングでおかしな動作をする。crontabの仕様としては、1時間以上の間隔で実行されるジョブはDSTで時間が進んだ時には即実行され、時間が遅れた時には２度実行されないようになっていて、1時間以内の間隔で実行されるジョブは普通にスケジュールされる。詳しくは [crontab の man page](http://man7.org/linux/man-pages/man8/cron.8.html) 。
- DBの時間の保存にもUTCを使う。こちらも間違えてDSTが適応される国にしてしまうと、クエリーを投げてる間に時間がずれた場合、結果がおかしくなる。
- サーバー、ミドルウェア、アプリケーション全てのタイムゾーンを一致させる。一つでも違う値を使っていると運営がカオスになる。後で発見しても移行後の動作確認が地獄に。
- 【MySQL限定】コラムの utf8 ではなく utf8mb4に設定する。MySQLのutf8は 3バイトまでしか対応していないので、一部の絵文字などに対応できない。ちなみにutf8mb4は、MySQL 5.5.3以降のみ対応。


# 翻訳
- 事前に翻訳する人に話をし、最も快適な翻訳のフォーマットやフローを模索し確立しておく
    - いろんなケースをお互い把握しないといけないので結構時間が掛かる
    - 実際にモノが出てきてからやろうとすると、もたついて全体のフローのボトルネックになったり、中途半端なフローが出来上がったりする
- 翻訳サンプルを作って翻訳者と共に事前にツールやフローの検証をしておく
    - 検証せずにツールを選ぶと、後で発覚したツールの制約や限界を運営やプログラムでカバーする羽目になったり、別のツールを併用したりすることになり、フローがカオス化する
- 翻訳者はなるべく日本語と翻訳対象言語をネイティブに話せる人にする
    - ネイティブな翻訳ができないと文脈がずれたり、物の例えなどが直訳されて意味不明になって全部やり直しになる
    - もしくはこちらがベースとする言語を英語にする
        - 日本語から他言語にネイティブな翻訳できる翻訳者の人口は少ないが、英語から他言語にネイティブ翻訳できる人口は多いため
        - 長期的に見たらこっちのほうが楽かも


# その他の発見・落とし穴

- 同じ英語圏でも米国・英国・豪州等で表現や書き方が違う。スペイン語も同じ。
- アメリカ、カナダは西海岸と東海岸で3時間の時差がある。
- カナダは英語とフランス語、両方とも公用語。