
系列:30 天打造企業級 PLM|面向:前端|素材:前端實碼與踩坑紀錄
元件庫替你做了 90% 的事,剩下那 10%,也就是它自作聰明的部分,會花掉你 90% 的時間。Mini-PLM 前端建在 Ant Design 6 加 Pro Components 上,今天集中講幾個最貴的陷阱與 i18n 架構
ProTable 在 ellipsis: true 與 render 並用時,render 的第一個參數不是 raw value,是包過 ellipsis 的 ReactElement。直接拿第一參數做字串處理,輕則顯示 [object Object],重則 toFixed is not a function 直接白屏。存活下來的寫法(實碼,AdminManufacturer.tsx):
{
title: "Notes",
dataIndex: "notes",
ellipsis: true,
render: (_, r) => r.notes || "—", // ← 第一參數棄用,一律從 record 取 raw
},
團隊紀律固定成一句話:只要欄位有 render,就從 record[dataIndex] 取原始資料,第一參數當作不存在。這條不分 ellipsis 有沒有開,因為別人維護時加一個 ellipsis: true,你的 render 就默默壞掉,而 TypeScript 型別救不了你,第一參數本來就宣告成聯集。

上半部是最常見的誤區:ellipsis 先把第一參數包成 ReactElement,後續再做字串或數值處理便可能直接出錯。下半部刻意繞過第一參數,從 record 取得原始值,讓顯示邏輯不受 ProTable 包裝行為影響。
以前在 Oracle Agile PLM 中,多語系是交由後端處理的。
底層透過 Java EE 的 ResourceBundle(.properties 資源檔)在 WebLogic 端解析,帶來幾大痛點:
.properties 資源檔,維護兩份翻譯檔,經常造成某一端缺字漏翻;Mini-PLM 將介面多語系完全移至前端 React 現代 i18n 體系,採用「4 語言 × 10 領域命名空間」結構:

這次調整不只是把翻譯檔搬到前端,而是重新劃分責任:程式介面的固定文字由 locale 與 namespace 管理;管理員建立的動態欄位則保留在資料層,交給 mp_localized 處理,兩者不共用同一套 key。
語系資源目錄 (locales)/
en/ zh-TW/ zh-CN/ th/
common.json auth.json status.json message.json nav.json
layout.json form.json item.json workflow.json admin.json
命名空間按領域切,跟 Day 17 的 store 切片同一個思路:form、item、workflow 對應業務領域,common、message、nav 對應框架層。取用時明示命名空間,t("form:workflow"),維護者一眼知道去哪個檔案找 key。
實戰規則兩條。新增 key 四語言一起補:缺 key 的語言會顯示 key 本身,等於把工程術語直接端給泰國產線的操作員。CI 還沒擋這件事,目前靠 code review 人肉守,這是 Day 30 工具化清單的一項。動態欄位的名稱不走 i18n:Day 4 的 metadata 欄位名稱(field_name)是管理員輸入的資料,不是程式資源,資料的多語言是另一個題目(mp_localized 表),跟程式 i18n 分開處理。
系列開頭提過 v1 到 v2 帶著 React 19 加 antd 6 升級。幾個實際的收斂點:ProTable v3 的 API 位移(actionRender 行為變動,Day 16 加減按鈕消失的坑)、gcTime 取代 cacheTime(TanStack Query v5)、useQuery 拿掉 onSuccess/onError 改用 useEffect 監聽。升級的心法是先鎖行為再升版本:E2E(Day 20)是升級的安全網,沒有它,升上去等於閉眼開車。
寫 Playwright 測試(與本系列的截圖腳本)時被 antd 咬過的,Day 20 會再回收:
isVisible() 不等待。它是即時判斷,antd 元件還在動畫中就回 false,一律改 waitFor
Escape 關掉建議清單再點按鈕getByRole("button", { name: /登\s*入/ })。這個坑在寫本系列截圖腳本時當場又踩一次hasText 是包含比對,「測試表單」會先命中「新測試表單」。精準選取要用 exact 或更特定的 locator共同教訓:UI 測試面對的不是你的程式,是元件庫渲染後的 DOM。寫 selector 前先開 DevTools 看真實結構,不要憑 API 文件想像。
render 一律從 record 取值,防的是別人日後加 ellipsis;i18n 按領域切命名空間、程式碼英文唯一;升級靠 E2E 鎖行為。跟元件庫相處的要訣大概就是:它幫你省的時間收下,它埋的雷記下來變成紀律。明日 Day 19:SSE 即時通知——「我明明把權限開給他了!」的完整解法。