日本語と英語の両方でサイトを運用していると、「同じ内容の記事が2つあるのに、検索エンジンはそれを別々のページとして扱ってしまうのでは」「日本語で検索した人に英語版が出てしまうのでは」という疑問が出てくる。この問題に対して、HTMLの <head> に書く hreflang という仕組みが用意されている。今回は、hreflangが何を伝えているのか、どんな書き方が必要なのか、そしてこのブログ(wpmm.jp/blog と en.wpmm.jp/blog)での実際の運用を例に整理する。
補足: hreflang は、検索エンジンに対して「このページには別の言語・地域向けの対応ページがある」と知らせるための属性である。ページの内容を翻訳するものではなく、あくまで「どのURLとどのURLが同じ内容の言語違いか」という対応関係を宣言するものにあたる。
hreflangが解決しようとしていること
言語違いのページが複数あるとき、検索エンジン側からは次のような判断が難しくなる。
- どちらのページを、どの言語で検索した人に見せるべきか
- 2つのページは別々の記事なのか、同じ内容の言語違いなのか
- 似た内容の重複ページとして扱うべきかどうか
hreflangは、これらの判断材料をサイト運営側が明示するための仕組みである。検索エンジンはページの文章から言語を推測することもできるが、推測に任せるよりも、対応関係が明記されているほうが判断の根拠がはっきりする。
基本の書き方
記事ページの <head> に、次のような link タグを並べる。
<link rel="alternate" hreflang="ja" href="https://wpmm.jp/blog/sample-article/" />
<link rel="alternate" hreflang="en" href="https://en.wpmm.jp/blog/sample-article/" />
<link rel="alternate" hreflang="x-default" href="https://wpmm.jp/blog/sample-article/" />
見るべき要素は次の3つである。
| 要素 | 意味 |
|---|---|
rel="alternate" |
「このページの別バージョン」を指す関係であることを示す |
hreflang="ja" など |
そのURLが対象とする言語(必要なら地域も。en-US のように書ける) |
href |
対応するページのURL(絶対URLで書く) |
x-default は特別な値で、「どの言語にも当てはまらない人に見せる既定のページ」を指す。言語を選ぶ入口ページや、主言語のページを指定するのが一般的である。
守るべき大事なルール: 相互参照(双方向)
hreflangで最も見落とされやすいのが、双方向で宣言する必要があるという点である。日本語ページが英語ページを指していても、英語ページ側が日本語ページを指し返していなければ、対応関係は成立しないものとして扱われうる。
したがって、日本語ページにも英語ページにも、上の3行と同じ内容を両方に置く。自分自身を指す行(日本語ページなら hreflang="ja" の行)も含めて、同じセットを両方のページに書くのが基本になる。
その他、実際に運用するうえで押さえておきたい点は次のとおりである。
- URLはcanonicalと矛盾させない。canonical(正規URL)と、hreflangで指すURLが食い違うと、どちらを信じるべきか判断が割れる
- 言語コードは
ja・enのようにISO 639-1 の2文字コードで書く - 指す先のページが実際に存在し、正常に表示できること(404や別ページへのリダイレクトを指さない)
このブログでの実例: 同一slugでペアを作る
wpmm.jp/blog(日本語)と en.wpmm.jp/blog(英語)は、別々のWordPressサイトとして動いている。そのうえで、記事ごとに日本語版と英語版で同じslugを使う運用にしている。たとえば日本語版が https://wpmm.jp/blog/○○/ なら、英語版は https://en.wpmm.jp/blog/○○/ になる。
この運用の利点は、テーマ側のコードがとても単純になる点にある。現在のページのURLから /blog/ 以降のパス部分を取り出し、日本語側のベースURLと英語側のベースURLにそれぞれ付け直すだけで、対応するURLが組み立てられる。
// 説明用に簡略化した疑似コード
$jp_base = 'https://wpmm.jp/blog/';
$en_base = 'https://en.wpmm.jp/blog/';
// 現在ページのURLから「/blog/ 以降」を取り出す($rel)
$jp_url = $jp_base . $rel;
$en_url = $en_base . $rel;
echo '<link rel="alternate" hreflang="ja" href="' . esc_url($jp_url) . '" />';
echo '<link rel="alternate" hreflang="en" href="' . esc_url($en_url) . '" />';
記事ごとに「この日本語記事の英語版はどれか」という対応表を持つ必要がなく、slugを揃えておくだけでペアが機械的に決まる。前回の記事で扱った esc_url() を出力時に通している点も、ここで実際に使われている。
一方で、この方式には前提がある。日本語版と英語版でslugを完全に一致させることと、公開後にslugを変更しないことである。片方のslugだけが変わると、組み立てたURLが存在しないページを指してしまい、対応関係が崩れる。記事を公開する際にslugを慎重に決め、公開後は変更しないことにしている理由のひとつがここにある。
もう1つの実例として、このブログではカテゴリページなどの一覧ページでも同じ考え方で対応するURLを組み立てている。記事ページに限らず、「言語違いで同じ相対パスを持つ」という規則を全体で守ることで、全ページで一貫したペアが成り立つ。
出力後に確認するには
hreflangは目に見える表示を変えないため、書いたつもりでも抜けていることに気づきにくい。公開後に確認する方法はいくつかある。
- ブラウザで対象ページのソースを表示し、
hreflangを検索して、ja・en・x-defaultの3つが出力されているか、URLが正しいかを見る - 日本語ページと英語ページの両方で確認し、同じセットが出ているかを見る
curlなどでHTMLを取得し、hreflangを含む行を抜き出して確認する
このブログでは、記事の公開後にSEO確認用のスクリプトで hreflang の出力を一覧し、ja・en・x-default のどれかが欠けていれば警告を出すようにしている。人間が目で見るよりも、欠落を機械的に拾うほうが見落としが少ないためである。
よくある落とし穴
- 片方向だけの宣言: 日本語側にだけ書いて、英語側に書かない。前述のとおり相互参照が必要になる
- canonicalとの食い違い: hreflangのURLとcanonicalのURLが別のものを指している
- 相対URLで書く: hreflangのhrefは、原則として絶対URLで書く
- 存在しないページを指す: 片方の言語の記事が未公開・削除済みなのに、対応するURLを出力し続ける。対応する記事が存在しない場合は、そのペアを宣言しない判断も必要になる
- 言語コードの書き間違い:
jp(正しくはja)のように、国コードと言語コードを取り違える
特に日本語の ja は、国コードの jp と混同しやすい。hreflangの値は言語コードを使う点は、確認する価値がある。
まとめ
hreflangは、言語違いのページ同士の対応関係を、検索エンジンに向けて明示する仕組みである。ポイントは、rel="alternate" と言語コード、絶対URLの組み合わせで書くこと、そして日本語ページと英語ページの双方に同じセットを置くことにある。運用面では、slugを言語間で揃えておくと対応URLの組み立てが機械的になり、記事が増えても対応表を管理せずに済む。書いたあとは、両言語のページで出力を確認する習慣をつけておくとよい。
次回以降は、同じ <head> に置かれる別の情報(構造化データやOGPなど)についても取り上げる予定である。