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!)
✅ With CJK support:
  • The model writes: **この用語(読み方など)**について説明します。- The user sees: この用語(読み方など)について説明します。 (properly bolded!)

Enabling CJK Support

CJK support requires the CJK plugin. Install it:

npm install @streamdown/cjk

Then import and pass the plugin to Streamdown:

app/page.tsx
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.

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:

app/page.tsx
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:

  1. remarkPluginsBefore runs before remarkGfm (modifies emphasis handling)
  2. remarkPluginsAfter runs after remarkGfm (enhances autolinks and strikethrough)