Translating Pages
Render localized strings with use-intl, declare route namespaces, and load translation bundles.
VitNode uses use-intl for frontend translations. To keep initial payloads small, pages only download the translation namespaces they explicitly declare.
Quick start
1. In a Plugin Route (Recommended)
Plugin routes declare their namespaces as messages in routes.ts. VitNode loads the strings in parallel with the route chunk automatically:
import { definePluginRoutes, lazy, page } from '@vitnode/core/routing'
export const routes = definePluginRoutes([
page('/blog/about', {
component: lazy(() => import('./pages/about-page')),
messages: ['@vitnode/blog.about'],
}),
])Read strings directly with useTranslations:
import { useTranslations } from 'use-intl'
const AboutPage = () => {
const t = useTranslations('@vitnode/blog.about')
return <h1>{t('title')}</h1>
}
export default AboutPageAnd define the messages in plugins/blog/src/locales/en.json:
{
"@vitnode/blog": {
"about": {
"title": "About Our Blog"
}
}
}Keep feature copy in the plugin
Host messages are for the site shell. A product page should declare its plugin
namespace as the route's messages and keep its locale JSON beside the route.
Placeholders and Pluralization
VitNode supports ICU message syntax out of the box:
{
"cart": {
"greeting": "Hello, {name}!",
"items": "{count, plural, =0 {No items} one {1 item} other {# items}}"
}
}In your React component:
const t = useTranslations('cart')
return (
<div>
<p>{t('greeting', { name: 'Alex' })}</p>
<p>{t('items', { count: 3 })}</p>
</div>
)Global namespaces
core.global is provided by the root shell to every route, supplying shared
strings for dialogs, toasts, and buttons.