我們接手過的跨境站,十個有九個 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 各寫一套、內容還互相矛盾,那比不寫還糟。

它不是什麼

這是最需要先講清楚的部分,因為誤解直接導致後面所有的錯誤決策。

它真正的價值在於:避免同一份內容的多個語系版本互相稀釋。當 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。這聽起來理所當然,但在真實的站上非常容易破功:

這類錯誤有一個共通點:它們都是隨時間腐化出來的,不是一開始就錯。第一次上線時 hreflang 是對的,然後網站改版、商品下架、URL 結構調整,沒有人記得回頭同步那張對照表。這也是為什麼我們主張 hreflang 不該手寫死在 template 裡,而該由資料源動態產生——後面會講。

3. x-default 到底怎麼用

x-default 是被誤解最深的一個值。大部分人把它當成「預設語言」,然後直接指向英文版。這不算錯到會被懲罰,但它多半不是你要的。

x-default 的正確定義是:當使用者的語系不符合你列出的任何一個版本時,要把他帶去哪裡。它是 fallback,不是 default language。

差別在哪?舉例:你的站有 zh-TWjaen 三個版本。一個在巴西、用葡萄牙文的使用者搜到你——他不屬於任何一個列出的語系。這時 Google 就會看 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 個錯誤中的兩個。

第二層:全站爬取比對

單頁對不代表全站對。要抓「單向連結」這種關係錯誤,必須全站爬一次然後做雙向比對。可用的工具:

第三層:Google 自己的視角

最終仲裁者是 Google 自己。兩個必看:

然後:把它自動化

誠實說,上面三層做完一次要 3–5 小時,而且六個月後網站一改版,它又會壞。這也是為什麼我們現在的做法是把第一、二層寫成腳本,掛在 CI 或排程裡:從 sitemap 拉出全部 URL,抓每一頁的 hreflang,在記憶體裡建一張圖,然後檢查每條邊是否雙向、每個節點是否有 self-loop、每個 URL 回應是否為 200。跑完輸出一份 diff。

一個 5 語系、2,000 頁的站,這支腳本跑完大約 6 分鐘,可以取代掉大部分的人工 audit。剩下需要人判斷的,只有 x-default 該指哪裡、以及語系碼的商業決策(要不要拆 en-GB)——這些本來也不該讓工具決定。

6. 我們的 hreflang audit checklist

這是我們每一個跨境專案都會跑一遍的清單。你可以直接拿去用。

誠實反思:什麼時候你根本不需要 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 把網址丟給我們,我們會直接跑一遍前兩層檢查,把發現的問題列給你——不收費,也不綁後續合作。多數情況下,你自己或你的工程師看完就能修好。

SHARE · 覺得有用?
分享到 LINE 分享到 X ← 回內容專區