ブラウザーの翻訳機能でページを日本語にしたとき、製品名やコマンド、変数名まで一緒に訳されてしまって意味が分からなくなった、という経験はないでしょうか。HTML には、そうした「訳してほしくない部分」を翻訳ツールに伝えるための translate 属性が用意されています。この記事では、translate="no" の書き方と値のルール、親から継承されるしくみ、翻訳の対象になる属性、lang 属性との違い、DOM の translate プロパティ、そして「これを付けても確実に翻訳を防げるわけではない」という現実的な位置づけまでを解説します。
目次
translate 属性でできること
translate は、その要素の中のテキストと翻訳可能な属性の値を、ページをローカライズするときに翻訳すべきか、そのまま残すべきかを示すグローバル属性です。グローバル属性なので、<span> や <code> だけでなく、あらゆる HTML 要素に付けられます。
使い方はいたって単純で、訳してほしくない要素に translate="no" を付けるだけです。次はサイトのフッターで、ブランド名だけを翻訳の対象から外す例です。
<footer>
<!-- 「Webool」だけは訳さないでほしい、と伝える -->
<small>2026 <span translate="no">Webool</span></small>
</footer>
ここで大事なのは、translate はブラウザーの表示を変える属性ではない、という点です。CSS のように見た目が変わるわけでも、JavaScript のように何かが実行されるわけでもありません。あくまで翻訳する側のツールに向けた指示であり、実際に従うかどうかはツール側の実装に委ねられています。この性質は記事の後半でもう一度詳しく取り上げます。
値は yes と no の2つ、そして親から継承される
translate は列挙型属性で、指定できるキーワードは yes と no の2つだけです。ただし「属性を書かなかったとき」と「決められた値以外を書いたとき」の扱いも仕様で定められていて、ここが少し独特です。まとめると次のようになります。
| 書き方 | 状態 | 意味 |
|---|---|---|
translate="yes" | Yes | 翻訳の対象にする |
translate="no" | No | 翻訳せずそのまま残す |
| 属性を書かない | Inherit | 親要素と同じ扱いになる |
translate=""(空文字列) | Yes | yes と同じ=翻訳される |
yes / no 以外の値 | Inherit | 無効な値として無視され、親要素と同じ扱いになる |
属性を書かない場合は Inherit(継承)になり、親要素の状態がそのまま引き継がれます。ルート要素まで遡っても指定がなければ翻訳可、つまり何も書かなければページ全体が翻訳の対象という結論になります。この継承のおかげで、コードブロックがたくさん並ぶ領域などは、共通の親要素に一度 translate="no" を付けるだけで中身をまとめて除外できます。
継承は途中で打ち消すこともできます。translate="no" の内側に translate="yes" を書けば、その要素から下は再び翻訳の対象に戻ります。
<div translate="no">
<p>この段落は翻訳されません(親から no を継承)。</p>
<!-- 途中で yes に戻せる -->
<p translate="yes">ここだけは翻訳されます。</p>
</div>
そして最大の落とし穴が、表にも書いた空文字列の扱いです。hidden や disabled のような真偽値属性に慣れていると、「属性名だけ書けば有効になる」と考えてしまいがちですが、translate は列挙型属性なので通用しません。空文字列は仕様上 yes と同じ状態になるため、翻訳を止めるどころか、明示的に翻訳を許可したことになってしまいます。
<!-- 意図どおり:翻訳されない -->
<span translate="no">Webool Pro</span>
<!-- 間違い:空文字列は yes と同じ扱いなので翻訳される -->
<span translate>Webool Pro</span>
<span translate="">Webool Pro</span>
<!-- 間違い:yes / no 以外は無効な値。親を継承するだけで no にはならない -->
<span translate="false">Webool Pro</span>
<span translate="none">Webool Pro</span>
どちらの間違いもブラウザーはエラーを出しませんし、見た目もまったく変わりません。だから気づきにくいのです。テンプレートエンジンで値を差し込んでいる場合は、変数が空になって translate="" が出力されていないかも確認しておきましょう。
翻訳の対象になる属性は決まっている
translate が効くのは要素の中のテキストだけではありません。HTML Standard は「翻訳可能な属性」を具体的に列挙しており、translate="no" が付いた要素ではこれらの属性値も翻訳されないものとして扱われます。逆に言えば、翻訳の対象になるのは次の属性だけです。
| 属性 | 対象の要素 |
|---|---|
title | すべての HTML 要素 |
alt | <area> / <img> / <input> |
placeholder | <input> / <textarea> |
label | <optgroup> / <option> / <track> |
abbr | <th> |
download | <a> / <area> |
value | <input>(type="button" と type="reset" のとき) |
srcdoc | <iframe>(中身が解析され再帰的に処理される) |
style | すべての HTML 要素(content プロパティの値など) |
lang | すべての HTML 要素(翻訳後の言語に合わせて書き換えられる) |
content | <meta>(name が翻訳可能なメタデータ名のとき) |
href や src、class、id などがこの一覧に入っていないのは当然として、style と lang が含まれているのは意外に思うかもしれません。style は CSS の content プロパティで文字列を出力できるため、lang は翻訳後の文書では言語表記も変わるべきだからです。なお HTML の仕様以外でも翻訳可能な属性は定義され得るとされており、ARIA の aria-label がその例として挙げられています。
実務でよく効いてくるのは placeholder と title です。たとえばライセンスキーの入力欄では、入力例のプレースホルダーまで訳されると混乱を招きます。要素に translate="no" を付けておけば、テキストと一緒にこれらの属性もまとめて除外されます。
<label for="license">ライセンスキー</label>
<!-- placeholder と title も翻訳の対象から外れる -->
<input
type="text"
id="license"
name="license"
translate="no"
placeholder="ABCD-1234-EFGH-5678"
title="ABCD-1234-EFGH-5678 の形式で入力してください">
ただし title のように説明のための文章が入る属性は、訳されたほうが親切なこともあります。上の例で言えば「ABCD-1234-EFGH-5678 の形式で」の部分は訳せたほうがよいはずです。属性ごとに細かく制御する手段はないので、そういう場合は説明文を <label> や補助テキストの側に出し、値そのものだけを <code translate="no"> で囲むといった作り方に切り替えるのが現実的です。
翻訳させたくないものの具体例
では実際にどこへ付けるべきなのか。判断の目安は「訳された結果をそのまま使うと壊れるもの」です。人間が読んで意味を取るための文章ではなく、文字列そのものが正しさを持っているものが該当します。代表的なのは製品名やブランド名、コードやコマンド、変数名や関数名、ユーザー名や ID、住所や施設名などの固有名詞、そしてライセンスキーやシリアル番号です。
<!-- 製品名・ブランド名 -->
<p><span translate="no">Webool Pro</span> では画像の一括変換に対応しています。</p>
<!-- コマンドやコード。訳されるとコピーして実行できなくなる -->
<p>ターミナルで <code translate="no">npm run build</code> を実行します。</p>
<!-- 変数名・関数名 -->
<p>戻り値は <code translate="no">isPublished</code> プロパティで判定できます。</p>
<!-- ユーザー名・ID -->
<p>投稿者:<span translate="no">@webool_dev</span></p>
<!-- ライセンスキー・シリアル番号 -->
<p>プロダクトキー:<code translate="no">ABCD-1234-EFGH-5678</code></p>
技術記事のようにコードが繰り返し登場するページでは、ひとつずつ属性を書くのは現実的ではありません。継承を利用して、コードブロック全体を包む要素に一度だけ付けるのが効率的です。HTML Standard 自身も、キーボード入力とプログラムの出力を <kbd> と <samp> ごと除外する例を載せています。
<!-- pre に付ければ中の code もまとめて除外される -->
<pre translate="no"><code>const user = await fetchUser(userId);
console.log(user.displayName);</code></pre>
<p>
<kbd translate="no">git switch -c feature/login</kbd> と入力すると、
<samp translate="no">Switched to a new branch 'feature/login'</samp>
と表示されます。
</p>
逆に、付けすぎにも注意が必要です。英語の文章をそのまま translate="no" で囲ってしまうと、その言語を読めない訪問者にとっては読む手段が失われます。除外するのは「訳しようのない文字列」に限り、意味のある文章は翻訳できる状態のままにしておくのが原則です。
lang 属性との違いと組み合わせ方
translate と混同されやすいのが lang 属性です。この2つは目的がまったく違います。lang はその部分が何語で書かれているかを示す属性で、スクリーンリーダーの読み上げ言語やフォントの選択、辞書の判定などに使われます。一方 translate は翻訳してよいかどうかを示すもので、言語が何であるかについては何も語りません。
そのため、英語の引用に lang="en" を付けたからといって翻訳が止まるわけではありませんし、translate="no" を付けても「これは英語です」という情報は伝わりません。両方を適切に使い分ける、というのが正しい姿勢です。次は英語の書名を引用する例で、言語を伝えつつ翻訳からは除外しています。
<p>
詳しい定義は
<cite lang="en" translate="no">HTML Standard</cite>
に書かれています。
</p>
<!-- 英語の文章そのものは訳せたほうが親切なので lang だけ付ける -->
<blockquote lang="en">
<p>The translate attribute is used to specify whether an element's
attribute values and the values of its Text node children are to be
translated when the page is localized.</p>
</blockquote>
先ほどの表で触れたとおり、lang 自体も翻訳可能な属性のひとつです。文書が翻訳されるときには、翻訳後の言語に合わせて書き換えられるべきものとして扱われます。ただし translate="no" が付いた要素では属性値もそのまま残されるため、そこに書いた lang="en" は書き換えの対象になりません。固有名詞の言語指定としては、むしろ都合のよい挙動です。
DOM から扱う element.translate プロパティ
JavaScript からは HTMLElement.translate プロパティでこの属性を扱えます。値は文字列ではなく真偽値で、翻訳の対象なら true、対象外なら false が返ります。
ここで押さえておきたいのは、このプロパティが返すのは属性の文字列ではなく継承を解決したあとの状態だという点です。属性を書いていない要素でも、親が translate="no" なら false が返ります。属性そのものの値が知りたいときは getAttribute() を使い分けてください。
// <div translate="no"><p class="name">Webool Pro</p></div> を想定
const name = document.querySelector('.name');
// 属性は書いていないが、親から継承した状態が返る
console.log(name.translate); // false
console.log(name.getAttribute('translate')); // null
// false を代入すると translate="no" が設定される
const brand = document.querySelector('.brand');
brand.translate = false;
console.log(brand.getAttribute('translate')); // "no"
// true を代入すると translate="yes" が設定される(属性が消えるのではない)
brand.translate = true;
console.log(brand.getAttribute('translate')); // "yes"
代入したときの挙動も覚えておくと役に立ちます。true を入れると属性が削除されるのではなく translate="yes" が設定され、false を入れると translate="no" が設定されます。継承の状態(Inherit)に戻したい場合はプロパティではなく removeAttribute('translate') を使ってください。
このプロパティが便利なのは、API から取得したユーザー名やファイル名を JavaScript で描画するときです。生成した要素に el.translate = false; と一行書けば、マークアップに属性を埋め込む処理を書かずに済みます。なお HTML Standard に併記されているブラウザー互換性データでは、この属性への対応は Chrome 19 以降、Safari 6 以降、Firefox 111 以降となっています。Firefox での対応が比較的最近なので、古い環境も想定するなら属性として HTML に書いておくほうが確実です。
translate=”no” が効かないとき
値が空文字列や yes / no 以外になっている
まず疑うべきはここです。前半で説明したとおり、translate だけ、translate=""、translate="false" のいずれも no にはなりません。開発者ツールで実際に出力されている属性値を確認し、正確に no という文字列になっているかを見てください。JavaScript から設定した場合も、setAttribute('translate', false) のように真偽値を渡すと文字列 "false" になってしまい、無効な値として扱われます。
祖先の no が途中で打ち消されている
継承が効くということは、途中で上書きもされるということです。親に translate="no" を付けたのに一部だけ翻訳される場合は、その間に translate="yes" を出力している要素がないかを探してみてください。自分では書いていなくても、フレームワークやプラグイン、リッチテキストエディターが挿入したマークアップに含まれていることがあります。element.translate を使えば、算出された状態を直接確認できるので原因を絞り込みやすくなります。
使っている翻訳ツールが属性を尊重していない
マークアップが正しくても訳されてしまうことはあります。translate は HTML の仕様として定義されている属性ですが、それを読み取って従うのは翻訳する側のソフトウェアです。属性を無視する実装であれば、書いてあっても効果はありません。
MDN でも、すべてのブラウザーがこの属性を認識するわけではないものの、Google 翻訳のような自動翻訳システムはこれを尊重しており、人間の翻訳者が使うツールでも尊重される可能性があると説明されています。Google 翻訳が translate="no" と後述の class="notranslate" を尊重することはよく知られており、それを利用している Chrome の組み込み翻訳でも同様の扱いになります。一方、Firefox や Safari の翻訳機能がどこまで従うかは実装依存で、バージョンによっても変わり得ます。断定できる話ではないので、確実に確かめたいなら対象の環境で実際に翻訳を実行してみるのが唯一の方法です。
テキストだけが抜き出されて翻訳されている
ページの文章をコピーして翻訳サービスに貼り付けたり、テキストだけを抽出して機械翻訳に流すような仕組みを通した場合、HTML の属性は最初から届いていません。この場合はどう書いても防げません。同様に、記事の内容を取り込んで再配信するサービスなど、自分のマークアップがそのまま届かない経路では効果を期待できないと考えておきましょう。
class=”notranslate” や meta タグとの関係
翻訳の除外を調べていると、class="notranslate" や <meta name="googlebot" content="notranslate"> という書き方も見つかります。役割が似ているので混ざりやすいのですが、位置づけはそれぞれ違います。
| 指定 | 適用範囲 | 位置づけ |
|---|---|---|
translate="no" | その要素と中身(子孫に継承) | HTML 標準のグローバル属性 |
class="notranslate" | その要素と中身 | Google 翻訳が解釈することが知られている慣習的な指定。HTML の仕様にはない |
<meta name="googlebot" content="notranslate"> | ページ全体 | Google 固有の指定。標準ではない |
class="notranslate" は Google 翻訳向けに古くから使われてきた指定です。標準ではないため第一候補にはなりませんが、両方書いても互いに干渉しないので、Google 翻訳での確実性を上げたい場合や、属性を自由に出力できない CMS を使っている場合に併記されることがあります。ただしクラス名なので、CSS のクラス設計と衝突しないよう気を付けてください。
<meta> による指定はまったく別物で、要素単位ではなくページ単位です。Google のドキュメントでは、検索結果に翻訳されたタイトルやスニペットが表示されるのを防ぎ、ページの翻訳版を提供しないよう指示するタグとして説明されています。name には googlebot のほか google と書かれた形も広く使われてきました。ページの一部を除外したいだけなら不要ですし、ページ全体の翻訳を止めることは読者から読む手段を奪う行為でもあります。使うかどうかは慎重に判断してください。
<head>
<!-- ページ全体の翻訳を提供しないよう Google に伝える(Google 固有・標準ではない) -->
<meta name="googlebot" content="notranslate">
</head>
<body>
<!-- 要素単位の除外はこちら。標準の属性を第一候補にする -->
<p>製品名は <span translate="no" class="notranslate">Webool Pro</span> です。</p>
</body>
ここまでを踏まえると、translate="no" の位置づけは「翻訳ツールへのお願い」だと理解するのが正確です。守られる保証はなく、翻訳を確実に防ぐ仕組みではありません。だからこそ、訳されると実害が出る情報――コピーして実行するコマンドや、入力を求めるキーの書式など――は、属性だけに頼らないほうが安全です。コピーボタンを用意する、値の形式を画面上でも明示する、といった別の備えを組み合わせておくと、万一訳されても読者が困らずに済みます。
まとめ
translate は、要素の中のテキストと翻訳可能な属性を翻訳の対象にするかどうかを示すグローバル属性です。値は yes と no の列挙型で、属性を書かなければ親の状態を継承し、ルートまで指定がなければ翻訳可になります。translate="" や属性名だけの書き方は yes と同じ扱いで、false のような無効な値は継承にフォールバックするため、どちらも翻訳を止められない点が最大の落とし穴です。翻訳の対象になる属性は title・alt・placeholder などに限られており、translate="no" を付ければテキストと一緒にこれらも除外されます。JavaScript からは element.translate で継承を解決したあとの状態を真偽値として読み書きできます。除外すべきなのは製品名やコマンド、変数名、ユーザー名、ライセンスキーのように文字列そのものが意味を持つものだけで、読める文章まで囲ってしまうのは逆効果です。そして最後に忘れてはいけないのが、これはあくまで翻訳ツールへのヒントであり、従うかどうかはツール側次第だということ。class="notranslate" の併記や画面上での明示など、現実的な備えと合わせて使っていきましょう。