はてなにおける
Web アプリケーションの国際化

前回

国際化とは何か

Wikipedia によると定義は

国際化 (アメリカ英語: internationalization イギリス英語: internationalisation、i18n) は、ソフトウェアに技術的な変更を加えることなく多様な言語や地域に適合できるようにする、ソフトウェア設計の工程である。

地域化 (アメリカ英語: localization イギリス英語: localisation、L10N) は、地域固有の構成部品や翻訳テキストを追加することによって、ソフトウェアを特定の地域や言語に適合させる工程である。

Wikipedia: 国際化と地域化

本発表ではもう少し広く、世界的に Web アプリケーションを提供するための諸々を取り上げます。

はてなサービス国際化の歴史

2006
Hatena Inc. 設立
Hatena::Serif
2007
Ridge::Plugin::I18N
Hatena::WWW Hatena::Message Hatena::Star Hatena::Haiku Hatena::World Hatena::Diary[com]
2009
Hatena::Translator
Hatena::Ugomemo Hatena::Bookmark[Fx] (Hatena::Haiku2)
Hatena::WWW Hatena::Message Hatena::Star Hatena::Diary[com] (リニューアル)
2010
Hatena::Monolith Hatena Developer Center (Hatena::Coco Hatena::Land)
Hatena::Haiku (リニューアル)
2011
Hatena::Blog
Hatena::FAQ (リニューアル)
2012
(Hatena::One)

国際化の要素

サービス

ユーザーサポート

コミュニティ設計・運営

広告営業

法務

翻訳

デザイン

課金と通貨

コンテンツの言語

アルゴリズム

アプリケーション

テキストの言語

テキスト管理

機械翻訳

数値

日付

国・地域

文字コード・フォント

インフラ

ドメイン・DNS

データセンター・クラウド

ストレージ

CDN

だいたいの目次

テキストの言語

Web アプリケーションのテキスト

どこで実装するのか

GNU gettext

printf (gettext ("Hello, world!\n"));
en.po
msgid "Hello, world!\n"
msgstr "Hello, world!\n"
ja.po
msgid "Hello, world!\n"
msgstr "こんにちは、世界。\n"

Locale::Maketext::Simple

use Locale::Maketext::Simple;
print loc("Hello, World!");
sub default : Public {
    ...
    $r->res->content($r->loc('hello_world'));
}

<p>[% l('hello_world') %]

テキスト管理

Hatena::Translator

はてなは高い技術力を誇る会社です。効率よくなおかつ正確に翻訳作業が進行するよう、翻訳システム「Hatena::Translator (はてな翻訳)」を自社で開発し、国際化に挑みました。

国際化を果たした「うごメモ」の世界での盛り上がりと自社開発翻訳システム「Hatena::Translator」

テキストメッセージ取得の新実装 (2009)

モジュール変更によるサーバー負荷の低下

メッセージデータ .pm ファイル

フレームワークと国際化

フレームワークと国際化 (続き)

ロケールオブジェクト (2009)

$channel->name_for_locale($r->locale);
$movie->to_rss_item(locale => $r->locale);
MyApp::Message->new(
    locale => $user->create_locale,
    body_template => ...,
);
[%- MACRO loc(text, args1, args2, args3, args4) BLOCK;
   r.locale.text(text, args1, args2, args3, args4);
END; -%]

言語の識別と選択

いったん話は飛びますがまた後でテキストの話に戻りますwww

IETF の言語タグ

ja日本語
en-GB英語 (イギリス)
es-021スペイン語 (北米)
zh-Hant-tw繁体字中国語 (台湾)

短い言語タグ

ja-JPja 日本語
en-USen 米語
en-GBen-gb 英語

HTTP Accept-Language: 要求ヘッダー

Accept-Language: ja,en-US,en-GB

言語の決定

うまく決定できない例

Accept-Language: en-US,ja,en

言語決定の優先順位

  1. URL により明示されている言語
  2. 言語選択メニューで設定した Cookie (あれば)
  3. ユーザー設定で設定した言語 (DB から)
  4. HTTP Accept-Language: の言語
  5. hatena.ne.jp ドメインなら日本語
  6. クライアントのIPアドレスに基づく推定値

URL による言語の明示

言語決定ふりかえり

言語選択メニュー

URL と言語選択

URL と言語選択 (続き)

言語別 URL の形式はどれが良いか

テキスト以外の国際化

画像

[%- loc_img('hoge') -%]

はこう展開される:

<img src="/images/en/hoge.png" alt="[% loc('image.hoge') %]">
<img src="/images/fr/hoge.png" alt="[% loc('image.hoge') %]">

デザイン

数値

12,345.67 日米英、加(英語)など
12 345,67 仏、加(仏語)、スイス(数値)など
12.345,67 独伊蘭など
12'345,67 スイス(価格)

数値の書き方

数字

数値に記号を入れるべきか?

スター
なんとなく見慣れているので記号無しのままにした
価格・ポイント数
何かのはずみで見慣れぬ表記が出て誤解したらまずい気がして、記号無しのままにした
12.345 ポイント
12ポイントと1000分の345? 1万2345ポイント?

日付表記

いつでもローカライズするべきか

数値や日付の表記のバリエーション

日時の書式の管理

日付の入力

タイムゾーン (時間帯)

タイムゾーンの決定

タイムゾーンの名前

タイムゾーンデータ管理

ロケールオブジェクトの日時 API

datetime, date, month_day, time, ... 日付の種類
なし / long 長さ
なし / no_tz タイムゾーン変換
なし / html 構文
$locale->datetime_html($dt)
$locale->month_day_no_tz($dt)
$locale->time_html($dt)
[% loc_date($dt) %]
[% loc_datetime($dt) %]

相対時刻っぽい表記

<time datetime="2013-04-04T00:12:44Z" title="2013/4/4 9:12:44">13日前</time>

time 要素の datetime 属性を JavaScript でチェックして、「○分前」をクライアント側で書き換えたりもしている

「日」の境界

うごメモランキング

記号とフォント

記号の意味

文字コード

フォント

bidi

キャッシュと国際化

キャッシュにご注意

クライアント側キャッシュ

クライアント側での国際化

JavaScript と国際化

JavaScript でテキスト

再びテキスト

引数つきメッセージ

単数形・複数形など

複雑なもの

指定した人 (id:hatena と id:hatenastaff) に公開などの条件
%1などの条件
  [
    指定した人 (%1) に公開
      [
        %1 と %2
          [
            id:hatena
            id:hatenastaff
          ]
      ]
  ]

テキストと HTML

メールテキスト

テキストメソッドと HTML メソッド

ロケールオブジェクトの引き回し

多言語テキストのある開発工程

現方式の良いところ

現方式の悪いところ

語形の揺れ

メッセージIDの命名規則

翻訳プロセス

  1. 開発者がメッセージを Hatena::Translator に登録する

    手順はケースバイケース、どれでもいい:

    • デザイナーがテンプレートを書くのと同時に登録する
    • 日本語でテンプレートを書いてから別の人が登録する
    • ディレクターが登録してからエンジニアがそれを使ってテンプレートを書く

    ただし沢山のテンプレートの文言をまとめて登録するのは極めて苦痛な作業なので避けたい

  2. 翻訳対象メッセージに 20130415hogefeature のようなタグをつけて翻訳者に引き渡す
  3. 翻訳が完了したら update-translations.pl で Hatena::Translator からアプリケーションにデータをエクスポートする
  4. 実際に動作させてみてチェック

動的反映

  1. 開発者・翻訳者共有の開発サーバーを用意する
  2. メッセージと開発サーバー上の URL の対応表をスクリプトで登録しておく
  3. Hatena::Translator で反映ボタンを押すと、 その時点でのメッセージセットが Hatena::Translator から開発サーバーに送られる
  4. 翻訳者はその場で翻訳テキストが入ったページを確認できる

メールのテキスト確認

その場翻訳

品質管理

翻訳の品質、いくつかの事例

翻訳発注

翻訳が足りていない場合

Hatena::Translator でのコミュニケーション

Hatena::Translator の一覧ビュー

Hatena::Translator の検索

進捗管理支援

Hatena::Translator のよくある要望

Hatena::Translator アンチパターン

Gengo (旧 myGengo)

国といろいろ

国判定

国コード

価格

単位

たくさんの軸、たくさんの組み合わせ

見ている人の言語
コンテンツ著者の言語
見ている人の地域
コンテンツ著者の地域
タイムゾーン
通貨
hatena.ne.jp vs hatena.com

どう出し分けたらいいのだろう

国旗

この画像は、旗、紋章、印章等といった公式の記章を表しています。このようなシンボルの使用については、多くの国で制限されています。これらの制限は、著作権の状態に関わらず適用されます。

Wikimedia における注意文

Until 2004, the flag was used exclusively on or in front of buildings owned by the government, ministries, statutory boards and educational institutions on a year round basis. The flag could only be flown by individuals and non-governmental organisations during the month of August to mark the country's national day on 9 August.

シンガポール国旗のレギュレーション

プライバシー

CLDR

国際化サービス設計と実装

コンテンツの言語

ハイクの場合

うごメモの場合

うごメモのチャンネル

コメント翻訳

ハッピィ

ハッピィショップ

言語の障壁

固有名詞

氏名

氏名の設定

住所

地域の選択

学校

地図

東京都や環境省のインターネットサイトの地図で日本海の名称に韓国が主張する「東海」、沖縄県・尖閣諸島には中国名の「釣魚島群島」が併記されていたことが12日、分かった。米インターネット検索大手「グーグル」の地図ソフト「グーグルマップ」のデータを使用したためで、既に併記を削除、またはサイトを閉鎖、修正している。

地図に「東海」「釣魚島群島」 東京都や環境省のサイト

多言語データ構造

アルゴリズムの国際化

はてなブログ

ヘルプ

FAQ

Hatena Developer Center

告知日記

メンテナンス画面

まとまらない