Intl.Segmenter counts characters the way a reader does
"๐จโ๐ฉโ๐ง".length is 8 and spreading it gives 5, so cutting a preview with slice(0, 20) can split a family emoji into strangers. Intl.Segmenter walks a string in graphemes, which is what a reader means by a character.
const graphemes = new Intl.Segmenter("tr", { granularity: "grapheme" });
const preview = [...graphemes.segment(text)]
.slice(0, 20)
.map((s) => s.segment)
.join("");With granularity: "word" each segment carries an isWordLike flag, a better count than splitting on spaces. Build the segmenter once; constructing one is the expensive part.
javascripti18n