グローバル変数と独自モジュールを使ってa-blog cmsの多言語サイト制作をラクにする
この記事は、a-blog cms Advent Calendar 2019 の24日目の記事です。
a-blog cmsで多言語サイトを構築する場合、子ブログを使って管理する方法と、エイリアスを使って表示するテーマを切り替える方法に分かれます。今回はそれぞれの方法のメリット、デメリットと、制作しやすくするちょっとしたコツをご紹介したいと思います。
a-blog cmsでの多言語サイトの管理方法
①子ブログを使って管理する
言語ごとにブログを分けて、記事、カテゴリー、コンフィグ等をそれぞれの言語で独立して管理する方法です。
それぞれの言語で違う内容を発信する場合は管理しやすいですが、共通の内容を発信する場合はそれぞれのブログに記事の登録が必要です。(5言語のサイトであれば5件分記事登録が必要)
プロフェッショナルライセンスもしくは、パートナー向けに配布されている拡張アプリ「子ブログ多言語管理(Google Translate for a-blog cms)」を使うと、管理画面を行き来する必要がなくなり、管理しやすくなります。
②エイリアスを使って表示するテーマを切り替える方法
記事、カテゴリー、コンフィグ等を共通にして、カスタムフィールドやユニットのタブを使って管理する方法です。
全ての言語の内容がひとつの編集画面で完結するため管理しやすいですが(5言語分のサイトでも1件分の記事登録で完結) それぞれの言語で違う内容を発信したり、記事のボリュームが異なる場合は管理しにくい方法です。また、少々複雑なカスタマイズが必要なため、導入までのハードルが高いです。
多言語サイトのテーマ作成をラクにする
子ブログを使った管理、エイリアスを使った管理、いずれの場合も通常であれば各言語サイト分のテーマを用意する必要がありますが、下記のような方法を採用することでファイルを共通化することができましたのでご紹介します。
独自モジュールを作成して、単語を各言語に変換する
extensionディレクトリにPHPファイルをアップロードすることでEntry_SummaryやEntry_Bodyといったモジュールを新たに作成することができます(独自モジュール)。今回は「カテゴリー」や「アーカイブ」など決まった単語を、各言語の単語に置換する独自モジュールを作成しました。
/themes/*****/*.html
置換したい単語をモジュールと変数の出力のように囲みます。日本語サイトでは変数のまま「アーカイブ」、英語サイトでは単語が変換されて「Archive」と出力されます。
<!-- BEGIN_MODULE Translate -->{アーカイブ}<!--END_MODULE Translate -->
/extension/acms/GET/Translate.php
置換したい言語ごとに '置換前の単語' => '置換後の単語'
のように記述します。言語は子ブログでの管理の場合はブログコード $lang = ACMS_RAM::blogCode(BID);
、エイリアスでの管理の場合はエイリアスコード $lang = ACMS_RAM::aliasCode(AID);
で判別します。
<?php
namespace Acms\Custom\GET;
use ACMS_GET;
use ACMS_RAM;
use Template;
use ACMS_Corrector;
class Translate extends ACMS_GET
{
function get()
{
$Tpl = new Template($this->tpl, new ACMS_Corrector());
$lang = ACMS_RAM::blogCode(BID);
$obj = array();
if( $lang === 'en' ){
$obj = array(
'ご意見・ご感想はこちら' => 'Contact Us',
'サイト内検索' => 'Search',
'お知らせ' => 'Information',
'人気の記事' => 'Popular posts',
'アーカイブ' => 'Archive',
'カテゴリー' => 'Category',
'キーワード' => 'Keywords',
'いいね!' => 'Like!',
KEYWORD . 'の検索結果' => 'Search results for "' . KEYWORD . '"',
TAG . 'の一覧' => 'List of ' . TAG,
);
}
if( $lang === 'tw' ){
$obj = array(
'ご意見・ご感想はこちら' => '點擊此處發表意見、感想',
'サイト内検索' => '網站內搜索',
'お知らせ' => '通知',
'人気の記事' => '熱門文章',
'アーカイブ' => '檔案館',
'カテゴリー' => '類別',
'キーワード' => '關鍵詞',
'いいね!' => '點讚!',
KEYWORD . 'の検索結果' => KEYWORD . '的搜索结果',
TAG . 'の一覧' => TAG . '清单',
);
}
if( $lang === 'cn' ){
$obj = array(
'ご意見・ご感想はこちら' => '点击此处发表意见、感想',
'サイト内検索' => '网站内搜索',
'お知らせ' => '通知',
'人気の記事' => '热门文章',
'アーカイブ' => '档案馆',
'カテゴリー' => '类别',
'キーワード' => '关键词',
'いいね!' => '点赞!',
KEYWORD . 'の検索結果' => KEYWORD . '的搜索結果',
TAG . 'の一覧' => TAG . '清單',
);
}
// 配列に該当する値がなければそのまま表示する
$key = preg_replace('/\{(.*?)\}/', '$1', $this->tpl);
if(!array_key_exists($key, $obj)){
$obj[$key] = $key;
}
return $Tpl->render($obj);
}
}
エイリアスIDを変数に使用する
a-blog cmsでは変数内にグローバル変数を使用することができます。グローバル変数のエイリアスID(%{ALIAS_ID}
)を記事タイトルやユニットの出力に使用することで、ユニットの多言語対応 に必要な出力側のカスタマイズを簡略化することができます。あらかじめカスタムフィールドなどでエイリアスIDが入ることを見越して構築を進めておくとよいでしょう。
/themes/*/entry.html
通常、各言語のテーマで {title}
や {title2}
のように出力するところを、{title%{ALIAS_ID}}
のように出力します。
<!-- BEGIN_MODULE Entry_Body -->
<!-- BEGIN entry:loop -->
<article class="entry clearfix {entry:loop.class}">
<!-- BEGIN title:veil -->
<h2 class="title entry-title">{title%{ALIAS_ID}}</h2>
<!-- END title:veil -->
(中略)
</article>
<!-- END entry:loop -->
<!-- END_MODULE Entry_Body -->
/themes/*/include/unit.html
unit.html も同様に、各言語のテーマで {text}
や {text2}
のように出力するところを、{text%{ALIAS_ID}}
のように出力します。
@extends("/_layouts/unit.html")
@section(text-unit)
<!-- BEGIN p -->
<p{class}>{text%{ALIAS_ID}}[nl2br]</p><!-- END p --><!-- BEGIN h2 -->
<h2{class} id="{extend_tag}">{text%{ALIAS_ID}}[nl2br]</h2><!-- END h2 --><!-- BEGIN h3 -->
<h3{class} id="{extend_tag}">{text%{ALIAS_ID}}[nl2br]</h3><!-- END h3 --><!-- BEGIN h4 -->
<h4{class} id="{extend_tag}">{text%{ALIAS_ID}}[nl2br]</h4><!-- END h4 --><!-- BEGIN h5 -->
<h5{class} id="{extend_tag}">{text%{ALIAS_ID}}[nl2br]</h5><!-- END h5 --><!-- BEGIN ul -->
<ul{class}>{text%{ALIAS_ID}}[list]</ul><!-- END ul --><!-- BEGIN ol -->
<ol{class}>{text%{ALIAS_ID}}[list]</ol><!-- END ol --><!-- BEGIN dl -->
<dl{class}>{text%{ALIAS_ID}}[definition_list]</dl><!-- END dl --><!-- BEGIN blockquote -->
<div class="entry-container"><blockquote{class}>{text%{ALIAS_ID}}[nl2br]</blockquote></div><!-- END blockquote --><!-- BEGIN table -->
<div class="entry-container"><table{class}>{text%{ALIAS_ID}}[table]</table></div><!-- END table --><!-- BEGIN pre -->
<div class="entry-container"><pre{class}>{text%{ALIAS_ID}}</pre></div><!-- END pre --><!-- BEGIN none -->
{text%{ALIAS_ID}}[raw]<!-- END none --><!-- BEGIN markdown -->
{text%{ALIAS_ID}}[markdown]<!-- END markdown --><!-- BEGIN wysiwyg -->
{text%{ALIAS_ID}}[raw]<!-- END wysiwyg -->
@include("/include/unit/tag-select.html")
@endsection
@section(table-unit)
<div class="column-table-{align}">
<div class="entry-container">
{table%{ALIAS_ID}}[raw]
</div>
</div>
@endsection
/extension/acms/Hook.php
ここからは上級編です。 %{ALIAS_ID}
でも問題ありませんが、最初にエイリアスを作りすぎてしまった場合や、複雑なエイリアス設定を行った場合に意図したとおりのエイリアスIDを取得できなくなることがあります。その場合は %{ALIAS_ID2}
のグローバル変数を作成します。
/**
* グローバル変数の拡張
*
* @param array $globalVars
*/
public function extendsGlobalVars(&$globalVars)
{
switch (AID) {
case 3:
// https://www.example.com/en/など
$globalVars->set('ALIAS_ID2', 2);
break;
default:
// https://www.example.com/ja/など
$globalVars->set('ALIAS_ID2', '');
break;
}
}
/extension/acms/GET/Topicpath2.php
Entry_SummaryやEntry_Bodyなどはグローバル変数でカスタムフィールドやユニットのタブを参照できますが、Topicpathは上記の方法に対応していません。/php/ACMS/GET/Topicpath.php をコピーして変数を追加します。
<!-- BEGIN_MODULE Topicpath2 -->
<ol class="breadcrumb">
<!-- BEGIN blog:loop -->
<li><a href="{url}">{name}</a></li><!-- END blog:loop --><!-- BEGIN category:loop -->
<li><a href="{url}">{name%{ALIAS_ID2}}</a></li><!-- END category:loop --><!-- BEGIN entry -->
<li>{title%{ALIAS_ID2}}</li><!-- END entry -->
</ol>
<!-- END_MODULE Topicpath2 -->
$Field = loadCategoryField($cid);
$Tpl->add('category:loop', array(
'name' => $row['category_name'],
'name2' => $Field->get('categoryName2'),
'url' => acmsLink(array(
'bid' => $this->bid,
'cid' => $cid,
)),
'sNum' => $loop,
));
$Field = loadEntryField($eid);
$Tpl->add('entry', array(
'title' => $row['entry_title'],
'title2' => $Field->get('title2'),
'url' => acmsLink(array(
'bid' => $this->bid,
'eid' => $eid,
)),
'sNum' => $loop,
));
参考記事
多言語化したユニットにCSVインポートで情報を格納する
ユニットの多言語対応 を行ったユニットに対してCSVインポートを行うには{日本語の内容}:acms_unit_delimiter:{英語の内容}
のようにデリミタを記述します。(使用する場合は全角コロンを半角コロンにしてください)
entry_title,title2,entry_datetime,unit@p[1]
日本語記事タイトル,英語記事タイトル,2015-05-19 00:00:00,32,日本語の内容:acms_unit_delimiter:英語の内容
例えば下記は既存のa-blog cmsサイトから、CSVを作成する際のテンプレートのサンプルです。(使用する場合は全角コロンを半角コロンにしてください)
entry_title,title2,entry_datetime,unit@p[1]<!-- BEGIN_MODULE Entry_Body id="all" --><!-- BEGIN entry:loop -->
{title},{title_en},{date#Y}-{date#m}-{date#d} 00:00:00,{summary}:acms_unit_delimiter:{summary_en}<!-- END entry:loop -->
<!-- END_MODULE Entry_Body -->
どの管理方法を採用するか
著者が最近関わった多言語サイトの実績は下記のような内訳です。
- 子ブログを使った管理 … 4件
- エイリアスを使った管理 … 2件
- カテゴリのみで管理 … 2件
- 静的ページのみ … 2件
このようにケースバイケースですが、各言語で少しでも記事の内容に差異が出てくる場合や、各言語で発信のタイミングが異なる場合は、①子ブログを使った管理方法がおすすめです。
エイリアスを使った管理方法だと1記事が全ての言語サイトに連動しているので、例えば翻訳の都合で先に日本語記事をリリースして、英語記事をあとからリリースするといったケースが出てきた場合、英語記事を記事一覧に表示しないようにする、などのカスタマイズが必要になります。(このカスタマイズについても実装できたのでまたブログに書きたいと思います。)
多言語化に際しては様々なアプローチがあり、非常に奥が深いですが、これぞCMSの醍醐味という感じがします。a-blog cmsでは標準機能で多言語化ができる機能が多く備わっていますので、「他にもこのような方法があるよ」などありましたらフィードバックいただけると嬉しいです。
コメント