Internationalization (I18n)

Messages & ICU Syntax

Format strings with ICU message syntax in VitNode, including variables, pluralization, rich text tags, and select rules.

VitNode localizes strings using standard ICU MessageFormat, parsed and rendered through use-intl.

Quick start

1. Define Message Strings

plugins/blog/src/locales/en.json
{
  "@vitnode/blog": {
    "welcome": "Welcome back, {name}!",
    "articles_count": "{count, plural, =0 {No articles} one {1 article} other {# articles}}",
    "terms_notice": "By clicking continue, you agree to our <link>Terms of Service</link>."
  }
}

2. Render in React Components

plugins/blog/src/views/blog-header.tsx
import { useTranslations } from "use-intl"
import { Link } from "@tanstack/react-router"

export const BlogHeader = ({ count, name }: { count: number; name: string }) => {
  const t = useTranslations("@vitnode/blog")

  return (
    <header className="flex flex-col gap-2">
      <h1>{t("welcome", { name })}</h1>
      <p>{t("articles_count", { count })}</p>

      {/* Rich text with custom tags */}
      <small className="text-muted-foreground">
        {t.rich("terms_notice", {
          link: (chunks) => <Link to="/terms" className="underline">{chunks}</Link>,
        })}
      </small>
    </header>
  )
}

ICU Syntax Reference

1. Variables & Numbers

{
  "price": "Total: {amount, number, ::currency/USD}",
  "date": "Published on {date, date, medium}"
}

2. Cardinal Pluralization

{
  "unread": "{count, plural, =0 {No unread messages} one {1 unread message} other {# unread messages}}"
}

3. Select / Enums

{
  "status": "{status, select, draft {Draft} published {Published} other {Archived}}"
}

Where Message Files Live

FolderAudiencePurpose
src/locales/{locale}.jsonFrontendBrowser UI, page text, and AdminCP navigation
src/locales/api/{locale}.jsonAPI ServerTransactional emails and backend validation errors

Learn More