Slugs
slug converts Chinese text to a URL-safe string.
import { slug } from "@kensio/pinyinjs";
slug(dictionary, "我想学中文。"); // "wo3-xiang3-xue2-zhong1wen2"Slugs use dictionary readings and word boundaries:
| Text | This | A slugifier over the characters |
|---|---|---|
| 银行 | yin2hang2 |
yin2xing2 — wrong reading |
| 西安 | xi1an1 |
xian — a different word |
| 中文 | zhong1wen2 |
zhong1-wen2 — not one word |
The conversion preserves these distinctions:
- Context selects the reading. 行 is
hángin 银行. See converting. - Separators follow word boundaries. 北京市银行 becomes
bei3jing1-shi4-yin2hang2. See orthography. - Syllable boundaries remain distinct. A toneless slug replaces the apostrophe
in
xī'ānwith a separator, producingxi-an.
slug(dictionary, "重庆火锅"); // "chong2qing4-huo3guo1"slug(dictionary, "重庆火锅", { tones: "none" }); // "chongqing-huoguo"Tone numbers are included by default to distinguish readings. Without tones,
树, 书 and 输 all become shu.
Different words with the same pronunciation still produce the same slug:
slug(dictionary, "权利"); // "quan2li4"slug(dictionary, "权力"); // "quan2li4"Use a hash suffix to reduce these collisions.
Hash suffixes
Section titled “Hash suffixes”hash appends a short hash of the original text.
slug(dictionary, "权利", { hash: true }); // "quan2li4-1lpt"slug(dictionary, "权力", { hash: true }); // "quan2li4-uta0"The suffix is calculated from the source text. Homophones can therefore get different suffixes, and a reading change in a later release leaves the suffix unchanged.
The default suffix has four base-36 characters (about 1.7 million values).
Use hash: 6 for six characters. The maximum is seven because the hash is
32 bits.
When enabled, the hash is appended to every slug.
Uniqueness and stable URLs
Section titled “Uniqueness and stable URLs”Tones and hashes reduce collisions but cannot guarantee uniqueness. Check a new slug against the slugs already stored by your application.
Store generated slugs as permanent values. Dictionary and reading-rule updates can change pronunciations or word boundaries in later releases.
Latin, digits and punctuation
Section titled “Latin, digits and punctuation”Latin text is folded to ASCII letters, and digits stay as digits. Punctuation, emoji and other marks become word boundaries.
slug(dictionary, "iPhone 15 发布"); // "iphone-15-fa1bu4"slug(dictionary, "《中文》:真好!"); // "zhong1wen2-zhen1-hao3"slug(dictionary, "2024年报告"); // "2024-nian2-bao4gao4"Set numbers: "read" to convert digits to their spoken reading:
slug(dictionary, "2024年报告", { numbers: "read" });// "er4-ling2-er4-si4-nian2-bao4gao4"Input with no usable content, such as an empty string or 《》!, returns an
empty string. Set fallback to use another value.
slug(dictionary, "!?。", { fallback: "untitled" }); // "untitled"Options
Section titled “Options”| Option | Default | Does |
|---|---|---|
tones |
"numbers" |
"none" leaves the tones off |
separator |
"-" |
what goes between words |
syllables |
"join" |
"separate" cuts every syllable apart |
umlaut |
"v" |
how ü is written; "u" merges 绿 into 路 |
numbers |
"keep" |
"read" says the digits out |
hash |
none | true for four characters, or a length |
maxLength |
none | the longest it may be, cut at a word |
fallback |
"" |
what to write where a text slugs to nothing |
locale |
"zh-CN" |
"zh-TW" for 國語 readings |
sandhi |
as convert |
一, 不 and optional third-tone sandhi |
Slugs control their own formatting. The conversion options notation,
capitals, apostrophe, punctuation and grouping are unavailable.
maxLength truncates at a word boundary and preserves the hash suffix:
slug(dictionary, "北京市银行", { maxLength: 20 }); // "bei3jing1-shi4"Search keys and identifiers
Section titled “Search keys and identifiers”Choose a different separator to make identifiers or search keys:
| Want | Options | 中文 |
|---|---|---|
| A URL slug | none | zhong1wen2 |
| A search key | { tones: "none", separator: "" } |
zhongwen |
| A name in code | { separator: "_" } |
zhong1wen2 |
| An anchor id | { tones: "none", hash: 4 } |
zhongwen-… |
A search key with no tones or separators lets zhongwen match 中文 and xian
match 西安. This intentionally combines readings that URL slugs distinguish.
slug(dictionary, "中文", { tones: "none", separator: "" }); // "zhongwen"At the command line
Section titled “At the command line”$ pinyinjs slug 我想学中文。wo3-xiang3-xue2-zhong1wen2
$ pinyinjs slug --tones none 西安交通大学xi-an-jiaotong-daxue
$ pinyinjs slug --hash 权利 权力quan2li4-1lptquan2li4-uta0The CLI accepts --tones, --separator, --syllables, --umlaut, --hash,
--hash-length, --max-length, --fallback, --read-numbers, --locale,
--third-tone and --no-sandhi. --hash-length enables hashing. With no
arguments, the command reads one title per line from standard input:
$ cat titles.txt | pinyinjs slug --hash