この記事はくふうカンパニー Advent Calendar 2019の19日目の記事となります。
Da Vinci StudioでWebエンジニアをしている@TAByasuです。
くふうグループ内の組織であるDa Vinci Studioではグループ内外の受託開発・デザインを生業にしています。
近頃はいくつかの案件で「Webサイト上に機械翻訳の機能を追加できないか」というお問い合わせをいただくことが増えてきました。
そう、Webサイトのヘッダー付近に翻訳対象の言語選択UIが鎮座し選択した言語にWebページをまるっと翻訳してくれる機能です。
有名なところはやはりGoogleウェブサイト翻訳ツールではないでしょうか。
しかし2019年にWebサイトに追加するタイプのGoogle翻訳はサービス終了してしまいました。
当時は無料で提供される翻訳機能の精度の高さと実装の手軽さからWebサイトに機械翻訳を実装するときに真っ先に検討したものでしたが。
もちろん他社が有料提供している機械翻訳サービスも検討の候補にあがります。
しかし導入したいサービスの規模に対してコストの折り合いがつきにくく二の足を踏むことが多いです。
そこで低コストで必要なWebページに必要な言語だけを機械翻訳できる術はないか模索しました。
その中でBeta版(2019年12月19日現在)ではありますがFirebase ExtensionsにTranslate TextというGoogle翻訳の拡張機能が提供されているのを見つけたので少し試してみました。
Firebaseの設定をざっくり
細かい説明は後回しにしてFirebase Extensionsを設定して試しに動かしてみます。
Firebaseのアカウント登録などは割愛しています。
Firebaseプロジェクトの左メニューからExtensionsを選択すると拡張機能一覧が表示されます。
Translate Textを選択して流れに沿って登録していきます。
拡張機能を使うにはBlazeプラン必須なのでクレカ登録する必要があります。
拡張機能の構成を設定。ここで翻訳対象の言語を指定します。(あとで変更もできます)
拡張機能のインストールに数分かかりますが、完了後は詳細画面で翻訳対象言語の設定変更などができます。
Webページの翻訳に使うのでWebアプリのFirebase登録をします。
ここでの手順は割愛。
サンプルコード
サンプルコードはこちら
https://github.com/tabyasu/google-translate-on-firebase/blob/master/sample.html
このサンプルコードでは大雑把にbody以下のテキスト、HTMLタグも含めて一気にFirestoreに登録してTranslate Textの翻訳対象にしています。
<script>
// FirebaseのWebアプリ設定は割愛
var db = firebase.firestore();
const sleep = time => {
return new Promise((resolve, reject) => {
setTimeout(resolve, time);
});
};
const translate = async e => {
e.preventDefault();
// Firestoreに翻訳対象を追加登録
const docRef = await db.collection('translations').add({
input: document.getElementsByTagName("body")[0].innerHTML,
created_at: firebase.firestore.FieldValue.serverTimestamp(),
});
// 翻訳がすぐに完了しないケースがあるので完了まで待ち
let doc = await docRef.get();
// TODO Error handling
while (!doc.data().translated) {
await sleep(10000);
doc = await docRef.get();
};
const translated = doc.data().translated;
document.getElementsByTagName("body")[0].innerHTML = translated[e.target.value];
};
// ページ上部にTranslate Textで設定した翻訳先の言語選択ボタンを表示
window.onload = () => {
const languages = { en:'英語', 'zh-CN':'中国語(簡体)', ko:'韓国語' }
const div = document.createElement('div');
const element = document.getElementsByTagName('body')[0];
element.insertAdjacentHTML('afterbegin', '<div style="background-color:#EDF7FF; height:30px;"></div>');
const translateButtons = element.firstElementChild;
Object.keys(languages).forEach(k => {
const button = document.createElement('button');
button.setAttribute('type', 'button');
button.setAttribute('name', 'translate');
button.setAttribute('value', k);
button.innerText = languages[k];
button.addEventListener('click', translate);
translateButtons.appendChild(button);
})
}
</script>
</head>
<body>
<div>JS導入部分のサンプルです</div>
</body>
</html>
翻訳結果
翻訳対象のテキストデータはFirestoreに登録されます。ドキュメントIDは指定してないのでランダムなIDでドキュメント登録されていますね。
フィールドのinputに翻訳対象のテキストデータが登録され、translatedフィールドにmapで翻訳結果が登録されています。
en:英語、zh-CN:中国語(簡体)、ko:韓国語 に一気に翻訳されたようですね。
考察
料金
FirebaseのBlazeブラン(従量課金)が必須ですが、Sparkプランの無料利用分を含みます。
https://firebase.google.com/pricing
Translate TextはGCPのCloud Translation APIを利用しています。が50万文字までの翻訳は無料です。
https://cloud.google.com/translate/?hl=ja#jump-to-3
一度に翻訳できる量
今回のサンプルや弊社コーポレートサイトのページのテキスト量だと一括で翻訳できましたが、サンプルコードのようにHTMLを文字列として一括で翻訳しようとすると翻訳結果が返ってきませんでした。
下記の注意書きがあったように長文翻訳には向かないようです。
Cloud Translation は、短いリクエストの翻訳に最適化されています。リクエストごとに推奨される最大の長さは 2,000 コードポイントです。リクエストが非常に大きいと、利用可能な割り当ての量にかかわらず、Cloud Translation によって拒否され、400 INVALID_ARGUMENT エラーとなります。
翻訳の精度?
僕が外国語に疎いので翻訳結果がネイティブに伝わるかどうかの精度判定はできていません。
が、Webページを一括で翻訳しようとするとHTML構文として 明日は<br>晴れるかな
のような改行を含む文章の翻訳結果が Will it be sunny tomorrow?
のように文章にならず tomorrow
と Will it be sunny
に分断された翻訳結果になっていました。
まとめ
コストについて
- HTMLを文字列として翻訳対象にしてしまうと当然コスト高くつくので、実戦投入する場合はテキストノードのみを翻訳対象にして丁寧に翻訳していく必要がある。
- 更新頻度の少ないページの翻訳であればFirestoreのドキュメントIDにページURLを指定して翻訳結果を登録し、ページに更新日時などの情報をもたせておいて一度翻訳した結果と差分無い場合は再利用できるようにすると翻訳コストを抑えられそう。
利用方法について
- 汎用的に使えるようにFunctionsでAPI化して、ドメイン指定やAPIキーを設定するなどFirebaseのconfig情報をWebサイト上に出さないつくりにしてアクセス制御するとよさそう。
-
<br>
や<span>
などが含まれている文章の翻訳結果を期待どおりにするためにJSの実装頑張る必要があるからちょっと大変そう。
結論
UI全体を精度高く機械翻訳するには実装工数のコストがかかるが、収益の低いWebサービスに導入するには選択肢になりえる。
・・・というのが僕の感想です。
今後、テキストのみの翻訳にブラッシュアップして本番導入できることを目指したい気持ちです😃