CJK Language Support
Full support for Chinese, Japanese, and Korean text with proper emphasis formatting.
Streamdown includes built-in support for CJK (Chinese, Japanese, Korean) languages, ensuring that emphasis markers like bold and italic work correctly with ideographic punctuation. This is particularly important for AI-generated content, where language models naturally place emphasis markers around phrases that include or end with punctuation.
The Problem
The CommonMark/GFM specification has a limitation where emphasis markers (** or *) adjacent to ideographic punctuation marks occasionally fail to be recognized. This causes formatting to break in CJK text:
**この文は太字になりません(This won't be bolded)。**この文のせいで(It is due to this sentence)。Without CJK-friendly parsing, the text above would render as plain text instead of bold because the closing ** appears next to the Japanese period.
The Solution
Streamdown uses the remark-cjk-friendly and remark-cjk-friendly-gfm-strikethrough plugins to handle CJK text properly. This plugin implements an improved parsing approach that correctly recognizes emphasis markers adjacent to ideographic punctuation.
Supported Features
Bold Text with Punctuation
Works correctly with all ideographic punctuation marks:
**日本語の文章(括弧付き)。**この文が後に続いても大丈夫です。
**中文文本(带括号)。**这句子继续也没问题。
**한국어 구문(괄호 포함)**을 강조.Japanese: 日本語の文章(括弧付き)。この文が後に続いても大丈夫です。
Chinese: 中文文本(带括号)。这句子继续也没问题。
Korean: 한국어 구문(괄호 포함)을 강조.
Italic Text with Punctuation
*これは斜体のテキストです(括弧付き)。*この文が後に続いても大丈夫です。
*这是斜体文字(带括号)。*这句子继续也没问题。
*이 텍스트(괄호 포함)*는 기울임꼴입니다.Japanese: これは斜体のテキストです(括弧付き)。この文が後に続いても大丈夫です。
Chinese: 这是斜体文字(带括号)。这句子继续也没问题。
Korean: 이 텍스트(괄호 포함)는 기울임꼴입니다.
Strikethrough with Punctuation
Streamdown includes remark-cjk-friendly-gfm-strikethrough for proper strikethrough support:
~~削除されたテキスト(括弧付き)。~~この文は正しいです。
~~删除的文字(带括号)。~~这个句子是正确的。
~~이 텍스트(괄호 포함)~~를 삭제합니다.Japanese: 削除されたテキスト(括弧付き)。この文は正しいです。
Chinese: 删除的文字(带括号)。这个句子是正确的。
Korean: 이 텍스트(괄호 포함)를 삭제합니다。
Mixed Content
CJK and English text work seamlessly together:
**重要提示(Important Notice):**请注意。Result: 重要提示(Important Notice):请注意。
Supported Punctuation
The plugin handles all common ideographic punctuation marks:
- Parentheses:
() - Brackets:
【】「」〈〉 - Periods:
。. - Commas:
,、 - Questions:
? - Exclamations:
! - Colons:
:
Why This Matters for AI
Language models generate markdown naturally, often placing emphasis markers around phrases that include punctuation. Without CJK-friendly parsing, AI-generated content in Chinese, Japanese, or Korean would have broken formatting.
- ❌ Without CJK support:
- The model writes:
**この用語(読み方など)**について説明します。- The user sees: **この用語(読み方など)**について説明します。 (not bold!)
- The model writes:
- ✅ With CJK support:
- The model writes:
**この用語(読み方など)**について説明します。- The user sees: この用語(読み方など)について説明します。 (properly bolded!)
- The model writes:
Enabling CJK Support
CJK support requires the CJK plugin. Install it:
npm install @streamdown/cjkThen import and pass the plugin to Streamdown:
import { Streamdown } from "streamdown";
import { cjk } from "@streamdown/cjk";
export default function Page() {
return (
<Streamdown plugins={{ cjk: cjk }}>
{markdown}
</Streamdown>
);
}Without the CJK plugin, emphasis markers adjacent to ideographic punctuation may not render correctly.
Autolink Boundary Handling
The CJK plugin also prevents autolinks from swallowing trailing CJK punctuation. When a URL ends with CJK punctuation characters, the plugin splits the link so the punctuation appears as regular text.
Example:
Check out https://example.com。这是一个链接。Without CJK support, the trailing 。 would be included in the URL. With the plugin, the link ends at https://example.com and the period is rendered as text.
Supported boundary characters:
。.,、?!:;()【】「」『』〈〉《》
Plugin Configuration
Using the Factory Function
For advanced configuration, use createCjkPlugin:
import { Streamdown } from "streamdown";
import { createCjkPlugin } from "@streamdown/cjk";
const cjk = createCjkPlugin();
export default function Page() {
return (
<Streamdown plugins={{ cjk }}>
{markdown}
</Streamdown>
);
}Plugin API
The CJK plugin provides remark plugins in a specific order for proper integration:
interface CjkPlugin {
// Plugins that run BEFORE remarkGfm (e.g., remark-cjk-friendly)
remarkPluginsBefore: Pluggable[];
// Plugins that run AFTER remarkGfm (e.g., autolink boundary, strikethrough)
remarkPluginsAfter: Pluggable[];
// @deprecated - Use remarkPluginsBefore and remarkPluginsAfter instead
remarkPlugins: Pluggable[];
}Streamdown automatically handles the plugin ordering. If integrating manually, ensure:
remarkPluginsBeforeruns beforeremarkGfm(modifies emphasis handling)remarkPluginsAfterruns afterremarkGfm(enhances autolinks and strikethrough)