早期網站或服務對於各種語言的使用者,在首頁都會出現一個選擇語系的畫面,這樣的設計已經非常過時,使用體驗很差。現在很多網站都是使用單一網址,當使用者進到網頁後,程式會自動判定瀏覽器所設定的語系進行轉頁,原理其實是透過判斷 HTTP Request 中的 Accept-Language Header 設定來實現,詳細規範可以參考 RFC-2616 (14.4 Accept-Language) 章節。
那麼如何設計自動判定語系跳轉頁面的功能呢?假設我們不同語系的入口網址設計如下:
- 繁體中文:http://domain.com/zh-TW/
- 簡體中文:http://domain.com/zh-CN/
- 預設英文:http://domain.com/en-US/
要實現判斷使用者語系自動跳轉網頁有兩種方法,一種為不需要 HTTP Server 的設定,直接透過 JavaScript 進行跳轉。範例程式碼如下 (GitHub),可以把這樣的程式放在 index.html 首頁,使用者進入厚就會自動跳轉,由於是透過 JavaScript 實現,如果 JavaScript 功能被關閉當然就 GG 惹!
try { var switchPage = function (language) { switch (language) { case 'zh-cn': console.log('/zh-CN' + window.location.pathname); window.location.href = '/zh-CN' + window.location.pathname; return true; break; case 'zh': case 'zh-tw': console.log('/zh-TW' + window.location.pathname); window.location.href = '/zh-TW' + window.location.pathname; return true; break; case 'en': case 'en-us': console.log('/en-US' + window.location.pathname); window.location.href = '/en-US' + window.location.pathname; return true; break; default: } return false; }; // detect window.navigator.languages var found = false; if (typeof(window.navigator.languages) === 'object') { for (var index in window.navigator.languages) { console.log(window.navigator.languages[index].toLowerCase()); found = switchPage(window.navigator.languages[index].toLowerCase()); if (found) break; } } if (!found) { var lang = window.navigator.userLanguage || window.navigator.language; var relang = lang.toLowerCase(); found = switchPage(relang); } if (!found) { window.location.href = '/en-US' + window.location.pathname; } } catch (e) { window.location.href = '/en-US' + window.location.pathname; }
上述使用 JavaScript 轉頁的方法雖然比較簡單,但是對於 SEO (搜尋引擎最佳化) 是比較不友善的做法,因為首頁 index.html 變成一個只能專門用來跳轉頁面的程式碼,對於搜尋引擎 Index 的建立與搜尋結果都不佳。
再來介紹第二種方法,透過 HTTP Server 判定 Header 來跳轉,這樣的方法不需要在 http://domain.com 回傳任何,僅需要送出正確的 302 讓瀏覽器自動跳轉即可,這樣的方法對於搜尋引擎是最友善的,可以正確的在不同國家顯示對應的搜尋結果。
以 Nginx 為例 (有好一陣子沒用 Apache 了),可以在設定檔中加入以下設定 (GitHub),這個版本已經有考慮 Request 透過 Proxy 的重導問題,對於大型的分散式架構也可以正確執行。
server { ... # detect Accept-Language auto redirect to langauge path location = / { # Setup language prefix set $prefix_language $http_accept_language; if ($http_accept_language ~* '^(.+?),') { set $prefix_language $1; } # Setup redirect Schema set $redirect_schema $scheme; if ($http_X_Forwarded_Proto = 'https') { set $redirect_schema $http_X_Forwarded_Proto; } # Setup redirect Host set $redirect_host $host; if ($http_X_Forwarded_Host != '') { set $redirect_host $http_X_Forwarded_Host; } # Setup URL set $lang_url $redirect_schema://$redirect_host; if ($prefix_language ~* 'zh-TW') { return 302 $lang_url/zh-TW/; } if ($prefix_language ~* 'zh-CN') { return 302 $lang_url/zh-CN/; } # Default en-US return 302 $lang_url/en-US/; } }
這樣一來,當使用者連線到 http://domain.com 就會自動偵測 HTTP Header 然後回應 302 讓瀏覽器跳轉,測試的時候要注意,由於瀏覽器通常都會有 Cache 機制,比較保險的測試方式可以透過以下 CURL 命令來模擬瀏覽器發送封包,確認設定後 Server 回應封包是正確的。
curl 'http://domain.com/' -H 'Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4' -v
最後提醒一下,不同語系頁面的 HTML 記得在 Head Tag 標註各種語系的 hreflang 設定 URL,SEO 才會比較友善喔。如下:
<link rel="alternate" hreflang="x-default" href="http://domain.com/" /> <link rel="alternate" hreflang="zh-TW" href="http://domain.com/zh-TW/" /> <link rel="alternate" hreflang="zh-CN" href="http://domain.com/zh-CN/" /> <link rel="alternate" hreflang="en-US" href="http://domain.com/en-US/" /> <link rel="alternate" hreflang="zh" href="http://domain.com/zh-CN/" /> <link rel="alternate" hreflang="en" href="http://domain.com/en-US/" />
收工!