Component Interpolation
Render Vue components and HTML tags with props inside translation strings — keeping the full sentence in one place for translators and content writers.
From template to translation string
The starting point is usually a hardcoded template with components inline:
<template>
<div>
Hi {{ name }}! Your <UserBadge :level="user.level" /> is ready.
<AppButton variant="primary" @click="startTour">Start tour</AppButton>
</div>
</template>With tanzlate you extract the sentence into a translation string and map the component tags.
PascalCase components must be registered
:components supplies props for a tag — it never resolves the component itself. Register PascalCase components once with registerComponent. An unregistered tag does not render as a component: its text stays visible and a console warning names the tag. Lowercase HTML tags (<a>, <strong>, <b>) work with no registration.
import { registerComponent } from '@tanzlate/vue';
import UserBadge from '@/components/UserBadge.vue';
import AppButton from '@/components/AppButton.vue';
registerComponent('UserBadge', UserBadge);
registerComponent('AppButton', AppButton);{
"onboarding": {
"welcome": "Hi {{ name }}! Your <UserBadge /> is ready. <AppButton>Start tour</AppButton>"
}
}<Tanzlate
:t-z="tanz"
i18n-key="welcome"
:values="{ name: user.name }"
:components="{
UserBadge: { level: user.level },
AppButton: { variant: 'primary', onClick: startTour },
}"
/>Props removed from the template move into the :components object. The translation string keeps the full readable sentence.
HTML tags
Lowercase tags (<b>, <a>, <strong>) are rendered as real HTML elements — no v-html and no registration needed:
{ "help": "Read the <a>documentation</a> or ask on <strong>Discord</strong>." }<Tanzlate
:t-z="tanz"
i18n-key="help"
:components="{
a: { href: 'https://tanzlate.dev', target: '_blank' },
}"
/>Using the same component twice
Suffix duplicate tags with -N to differentiate them:
{ "links": "Go to <NuxtLink>home</NuxtLink> or <NuxtLink-2>profile</NuxtLink-2>." }<Tanzlate
:t-z="tanz"
i18n-key="links"
:components="{
NuxtLink: { to: '/' },
'NuxtLink-2': { to: '/profile' },
}"
/>The suffix is stripped before resolving the component — both resolve to NuxtLink.
Nested components
Components can nest — the parser handles it recursively:
{
"course": "Wunderbar! <NuxtLink>The customer <strong>{{ name }}</strong></NuxtLink> finished the <NuxtLink-2>course</NuxtLink-2>."
}The parser produces this structure before rendering:
[
'Wunderbar! ',
{
tag: 'NuxtLink',
content: ['The customer ', { tag: 'strong', content: 'Arthur' }],
},
' finished the ',
{ tag: 'NuxtLink-2', content: 'course' },
'.',
];Component registry
For components used across many translation strings, register them once globally instead of passing :components on every usage:
// main.ts
import { registerComponent } from '@tanzlate/vue';
import UserBadge from '@/components/UserBadge.vue';
registerComponent('UserBadge', UserBadge);The two are not alternatives — they do different jobs:
| Resolves the tag to a component | Supplies props | |
|---|---|---|
registerComponent | ✅ required for PascalCase | — |
:components | ❌ never | ✅ per usage |
So a PascalCase tag needs registerComponent. :components is optional on top, for props that vary between usages.