中文在地化
字數統計文字區
中英混排字數統計 React textarea 元件:字數/字元/位元組三種計法即時切換、上限進度環、接近與超限警示,IME 組字中凍結計數不誤計,可選硬性上限。
中文的「字數」和英文的 word count 不是同一回事:漢字每個字算一字,英文則是連續字母整段算一個 word;送進資料庫或舊系統時,又常以位元組計。這個 textarea 把三種計法放在右下角的切換籤裡,即時顯示「目前數字 / 上限」與一個 SVG 進度環——超過 warnAt 比例轉琥珀色、超限轉紅並抖動一下。注音、假名等輸入法組字期間計數會凍結,不會把組字字母算進去;開啟 hardLimit 時超限即阻止輸入,但會等組字結束才裁切,不會把正在組的字剪成半個。文字值與計數模式各自支援受控/非受控雙模式。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add cjk-word-count-textareaPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
60
0.8
編輯中的呼叫預設屬性
<CjkWordCountTextarea/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/cjk-word-count-textarea.json或在 components.json 設定 registries 後,改用 @webberui/cjk-word-count-textarea 安裝。
使用
import { CjkWordCountTextarea } from "@/components/ui/cjk-word-count-textarea";
<CjkWordCountTextarea
label="貼文內容"
maxCount={140}
defaultMode="words"
autoResize
onChange={(text, counts) => {
// counts 同時帶有三種計法的數字
console.log(counts.words, counts.chars, counts.bytes);
}}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
value | string | — | 受控文字值;未提供時為非受控模式 |
defaultValue | string | "" | 非受控模式的初始文字 |
onChange | (text: string, counts: CjkCounts) => void | — | 文字變動時回呼,第二參數為三種計法的即時計數 |
maxCount | number | — | 計數上限(依目前模式的數字);未提供時僅顯示計數、不畫進度環 |
mode | "words" | "chars" | "bytes" | — | 受控的計數模式,與 onModeChange 搭配使用 |
defaultMode | "words" | "chars" | "bytes" | "words" | 非受控模式的初始計數模式 |
onModeChange | (mode: CjkCountMode) => void | — | 計數模式切換時回呼 |
warnAt | number | 0.8 | 進入琥珀色警示狀態的比例門檻(0–1) |
rows | number | 4 | textarea 顯示行數 |
autoResize | boolean | false | 高度是否隨內容自動調整(以 scrollHeight 計算) |
label | string | — | 欄位標籤;未提供時以 placeholder 作為無障礙名稱 |
placeholder | string | "輸入內容⋯" | 輸入框佔位提示文字 |
hardLimit | boolean | false | 超過上限即阻止輸入;IME 組字中不截斷,組字結束才裁切 |
countOptions | CountCjkOptions | — | 傳給 countCjk 的計數選項(全形標點、Big5 折算) |
labels | CjkWordCountLabels | — | 介面文字覆寫(模式籤與警示宣告) |
className | string | — | 透傳到最外層容器並以 cn() 併入 |
CjkCounts
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
words | number | — | 中文式字數:漢字逐字計,拉丁序列以空白斷詞 |
chars | number | — | 字元數:以 Unicode code point 計 |
bytes | number | — | 位元組數:UTF-8 長度或依 bytesPerCjk 折算 |
CountCjkOptions
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
countPunctuation | boolean | false | words 模式是否把全形標點(,。!?…)也各計一字 |
bytesPerCjk | number | — | bytes 模式下每個 CJK 字元(含全形標點)固定折算的位元組數;未提供時依 UTF-8 實際長度 |
CjkWordCountLabels
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
words | string | "字數" | words 模式籤文字 |
chars | string | "字元" | chars 模式籤文字 |
bytes | string | "位元組" | bytes 模式籤文字 |
modeGroup | string | "計數模式" | 模式切換群組的無障礙名稱 |
nearLimit | string | "接近上限" | 跨越 warnAt 門檻時的螢幕閱讀器宣告前綴 |
overLimit | string | "已超過上限" | 超過上限時的螢幕閱讀器宣告前綴 |
另外具名匯出 countCjk(text, mode, opts) 與 clampCjk(text, max, mode, opts),方便在表單驗證或伺服器端用同一套規則計數與裁切;兩者都是純函式,不依賴瀏覽器 API。
細節
- words 計法:漢字(含日文假名、韓文字)每個字元算一字;英文字母、數字等連續序列以空白或 CJK 字元斷詞,整段算一個 word;全形標點預設不計,
countPunctuation: true時逐個計入。例如「我買了 3 本 React 書」算 7。 - chars 計法以 Unicode code point 計(
Array.from),emoji 等 surrogate pair 不會被拆成兩個字元。 - bytes 計法預設是 UTF-8 長度(漢字多為 3 bytes);台灣不少舊系統以 Big5 計(漢字 2 bytes),傳
countOptions={{ bytesPerCjk: 2 }}即可折算。 - 硬性上限用二分搜尋找出最長合法前綴:計數對前綴長度單調遞增,因此不必逐字重算。
autoResize先把高度歸零再讀scrollHeight,內容變少時高度也縮得回來。
可及性
label以htmlFor關聯至 textarea;未提供label時以placeholder作為aria-label- 計數文字透過
aria-describedby關聯至 textarea;超限時設定aria-invalid - 模式切換是
role="radiogroup",每個籤為role="radio"並帶aria-checked,採 roving tabindex,方向鍵可循環切換,具 focus-visible 外框 - 警示宣告位於
role="status"、aria-live="polite"區域,只在跨越warnAt或超限的瞬間宣告一次,避免每個按鍵都播報;進度環與警示圖示對輔助科技隱藏 - 使用者系統開啟「減少動態效果」時,停用超限抖動與模式籤滑動動畫,狀態直接切換