Verteilung von i18n-freundlichen Bibliotheken
Diese Seite wurde von PageTurner AI übersetzt (Beta). Nicht offiziell vom Projekt unterstützt. Fehler gefunden? Problem melden →
Bei umfangreichen Anwendungen/Monorepos befinden sich nicht alle Komponenten/Bibliotheken im selben Repository/Projekt, und sie können unterschiedlich verteilt werden. Obwohl es mehrere Lösungsansätze gibt, bietet dieser Leitfaden eine bewährte Methode, die sich in großen Entwicklerorganisationen als effektiv erwiesen hat.
Grundkonzept
Übersetzte Zeichenketten sind im Wesentlichen Assets – ähnlich wie CSS, statische Konfigurationen oder Bilder. Die übergeordnete Struktur umfasst typischerweise mehrere Ebenen:
-
Wiederverwendbare Komponenten/Bibliotheken mit übersetzten Zeichenketten, die verschachtelt sein können.
-
Konsumierende Anwendungen höherer Ebene, die diese Komponenten/Bibliotheken nutzen.
Jede Funktion/Bibliothek ist verantwortlich für:
-
Integration in die Übersetzungspipeline.
-
Deklaration ihrer übersetzten und aggregierten Zeichenketten entweder über ein Manifest wie package.json, eine Konvention (Ausgabe immer an bestimmten Ort) oder beides.
Deklaration in package.json
Dies ähnelt der Verwendung des style-Attributs für CSS. Beispielsweise können Sie Folgendes deklarieren:
{
"name": "my-library",
"version": "1.0.0",
"lang": "my-strings",
"supportedLocales": ["en", "en-GB", "ja"]
}
Hier ist my-strings der Ordner mit Ihren übersetzten Zeichenketten in Ihren supportedLocales:
my-strings
|- en.json
|- en-GB.json
|- ja.json
Konsumierende Anwendungen können node_modules durchsuchen, um package.json-Dateien mit diesen Feldern zu finden, die Zeichenketten in einem einzigen Bundle (oder mehreren Bundles) aggregieren und diese JSONs nach Belieben bereitstellen.
Dies bietet Flexibilität bei der Ausgabeposition von Übersetzungen, solange sie in package.json deklariert ist. Allerdings entstehen dadurch zusätzliche Verarbeitungskosten auf Anwendungsebene und es fördert Inkonsistenzen im Ausgabepfad.
Deklaration durch Konvention
Dies ähnelt der Deklaration in package.json, nur dass Übersetzungen immer nach lang/{locale}.json ausgegeben werden. Übergeordnete Anwendungen können
formatjs compile "node_modules/**/lang/en.json" --ast --out-file lang/en.json
verwenden, um alle vorkompilierten Zeichenketten ihrer Bibliotheken zu aggregieren.
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
Dies gewährleistet Konsistenz und minimiert den Verarbeitungsaufwand für verschiedene Manifestdateien, ist aber weniger flexibel.
In großen Entwicklerorganisationen hat sich der convention-Ansatz aufgrund durchgesetzter Standards besser bewährt, während der manifest-Ansatz in offeneren Umgebungen funktioniert.
Weitergabe des intl-Objekts
Der Kern einer i18n-Anwendung ist das intl-Objekt, das vorkompilierte Nachrichten, Locale-Einstellungen, Formatierungsoptionen und Cache enthält. Daher sollte es nur auf oberster Anwendungsebene initialisiert werden.
Komponentenbibliotheken können intl: IntlShape als Prop deklarieren und direkt weitergeben:
- 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)
},
}