Cloud Translation API を使った多言語対応


Google の「Cloud Translation API」を使った a-blog cms用拡張アプリが公開されています。この拡張アプリを使用すると、 エントリー(記事)の多言語化を簡単に行うことができますのでぜひ試してみましょう。

現状この拡張アプリはプロ版以上での利用に限定されています。(スタンダード版でも有償になりますが、ご利用いただけるように準備中です)


仕組み概要

この拡張アプリでの多言語エントリーの管理の仕方ですが、言語ごとにブログを切り、言語毎の記事を別エントリーとして管理するようにします。

1つのエントリーで一元管理できていないので、あまりよくないように思いますが、別管理とすることで以下のようなメリットがあります。

  • 既存の仕組みで管理できる
  • 言語ごとに承認機能を利用できる
  • 言語ごとにコンテンツの内容を大きく変更できる
  • 一部の言語にしかないコンテンツを用意できる

ただ各言語が別管理になってしまうので、管理しづらいところがあります。そこでこの拡張アプリではエントリー詳細で、各言語にリンクできるようになっており、ステータスの状態を確認できるようになっています。


完成イメージ

完成イメージ


下準備

さっそく実装していきましょう。

ここでは、beginner2019テーマの初期インストール状態を例に解説していきます。環境が異なる場合はご自身の環境に合わせて読み替えてください。

フック機能の有効化

config.server.php の HOOK_ENABLE を「1」に設定します。

define('HOOK_ENABLE', 1);

APIキーの取得

まずは Google Translate API を使用するためにAPIキーの発行が必要になります。

ablogcms.io をお使いの場合

以下のAPIキーを使用します。

AIzaSyA9uMj7N7oWXDJGcRcPA00pL8O_f7pp7zY

ご自身で取得する場合

ablogcms.io 以外で試している場合、以下の方法でAPIキーを取得します。

Google API Console にアクセスしてログインしてください。ログイン後、任意の名前でプロジェクトを作成します。 下画像のように 1, 2 の手順でプロジェクトを新規作成できます。


Google API Console

Google API Console


左上のセレクトメニューをクリックし、先ほど作成したプロジェクトを選択します。


プロジェクトの選択

プロジェクトの選択


次は、サブカラムより「ライブラリ」という項目をクリックし、API ライブラリのページに移動します。そのページにて、Google Cloud Translation APIという項目を検索して有効化してください。


ライブラリに移動

ライブラリに移動


Translate API の有効化

Translate API の有効化


最後に「認証情報」をクリックして認証情報の設定画面に移動します。そこで新たに API key を作成します。

必ずキーの制限 をかけるようにしてください。HTTPリファラー での制限はできませんので、IPアドレスによる制限になります。


認証情報に移動

認証情報に移動


APIキーの作成

APIキーの作成


この時発行される API key を覚えておきましょう。

英語用のブログを作成する

サイトを多言語化するにあたり、各言語をブログを切って設計します。 今回の場合は、ルートブログ(日本語)と子ブログ(英語)だけで大丈夫です。 英語ブログのコードを「en」としておきましょう。

日本語サイト
   ┗ 英語サイト

英語用ブログの作成

英語用ブログの作成


もし他ブログや言語が増えた場合は以下のような構成になります。 各言語ともブログ構造を保って作ります。

例:
日本語サイト
   ┗ 日本語ブログ
   ┗ 英語サイト
     ┗英語ブログ
   ┗ 中国語サイト
     ┗中国語ブログ

拡張アプリのインストール

まずは、Google Translate for a-blog cms から zipファイルをダウンロードし、解凍したディレクトリ(GoogleTranslate)を extension/plugins/ に設置します。


拡張アプリのファイル設置

拡張アプリのファイル設置


次に、管理者で a-blog cms にログインし、 拡張アプリに移動し、「Google Translate」をインストールします。多言語管理するブログ全てで、「Google Translate」拡張アプリを有効にします。


拡張アプリのインストール

拡張アプリのインストール


子ブログでも有効化

子ブログでも有効化


これで拡張アプリのインストールは完了です。

拡張アプリの設定

拡張アプリをインストールすると、拡張メニューに「Google Translate」が増えます。ベースとなる言語ブログのみで設定を行なっていきます。つまり日本語サイトのルートブログで設定を行います。


設定項目 説明
ベース言語 翻訳元となる言語を設定します
Google Translate API Key 事前準備で用意した APIキー を設定します
カテゴリー作成 翻訳先の記事を作成するときに、カテゴリーも自動で複製するか設定します
ベース言語(このブログ)と関連づける他言語ブログを設定 ベース言語のブログと翻訳先のブログの関連を設定します
訳対象のフィールドを設定します 翻訳対象のカスタムフィールド名を指定します
eidを指定するカスタムフィールドを設定します eidを設定するようなフィールドを指定します
bidを指定するカスタムフィールドを設定します bidを設定するようなフィールドを指定します
cidを指定するカスタムフィールドを設定します cidを設定するようなフィールドを指定します

ここでは以下の設定だけ行えば大丈夫です。

  • ベース言語の設定: 日本語を指定
  • カテゴリー作成: 作成するにチェック
  • 下準備で取得したAPIキーの設定
  • ベース言語(このブログ)と関連づける他言語ブログを設定

アプリの設定

アプリの設定


試してみる

ここまで設定できると、実際に翻訳できるようになります。エントリー編集画面に移動すると、下画像のようなメニューがあります。ここで「翻訳して作成」ボタンを押すと、このエントリーを設定した、ブログに翻訳して記事を非公開で複製します。

実際に試してみましょう。


多言語メニュー

多言語メニュー


表側でもこのメニューを表示するには、以下のコードをテンプレートに追記してください。

<!-- BEGIN_MODULE Touch_Entry -->
<!-- BEGIN_MODULE Touch_SessionWithAdministration -->
<!-- BEGIN_MODULE GoogleTranslate_EmptyModule -->
<!-- BEGIN_MODULE Admin_InjectTemplate id="admin-entry-editor-top" --><!-- END_MODULE Admin_InjectTemplate -->
<!-- END_MODULE GoogleTranslate_EmptyModule -->
<!-- END_MODULE Touch_SessionWithAdministration -->
<!-- END_MODULE Touch_Entry -->

Google帰属表示

試すだけならここで終わってもいいのですが、実際に運用することを考えて、Translation APIを使った時のGoogle帰属表示に対応しましょう。

参考: https://cloud.google.com/translate/attribution

概要

以下のような対応が必要になってきます。

ロゴ表示について

Cloud Translation API を使用する際には、Googleへの帰属表示が必須になります。ロゴ画像をつかってリンクを表示するようにします。


Google ロゴ

Google ロゴ


Translation API マークアップ

変更されていない Cloud Translation API の結果をウェブ上で公開し、検索できるようにする場合、 翻訳されるテキストを機械翻訳されたコンテンツとして指定する必要があります。

<テキストの翻訳先言語の言語コード>-x-mtfrom-<原文の言語の言語コード>

次のように、HTML ドキュメントの headタグ内 に link要素を追加し、 rel="" 属性を "alternate machine-translated-from" に、hreflang="" 属性を翻訳元の言語コードに、href="" を翻訳元のページに設定します。

<html lang="en-x-mtfrom-ja">
<head>
    <link rel="alternate machine-translated-from" hreflang="ja" href="http://ja.example.com/hello.html">
</head>
<body>
...

実装方法

上記のロゴと Translation API マークアップ を行うのに便利なグローバル変数とモジュールが用意されていますので用いましょう。


変数 説明
%{TRANSLATION_LANG_BASE_CODE} 翻訳元の言語コード ja
%{TRANSLATION_LANG_CODE} 現在いるページの言語コード en, en-x-mtfrom-ja
%{TRANSLATED_BY_GOOGLE} 機械翻訳されたページのみ「yes」を出力 yes
%{TRANSLATION_ORIGIN_URL} 翻訳元記事のURL http://ja.example.com/hello.html

%{TRANSLATION_LANG_CODE} 変数は、人力翻訳、機械翻訳を判断して、Translation API マークアップ にあった コードを出力します。

このグローバル変数と専用モジュールを使って、Translation API マークアップ をします。

<html lang="%{TRANSLATION_LANG_CODE}">
<head>
    <!-- BEGIN_MODULE GoogleTranslate_EntryList -->
    <!-- BEGIN_IF [%{TRANSLATED_BY_GOOGLE}/eq/yes] -->
    <link rel="alternate machine-translated-from" href="%{TRANSLATION_ORIGIN_URL}" hreflang="%{TRANSLATION_LANG_BASE_CODE}">
    <!-- END_IF -->
    <!-- BEGIN lang:loop -->
    <!-- BEGIN_IF [{base_bid}/neq/{relation_bid}/_and_/%{BID}/neq/{relation_bid}] -->
    <link rel="alternate" href="{url}" hreflang="{lang_code}">
    <!-- END_IF -->
    <!-- END lang:loop -->
    <!-- END_MODULE GoogleTranslate_EntryList -->
</head>
<body>
...

ロゴも、%{TRANSLATED_BY_GOOGLE} という機械翻訳されたページか判定するグローバル変数があるので、IFブロックなどで、ロゴ画像を表示、非表示を切り替えてあげればOKです。

以上で完了です。お疲れ様でした。

CSVインポートを使ったユーザー作成について

CSVファイルを使ったインポートには、通常WordPressからのエントリーのインポート、Movable Typeからのエントリーのインポート、CSVファイルのエントリーのインポート機能が利用できます。
その他に、ユーザーをCSVファイルからインポートする事も可能です。利用するには、エンタープライズライセンスか、無制限ユーザーのオプションが必要になります。



  • CSV形式のファイル(カンマ区切りデータ)をユーザーと、ユーザーのカスタムフィールドに変換してインポートします。
  • user_code, user_mail, user_passは必須項目です。
  • CSVに user_id を指定することで既存のユーザーを上書きすることができます。

表示されていないカスタムフィールドの値を削除しないようにする

通常、エントリーデータの変更時にはカスタムフィールドの値は全更新が行われます。そのエントリー ※1 に登録されているカスタムフィールドの値を全て削除したのちに、入力されている値を登録します。
例えば、新規エントリー登録時には、カスタムフィールドとしてTEL、FAXの項目があったとします。編集時に入力項目としてTELしかなかった場合 ※2 編集データの登録が行われると画面になかったFAXの値は削除されます。
※1 カテゴリーのカスタムフィールド、ブログのカスタムフィールドも同様です。
※2 hiddenではなくHTMLのソース上に存在しないの意味

全て削除してから登録するのではなく、画面に存在している値のみ上書きするには、下記の2行を field.html の中にご記入ください。

<input type="hidden" name="updateField" value="on" />
<input type="hidden" name="field[]" value="updateField" />

SmartBlock でブロックを増やそう

SmartBlockとは

SmartBlock とは Ver.2.11より、a-blog cmsに新しく追加される予定のブロックベースのエディターです。


SmartBlockの特徴は以下になります。

余分なタグが入らない

あらかじめ設定したタグ以外の情報が一切入りません。そのため、一般的なエディターでよくあるような、意図しないタグが知らない間に挿入されているといったことが起こりません。また他のページの内容をコピー、ペーストした際もあらかじめ設定したタグ以上の情報は入りません。

ブロックベースの考え方

また、ブロックベースの考え方でできているため、見出しと本文を入れ替えたり画像と本文を入れ替えたり、順番の制御が容易に行えます。

カスタマイズ性

SmartBlockはカスタマイズ性にもすぐれ、JavaScriptにそれほど精通していない人でも独自のブロックを作成することができます。

SmartBlockを使ってみよう

では早速SmartBlockを使ってみましょう。

ユニットで SmartBlock を利用する

Ver.2.11にはユニットでは「リッチエディター」という名前でPaperEditorが導入されます。デフォルトでは追加ユニットのボタン群にリッチエディターボタンが追加されていないので、追加してみましょう。

管理画面 > コンフィグ > 編集設定 の順にページを移動し、 ユニット追加ボタンより以下のようにリッチエディターを追加してください!


その後、エントリー編集画面に行くと以下のようにボタンが追加されているのが確認できます。


ボタンをクリック後、下図のような見た目でユニットが表示されたら成功です。


組み込みJS の SmartBlock を利用する

SmartBlockは組み込みJSとしても使用できます。カスタムフィールドメーカーを使ってSmartBlockを設置してみましょう。

Ver.2.11よりカスタムフィールドメーカーが強化され、あらたにLiteEditor、SmartBlock、テーブルの組み込みJS用のソースコードが出力できるようになりました。管理画面 > コンフィグ > カスタムフィールドメーカーの順にページを移動して、以下のようにセレクトメニューからリッチエディターを選択し、ソースコードを生成しましょう。


生成されたコードを各種カスタムフィールドの設置したい箇所に貼り付け、使用してください。

SmartBlockのカスタマイズ(ハンズオン)

さて、ここからいよいよハンズオンです。

SmartBlockではユニットのようにブロックを簡単に作ることが可能です。このハンズオンでは、編集画面を SmartBlock 用のテーマに変更し、実際に新しいブロックを追加する方法を紹介します。

今回は blog2019 を継承した paper-editor@blog2019 を用意しました。

以下のフォルダをダウンロードしてthemesディレクトリに設置してください。


ファイルを開く

paper-editor@blog2019

設置したら、管理画面 > コンフィグ > テーマ設定の順にページを移動します。
先ほど設置した paper-editor@blog2019 をテーマディレクトリ名に選択し、テンプレート設定のチェックを外してください。


そして、以下のようにテンプレートファイルを設定します。


あとは、管理画面>コンフィグ>編集設定の順にページを移動し、エントリーの編集画面の設定を表側で統一すれば準備完了です!


エントリー編集画面で以下のように記事を書けば


SmartBlockの編集画面


エントリー保存後、書いた内容がそのまま表示されているのが確認できます!


エントリー保存後の画面


オリジナルのブロックを追加してみよう

次にオリジナルブロックを追加してみましょう。
/themes/paper-editor@blog2019/include/head/js.html に以下のように記述します。

<script src="%{JS_LIB_JQUERY_DIR}jquery-%{JS_LIB_JQUERY_DIR_VERSION}.min.js"></script>
<!-- BEGIN_MODULE Js -->
<script src="%{ROOT_DIR}acms.js{arguments}" id="acms-js"></script><!-- END_MODULE Js -->
<!-- BEGIN_MODULE Touch_Unlogin --><!-- BEGIN_MODULE Blog_Field -->{google_analytics}[raw]<!-- END_MODULE Blog_Field --><!-- END_MODULE Touch_Unlogin -->
<script>
ACMS.Ready(function() {
  // ここに処理を書いていく
});
</script>

使用できるプロパティ


プロパティ名 説明 記述例
tagName HTML要素を指定 例)p
className クラス名を指定 例)acms-text-error
customName ユニークな名前を記述 例)error-text
icon アイコンを挿入するときはHTMLタグを記述 例)<img src="画像のファイルパス"> または <svg>...</svg>

アラートボックスを表示するブロックを追加

ACMS.Config.SmartBlockAdds = function(Extensions) {
  return [
  new Extensions.CustomBlock({
     tagName: 'div',
     className: 'acms-alert',
     customName: 'alert',
     icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 1792 1792"><title>アラート</title><path d="M1777.67,1567.49,960.05,49.07c-35.23-65.43-92.87-65.43-128.1,0L14.33,1567.49c-35.22,65.43-3.25,119,71.06,119H1706.61C1780.92,1686.45,1812.89,1632.92,1777.67,1567.49ZM1024,1536H768V1280h256Zm0-384H768L704,576h384Z"/></svg>'
  })
  ]
};

追加されるアラート

small要素を挿入するマーカーを追加

さらにSmartBlockではブロックだけでなく、インライン用の装飾(マーカー)を追加することが可能です。

ACMS.Config.SmartBlockAdds = function(Extensions) {
  return [
  new Extensions.CustomBlock({
     tagName: 'div',
     className: 'acms-alert',
     customName: 'alert',
     icon: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 1792 1792"><title>アラート</title><path d="M1777.67,1567.49,960.05,49.07c-35.23-65.43-92.87-65.43-128.1,0L14.33,1567.49c-35.22,65.43-3.25,119,71.06,119H1706.61C1780.92,1686.45,1812.89,1632.92,1777.67,1567.49ZM1024,1536H768V1280h256Zm0-384H768L704,576h384Z"/></svg>'
  }),
  //さらに追加
  new Extensions.CustomMark({
     tagName: 'small',
     customName: 'small',
     icon: 's' // 本来であればSVGまたはimg要素を指定できるのですが、現在のベータ版では対応されていないので代わりにテキストを記述してください
  })
  ]
};

追加されるsmall要素

8/22(金)にa-blog cms DAYが開催されました

8/22(金)にa-blog cms DAYが開催されました。山形・富士・名古屋・神戸・広島の5カ所のサテライト会場で行われました。

a-blog cms DAYとは、全国各地でa-blog cmsの勉強をする日です。ビデオチャットを通して全国各地のa-blog cmsユーザーと繋がることができ、リアルタイムでわからないところを質問することができます。5カ所の都市で開催されていますが、ビデオチャットで各地とつながっているため、お近くに会場がない場合は開催していただくこともできますし、ご自宅からでもご参加できます。


名古屋会場の勉強会風景


#ablogcms STREAMも放送しました


今回の新しい試みとして、今まで使っていたチャットワークではなく、リアルタイムで会話ができるYouTube Liveを活用して開催地5カ所とつながりました。画面越しではありますが、実際に相手の顔や声も聞ける状態でサポートすることができました。