Ŵŕîţîñĝ ţŕàñšļàţàƃļé çöḿþöñéñţš
Àļḿöšţ éṽéŕýţĥîñĝ ýöü àļŕéàđý ŵŕîţé îš ţŕàñšļàţàƃļé. Ţĥîš þàĝé ŵàļķš ţĥŕöüĝĥ ţĥé ŕüļéš ţĥé þļüĝîñ àþþļîéš, ţĥé ŵàŕñîñĝš îţ ƒîŕéš ŵĥéñ îţ ḿàķéš à ĵüđĝéḿéñţ çàļļ ýöü šĥöüļđ ķñöŵ àƃöüţ, àñđ ţĥé ĥàļƒ-đöžéñ þàţţéŕñš ţĥàţ ƃŕéàķ éẋţŕàçţîöñ šîļéñţļý.
Ţĥé šĥöŕţ ṽéŕšîöñ
- ĴŠẊ ţéẋţ îñšîđé à ţŕàñšļàţàƃļé éļéḿéñţ → éẋţŕàçţéđ.
- Đîŕéçţ ţéẋţ îñšîđé à çöñţàîñéŕ (
<div>,<section>, …) → éẋţŕàçţéđ (àüţö-þŕöḿöţîöñ, šîļéñţ). - Đîŕéçţ ţéẋţ îñšîđé àñ üñḿàþþéđ Ŕéàçţ çöḿþöñéñţ → éẋţŕàçţéđ, ŵîţĥ à ŵàŕñîñĝ àñđ à šüĝĝéšţîöñ ţö àđđ à
componentMapéñţŕý. - Îñļîñé éļéḿéñţš ŵîţĥ çĥîļđŕéñ (
<strong>foo</strong>,<a href="…">here</a>,<em>{name}</em>) → çàþţüŕéđ àš öñé ţŕàñšļàţàƃļé ƃļöçķ; ţĥé îñļîñé éļéḿéñţ ƃéçöḿéš à þàîŕéđ ḿàŕķéŕ ŵŕàþþîñĝ îţš îññéŕ çöñţéñţ, šö ţĥé ţŕàñšļàţöŕ šééš ţĥé îññéŕ ŵöŕđš àñđ çàñ ḿöṽé ţĥé ŵŕàþþîñĝ àŕöüñđ. - Žéŕö-çĥîļđŕéñ îñļîñé éļéḿéñţš (
<br/>,<Icon/>,<Spinner/>,<Badge/>) → ƃéçöḿé šţàñđàļöñé ḿàŕķéŕš ({=mN}ŵîţĥ ñö ḿàţçĥîñĝ çļöšé) îñ ţĥé šüŕŕöüñđîñĝ ţéẋţ. - ĤŢḾĻ àñđ ÀŔÎÀ ţéẋţ àţţŕîƃüţéš (
alt,title,placeholder,aria-label, …) öñ àñý éļéḿéñţ → éẋţŕàçţéđ, îñçļüđîñĝ öñ àñ îñļîñé çĥîļđ ŵĥöšé ţéẋţ ţĥé šéñţéñçé àŕöüñđ îţ àļŕéàđý çàŕŕîéš. - Ŕéàçţ þŕöþ-ñàḿé çöñṽéñţîöñš (
label,description,heading,helpText,tooltip, …) öñ ÞàšçàļÇàšé çöḿþöñéñţš öñļý → éẋţŕàçţéđ. Öñ à þļàîñ<div>ţĥéšé ñàḿéš àŕé üšüàļļý ĐÖḾ þŕöþš öŕ éñüḿ ķéýš, ñöţ çöþý. - Ţŕàñšļàţàƃļé àţţŕîƃüţéš ŵîţĥ šţŕîñĝ-ļîţéŕàļ ţéŕñàŕîéš (
title={cond ? "A" : "B"}) → éàçĥ ƃŕàñçĥ éẋţŕàçţéđ àš îţš öŵñ ƃļöçķ. - Çöđé šþàñš îñšîđé à šéñţéñçé (
<code>,<kbd>,<samp>,<var>) → ţĥé šéñţéñçé éẋţŕàçţš àš öñé ƃļöçķ, ţĥé šþàñ ƃéçöḿéš à þàîŕéđ ḿàŕķéŕ, àñđ îţš ţéẋţ îš çàŕŕîéđ ţĥŕöüĝĥ ṽéŕƃàţîḿ. - À çöñţŕöļ îñšîđé à šéñţéñçé (
<button>,<label>,<select>,<img>, …) → ţĥé šéñţéñçé éẋţŕàçţš àš öñé ƃļöçķ àñđ ţĥé çöñţŕöļ ƃéçöḿéš à þàîŕéđ ḿàŕķéŕ, ŵîţĥ îţš ļàƃéļ ţŕàñšļàţàƃļé îñšîđé. À çöñţŕöļ ţĥàţ îš îţš þàŕéñţ'š öñļý çöñţéñţ ķééþš îţš öŵñ ƃļöçķ. - ĴŠẊ îñšîđé à çöñđîţîöñàļ (
{cond && <span>…</span>}, à ţéŕñàŕý, à.map()) → à šţàñđàļöñé ḿàŕķéŕ îñ ţĥé šéñţéñçé, àñđ ţĥé éļéḿéñţš îñšîđé îţ àŕé éẋţŕàçţéđ àñđ ţŕàñšļàţéđ öñ ţĥéîŕ öŵñ. - À šţŕîñĝ ļîţéŕàļ îñ à çöñđîţîöñàļ'š ƃŕàñçĥ (
{saving ? "Saving..." : "Save"},{cond && "Folder moved"}) → öñé ƃļöçķ þéŕ ƃŕàñçĥ, àđđŕéššéđ ƃý îţš šļöţ. - À þļàîñ éẋþŕéššîöñ ƃéšîđé ţĥé ţéẋţ (
{icon},{rows},{count}) → à ñàḿéđ þļàçéĥöļđéŕ ţĥé ţŕàñšļàţöŕ çàñ ḿöṽé. Ŵĥàţéṽéŕ îţ éṽàļüàţéš ţö îš ŕéñđéŕéđ ŵĥéŕé îţš ţöķéñ šîţš, šö àñ éļéḿéñţ šţàýš àñ éļéḿéñţ àñđ à ñüḿƃéŕ šţàýš à ñüḿƃéŕ. - À ŵĥîţéšþàçé-öñļý éẋþŕéššîöñ (
{" "},{' '},{` `}) → à šþàçé îñ ţĥé ƃļöçķ'š ţéẋţ, ñöţ à ṽàŕîàƃļé. - Ñöñ-ţŕàñšļàţàƃļé éļéḿéñţš öñ ţĥéîŕ öŵñ (
<code>,<pre>,<kbd>,<var>,<script>,<style>,<textarea>) → šķîþþéđ. - Éļéḿéñţš ḿàŕķéđ
translate="no"(öŕ àñý àñçéšţöŕ) → šķîþþéđ.
Ţĥé đéţàîļ
Ţŕàñšļàţàƃļé ĴŠẊ ţéẋţ
Ĥéàđîñĝš, þàŕàĝŕàþĥš, ƃüţţöñš, ļàƃéļš, öþţîöñš, <span>, <strong>, <em>, <a>, <b>, <i>: ţĥé ŵĥöļé šéţ öƒ éļéḿéñţš ţĥé Ŵ3Ç ĤŢḾĻ5 šþéç çļàššîƒîéš àš þĥŕàšîñĝ öŕ ţŕàñšļàţàƃļé ƃļöçķ çöñţéñţ.
<h1>Welcome</h1> // ✓ extracted
<p>Ship in every language.</p> // ✓ extracted
<button>Get started</button> // ✓ extracted
<label>Email address</label> // ✓ extracted
<a href="/docs">Read the docs</a> // ✓ extracted
<option value="fr">French</option> // ✓ extracted
Îñļîñé çĥîļđŕéñ: öñé ƃļöçķ, þàîŕéđ ḿàŕķéŕš
Ŵĥéñ àñ éļéḿéñţ ḿîẋéš ţéẋţ ŵîţĥ îñļîñé çĥîļđŕéñ, ţĥé ŵĥöļé ţĥîñĝ ƃéçöḿéš öñé ţŕàñšļàţàƃļé ƃļöçķ. Éàçĥ îñļîñé éļéḿéñţ ŵîţĥ çĥîļđŕéñ ƃéçöḿéš à þàîŕéđ ḿàŕķéŕ îñ ţĥé þàŕéñţ'š ţéẋţ: ţĥé ţŕàñšļàţöŕ šééš ţĥé îññéŕ ŵöŕđš àñđ çàñ ḿöṽé ţĥé ŵŕàþþîñĝ àŕöüñđ:
<p>
Click <a href="/docs">here</a> to read the docs.
</p>
Ţĥé éẋţŕàçţöŕ šţöŕéš ţĥîš àš "Click {=m0}here{/=m0} to read the docs.". À Ĝéŕḿàñ ţŕàñšļàţîöñ ŕéàđš "Klicken Sie {=m0}hier{/=m0}, um die Dokumentation zu lesen.": ţĥé ļîñķ ŵŕàþš ţĥé ŕîĝĥţ ŵöŕđ, àñđ à Ƒŕéñçĥ ţŕàñšļàţöŕ çàñ ḿöṽé îţ éļšéŵĥéŕé îñ ţĥé šéñţéñçé éñţîŕéļý.
Îñļîñé éļéḿéñţš ţĥàţ þŕöđüçé þàîŕéđ ḿàŕķéŕš: <span>, <strong>, <em>, <b>, <i>, <a>, <small>, <sub>, <sup>, <time>, <u>, <wbr>, <del>, <ins>, þļüš <code>, <kbd>, <samp> àñđ <var>, ŵĥöšé ţéẋţ îš çàŕŕîéđ ţĥŕöüĝĥ ṽéŕƃàţîḿ (šéé Çöđé šþàñš îñšîđé þŕöšé).
Ţĥé ƒöŕḿ çöñţŕöļš ĵöîñ ţĥàţ ļîšţ ŵĥéŕé ţĥé šéñţéñçé àŕöüñđ ţĥéḿ ĥàš ŵöŕđš öƒ îţš öŵñ (šéé Çöñţŕöļš îñšîđé þŕöšé).
Ţĥé ŕüļé îš üñîƒöŕḿ: àñý îñļîñé éļéḿéñţ ŵîţĥ àţ ļéàšţ öñé çĥîļđ → þàîŕéđ þàîŕ, ŕéĝàŕđļéšš öƒ ŵĥéţĥéŕ ţĥé îññéŕ çöñţéñţ îš ţéẋţ, àñ éẋþŕéššîöñ, àñ îçöñ, öŕ ƒüŕţĥéŕ ñéšţéđ éļéḿéñţš. Éḿþţý îñļîñé éļéḿéñţš ƃéçöḿé šţàñđàļöñé ḿàŕķéŕš îñšţéàđ. À ƒéŵ éẋàḿþļéš:
| Šöüŕçé | Éẋţŕàçţéđ ƒöŕḿ |
|---|---|
<a>here</a> | "{=m0}here{/=m0}" |
<a><Icon/></a> | "{=m0}{=m1}{/=m0}" |
<a>{userName}</a> | "{=m0}{userName}{/=m0}" |
<strong>{count}</strong> | "{=m0}{count}{/=m0}" |
<a>read <em>the</em> docs</a> | "{=m0}read {=m1}the{/=m1} docs{/=m0}" |
<Icon/> (ñö çĥîļđŕéñ) | "{=m0}" (ñö ḿàţçĥîñĝ {/=m0} çļöšé) |
<br/> (ñö çĥîļđŕéñ) | "{=m0}" (ñö ḿàţçĥîñĝ {/=m0} çļöšé) |
ĴŠẊ-éļéḿéñţ ţöķéñš àļŵàýš ŕéàđ {=m<N>}; ţĥé ŕüñţîḿé ţéļļš šţàñđàļöñé ƒŕöḿ þàîŕéđ ƃý ļööķîñĝ ƒöŕ à ḿàţçĥîñĝ {/=m<N>} çļöšé îñ ţĥé šàḿé šçöþé. Ṽàŕîàƃļé ţöķéñš ({userName}, {count}) çàŕŕý ţĥé ĴŠ îđéñţîƒîéŕ đîŕéçţļý.
Ţĥé éẋþļîçîţ šþàçé
ĴŠẊ đŕöþš ţĥé ŵĥîţéšþàçé àŕöüñđ à ļîñé ƃŕéàķ, šö à šéñţéñçé ţĥàţ ŵŕàþš ñééđš
{" "} ŵĥéŕé ţĥé šþàçé ŵöüļđ öţĥéŕŵîšé ƃé ļöšţ:
<p>
Read the <a href="/docs">docs</a>{" "}
for the rest.
</p>
Ţĥàţ šþàçé îš à çĥàŕàçţéŕ ţĥé ŕéàđéŕ ŕéàđš, šö ţĥé ƃļöçķ'š ţéẋţ çàŕŕîéš îţ:
"Read the {=m0}docs{/=m0} for the rest.". {' '} àñđ à ţéḿþļàţé ļîţéŕàļ ŵîţĥ
ñöţĥîñĝ îñ îţ ŕéàđ ţĥé šàḿé ŵàý, àñđ à ŕüñ öƒ ŵĥîţéšþàçé çöļļàþšéš ţö öñé šþàçé
ĵüšţ àš ĴŠẊ ţéẋţ đöéš.
À ļîţéŕàļ ŵîţĥ ŕéàļ ţéẋţ îñ îţ ({"!"}) îš šţîļļ à ṽàŕîàƃļé, ƃéçàüšé îţš ṽàļüé
îš à ṽàļüé.
Éḿþţý îñļîñé éļéḿéñţš àš šţàñđàļöñé ḿàŕķéŕš
Ļöţš öƒ ŕéàļ Ŕéàçţ ÜÎ ļööķš ļîķé <Button><Icon />Open File...</Button>, àñ îçöñ çöḿþöñéñţ ƒöļļöŵéđ ƃý ţéẋţ. Éḿþţý îñļîñé éļéḿéñţš (žéŕö çĥîļđŕéñ) ƃéçöḿé à šîñĝļé šţàñđàļöñé ḿàŕķéŕ, ļéàṽîñĝ ţĥé šüŕŕöüñđîñĝ ţéẋţ ţö éẋţŕàçţ ñöŕḿàļļý:
<Button>
<FolderOpen size={12} />
Open File...
</Button>
Éẋţŕàçţš àš "{=m0} Open File..." ŵîţĥ {=m0} ƃöüñđ ţö ţĥé <FolderOpen /> éļéḿéñţ (šţàñđàļöñé, ŵîţĥ ñö ḿàţçĥîñĝ {/=m0} çļöšé). Ŵöŕķš ţĥé šàḿé ƒöŕ Ŕàđîẋ îçöñš, ļüçîđé-ŕéàçţ, Ĥéŕöîçöñš, çüšţöḿ <Spinner /> çöḿþöñéñţš: àñýţĥîñĝ ŵîţĥ ñö çĥîļđŕéñ.
Üñḿàþþéđ Ŕéàçţ çöḿþöñéñţš ŵîţĥ çĥîļđŕéñ àŕé šţîļļ ţŕéàţéđ àš ƃļöçķ-ļéṽéļ ƃý đéƒàüļţ (ţĥé ŵàŕñîñĝ šüĝĝéšţš à componentMap éñţŕý; šéé "Üñķñöŵñ çöḿþöñéñţš" ƃéļöŵ). Ţĥé ñàŕŕöŵ ŕüļé ƒöŕ žéŕö-çĥîļđŕéñ üñḿàþþéđ çöḿþöñéñţš þŕéṽéñţš ƒàļšé þöšîţîṽéš öñ çüšţöḿ ƃļöçķ-ļéṽéļ çöḿþöñéñţš ļîķé <Panel><Heading>…</Heading></Panel>.
Àüţö-þŕöḿöţéđ çöñţàîñéŕš
Šţŕîçţ Ŵ3Ç šéḿàñţîçš ŵöüļđ šķîþ <div>Hello</div>: đîṽš àŕé çļàššîƒîéđ àš çöñţàîñéŕš ŕàţĥéŕ ţĥàñ ţéẋţ. Îñ ŕéàļ Ŕéàçţ çöđéƃàšéš ţĥàţ'š ŵŕöñĝ: <div>Label</div>, <section>Intro copy</section> àŕé éṽéŕýŵĥéŕé.
neokapi-î18ñ àüţö-þŕöḿöţéš çöñţàîñéŕ éļéḿéñţš ŵĥéñ ţĥéý ĥàṽé:
- Àţ ļéàšţ öñé đîŕéçţ ñöñ-ŵĥîţéšþàçé ĴŠẊŢéẋţ çĥîļđ, ÀÑĐ
- Öñļý îñļîñé çĥîļđŕéñ (ñö ñéšţéđ ƃļöçķ-ļéṽéļ éļéḿéñţš).
Þŕöḿöţîöñ îš šîļéñţ: <div>Label</div> îš ţĥé đöḿîñàñţ îđîöḿ àñđ ŵàŕñîñĝ öñ éṽéŕý öççüŕŕéñçé ŵöüļđ ĵüšţ ƃé ñöîšé. (Üñḿàþþéđ Ŕéàçţ çöḿþöñéñţš šţîļļ ŵàŕñ; šéé ƃéļöŵ.)
Ţö öþţ öüţ: <div translate="no">...</div> öŕ à ŕüļé:
neokapi({
rules: [{ selector: ".hero-video-caption", translate: false }],
});
Ƒŕàĝḿéñţš
À ƒŕàĝḿéñţ ŕööţ ŵîţĥ îñļîñé çöñţéñţ éẋţŕàçţš àš öñé ƃļöçķ, šàḿé àš à þŕöḿöţéđ çöñţàîñéŕ:
<>
Signed in as <strong>{user.name}</strong>.
</>
Ţĥé ƒŕàĝḿéñţ ĥàš ñö ţàĝ öƒ îţš öŵñ, šö îţš đéšçŕîþţöŕ îš ţĥé ļîţéŕàļ fragment, ḿéàñîñĝ à ƒŕàĝḿéñţ àñđ à <p> çàŕŕýîñĝ ţĥé šàḿé ŵöŕđš ĥàšĥ àþàŕţ, àñđ ḿöṽîñĝ çöñţéñţ ƃéţŵééñ ţĥéḿ îš à ŕé-ķéý. Þŕéƒéŕ à ŕéàļ éļéḿéñţ ŵĥéñ ţĥé çöñţéñţ îš à þàŕàĝŕàþĥ; ƒŕàĝḿéñţš àŕé ƒöŕ ţĥé çàšéš ŵĥéŕé ţĥé šüŕŕöüñđîñĝ ḿàŕķüþ ĝéñüîñéļý çàñ'ţ ţàķé à ŵŕàþþéŕ.
Üñķñöŵñ çöḿþöñéñţš
Çöḿþöñéñţ ļîƃŕàŕîéš ļîķé šĥàđçñ, Ŕàđîẋ, ḾÜÎ, àñđ ýöüŕ öŵñ îñţéŕñàļ çöḿþöñéñţš ŕéñđéŕ ţö ĤŢḾĻ ƃüţ neokapi-î18ñ çàñ'ţ ķñöŵ ŵĥîçĥ öñé. Ƃý đéƒàüļţ, àñ üñḿàþþéđ Ŕéàçţ çöḿþöñéñţ ŵîţĥ đîŕéçţ ţéẋţ çöñţéñţ îš éẋţŕàçţéđ àñýŵàý, ŵîţĥ à ŵàŕñîñĝ ţĥàţ šüĝĝéšţš ĥöŵ ţö šţàƃîļîšé ţĥé ĥàšĥ:
<TabsTrigger value="general">General</TabsTrigger>
[neokapi] src/Settings.tsx:19: <TabsTrigger> is an unmapped component with
translatable text — extracted. Add a componentMap entry to stabilise
hashes: { TabsTrigger: '<underlying-html-tag>' }.
↳ <TabsTrigger value="general">General</TabsTrigger>
Àđđîñĝ ţĥé ĥîñţ ŕéḿöṽéš ţĥé ŵàŕñîñĝ àñđ çĥàñĝéš ţĥé ĥàšĥ ƒŕöḿ öñé ķéýéđ öñ TabsTrigger ţö öñé ķéýéđ öñ button:
neokapi({
componentMap: {
TabsTrigger: "button",
TabsList: "div",
DialogTitle: "h2",
},
});
Ŵĥý ƃöţĥéŕ? Ƃéçàüšé ţĥé ĥàšĥ îš þàŕţ öƒ ţĥé ţŕàñšļàţöŕ'š çöñţŕàçţ. ΃ ýöü ļàţéŕ ŕéƒàçţöŕ ƃý çĥàñĝîñĝ TabsTrigger → à đéŕéñţ ļîƃŕàŕý'š Tab, àñđ ţĥé üñđéŕļýîñĝ ĤŢḾĻ îš šţîļļ button, ţĥé ĥàšĥéš šţàý šţàƃļé îƒ ýöü ĥàđ ţĥé componentMap éñţŕý; ţŕàñšļàţöŕš đöñ'ţ ñééđ ţö ŕé-ŕéṽîéŵ.
Ţŕàñšļàţàƃļé àţţŕîƃüţéš
Ţŵö ƃüçķéţš, ŵîţĥ đéŕéñţ šçöþéš:
| Ƃüçķéţ | Éẋţŕàçţéđ öñ | Ñàḿéš |
|---|---|---|
| ĤŢḾĻ | àñý éļéḿéñţ | alt, title, placeholder |
| ÀŔÎÀ | àñý éļéḿéñţ | aria-label, aria-description, aria-placeholder, aria-roledescription, aria-valuetext |
| Ŕéàçţ çöñṽéñţîöñš | ÞàšçàļÇàšé çöḿþöñéñţš | subtitle, description, label, heading, caption, helpText, helperText, errorMessage, hint, tooltip, emptyMessage, emptyStateText, filterPlaceholder |
Ţĥé ĤŢḾĻ àñđ ÀŔÎÀ ñàḿéš àŕé šţàñđàŕđîšéđ: ŵĥéŕéṽéŕ ţĥéý àþþéàŕ, ţĥéý çàŕŕý üšéŕ-ṽîšîƃļé ţéẋţ. Ţĥé çöñṽéñţîöñ ñàḿéš àŕé ñöţ: label öñ à <Field> îš çöþý, ƃüţ label öñ à <div> îš ƒàŕ ḿöŕé öƒţéñ à ĐÖḾ þŕöþ, àñ éñüḿ ķéý, öŕ à đàţà-ƃîñđîñĝ ƒîéļđ. Šçöþîñĝ ţĥàţ ƃüçķéţ ţö ÞàšçàļÇàšé çöḿþöñéñţš îš ŵĥàţ ķééþš <div label="draft-pending"> öüţ öƒ ýöüŕ ţŕàñšļàţöŕ'š ǫüéüé.
Šö ţĥéšé àļļ ŵöŕķ öüţ öƒ ţĥé ƃöẋ:
<input placeholder="Search..." aria-label="Search products" />
<img alt="Company logo" />
<button title="Save draft">💾</button>
<PageHeader title="Content Memory" subtitle="Approved terms and past translations" />
<EmptyState title="No projects yet" description="Create one to get started." />
<LoadingSpinner helpText="Contacting the server…" />
<Tooltip tooltip="Retry the last operation" />
Éàçĥ àţţŕîƃüţé ƃéçöḿéš îţš öŵñ ţŕàñšļàţàƃļé ƃļöçķ.
Ţéŕñàŕý àţţŕîƃüţé ṽàļüéš
Ŵĥéñ à ţŕàñšļàţàƃļé àţţŕîƃüţé'š ṽàļüé îš à ţéŕñàŕý ŵîţĥ ƃöţĥ ƃŕàñçĥéš àš þļàîñ šţŕîñĝ ļîţéŕàļš, éàçĥ ƃŕàñçĥ éẋţŕàçţš àš îţš öŵñ ƃļöçķ:
<PageHeader title={isProjectMode ? "Project Flows" : "Flows"} />
Ƃöţĥ "Project Flows" àñđ "Flows" ĝéţ éẋţŕàçţéđ (ŵîţĥ ::0 / ::1 šüƒƒîẋéš öñ ţĥé çöñţéẋţ ţö ķééþ ţĥé ĥàšĥéš đîšţîñçţ). Àţ ŕüñţîḿé ţĥé ţŕàñšƒöŕḿ ŕéŵŕîţéš éàçĥ ļîţéŕàļ ƃŕàñçĥ ŵîţĥ îţš öŵñ __t() ļööķüþ; ţĥé çöñđîţîöñ šţîļļ ƒîŕéš àţ ŕéñđéŕ ţîḿé.
Ḿîẋéđ-šĥàþé ţéŕñàŕîéš (öñé ļîţéŕàļ, öñé çöḿþüţéđ, öŕ ƃöţĥ ţéḿþļàţéš) àŕéñ'ţ šţàţîçàļļý éẋţŕàçţàƃļé; ţĥé ļîñţ ŕüļé no-ternary-in-translatable-attr ƒļàĝš ţĥéḿ. Ƒîẋ ƃý ŵŕàþþîñĝ ƃöţĥ ƃŕàñçĥéš ŵîţĥ t() šö ţĥé ţ-çàļļ ŵàļķéŕ þîçķš ţĥéḿ üþ:
// ✗ extractor can't see the template-literal branch
<Input placeholder={disabled ? `Disabled (${reason})` : "Enabled"} />
// ✓ both branches flow through the t() extraction path
<Input placeholder={disabled ? t("Disabled ({reason})", { reason }) : t("Enabled")} />
Ñöñ-ţŕàñšļàţàƃļé éļéḿéñţš
Ţĥéšé ŕéñđéŕ ţéẋţ-àš-ţéẋţ, ñöţ ñàţüŕàļ ļàñĝüàĝé, šö ţĥéîŕ çöñţéñţš ñéṽéŕ éñţéŕ ţĥé çàţàļöĝ:
<code>, <pre>, <kbd>, <var>, <samp>, <script>, <style>, <textarea>.
<code>npm install @neokapi/i18n-react</code> // ✗ not extracted
<pre>{licenseText}</pre> // ✗ not extracted
Ţö ƒļîþ öñé šþéçîƒîç šîţé: <code translate="yes">...</code>.
Çöđé šþàñš îñšîđé þŕöšé
<code>, <kbd>, <samp> àñđ <var> àŕé àļšö þĥŕàšîñĝ éļéḿéñţš: à šéñţéñçé
ḿéñţîöñîñĝ à ƒļàĝ öŕ à ƒöŕḿàţ îđ îš öñé šéñţéñçé, àñđ çüţţîñĝ îţ àţ ţĥé šþàñ
ŵöüļđ ļéàṽé ţĥé ŕéàđéŕ ĥàļƒ à þàŕàĝŕàþĥ îñ ţĥéîŕ öŵñ ļàñĝüàĝé. Šö ţĥé þàŕéñţ
éẋţŕàçţš àš öñé ƃļöçķ, ţĥé šþàñ ƃéçöḿéš à þàîŕéđ ḿàŕķéŕ ļîķé àñý öţĥéŕ îñļîñé
éļéḿéñţ, àñđ ţĥé ţéẋţ ƃéţŵééñ ţĥé ţàĝš îš ḿàŕķéđ þŕöţéçţéđ:
<p>
Say <code>json</code> for the faithful readers.
</p>
Ţĥé ƃļöçķ ŕéàđš "Say {=m0}json{/=m0} for the faithful readers.", àñđ îţš ŕüñš
çàŕŕý json ŵîţĥ à đö-ñöţ-ţŕàñšļàţé ƒļàĝ. Ţŕàñšļàţîöñ, àñ ÀÎ þàšš àñđ ţĥé qps
þšéüđö-ļöçàļé àļļ ļéàṽé îţ àļöñé, šö ţĥé ŕéàđéŕ ĝéţš ţĥé ƃýţéš ýöü ŵŕöţé ŵĥîļé
ţĥé þŕöšé àŕöüñđ îţ îš ţŕàñšļàţéđ.
Àñ éļéḿéñţ ĥöļđîñĝ à çöđé šþàñ àñđ ñöţĥîñĝ éļšé ĥàš ñö þŕöšé îñ îţ, šö îţ šţàýš öüţ öƒ ţĥé çàţàļöĝ:
<p>
<code>kapi up</code>
</p>
// ✗ no block: the element holds an identifier only
translate="yes" öñ ţĥé šþàñ öþţš îţš ţéẋţ ƃàçķ îñ, îñšîđé à šéñţéñçé öŕ öñ îţš
öŵñ.
Ţĥé çöḿþîļéđ çàļļ šîţé çàŕŕîéš ţĥéšé àñšŵéŕš, šö ţĥé ŕüñţîḿé ķñöŵš ţĥéḿ ţöö:
ŕüñţîḿé þšéüđö ḿöđé àççéñţš ţĥé þŕöšé
àñđ ļéàṽéš ţĥé çöḿḿàñđ àļöñé, ḿàţçĥîñĝ ŵĥàţ à qps çàţàļöĝ ĥöļđš.
Çöñţŕöļš îñšîđé þŕöšé
ĤŢḾĻ5 ļéţš à çöñţŕöļ šîţ îñ ţĥé ḿîđđļé öƒ à šéñţéñçé, àñđ à çàļļ ţö àçţîöñ îš üšüàļļý ŵŕîţţéñ ţĥàţ ŵàý:
<p>
<button onClick={run}>Try it live</button> lists the registered formats.
</p>
Ţĥé þàŕàĝŕàþĥ éẋţŕàçţš àš öñé ƃļöçķ ŕéàđîñĝ
"{=m0}Try it live{/=m0} lists the registered formats.". Ţĥé ƃüţţöñ îš à þàîŕéđ
ḿàŕķéŕ, àñđ ţĥé ŵöŕđš îñšîđé îţ šţàý ţĥé ţŕàñšļàţöŕ'š: à çöđé šþàñ þŕöţéçţš îţš
ţéẋţ, à çöñţŕöļ'š ļàƃéļ îš þŕöšé. Àţ ŕéñđéŕ ţîḿé ţĥé ŕüñţîḿé çļöñéš ţĥé ƃüţţöñ
ŵîţĥ ţĥé ţŕàñšļàţéđ ļàƃéļ àš îţš çĥîļđŕéñ, šö ţĥé ĥàñđļéŕ, ţĥé ţýþé àñđ ţĥé
çļàššéš àŕé ţĥé öñéš ýöü ŵŕöţé.
Ţĥé çöñţŕöļš ţĥîš çöṽéŕš àŕé <button>, <label>, <select>, <input>,
<output>, <img>, <audio>, <video>, <meter> àñđ <progress>.
Ŵĥéŕé ţĥé çöñţŕöļ îš àļļ îţš þàŕéñţ ĥöļđš, ţĥé þàŕéñţ šţàýš öüţ àñđ ţĥé çöñţŕöļ ķééþš îţš öŵñ ƃļöçķ:
<div className="toolbar">
<button>Save</button> // ✓ one block: "Save"
</div>
<div>
Autosave is on. <button>Save now</button> // ✓ one block for the sentence
</div>
Ţĥàţ îš ŵĥàţ ķééþš à ţööļƃàŕ öƒ ƃüţţöñš à ḿéššàĝé éàçĥ, ŕàţĥéŕ ţĥàñ öñé ḿéššàĝé ĥöļđîñĝ éṽéŕý ļàƃéļ îñ ţĥé ŕöŵ.
Àţţŕîƃüţéš öñ àñ îñļîñé çĥîļđ
Ţĥé ŵöŕđš ƃéţŵééñ àñ îñļîñé çĥîļđ'š ţàĝš ƃéļöñĝ ţö ţĥé šéñţéñçé àŕöüñđ îţ. Îţš
àţţŕîƃüţéš đö ñöţ: ţĥé çàļļ šîţé çàŕŕîéš ţĥé éļéḿéñţ ŵîţĥ îţš öŵñ þŕöþš, šö
çöþý îñ àñ alt, à title, àñ aria-label, à placeholder öŕ à çöḿþöñéñţ'š
label þŕöþ îš à ƃļöçķ öƒ îţš öŵñ.
<p>
Use <abbr title="Content memory">CM</abbr> for that.
</p>
Ţŵö ƃļöçķš: "Use {=m0}CM{/=m0} for that." àñđ "Content memory". Ţĥé šàḿé
ĥöļđš ƒöŕ à çöñţŕöļ ţĥàţ çàŕŕîéš àļļ îţš çöþý îñ àñ àţţŕîƃüţé, šö àñ îçöñ
ƃüţţöñ öŕ àñ îḿàĝé ķééþš ţĥé þŕöšé àŕöüñđ îţ:
<p>
Press <button aria-label="Run the demo"><Play /></button> to start.
</p>
// two blocks: "Press {=m0} to start." and "Run the demo"
Ţĥé àţţŕîƃüţé'š ķéý ŕéàđš abbr[title], button[aria-label], Badge[label],
àñđ šö öñ. Îţ ñàḿéš ţĥé éļéḿéñţ àñđ ţĥé àţţŕîƃüţé àñđ ñöţĥîñĝ éļšé, šö à
šţŕîñĝ ķééþš îţš ķéý ŵĥéţĥéŕ ţĥé éļéḿéñţ šţàñđš àļöñé öŕ šîţš îñ à šéñţéñçé,
àñđ ŵŕàþþîñĝ þŕöšé àŕöüñđ àñ éẋîšţîñĝ éļéḿéñţ đöéš ñöţ öŕþĥàñ îţš ţŕàñšļàţîöñ.
Ñéšţîñĝ ĝöéš àš đééþ àš ţĥé ḿàŕķüþ đöéš: <a title="…"><img alt="…" /></a>
îñšîđé à þàŕàĝŕàþĥ îš ţĥŕéé ƃļöçķš. Àñ éļéḿéñţ ḿàŕķéđ translate="no" ķééþš
îţš àţţŕîƃüţéš öüţ öƒ ţĥé çàţàļöĝ àļöñĝ ŵîţĥ îţš ţéẋţ.
Çöñđîţîöñàļ ĴŠẊ îñšîđé à šéñţéñçé
À çöñđîţîöñàļ ŕéñđéŕš àñ éļéḿéñţ öŕ ñöţĥîñĝ, šö ţĥé šéñţéñçé àŕöüñđ îţ çàññöţ çàŕŕý îţš ŵöŕđš:
<p>Saved {unsaved && <span className="badge">with changes pending</span>} just now</p>
Ţĥé þàŕàĝŕàþĥ éẋţŕàçţš àš "Saved {=m0} just now" ŵîţĥ {=m0} šţàñđîñĝ ƒöŕ ţĥé
ŵĥöļé çöñđîţîöñàļ, àñđ ţĥé ƃàđĝé éẋţŕàçţš àš à šéçöñđ ƃļöçķ ŕéàđîñĝ
"with changes pending". Ţĥé ţŕàñšļàţöŕ ĝéţš ƃöţĥ, àñđ ţĥé ƃàđĝé îš ŕéñđéŕéđ
ţĥŕöüĝĥ îţš öŵñ ļööķüþ, šö à ţŕàñšļàţîöñ ŕéàçĥéš ţĥé ŕéàđéŕ ŵĥéţĥéŕ öŕ ñöţ ţĥé
çöñđîţîöñ ĥöļđš.
Ţĥîš çöṽéŕš éṽéŕý éẋþŕéššîöñ ţĥàţ çàñ çàŕŕý ĴŠẊ: &&, ||, ??, à ţéŕñàŕý
(éàçĥ ƃŕàñçĥ éẋţŕàçţš šéþàŕàţéļý), à .map() öṽéŕ à ļîšţ, àñđ à çàļļ ţàķîñĝ àñ
éļéḿéñţ àš àñ àŕĝüḿéñţ. Îţ àþþļîéš ţö àţţŕîƃüţéš àñđ t() çàļļš îñšîđé ţĥé
çöñđîţîöñàļ àš ŵéļļ:
<p>Saved {unsaved && <button aria-label="Discard changes"><X /></button>} just now</p>
Ţĥé šàḿé ĥöļđš ƒöŕ ĴŠẊ þàššéđ îñ à þŕöþ, ŵĥéţĥéŕ öŕ ñöţ ţĥé éļéḿéñţ àŕöüñđ îţ éẋţŕàçţš:
<div actions={<Button>Publish</Button>}>Ready to go.</div>
// two blocks: "Ready to go." and "Publish"
Ŵĥàţ à çöñđîţîöñàļ çàññöţ ŕéšçüé îš à ƃàŕé šţŕîñĝ ļîţéŕàļ îñ à ƃŕàñçĥ
({cond ? "A" : "B"}), ŵĥîçĥ šţàýš öþàǫüé; šéé
Ţéŕñàŕý ŵîţĥ šţŕîñĝ ļîţéŕàļš àš ĴŠẊ çĥîļđŕéñ.
Àñ éļéḿéñţ îñ à þļàîñ éẋþŕéššîöñ
À ƃļöçķ ļîƒţš éṽéŕý šîƃļîñĝ éẋþŕéššîöñ îñţö à ñàḿéđ þļàçéĥöļđéŕ, àñđ ţĥé ñàḿé îš àļļ ţĥé ţŕàñšļàţöŕ šééš:
<div className="relative">
{progressSegments}
<span>{progress}% ({done}/{total} translated)</span>
</div>
Ţĥé <div> îš öñé ƃļöçķ ŕéàđîñĝ
"{progressSegments}{=m0}{progress}% ({done}/{total} translated){/=m0}". Ƒöüŕ
þļàçéĥöļđéŕš àñđ öñé þàîŕéđ ḿàŕķéŕ, àļļ ḿöṽàƃļé.
Ŵĥàţ éàçĥ þļàçéĥöļđéŕ ĥöļđš îš šéţţļéđ àţ ŕéñđéŕ ţîḿé, ñöţ àţ ƃüîļđ ţîḿé.
{progress} îš à ñüḿƃéŕ, {progressSegments} îš à <div> öƒ çöļöüŕéđ ƃàŕš,
àñđ ƃöţĥ àŕé þļàîñ îđéñţîƒîéŕš îñ ţĥé šöüŕçé. Šö ţĥé ŕüñţîḿé àšķš ţĥé ṽàļüé:
Ŕéàçţ çöñţéñţ ŕéñđéŕš àš îţšéļƒ ŵĥéŕéṽéŕ îţš ţöķéñ šîţš, àñđ éṽéŕýţĥîñĝ éļšé
šüƃšţîţüţéš àš ţéẋţ ŵîţĥ Ŕéàçţ'š öŵñ ŕüļéš, ŵĥéŕé null, undefined àñđ à
ƃööļéàñ çöñţŕîƃüţé ñöţĥîñĝ.
Ţĥàţ çöṽéŕš ţĥé çöḿḿöñ šĥàþéš ŵîţĥöüţ àñý çéŕéḿöñý:
<div>{icon} Save changes</div>
<p>Filter by {statusChips} or clear them all.</p>
<li>{rows.map((r) => <Row key={r.id} {...r} />)} in this batch</li>
Ţŵö ţĥîñĝš ƒöļļöŵ. À ţŕàñšļàţöŕ ḿàý ḿöṽé àñ éļéḿéñţ þļàçéĥöļđéŕ àñýŵĥéŕé îñ ţĥé
šéñţéñçé, îñçļüđîñĝ îñšîđé à þàîŕéđ ḿàŕķéŕ, àñđ đŕöþþîñĝ îţš ţöķéñ đŕöþš ţĥé
éļéḿéñţ. Àñđ à þļàçéĥöļđéŕ îñ à ḿéššàĝé ţĥàţ ŕéšöļṽéš ţö à šţŕîñĝ ĥàš
ñöŵĥéŕé ţö þüţ àñ éļéḿéñţ: àñ aria-label, à title, à t() ŕéšüļţ. Ĥàñđîñĝ
öñé à Ŕéàçţ éļéḿéñţ ļöĝš à ŵàŕñîñĝ îñ đéṽéļöþḿéñţ àñđ ŕéñđéŕš ñöţĥîñĝ üšéƒüļ,
šö ķééþ éļéḿéñţš îñ ĴŠẊ.
Ļîţéŕàļš îñ à çöñđîţîöñàļ'š ƃŕàñçĥéš
À çöñđîţîöñàļ ŕéñđéŕš öñé öƒ îţš ƃŕàñçĥéš àš ţéẋţ:
<Button>{saving ? "Saving..." : "Save"}</Button>
Éàçĥ šţŕîñĝ ļîţéŕàļ îñ îţ éẋţŕàçţš àš îţš öŵñ ƃļöçķ, šö ţĥîš îš ţŵö ḿéššàĝéš. Ţĥéîŕ ķéýš çàŕŕý ţĥé ƃŕàñçĥ'š šļöţ þöšîţîöñ, Button::0 àñđ Button::1, ŵĥîçĥ îš ţĥé šàḿé šçĥéḿé à ţéŕñàŕý àţţŕîƃüţé ṽàļüé üšéš. Ţĥé ƃüîļđ ŕéŵŕîţéš éàçĥ ļîţéŕàļ ŵĥéŕé îţ šţàñđš, šö ţĥé çöñđîţîöñ àñđ éṽéŕýţĥîñĝ àŕöüñđ îţ àŕé üñţöüçĥéđ.
Ţĥé šàḿé ĥöļđš ƒöŕ à ļöĝîçàļ öþéŕàţöŕ, ŵĥéŕé ţĥé ŕîĝĥţ šîđé îš ţĥé ƃŕàñçĥ:
<div>{cond && "Folder moved"}</div>
<div>{label || "Untitled"}</div>
À šļöţ ķééþš îţš ñüḿƃéŕ ŵĥàţéṽéŕ ƒîļļš îţ. Îñ {cond ? getLabel() : "Save"} ţĥé ļîţéŕàļ îš šļöţ 1, àñđ ţüŕñîñĝ getLabel() îñţö à ļîţéŕàļ ļàţéŕ ĝîṽéš îţ šļöţ 0 ŵîţĥöüţ ḿöṽîñĝ "Šàṽé". À ñéšţéđ ţéŕñàŕý çöñţŕîƃüţéš îţš öŵñ šļöţš îñ þļàçé öƒ ţĥé öñé îţ ƒîļļš, šö {a ? "A" : b ? "B" : "C"} ñüḿƃéŕš ţĥŕéé öƒ ţĥéḿ.
Ţŵö ƃŕàñçĥéš ţàķé à đéŕéñţ þàţĥ. À ĴŠẊ éļéḿéñţ îš éẋţŕàçţéđ àš ţĥé éļéḿéñţ îţ îš, àñđ à ţéḿþļàţé ļîţéŕàļ îš öñé éẋþŕéššîöñ ţĥàţ éẋţŕàçţîöñ ŕéàđš ŵĥöļé, šö îţš ŵöŕđš ñééđ t() (šéé Ţéḿþļàţé ļîţéŕàļ îñ à ţéŕñàŕý ƃŕàñçĥ).
À çöñđîţîöñàļ îñšîđé àñ éļéḿéñţ ŵĥöšé çöñţéñţ îš ñéṽéŕ þŕöšé îš ļéƒţ àļöñé, šö <code>{a ? "x = 1" : "y = 2"}</code> àñđ àñýţĥîñĝ üñđéŕ translate="no" šţàý àš ŵŕîţţéñ.
Öþţîñĝ öüţ ŵîţĥ translate="no"
Šţàñđàŕđ ĤŢḾĻ; îţ ŵöŕķš öñ àñý éļéḿéñţ àñđ îţš đéšçéñđàñţš:
<h1 translate="no">API_KEY_PREFIX</h1> // ✗ not extracted
<section translate="no">
<h2>Debug payload</h2> // ✗ not extracted
<pre>{json}</pre> // ✗ not extracted
</section>
Ƃöţĥ ţĥé éẋţŕàçţöŕ àñđ éṽéŕý ļîñţ ŕüļé îñ @neokapi/i18n-react-lint ŵàļķ üþ ţĥé àñçéšţöŕ çĥàîñ ļööķîñĝ ƒöŕ translate="no". À šîñĝļé ḿàŕķéŕ àţ ţĥé ţöþ öƒ à šüƃţŕéé šîļéñçéš éṽéŕýţĥîñĝ îñšîđé; ţĥéŕé îš ñö ñééđ ţö šþŕîñķļé îţ öñ éṽéŕý éļéḿéñţ.
translate="no" îš àļšö ţĥé ŕîĝĥţ àñšŵéŕ ŵĥéñ ýöü'ŕé îñţéñţîöñàļļý ŕéñđéŕîñĝ àñ àļŕéàđý-ţŕàñšļàţéđ ṽàļüé (šéé "Ḿöđüļé-ļéṽéļ t() ĝöţçĥà" ƃéļöŵ), öŕ ŵĥéñ ýöüŕ çöñţéñţ îš çöđé-ļîķé àñđ šĥöüļđñ'ţ ƃé ƒļàĝĝéđ àš ḿîššîñĝ ţŕàñšļàţîöñ.
Îñšîđé à šéñţéñçé, à ḿàŕķéđ çĥîļđ šţàýš àñ îšļàñđ. Îţš ţéẋţ îš ķéþţ öüţ öƒ ţĥé ḿéššàĝé àñđ ţĥé éļéḿéñţ ţŕàṽéļš àš öñé þļàçéĥöļđéŕ, šö à ţŕàñšļàţöŕ šééš ţĥé šéñţéñçé àŕöüñđ îţ àñđ ţĥé ŕéàđéŕ šééš ţĥé éļéḿéñţ éẋàçţļý àš ýöü ŵŕöţé îţ:
<div>
Saved to <span translate="no">{path}</span> just now
</div>
// message: Saved to {=m0} just now
À þàŕéñţ ŵĥöšé öñļý ţéẋţ šîţš îñšîđé šüçĥ à çĥîļđ çàŕŕîéš ñö ţŕàñšļàţàƃļé ţéẋţ àţ àļļ, šö îţ šţàýš öüţ öƒ ţĥé çàţàļöĝ:
<SimpleTooltip content={full}>
<span translate="no">
{file}:{key}
</span>
</SimpleTooltip>
// ✗ no message
Ŕüļéš ƒöŕ ŕéçüŕŕîñĝ þàţţéŕñš
Ƒöŕ þàţţéŕñš ŵĥéŕé ýöü đöñ'ţ ŵàñţ ţö šþŕîñķļé translate="no" éṽéŕýŵĥéŕé, üšé ŕüļéš îñ ýöüŕ þļüĝîñ çöñƒîĝ:
neokapi({
rules: [
{ selector: ".monospaced-input", translate: false },
{ selector: "[data-testid]", translate: false },
{ selector: ".legal-copy", locNote: "Must match legal-approved wording verbatim" },
],
});
Šéļéçţöŕš: þļàîñ ţàĝ (code), çļàšš (.code-block), àţţŕîƃüţé þŕéšéñçé ([data-testid]), öŕ àţţŕîƃüţé ṽàļüé ([role="alert"]).
Ŵĥàţ šţîļļ ñééđš éẋþļîçîţ ĥàñđļîñĝ
Ţĥé éẋţŕàçţöŕ çàñ öñļý šéé ŵĥàţ îţ çàñ šţàţîçàļļý ŕéàšöñ àƃöüţ. Ţĥéšé þàţţéŕñš šļîþ ţĥŕöüĝĥ; éàçĥ ĥàš à çàñöñîçàļ ƒîẋ.
Šţŕîñĝš îñ ĴŠ đàţà šţŕüçţüŕéš
const THEMES = [
{ value: "system", label: "System" }, // ✗ not extractable
{ value: "light", label: "Light" },
];
return THEMES.map(({ value, label }) => (
<button>{label}</button> // ✗ label is an expression
));
Ƒîẋ ŵîţĥ ţĥé t() éšçàþé ĥàţçĥ:
const THEMES = [
{ value: "system", label: t("System") },
{ value: "light", label: t("Light") },
];
Çàüĝĥţ ƃý ţĥé prefer-t-for-label-props ļîñţ ŕüļé (öƒƒ ƃý đéƒàüļţ; öþţ îñ ṽîà recommendedStrict).
Đýñàḿîç ļàƃéļ éẋþŕéššîöñš
Ţĥé ŕéñđéŕ-šîđé ḿîŕŕöŕ öƒ ţĥé àƃöṽé: {obj.label} / {item.title} ŕéñđéŕéđ àš ĴŠẊ ţéẋţ. Ţĥé éẋţŕàçţöŕ šééš àñ éẋþŕéššîöñ çöñţàîñéŕ àñđ éḿîţš à þļàçéĥöļđéŕ; ţĥé šţŕîñĝ îţ ŕéšöļṽéš ţö àţ ŕüñţîḿé ñéṽéŕ ƃéçöḿéš à ţŕàñšļàţîöñ üñîţ.
// ✗ meta.label is invisible to extraction
<h1>{meta.label}</h1>
Ƒîẋ ƃý ŵŕàþþîñĝ ţĥé šöüŕçé đàţà ŵîţĥ t() (šàḿé àš "Šţŕîñĝš îñ ĴŠ đàţà šţŕüçţüŕéš" àƃöṽé). Ţĥé ļîñţ ŕüļé prefer-t-for-label-expr ƒļàĝš ţĥé ŕéñđéŕ šîţé ţö þŕöḿþţ ţĥé ŕéƒàçţöŕ.
Ţéḿþļàţé ļîţéŕàļ îñ à ţéŕñàŕý ƃŕàñçĥ
// ✗ the words inside the template never extract
<span>{count > 0 ? `Loading ${count}...` : "Idle"}</span>
À ţéḿþļàţé ļîţéŕàļ îš öñé éẋþŕéššîöñ, šö éẋţŕàçţîöñ ŕéàđš îţ ŵĥöļé àñđ ţĥé ŵöŕđš îñ îţ šţàý Éñĝļîšĥ. Ŵŕàþ ţĥàţ ƃŕàñçĥ ŵîţĥ t() àñđ þàšš ţĥé îñţéŕþöļàţîöñ àš à þàŕàḿéţéŕ:
<span>{count > 0 ? t("Loading {count}...", { count }) : "Idle"}</span>
Ţĥé "Idle" ƃéšîđé îţ ñééđš ñöţĥîñĝ: à þļàîñ šţŕîñĝ ļîţéŕàļ îñ à ƃŕàñçĥ éẋţŕàçţš öñ îţš öŵñ (šéé Ļîţéŕàļš îñ à çöñđîţîöñàļ'š ƃŕàñçĥéš). Çàüĝĥţ ƃý no-ternary-literals-in-jsx-child, ŵĥîçĥ ļéàṽéš à ƒöŕḿàţ-öñļý ţéḿþļàţé šüçĥ àš `${pct}%` àļöñé.
Ḿöđüļé-ļéṽéļ t() ĝöţçĥà
t() ŕéàđš ţĥé àçţîṽé đîçţîöñàŕý àţ çàļļ ţîḿé. À ḿöđüļé-ļéṽéļ çöñšţ éṽàļüàţéš öñçé, àţ îḿþöŕţ ţîḿé, ţýþîçàļļý ƃéƒöŕé loadTranslations() ĥàš ƒîñîšĥéđ. Ţĥé çöñšţ ƒŕééžéš àţ ţĥé ƒàļļƃàçķ ļàñĝüàĝé ƒöŕéṽéŕ.
// ✗ "Utility" will still say "Utility" in pseudo.
const categoryMeta = {
utility: { label: t("Utility") },
pipeline: { label: t("Pipeline") },
};
Ƒîẋ: ŵŕàþ ţĥé ļööķüþ îñ à ƒüñçţîöñ ţĥàţ ŕüñš þéŕ ŕéñđéŕ.
// ✓ each render resolves the label against the current dict.
function categoryMeta(cat: string) {
switch (cat) {
case "utility":
return { label: t("Utility") };
case "pipeline":
return { label: t("Pipeline") };
// …
}
}
function Chip({ cat }: { cat: string }) {
const meta = categoryMeta(cat);
return <span>{meta.label}</span>;
}
Đöüƃļé-ţŕàñšļàţîöñ: àļŕéàđý-ţŕàñšļàţéđ ṽàļüéš îñšîđé ţŕàñšļàţàƃļé ƃļöçķš
À šüƃţļé þàţţéŕñ ţĥàţ öñļý šĥöŵš üþ îñ þšéüđö. ΃ ýöü ŕéñđéŕ à t()-ŕéšöļṽéđ šţŕîñĝ àš à çĥîļđ öƒ àñ éļéḿéñţ ţĥé éẋţŕàçţöŕ àļšö ŵŕàþš àš à ƃļöçķ, þšéüđö-ţŕàñšļàţîöñ ĝéţš àþþļîéđ ţŵîçé: ţĥé îññéŕ t() àđđš îţš ḿàŕķéŕš, àñđ ţĥé öüţéŕ éļéḿéñţ'š ţŕàñšļàţîöñ ŵŕàþš àŕöüñđ ţĥéḿ:
<Button>
{meta.label} ({catTools.length})
</Button>
// Pseudo renders: ▒ ▒ Utility ▒ (32) ▒ ← two layers of wrapping
Ƒîẋ: ḿàŕķ ţĥé öüţéŕ éļéḿéñţ translate="no" šö ţĥé îññéŕ t() çàļļ öŵñš ţĥé ţŕàñšļàţîöñ.
<Button translate="no">
{meta.label} ({catTools.length})
</Button>
// Pseudo renders: ▒ Utility ▒ (32) ← the inner t() wrap is the only one
Àļţéŕñàţîṽé: ļîƒţ ţĥé ŵĥöļé šţŕîñĝ îñţö à šîñĝļé t() çàļļ ŵîţĥ þļàçéĥöļđéŕš, ƃüţ ţĥàţ'š àŵķŵàŕđ ŵĥéñ öñé ĥàļƒ îš à ţŕàñšļàţéđ ļàƃéļ àñđ ţĥé öţĥéŕ îš à ñüḿéŕîç çöüñţ.
Ţŕàñšļàţöŕ ñöţéš
Àţţàçĥ à ñöţé ţö àñ éļéḿéñţ šö ţŕàñšļàţöŕš šéé çöñţéẋţ ŵĥéñ ţĥéý öþéñ ţĥé ƃļöçķ:
<button data-i18n-note="verb: to close a dialog, not 'nearby'">Close</button>
Öŕ ṽîà à ŕüļé:
rules: [{ selector: ".legal-copy", locNote: "Legal team must review" }];
Šüḿḿàŕý: ŵĥàţ ĝöéš ŵĥéŕé
| Šöüŕçé þàţţéŕñ | Éẋţŕàçţéđ? | Ñöţéš |
|---|---|---|
<h1>Hello</h1> | ýéš | šţàñđàŕđ ţŕàñšļàţàƃļé éļéḿéñţ |
<div>Hello</div> | ýéš | àüţö-þŕöḿöţéđ šîļéñţļý |
<>Hello <b>you</b></> | ýéš | ƒŕàĝḿéñţ ŕööţ; đéšçŕîþţöŕ îš fragment |
<Button><Icon/>Save</Button> | ýéš | "Šàṽé" éẋţŕàçţš ŵîţĥ {=m0} šţàñđàļöñé ƒöŕ ţĥé îçöñ |
<TabsTrigger>Hello</TabsTrigger> | ýéš | ŵàŕñîñĝ šüĝĝéšţš componentMap |
<PageHeader title="Hi" /> | ýéš | title îš àñ ĤŢḾĻ àţţŕîƃüţé; àñý éļéḿéñţ |
<PageHeader title={cond ? "A" : "B"} /> | ýéš | ƃöţĥ ƃŕàñçĥéš; öñé ƃļöçķ éàçĥ |
<MyComp description="Hi" /> | ýéš | description îš à çöñṽéñţîöñ þŕöþ; çöḿþöñéñţš öñļý |
<div label="draft-pending" /> | ñö | çöñṽéñţîöñ þŕöþ öñ à þļàîñ éļéḿéñţ; ñöţ çöþý |
<p>Click <a>here</a></p> | ýéš | öñé ƃļöçķ, <a> ƃéçöḿéš þàîŕéđ {=m0}…{/=m0} |
<code>foo</code> | ñö | ñöñ-ţŕàñšļàţàƃļé éļéḿéñţ |
<p>Say <code>json</code> now</p> | ýéš | öñé ƃļöçķ; json çàŕŕîéđ ţĥŕöüĝĥ àš þŕöţéçţéđ ţéẋţ |
<p>Use <abbr title="X">CM</abbr> ok</p> | ýéš | ţŵö ƃļöçķš: ţĥé šéñţéñçé, àñđ ţĥé title |
<h1 translate="no">X</h1> | ñö | éẋþļîçîţ öþţ-öüţ (šüþþŕéššéš ļîñţ ţöö) |
<button>{label}</button> | ñö | ƃàŕé éẋþŕéššîöñ; üšé t() öñ ţĥé šöüŕçé |
<button>{obj.label}</button> | ñö | ƒļàĝĝéđ ƃý prefer-t-for-label-expr; ŵŕàþ ţĥé šöüŕçé |
<button>{cond ? "A" : "B"}</button> | ýéš | öñé ƃļöçķ þéŕ ƃŕàñçĥ, ķéýéđ button::0 / button::1 |
<b>{c ? `Hi ${n}` : "Bye"}</b> | þàŕţļý | "Ƃýé" éẋţŕàçţš; ţĥé ţéḿþļàţé ñééđš t() |
<div>{cond && "Hi"}</div> | ýéš | ţĥé ŕîĝĥţ šîđé öƒ ţĥé öþéŕàţöŕ îš à ƃŕàñçĥ, ķéýéđ div::0 |
<p>Saved {cond && <b>a note</b>}</p> | ýéš | ţŵö ƃļöçķš: ţĥé šéñţéñçé, àñđ ţĥé çöñđîţîöñàļ'š öŵñ éļéḿéñţ |
<div>{icon} Save changes</div> | ýéš | öñé ƃļöçķ; {icon} ŕéñđéŕš àš àñ éļéḿéñţ ŵĥéŕéṽéŕ îţš ţöķéñ šîţš |
<div actions={<Button>Go</Button>}>Hi</div> | ýéš | ţŵö ƃļöçķš: ĴŠẊ îñ à þŕöþ éẋţŕàçţš àš ŵéļļ |
<p>Read <a>docs</a>{" "}now</p> | ýéš | öñé ƃļöçķ; ţĥé éẋþļîçîţ šþàçé îš ţéẋţ, ñöţ à ṽàŕîàƃļé |
Ñéẋţ
t()éšçàþé ĥàţçĥ: ƒöŕ ţĥé ĴŠ-đàţà-šţŕîñĝ àñđ ţéŕñàŕý-îñ-ĴŠẊ þàţţéŕñš.- Þļüŕàļš àñđ šéļéçţ: çöüñţ-àŵàŕé àñđ çĥöîçé-ƃàšéđ ţéẋţ.
- Ļîñţîñĝ: éđîţöŕ šǫüîĝĝļîéš ƒöŕ éṽéŕý àñţî-þàţţéŕñ öñ ţĥîš þàĝé.
- Éẋţŕàçţ þîþéļîñé: ĥöŵ ţĥé þļüĝîñ šĥîþš ţĥîš ţö ţŕàñšļàţöŕš.