Replies: 1 comment 3 replies
-
|
Hey @debel27, thanks for taking the time to write up this RFC! On a first look, it seems like this use case is already supported to some extend, see e.g.: #1575 (comment). Separating data from translations is quite common and good practice IMO. E.g. in a codebase I'm currently working on I have the rule that any "service" works purely on data and translations must only be applied in components (with Server Actions that are defined along with components also counting as part of that). E.g. Regarding your examples, it seems like these can already be realized currently: const topBarEntries = [
{
id: "profile",
link: "/profile",
},
{
id: "settings",
link: "/settings"
}
];
function TopBar() {
const t = useTranslations();
return (
<div className="top-bar">
{topBarEntries.map(entry => {
const {id, link} = entry;
return <a key={id} href={link}>{t(`topBarItem.${id}`)}</a>
})}
</div>
);
}import { useTranslations } from 'next-intl';
function Component() {
const t = useTranslations();
return (
<Input label={t("field.firstName")} />
);
}(Benefit: Any label can be accepted, translated or not) So as things stand currently, I have to say that don't really see a large benefit of introducing this. Does that make sense to you? I tend to be quite conservative with APIs that are added to |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Introduction
next-intl promotes translating messages within React components. This is a great design decision, because messages depend on reactive data that can change across renders (such as the user locale).
However, like many internationalization libraries, next-intl expects developers to identify the message to translate directly within the call site of
t. As explained later, this approach results in usability issues.I would like to introduce the concept "message references" to next-intl, which gives the ability to identify messages without immediately translating them.
Motivations
Giving the ability to reference a message separately from the translation operation introduces a useful decoupling, improving flexibility and ergonomics:
tfunction is not available.useTranslationsevery time they need to translate something. They can simply declare a message reference and pass it to translation-aware components/hooks, which will deal with the actual translation operation.Those benefits are particularly appreciated in data-driven codebases, as the upcoming examples will illustrate.
Before getting to the examples, I will formalize the proposal a bit.
Proposal
Basic principle
next-intl will introduce an
IntlMessagetype, defined as follows:The signature of the
tfunction will be updated to acceptIntlMessageas an argument.Here is a simple example to illustrate the idea:
Creating
IntlMessageobjectsDevelopers will not create
IntlMessageobjects directly. They will do it with the help of a utilityi18nfunction.i18naccept the exact same parameters ast:i18nis not to be confused witht!i18ncan be called outside React components and does not translate anything. It only allows declaring a reference to a message, to be translated later byt.i18nmakes declaring references easier and will play nicer with TypeScript (as shown later). To make sure developers use it, we can makeIntlMessagebranded:TypeScript augmentation
i18naccepts the exact same parameters ast. Therefore, it can benefit from the same TypeScript APIs, includng the strict typing of ICU arguments. For this reason, I'm assuming type safety will be trivial to implement.Examples
These examples illustrate the possibilities unlocked by the new
IntlMessagetype.Static references
IntlMessageallows developers to declare messages references statically, outside React space. This gives more flexibility to organize code.topBarEntries.ts
topBar.ts
I18n-first components
Now that message references are first-class citizen of the next-intl package, they can be used to improve developer experience in application space, since they allow writing components with built-in I18n support.
For instance, consider we developed a wrapper on top of
<input/>to support label internationalization:Our
Inputhas an API that improves developer experience, because callers of that component no longer need to calluseTranslationsto pass down a translated label.Given
i18ncan be auto-imported by the IDE, there is less ceremony involved when dealing with internationalization.Additional utilities
We can leverage the
IntlMessageecosystem by introducing the following utility functionsi18nIdentityIf an API only accepts an
IntlMessageas input, the developer needs a workaround when they want to display some text "as is" instead of an internationalized message.The
i18nIdentityfunction can be for such case:The utility relies on a built-in message
__identity: "{data}", inserted automatically by next-intl.Example:
i18nIdentity("Some text coming from the server")isIntlMessageConvenience function to determine if an object is an
IntlMessageThis can be particularly handy for I18n-first components:
Beta Was this translation helpful? Give feedback.
All reactions