Safie Engineers' Blog!

Safieのエンジニアが書くブログです

Safieのサービスを国際化対応した話(モバイルアプリ編)

この記事は Safie Advent Calendar 15日目の記事です。

はじめに

こんにちは。開発本部モバイルグループの池田です。

私は普段、モバイルグループのマネジメントおよび Safie Viewer for Mobile の PdM としてお仕事をしていますが、今年はそれに加えて国際化対応の開発PMとしても活動してきました。

今年の初めに海外展開のための組織が立ち上がり、そこの社内募集に手を上げて、兼務でお手伝いすることとなったためです。セーフィーではこのように、社内でも新しい試みにチャレンジしやすい制度が整っています。

実は、2023年中にセーフィーはグローバル進出のためのビジネス立ち上げ準備と開発を進めており、Safie Viewer モバイルアプリは英語・ベトナム語・タイ語への対応をリリースしています。また時差対応もほぼ完了し、以前はいくつか問題のあった日本以外のタイムゾーンでも、正しく快適に使えるようにアップデートされています。

エキゾチックSafie!!

今回は、主にモバイルアプリの開発に着目して、セーフィーのグローバル対応について書いてみたいと思います。(Web フロントエンドやサーバー、デバイスについても近々きっと書いてくれる人がいると思います!)

国際化(Internationalization)と地域化(Localization)

ソフトウェアを異なる地域や時間に対応するためには、(トートロジー的ですが、)それが「対応できるようにする」必要があります。

扱う言語や地域に汎用性を持たせて、たとえばテキストをソースコードから分離して異なる言語に翻訳しやすくすること、また日付や通貨のフォーマットを動的に変更できるようにすることなどが含まれ、この作業を「国際化」と呼びます。この仕組みはすでに OS やプラットフォームにも含まれている部分が多くあります。

そうして国際化に対応したソフトウェアを、今度は特定の言語・地域に適合させるプロセスを「地域化(ローカライズ)」と呼びます。テキストの翻訳や日付・通貨フォーマットの現地化などの作業がこれにあたります。

一口にローカライズと言っても、そこには多くの要素が含まれます。 言語と文字コード、日時や数値の書式、暦、時差とタイムゾーン、各国の通貨や税金、法規制(電波関連法規や個人情報保護関連法規)への対応などなど。あるいは文化的な背景から利用・推奨できない表現やシンボルがあるかもしれません。ヘルプやユーザーサポートをどうしていくかも重要になってきます。

本記事では、その中でも特に大きな割合を占める多言語対応とタイムゾーン対応について触れていきたいと思います。

(どうでもいいですが、i18n (internationalization) や l10n(localization)という略語、知っててもなかなか使う機会がないので今年はたくさん使えて満足です。笑)

言語について

冒頭にも触れた通り、今年の前半にキックオフされたグローバル進出PJにより、Safie Viewer は英語、ベトナム語、タイ語に順次対応していくこととなりました。

モバイルアプリの開発環境である XCode や Android Studio には、すでに言語ローカライズのための仕組みが用意されています。

iOS の場合は、XCode のプロジェクトの設定で ”Localizations” から対応言語を追加して、生成された Localizable.strings ファイルにその言語でのテキスト定義を追加していけば基本的に OK です。これらを追加することで、OS やアプリごとの言語設定に応じて、UIに表示される言語が切り替わってくれます。簡単ですね。

XCode プロジェクトの Localization

また、リソースファイルの型安全性やオートコンプリートを提供してくれる R.swift の利用によってローカライズ開発の生産性を上げてもいます。

ベトナム語の Localizable.strings ファイル

さて、アプリ UI の多言語化の方法はわかりましたが、アプリに表示される文字列は自らが持つリソーステキストだけではありません。

たとえば動的に変化する設定可能な項目を API で取得して、そのリストを選択メニューに表示したりします。あるいはサーバー側で定義された任意のお知らせメッセージを出したりもします。これらの中にはアプリが予め定義しておくことができないものもあります。

API から返却するレスポンスの言語をクライアントによって変えてもらうにはどうしたらいいでしょうか。それには大きく2つの方法があります。

ひとつは、ユーザーの属性として言語設定を持たせ、それをサーバーで判定して言語を切り替えること。ただしこれはユーザーがログイン済みの場合に限られ、いくつかの匿名 API(購入前お問合せとか)では対応できません。また、環境によってユーザーが言語を変えたい時(職場の PC は英語なんだけどスマホは日本語とか)なども対応が難しいです。

もうひとつは Accept-Language リクエストヘッダを利用することです。これはクライアントがどの言語を理解できるか、どのロケール(地域情報)が推奨されるかのヒントをサーバーに示すものです。一般的なブラウザや HTTP クライアントライブラリは環境から設定を読み取り、ユーザーが意識せずともすでにこのヘッダをリクエストに付加してくれている場合が多いようです。

今回は、これらをハイブリッドに対応することにしました。 すなわち、ユーザーには使用言語の設定を追加して、下記表のような選択を可能とする。且つ、それぞれの場合の Accept-Language を表のようにクライアントで付加して、サーバーでレスポンスを切り替えるようにします。

Webアプリ

ユーザー言語設定 クライアント UI Accept-Language サーバーレスポンス メール、PUSH通知
システム(自動設定) ブラウザ設定に従う ブラウザ設定に従う ALに従う
ALが無ければ日本語
ALがSafie非対応言語なら日本語
日本語
日本語 日本語 ja 日本語 日本語
英語 英語 en 英語 英語
ベトナム語 ベトナム語 vi 英語 英語
タイ語 タイ語 th 英語 英語

※サーバー対応言語は日・英のみ

モバイルアプリ

ユーザー言語設定 クライアント UI Accept-Language サーバーレスポンス メール、PUSH通知
システム(自動設定) OS/アプリ設定に従う OS/アプリ設定に従う ALに従う
ALが無ければ日本語
ALがSafie非対応言語なら日本語
日本語
日本語 OS/アプリ設定に従う OS/アプリ設定に従う 日本語 日本語
英語 OS/アプリ設定に従う OS/アプリ設定に従う 英語 英語
ベトナム語 OS/アプリ設定に従う OS/アプリ設定に従う 英語 英語
タイ語 OS/アプリ設定に従う OS/アプリ設定に従う 英語 英語

※サーバー対応言語は日・英のみ
※モバイルのUI言語はセーフィー設定よりもOS/アプリ設定を優先

このように定義した上でデフォルト設定を「システム(自動設定)」とし、且つ「不明な場合は日本語を優先」とすることで、すでに日本語環境でセーフィーを利用している大半の既存ユーザーには影響がなく、その中でブラウザやスマホを英語やベトナム語で使っている人がいれば何もせずその使用言語に切り替わり、さらに明示的に言語を切り替えたユーザーには、メールやPUSH通知といったサービスも言語切り替えをすることができます。

翻訳について

さて、言語表示仕様とテキストデータの外出しは終わったので、次は翻訳です。

まず英語は社内でなんとかなるだろうと考えました。アプリ UI に表示されるメッセージの類はある程度形式化されていますし、昨今の deepL や ChatGPT などによる AI 機械翻訳は非常に優秀と言われます。迷った時には社内にいる英語話者を頼ることもできそうです。

どうにもならなさそうなのがタイ語とベトナム語です。機械翻訳できたとしてもその精度がどうなのかまったくわかりません。

ここは素直に専門家を頼りましょう。ということで、いくつかの技術翻訳の会社に見積もりを取り、またいくつかの SaaS 翻訳プラットフォームも検討しました。その結果、ある程度老舗として実績があり、またある程度細かく相談もできそうな会社さんに翻訳依頼を出すことに決定しました。

その際、日本語→タイ・ベトナム語よりも英語→タイ・ベトナム語の方が精度が高いというアドバイスを受け、まずは初回だけ社内で行った英訳にチェックを入れてもらい、英語からタイ・ベトナム語への翻訳依頼としています。

(ちなみにその英語チェックではほとんど赤が入らなかったので、社内+機械翻訳で充分いけるという確信を強めることができました。AIの恩恵に喜びながらも、翻訳業界は大変だろうなという思いもありつつ。。)

翻訳について・2

翻訳会社さんとのやり取りは Excel ファイルでのシンプルなものでした。

その際、サービスで利用する固有名詞のルールをまとめて伝えることは重要です。セーフィーであれば「『カメラ』は基本的に”Device”で表します。ただし表現的にスマホと紛らわしい場合は”Camera”も使います」とか、「 “Movie Clip” は他言語でも英語のままで」など。

また、スクリーンショットは可能な限りすべてお渡ししましょう。数十画面・数千ワードという翻訳になるので、ある程度は機械的な作業にならざるを得ず、すべてのサービス文脈を読み取ってもらうことは難しいですが、それでも「ここのスペースにだいたい収まるようにできませんか?」とか「英語での文字幅と同じくらいにできますか?」などのやり取りができる余地を作っていくことも非常に重要です。今回は最初に「基本的に英語でのテキスト幅を越えないようにしたいです」とお伝えしていました。

日付や通貨のフォーマットについてはどうしたら良いでしょうか。

各言語での日付表記

これについては、Google の developer documentation style guide を参考に実装しました。日本語でよく見るスラッシュ区切りの「年/月/日」は他地域ではあまり利用されないなど、様々な知見がありがたく集まっています。

また、Excel(社内では Google スプレッドシートで管理)データのソースコードへの組み込みですが、さすがにコピペではやってられません。ここはスプレッドシートから iOS/Android で必要なリソースファイル(Localizable.strings, values**/strings.xml)へ変換して書き出す Google App Script を書いて省力化しました。

Google App Script による言語リソースファイルの書き出し

ただしこの方法では、言語定義の神様(マスター)が GitHub 管理の外になってしまい、メンバーが各自のブランチで神様データをエクスポートして作業すると、それらをマージするとき多重に定義が追加され、コンフリクトが発生してしまいます。

そこで、今度はリポジトリ中のリソースファイルをまとめて csv ファイルを作成し、それを Google スプレッドシートにアップロードする GitHub Actions のワークフローを書いて、リリースごとに神様データを自動更新していくことにしました。

GitHub Actions によるローカライズ対応スプレッドシートの更新

より効率的な翻訳対応にはまだ改善余地があると思いますが、一旦このような形に落ち着いています。

ちなみに翻訳依頼の頻度としては、英訳はリリースごとに社内で対応し、タイ・ベトナム語はある程度溜まってきた数ヶ月ごとに発注するとして、その間はタイ・ベトナム版には英語が混在することを許容する、といった仕様にしています。

翻訳課題:ベトナム語意外と横長問題

日本語を英語にしたとき、文字数が増えてレイアウトが横長になることへの対応が必要なことは予想していました。 その上で意外と大変だったのがベトナム語です。

日本語とベトナム語のフッタメニュー

英語よりもさらに長い表現になることが多く、QA 確認ではテキストの見切れ指摘が多発しました。 ここは、「ユーザー設定」→「設定」などテキストをシンプルにできないかを検討するとともに、レイアウトに収まらないもののいくつかは英語に戻すことで対応しました。

ここについては複数の著名なアプリをベトナム語設定で見てみて、このくらいは英語でもOKかなという肌感をひとまずの根拠としています。

メジャーなアプリのベトナム語対応例

さらに理想なのは、テキストがなくてもメニューの意味がわかってもらえることですね。ここは自らの認知度とデザイン双方に対しての自信が必要なところだとは思います。

メジャーなアプリのフッタデザイン

それぞれ、どれが何のアプリか、わかりますでしょうか?

翻訳課題:テキストデザインとFigmaのローカライズ

たとえば、これはあくまでも例ですが、このようなダイアログの本文をローカライズするとします。

カメラ再起動の警告ダイアログサンプル

言語リソース定義は以下のように分解すれば対応できます。

“restart_dialog_text_prefix” = “再起動中は”;
“restart_dialog_text_body” = “録画が停止します”;
“restart_dialog_text_suffix” = “ので、しばらく経ってからご確認ください”;

英語はこう。

“restart_dialog_text_prefix” = “”;
“restart_dialog_text_body” = “Recording will be paused”;
“restart_dialog_text_suffix” = “ during the reboot, so please check back after some time”;

このようにして、prefix, body, suffix を結合し、restart_dialog_text_body を赤文字のボールドで装飾するルールにすれば、近い表現の英語になると思います。

しかし、ベトナム語やタイ語ではどうなるのでしょうか。語順がどうなるかわからないし、翻訳者に細かいニュアンスを伝えることも手間がかかりそうです。

こういったことを防ぐためには、

  • できる限りテキストはシンプルにすること(説明無しでわかるUIが最高)
  • テキストの一部を装飾する場合は少なくともセンテンス単位にして、一文を短くすること

などを心がけることが大事になりそうです。ここまでがワンセンテンスだ、よろしいか?

デザインの段階で、国際化を意識した作業ができていると良いですね。

また、今回は既存のアプリをローカライズするという要件と、スケジュールの都合もあり、レイアウト調整などの作業もすべて開発チームで行いました。が、本来は社内で英訳までするのであれば企画・デザインの段階で各言語での見た目を確認できた方が良いはずです。

過去の記事でも触れたように、モバイルチームではデザインのやり取りに Figma を利用しています。Figma 上でのローカライズ方法もこれから調査・検討していくところですが、lokalise などのサービスは試してみたいなと思っています。

時間について

さて、言語の話だけでずいぶん長くなってしまいましたが、お次は時間(タイムゾーン)についてです。

幸いにして、セーフィーのサービス開始当初から、データベース内の時間はすべて UTC で管理されており、また多くの時間関連 API はリクエストに timezone のパラメータを受けて、その時間帯でのレスポンスを返せるようになっていました。(先見の明!)

なので、クライアントとしては基本的に現在の OS のタイムゾーン設定をリクエストパラメータに追加するだけで良さそうです。が、むしろここで悩んだのは仕様の方です。

Safie 三位一体

セーフィーのサービスを構成する基本3要素、カメラデバイス、クラウドサーバー、ビューアークライアントは、地理的にすべて別の場所にいることがありえます。それぞれに OS があり、それぞれのシステムに時間とタイムゾーン情報を持っています。

タイのバンコクに置いたカメラを、ハワイで休暇中のユーザーが見ている時、ビューアーに表示される時間はどこになるのが良いのでしょうか?セーフィーは東京に本社がある日本のサービスですが、そこから「xx時xx分にカメラが動きを検出しました」というメールが来る時、その時間帯はどこになるのが正しいのでしょうか?夜間だけ録画するようにタイマーを設定する UI の時間はどう見せましょうか?

ここもおそらく議論の余地があると思いますが、結論としては

  • クライアントの UI で表示・設定する時間はすべてクライアントの(PCやスマホに設定された)タイムゾーンに従う
  • ただし、カメラ映像に重畳して録画される時間情報は、カメラデバイスのタイムゾーンに従う
    • これは例えば犯罪行為のエビデンスとして映像上に表示された時刻が用いられることがあることを重視して、カメラが見ている「その場所」のタイムゾーンを優先しています
  • メールに記載する時間については、デバイスに関連するものはそのタイムゾーンに従い、”(UTC+09)”といった注記を加える
  • PUSH 通知に載せる時間情報は epoch ミリ秒で表し、受け取ったクライアントは自分のタイムゾーンで適切に再生処理する

などのルールを定めました。

Viewerの時間表示

この対応のため、JST 固定になっていたデバイスのタイムゾーンを可変にできるよう FW を更新してもらい、サーバーとカメラの I/F やメールテンプレート生成などのロジックを変更してもらった上で、クライアントは先述の通りリクエストにタイムゾーンを付加するだけでほぼ対応が終わりました。サーバー・デバイス各チームの尽力に感謝です。このあたりの実装のお話もいつかエンジニアブログで読んでみたいところ。

ちなみに、今回はできるだけシンプルな対応にとどめていますが、タイムゾーンは突き詰めると考えなくてはならないことがたくさん出てくるようです。気になった方は有名な魔導書「タイムゾーン呪いの書」を読んでみてください。

おわりに

日本語と日本時間を前提としていたサービスを、国際化・ローカライズした活動について、ひとまずアプリ視点からのまとめを書いてみました。その後、面接で海外からの候補者がアプリの話をしてくれた時に、英語で何も違和感ないですよと言われてひそかに喜んだりなどしています。さらに対応を拡げていきたいですね。

文中で何度も触れているように、この PJ はモバイル以外も各チーム対応に尽力いただいたので、そちらはぜひ別記事を楽しみにしていていただきたいと思います。(ちなみに国内サービスが初めて海外展開をする際に、多くの場合最も重要なトピックは「クラウドインフラどこでどう構築する?」になると思います)

グローバルを見据えたサービス開発をする方々に、参考になる情報があれば幸いです。

また、セーフィーでは一緒に世界を目指すエンジニアも募集しています!興味をもった方はぜひこちらへどうぞ。

open.talentio.com

© Safie Inc.