Chinese Localization

Language Flip Text

Flips one sentence between languages with a split-flap or vertical roll, and can settle on a chosen locale — demoed in Traditional Chinese, English and Japanese.

Cycles one sentence through its language versions — 繁中, English, 日本語 and so on. The default roll mode scrolls the old sentence up and springs the new one in from below while the container width eases between lengths; languages differ wildly in length, and that is what sets this apart from an ordinary text rotator. The flap mode flips a split-flap board character by character, padding shorter sentences with blank cells. Set settleOn and it plays one full round before stopping on the chosen language; pass "auto" to stop on the visitor's browser language — a good fit for a "now available in your language" announcement headline.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add language-flip-text.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

2000
Active edited usageDefault props
<LanguageFlipText/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/language-flip-text.en.json

Or, once registries are configured in components.json, install it as @webberui/language-flip-text.

Usage

import { LanguageFlipText } from "@/components/ui/language-flip-text";

const phrases = [
  { lang: "zh-Hant", label: "繁中", text: "現在,用你的語言" },
  { lang: "en", label: "English", text: "Now, in your language" },
  { lang: "ja", label: "日本語", text: "いま、あなたの言葉で" },
];

<LanguageFlipText
  phrases={phrases}
  settleOn="auto"
  className="text-3xl font-semibold"
/>

<LanguageFlipText
  variant="flap"
  as="p"
  phrases={[
    { lang: "zh-Hant", label: "繁中", text: "歡迎" },
    { lang: "en", label: "English", text: "Welcome" },
    { lang: "ja", label: "日本語", text: "ようこそ" },
  ]}
/>

Props

PropTypeDefaultDescription
phrasesLanguageFlipPhrase[]—Sentences to cycle through, one per language
variant"roll" | "flap""roll"Transition style: roll scrolls vertically (container width eases between lengths), flap flips character by character
indexnumber—Controlled current phrase index; when omitted the component manages it (uncontrolled)
defaultIndexnumber0Initial index in uncontrolled mode
onIndexChange(index: number) => void—Called when the phrase changes, with the new index
autoPlaybooleantrueWhether to cycle automatically
intervalnumber2000Autoplay interval (milliseconds)
settleOnstring—Which language to stop on after one full round: a lang (e.g. "zh-Hant"), or "auto" to read the browser language
loopbooleantrueWhether to wrap back to the first phrase after the last; ignored when settleOn is set
showLabelbooleantrueWhether to show the language pill
as"h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "div" | "span""h2"Tag of the root element
classNamestring—Passed to the root element

LanguageFlipPhrase

FieldTypeDefaultDescription
langstring—BCP 47 language tag (e.g. zh-Hant, en, ja), written to the sentence node's lang attribute
labelstring—Name shown on the language pill (e.g. 「繁中」 (Traditional Chinese), "English")
textstring—The sentence in this language

matchPhraseLocale(phrases, locale) is also exported by name; it returns the index of the closest phrase for a locale (or -1 when none matches).

CSS variables

VariableDefaultDescription
--wb-language-flip-duration420msDuration of the roll container's width/height easing and the pill crossfade
--wb-language-flip-flap280msDuration of one cell flip (both halves together)
--wb-language-flip-stagger30msLeft-to-right delay between flap cells

How it works

  • Width easing: roll measures the active sentence and tweens the container's width/height directly rather than using a scale-based layout animation, so the text never squashes or stretches mid-transition. Sentences render on one line; shrink the type for long ones.
  • Flaps: each cell is split into two halves — the top half falls back and the bottom half drops from 90°. The cell count follows the longest phrase and shorter ones are padded with blank cells; strings are split with Array.from, so CJK characters and emoji are never broken apart.
  • Settling: settleOn waits until every phrase has shown once before stopping on the chosen language. "auto" reads navigator.languages inside useEffect, so the server render matches the first client render; browsers reporting zh-TW/zh-HK map to zh-Hant and zh-CN maps to zh-Hans, and with no match it settles back on the initial phrase.
  • Every sentence node carries a lang attribute so the browser picks the right fonts and line-breaking rules for CJK text.

Accessibility

  • The root has aria-live="off" so autoplay does not make screen readers announce every change; an sr-only copy of the current sentence, with the correct lang, provides the full text
  • The visual roll layer, flap cells and language pill are hidden from assistive technology to avoid double reading and letter-by-letter announcements
  • Autoplay pauses on hover or keyboard focus; while autoplaying the root is focusable with Tab (with a focus-visible ring), and arrow keys then step to the previous/next phrase
  • When the user's system has reduce motion enabled, nothing flips or rolls — the text switches directly with a 150ms fade-in