最近因為想要讓網站的「關於我」、「首頁」與「作品集」能有中英文對照的功能(我需要增加外國的觸及!),所以我嘗試用 AI 幫我寫了一個自動切換語系的按鈕。原本以為只是一個簡單的 JavaScript 按鈕與 CSS 的切換,沒想到卻意外踩了個不小的坑。

這篇快速紀錄一下我遇到的問題,以及後來如何透過改寫 Hugo Shortcode 來優化這個功能。

踩到的坑:全域綁定的災難

一開始,我請 AI 幫我設計一個語言切換功能。它給我的解法看起來很強大:

  1. 注入到導航列 (Nav Bar):透過一段全局的 JavaScript,在網頁載入後,強制去尋找網站右上角的選單 #menu,把一個「中/英」切換按鈕塞進去。
  2. 全域狀態綁定 (Global State):當你按下按鈕時,會把 lang-en 這個 class 綁定在整個網頁的 <html> 標籤上。
  3. 瀏覽器記憶 (Local Storage):甚至還貼心地加了 localStorage 來記住使用者的選擇,讓他們切換到其他頁面時「保持」英文。

聽起來很完美,對吧?但這就是災難的開始:

  • 並非每篇文章都有英文版:我的部落格文章多半只有中文,只有特定幾頁介紹頁面有雙語翻譯。但因為這個按鈕是「全域」的,當讀者在某頁切成英文後,點進其他純中文的文章時,全域 CSS 會嘗試把中文隱藏(因為 <html> 標籤上記住了要看英文),或者是這會導致沒有英文的頁面內容排版錯亂。
  • 畫面閃爍 (Flash of Unstyled Content):由於是用 JS 動態注入按鈕到右上角導航列,這會導致網頁載入完成時,選單才突然跳出一個按鈕。
  • 影響範圍不可控:將行為綁定在最高層級的 HTML 結構與 localStorage 往往會牽連到其他完全不需要多語系的頁面。

解決方法:回歸局部、擁抱 Shortcode

為了一次解決這些問題,我決定拔除所有全域性的語言切換腳本,改成採用「局部(限定頁面)」的作法,主要包含兩個步驟:

1. 限定作用域的 CSS 寫法

捨棄在 <html> 掛載 class,改成針對當前身處頁面的 <body class="page-lang-en"> 進行操作。修改 layouts/partials/extend_head.html 裡面與語言相關的 CSS:

<style>
/* 預設隱藏英文版 */
.lang-en { display: none; }

/* 當特定所在頁面觸發切換時,才隱藏中文,顯示英文 */
body.page-lang-en .lang-en { display: block; }
body.page-lang-en .lang-zh { display: none; }
</style>

2. 製作專屬的 Hugo Shortcode

我拔掉了會亂篡改全域導航列的 JavaScript,以及會惹麻煩的 localStorage。取而代之的是建立了一個專屬頁面內的 Hugo 短代碼 (Shortcode) layouts/shortcodes/lang-toggle.html

<div class="lang-toggle-container" style="margin-bottom: 20px;">
  <button onclick="document.body.classList.toggle('page-lang-en'); var isEn = document.body.classList.contains('page-lang-en'); this.innerHTML = isEn ? '🌐 切換為中文 (Switch to Chinese)' : '🌐 切換為英文 (Switch to English)';" style="font-size: 0.9rem; font-weight: 600; padding: 6px 14px; border: 1.5px solid var(--border, #ccc); border-radius: 6px; cursor: pointer; background: transparent; color: var(--primary, inherit); transition: all 0.2s;">
    🌐 切換為英文 (Switch to English)
  </button>
</div>

3. 手動安插在需要的頁面

現在,我只需要在真正有提供雙語版本的 Markdown 檔案最上方加上 {{< lang-toggle >}} 即可(文章中需加上註解避讓解析):

---
title: "關於我 | About Me"
---

<div class="lang-zh"> 這裡是中文介紹... </div> <div class="lang-en"> This is English introduction... </div>

結論

這次的教訓提醒我,「全域型功能」雖然方便,但帶來的副作用往往很難收拾。 尤其是在處理多語系這種並非 100% 覆蓋全站的漸進式功能時,捨棄全局設定並給予特定頁面局部控制權,才是更穩健且好維護的做法!