我們接手過的跨境站,十個有九個 hreflang 是壞的。而且壞得很安靜——Search Console 不會跳紅字,流量不會一夜歸零,只會有一種說不上來的鈍痛:日本的使用者被丟到英文頁、台灣繁中頁在 Google 上被簡中頁蓋掉、明明每個語系都寫了文案,卻只有一個版本吃得到排名。
更麻煩的是,hreflang 出錯的成本不是「排名掉幾名」,而是「整組語系的權重互相打架」。這篇是我們做多語系 audit 這幾年,把同一批錯誤看到麻木之後整理出的東西:hreflang 到底在幹嘛、最常見的 4 個錯法、x-default 跟 self-reference 這兩條最多人誤解的規則、我們實際在用的驗證工具,以及一份可以直接照抄的 checklist。
1. hreflang 到底是什麼(以及它不是什麼)
hreflang 是一個標註,用來告訴 Google:「這一頁,還有其他語言/地區的對應版本,它們長這樣。」你可以把它想成一張對照表,掛在每一頁上。
最基本的長相是放在 <head> 裡的一組 link:
<link rel="alternate" hreflang="zh-TW" href="https://example.com/tw/product" />
<link rel="alternate" hreflang="ja" href="https://example.com/ja/product" />
<link rel="alternate" hreflang="en" href="https://example.com/en/product" />
<link rel="alternate" hreflang="x-default" href="https://example.com/product" />
除了 <head>,也可以放在 XML sitemap 或 HTTP header(給 PDF 這類非 HTML 檔用)。三種擇一即可,但不要混用——我們看過同一個站 head 跟 sitemap 各寫一套、內容還互相矛盾,那比不寫還糟。
它不是什麼
這是最需要先講清楚的部分,因為誤解直接導致後面所有的錯誤決策。
- hreflang 不是排名訊號。設對了不會讓你排名上升,它只影響「Google 決定把哪一個語系版本端到使用者面前」。
- hreflang 不能取代 canonical。它處理的是「跨語系的對應」,不是「同語系的重複內容」。兩者要同時存在,且不能打架。
- hreflang 不是給 Bing 用的。Bing 官方明說它主要看
content-language,Yandex 才吃 hreflang。所以如果你的主力市場在英語系搜尋引擎以外,別以為設完 hreflang 就萬事俱備。 - hreflang 不會幫你解決薄內容。如果德文版是機器翻譯的一坨,hreflang 只會確保德國使用者更快看到那一坨。
它真正的價值在於:避免同一份內容的多個語系版本互相稀釋。當 Google 知道 /tw/ 和 /cn/ 是同一頁的兩個語系版本,它就不會把它們當成重複內容互相競爭,而是把權重視為一組來評估。這也是為什麼 hreflang 壞掉時,症狀往往是「其中一個語系莫名吃掉全部流量」。
2. 最常見的 4 個錯誤
我們把過去做過的多語系 audit 攤開來看,錯誤分布高度集中——不是各種千奇百怪的問題,而是同樣 4 個錯,反覆出現。
錯誤 1:單向連結(return tag 缺失)
這是最致命的一個,也是最多人中的。規則很簡單:hreflang 必須是雙向的。如果 A 頁指向 B 頁,B 頁也必須指回 A 頁。少了任何一個方向,Google 會把整組標註視為不可信,然後——直接忽略。不是部分忽略,是整組。
最常見的成因是「主站有、子站沒有」。我們看過一個 SaaS 站,英文主站每一頁都乖乖列出 6 個語系的 alternate,但德文站是外包廠商另外做的、用不同的 CMS,head 裡什麼都沒有。結果就是:那 6 個語系的 hreflang 全部失效,一年多的多語系工程等於沒做。
另一個成因更陰險:語系數量不對稱。日文版只有部分商品頁,於是日文站的 hreflang 只列了它有的那些,而其他語系卻對每一頁都指向日文。這種「多指一少」的情況會產生大量的斷鏈 return tag,Search Console 的國際定位報告會顯示「沒有回傳標記」——而多數人看到這個警告,選擇的是無視。
錯誤 2:語系碼寫錯
hreflang 的值必須是 ISO 639-1 語言碼(可選加上 ISO 3166-1 Alpha-2 地區碼),順序是「語言-地區」,不能只寫地區。實務上我們看到的錯誤大概是這幾種:
| 寫法 | 對錯 | 說明 |
|---|---|---|
zh-TW |
正確 | 中文(台灣)。大小寫不敏感,zh-tw 也可以 |
tw |
錯 | 只給地區碼無效,hreflang 一定要有語言 |
en-UK |
錯 | 英國的 ISO 碼是 GB,不是 UK |
zh-Hant |
可用但要小心 | script subtag,Google 支援,但同時混用 zh-TW 容易衝突 |
zh-CN-Hans |
錯 | 順序錯,正確是 zh-Hans-CN |
en-EU |
錯 | EU 不是國家,ISO 3166-1 沒有這個碼 |
另外一個高頻誤解:en-US 的意思不是「給美國人看的英文」,而是「給『在美國的、使用英文的人』看的版本」。地區碼只會收窄受眾,不會擴大。所以如果你只有一個英文版,卻標成 en-US,那英國、澳洲、新加坡的英文使用者在演算法眼中就沒有對應版本——你等於親手把他們排除掉。不確定要不要加地區碼時,就別加。
錯誤 3:hreflang 與 canonical 打架
這個錯很隱蔽,因為兩個標註分開看都對,合在一起才爆炸。
規則是:hreflang 指向的 URL,必須是該語系版本的 canonical URL 自己。如果 /de/product 的 canonical 指向 /en/product(常見於「德文版還沒翻完,先 canonical 到英文」這種偷懶做法),而其他語系的 hreflang 又指向 /de/product——這組訊號就自相矛盾:你一邊說「德文版是獨立的語系版本」,一邊說「德文版不是正規版本,請看英文版」。Google 面對矛盾訊號的處理方式一律是:忽略比較弱的那個,也就是 hreflang。
我們處理過一個跨境電商站,全站約 800 個商品頁、5 個語系。前一個廠商為了「避免重複內容」,把所有非英文語系的 canonical 全部指回英文版。結果是全站 4,000 組 hreflang 全數失效,日本站在 google.co.jp 上幾乎搜不到自己的商品頁。修正做法很單純——每個語系頁的 canonical 指向自己,重複內容交給 hreflang 處理,這本來就是它的工作。修完之後約六週,日文站的自然曝光回到同期的 3 倍以上。
錯誤 4:指向 redirect、404、或 noindex 的頁面
hreflang 必須指向一個可以被索引的、200 狀態碼的最終 URL。這聽起來理所當然,但在真實的站上非常容易破功:
- 站台從 http 換到 https,hreflang 裡的 URL 沒跟著換,全部變成 301
- URL 結尾斜線規則改過(
/tw/productvs/tw/product/),hreflang 寫的是舊格式 - 某個語系的頁面下架了,但其他語系的 hreflang 還指著它,變成 404
- 測試環境的頁面設了
noindex,上線後忘了拿掉,而 hreflang 正指著它
這類錯誤有一個共通點:它們都是隨時間腐化出來的,不是一開始就錯。第一次上線時 hreflang 是對的,然後網站改版、商品下架、URL 結構調整,沒有人記得回頭同步那張對照表。這也是為什麼我們主張 hreflang 不該手寫死在 template 裡,而該由資料源動態產生——後面會講。
3. x-default 到底怎麼用
x-default 是被誤解最深的一個值。大部分人把它當成「預設語言」,然後直接指向英文版。這不算錯到會被懲罰,但它多半不是你要的。
x-default 的正確定義是:當使用者的語系不符合你列出的任何一個版本時,要把他帶去哪裡。它是 fallback,不是 default language。
差別在哪?舉例:你的站有 zh-TW、ja、en 三個版本。一個在巴西、用葡萄牙文的使用者搜到你——他不屬於任何一個列出的語系。這時 Google 就會看 x-default。
- 如果你的
x-default指向英文版:他會看到英文頁。合理,但你放棄了引導他的機會。 - 如果你的
x-default指向一個語言/地區選擇頁(或會自動偵測的全球首頁):他會看到一個能自己選的入口。這通常是更好的選擇。
實務上我們的判斷標準很簡單:
- 有語言選擇頁 / 全球版首頁 →
x-default指向它 - 沒有,但有一個明確的「主市場」版本(例如英文版是原始版本、內容最完整)→ 指向它,並接受這個折衷
- 所有語系地位對等、沒有主版本 → 建一個語言選擇頁,別硬選一個
還有兩個容易忽略的技術點。第一,x-default 不是必填——沒有它 hreflang 依然有效,Google 只是在比對失敗時自行猜測。第二,x-default 也要遵守雙向規則:它指向的那個頁面,自己的 hreflang 清單裡也必須包含 x-default 指回自己,以及所有其他語系。這一點漏掉的人非常多。
4. self-reference:那一行大家都忘了寫
這是標題裡「99% 網站都設錯的那一行」的主角。
規則本身一句話就講完:每一頁的 hreflang 清單,都必須包含指向自己的那一筆。中文頁要有 hreflang="zh-TW" 指向中文頁自己,日文頁要有 hreflang="ja" 指向日文頁自己。
聽起來像廢話——「我自己就是中文頁,還要標自己是中文頁?」但這正是它被漏掉的原因。工程師實作時的直覺是「列出其他語系版本」,於是寫出這樣的 template 邏輯:
// 錯誤:排除了自己
locales
.filter(l => l !== currentLocale)
.map(l => `<link rel="alternate" hreflang="${l}" href="${urlFor(l)}" />`)
這個 .filter() 就是那一行害人的 code。正確的版本是不要過濾:
// 正確:每一頁都列出完整清單,包含自己
locales
.map(l => `<link rel="alternate" hreflang="${l}" href="${urlFor(l)}" />`)
換句話說,每一個語系版本的 hreflang 清單應該完全相同。三語系的站,每一頁都應該有 3 筆(加 x-default 就是 4 筆),三個版本的那 3 筆內容一模一樣。如果你的頁面上 hreflang 筆數比語系總數少一,八成就是漏了 self-reference。
為什麼這件事重要?因為 hreflang 是「一組」在運作的。缺少 self-reference 時,Google 收到的是一組殘缺的對照表——每一頁都在描述別人、沒有一頁描述自己,這組關係無法閉合。實務上的表現是:Search Console 的國際定位報告看起來有資料,但語系比對就是不生效,你怎麼查都查不出原因。
我們曾接一個 WordPress 多語系站的 audit,客戶用的是一套知名的多語系外掛,設定介面全綠、外掛也宣稱「自動處理 hreflang」。實際 curl 下來看 head,就是漏了 self-reference——外掛的預設行為正是上面那段 .filter()。加回來、三週後語系錯配的客訴歸零。整件事的工作量:讀 head、確認、寫一段 20 行的 functions.php 補丁。約 3 小時。
5. 驗證工具:怎麼確認自己沒設錯
hreflang 的驗證不能靠肉眼,因為錯誤幾乎都是「跨頁面的關係錯誤」,單看一頁看不出來。我們的標準流程是三層:
第一層:單頁快速檢查
直接把渲染後的 head 撈出來看。注意是渲染後——如果站是 SPA 或用 JS 注入 hreflang(拜託不要這樣做),curl 看到的會是空的。
curl -s https://example.com/tw/product | grep -i 'hreflang'
看三件事:筆數對不對(=語系數,或語系數+1)、有沒有自己、URL 是不是絕對路徑且是 https。這一步 30 秒,就能篩掉我們前面講的 4 個錯誤中的兩個。
第二層:全站爬取比對
單頁對不代表全站對。要抓「單向連結」這種關係錯誤,必須全站爬一次然後做雙向比對。可用的工具:
- Screaming Frog SEO Spider:內建 hreflang 報表,會直接列出「Missing Return Links」「Inconsistent Language Confirmation Links」「Non-200 hreflang URLs」。付費版但無腦好用,中小型站首選。
- Sitebulb:hreflang 的視覺化關係圖做得比 Screaming Frog 好,適合語系多、關係複雜的站。
- Ahrefs Site Audit:如果你已經在付 Ahrefs,它的技術 SEO 報表裡有 hreflang 區塊,涵蓋度堪用。
第三層:Google 自己的視角
最終仲裁者是 Google 自己。兩個必看:
- Search Console 的網址檢查工具:看 Google 實際抓到的 HTML 裡有沒有你的 hreflang。這是唯一能戳破「我明明有寫啊」的方法——很多時候是 CDN 快取、A/B testing 工具、或 JS 渲染把它吃掉了。
- Search Console 的效能報表按國家/查詢拆分:如果日本的曝光量高、點擊率卻異常低,很可能是被端了錯誤語系的頁面出去。這是 hreflang 壞掉最典型的流量指紋。
然後:把它自動化
誠實說,上面三層做完一次要 3–5 小時,而且六個月後網站一改版,它又會壞。這也是為什麼我們現在的做法是把第一、二層寫成腳本,掛在 CI 或排程裡:從 sitemap 拉出全部 URL,抓每一頁的 hreflang,在記憶體裡建一張圖,然後檢查每條邊是否雙向、每個節點是否有 self-loop、每個 URL 回應是否為 200。跑完輸出一份 diff。
一個 5 語系、2,000 頁的站,這支腳本跑完大約 6 分鐘,可以取代掉大部分的人工 audit。剩下需要人判斷的,只有 x-default 該指哪裡、以及語系碼的商業決策(要不要拆 en-GB)——這些本來也不該讓工具決定。
6. 我們的 hreflang audit checklist
這是我們每一個跨境專案都會跑一遍的清單。你可以直接拿去用。
- 實作位置單一:head、sitemap、HTTP header 只用其中一種,沒有混用、沒有互相矛盾
- self-reference 存在:每一頁的清單都包含自己
- 清單一致:所有語系版本的 hreflang 清單內容完全相同
- 雙向閉合:全站爬取後,每一條 A→B 都有對應的 B→A,沒有 missing return link
- 語系碼合法:ISO 639-1 + ISO 3166-1 Alpha-2,順序正確,沒有
en-UK/zh-CN-Hans這種東西 - 不必要的地區碼已移除:只有一個英文版就寫
en,不要寫en-US - canonical 自指:每個語系頁的 canonical 指向自己,不是指向主語系
- URL 全部是絕對路徑:含協定與網域,不是
/tw/product這種相對路徑 - URL 全部回 200:沒有 301、沒有 404、沒有 noindex
- 協定與斜線一致:全站 https,結尾斜線規則統一
- x-default 有意識地設定:知道自己為什麼指向那一頁,而且它也雙向指回來
- Search Console 已驗證:網址檢查工具看得到 hreflang,且國際定位報表沒有 return tag 警告
- 已納入回歸檢查:改版、加語系、調 URL 結構之後會重跑一次,不是設完就忘
誠實反思:什麼時候你根本不需要 hreflang
講完這麼多,反過來說一句公道話:hreflang 被過度推銷了。有幾種情況,你花在 hreflang 上的時間應該拿去做別的事。
你只有一個語系版本。 那就別碰。單語系站不需要 hreflang,寫了只是徒增出錯機會。
你的多語系版本內容其實不同。 hreflang 的前提是「同一份內容的不同語言版本」。如果你的日文站是完全獨立的內容策略、寫的是不同主題,那它們不是 alternate 關係,是不同的頁面,各自做各自的 SEO 就好。硬套 hreflang 反而傳遞錯誤訊號。
你的翻譯品質很差。 這聽起來刺耳但很現實:如果你的德文版是機器翻譯直出、讀起來像機器人,那 hreflang 只是幫你把德國使用者更精準地送到一個會讓他們立刻跳出的頁面。跳出率會回頭傷你。先把內容做好,再談語系分流。
你的多語系流量佔比 < 5%,而且沒有成長計畫。 我們遇過客戶花了兩週修 hreflang,結果非主語系的自然流量本來就只佔 3%,修完變 4%。同樣的兩週如果拿去修主市場的頁面速度或內部連結,回報高一個量級。技術 SEO 的優先序,永遠該由流量結構決定,不是由「哪個問題看起來最刺眼」決定。
我們自己在接案時的判斷線大概是:非主語系流量佔比超過 15%、或客戶有明確的海外拓展計畫,hreflang audit 才會排進前三優先。 否則它就是一個「知道有問題、但先記在 backlog」的項目。
結語:那一行,其實只值三小時
回頭看,hreflang 這件事有一個很反直覺的性質:它的錯誤成本很高,但修復成本極低。前面那個 WordPress 案例,一年多的語系錯配、無數客訴,修起來是 3 小時。那個 800 頁的電商站,canonical 全站錯指,改的是 template 裡的一行邏輯。
真正貴的不是修,是「不知道自己壞了」。因為 hreflang 壞掉不會報警——它只會安靜地讓你的多語系投資打折,而你以為是市場不好、以為是內容不夠強、以為海外就是難做。
所以如果你的站有兩個以上語系,今天就做一件事:curl 一個頁面,數一數 hreflang 有幾筆,有沒有自己。30 秒。多數人在這一步就會發現問題。
如果數完之後你不確定該怎麼修,或者你的站規模大到手動查不完,加 LINE 把網址丟給我們,我們會直接跑一遍前兩層檢查,把發現的問題列給你——不收費,也不綁後續合作。多數情況下,你自己或你的工程師看完就能修好。