Distribuer des bibliothèques compatibles i18n
Cette page a été traduite par PageTurner AI (bêta). Non approuvée officiellement par le projet. Vous avez trouvé une erreur ? Signaler un problème →
Dans les applications/monorepos à grande échelle, tous les composants/bibliothèques ne résident pas dans le même dépôt/projet et peuvent être distribués différemment. Bien qu'il existe plusieurs approches pour résoudre ce problème, ce guide présente une méthode que nous avons observée comme très efficace dans les grandes organisations d'ingénierie.
Concept de haut niveau
Les chaînes traduites sont fondamentalement des ressources, au même titre que le CSS, la configuration statique ou les images. La structure globale comprend généralement plusieurs couches :
-
Composants/Bibliothèques réutilisables contenant des chaînes traduites, pouvant être imbriqués.
-
Applications de niveau supérieur qui consomment ces composants/bibliothèques.
Chaque fonctionnalité/bibliothèque est responsable de :
-
S'intégrer à la chaîne de traduction.
-
Déclarer ses chaînes traduites et agrégées via un manifeste comme package.json, une convention (sortie systématique à un emplacement spécifique) ou les deux.
Déclaration dans package.json
Similaire à l'utilisation de l'attribut style pour le CSS. Vous pouvez déclarer :
{
"name": "my-library",
"version": "1.0.0",
"lang": "my-strings",
"supportedLocales": ["en", "en-GB", "ja"]
}
où my-strings est le dossier contenant vos chaînes traduites pour vos supportedLocales :
my-strings
|- en.json
|- en-GB.json
|- ja.json
L'application consommatrice peut parcourir node_modules pour trouver les fichiers package.json contenant ces champs, agréger les chaînes en un bundle unique (ou multiples) et servir ces JSON comme bon lui semble.
Cette approche offre la flexibilité de sortir les traductions où vous voulez, tant que c'est déclaré dans package.json. Cependant, elle induit un surcoût de traitement au niveau applicatif et favorise l'incohérence des emplacements de sortie.
Déclaration par convention
Similaire à la déclaration dans package.json, sauf que les traductions sont toujours sorties dans lang/{locale}.json. L'application parente peut alors :
formatjs compile "node_modules/**/lang/en.json" --ast --out-file lang/en.json
agréger toutes les chaînes pré-traduites de ses bibliothèques.
my-lib
|- src
|- lang
|- en.json
|- en-GB.json
|- ja.json
|- node_modules
|- library1
|- lang
|- en.json
|- en-GB.json
|- ja.json
|- library2
|- lang
|- en.json
|- en-GB.json
|- ja.json
Cette méthode assure la cohérence et minimise le traitement des manifestes, mais est moins flexible.
Nous observons que l'approche par convention fonctionne mieux dans les grandes organisations grâce à l'imposition de standards, tandis que le manifest convient mieux à des environnements plus ouverts.
Transmission de l'objet intl
Le cœur d'une application i18n est l'objet intl, qui contient les messages précompilés, les paramètres de locale, les formats et le cache. Il doit donc être initialisé uniquement au niveau racine de l'application.
Les bibliothèques de composants peuvent déclarer intl: IntlShape comme prop et le transmettre directement ainsi :
- React
- Vue3
import {IntlShape} from 'react-intl'
import {MyButton, MyForm} from 'my-components'
interface Props {
intl: IntlShape
}
function MyFeature(props: Props) {
return (
<div>
<MyButton intl={props.intl} />
<MyForm intl={props.intl} />
</div>
)
}
or passing down via context using RawIntlProvider:
import {IntlShape, RawIntlProvider} from 'react-intl'
import {MyButton, MyForm} from 'my-components'
interface Props {
intl: IntlShape
}
function MyFeature(props: Props) {
return (
<RawIntlProvider value={props.intl}>
<MyButton />
<MyForm />
</RawIntlProvider>
)
}
import {useIntl} from 'vue-intl'
const MyFeature = {
setup() {
const intl = useIntl()
return () =>
h(
'p',
{},
intl.formatMessage({
id: 'foo',
defaultMessage: 'Hello',
})
)
},
}
or passing down via provideIntl
import {createIntl} from '@formatjs/intl'
import {provideIntl, useIntl} from 'vue-intl'
const Ancestor = {
setup() {
provideIntl(
createIntl({
locale: 'en',
defaultLocale: 'en',
messages: {
foo: 'Composed',
},
})
)
},
render() {
return h(MyFeature)
},
}