Je voudrais utiliser react-i18next avec mon composant connecté react-redux et je ne sais pas comment procéder.
J'ai simplifié mon code pour montrer un exemple de composant connecté:
import React from 'react';
import {connect} from 'react-redux';
import {userSelectors} from "./userSelectors";
interface IConnectedProps {
activeUserName: string | undefined;
}
export class LandingPageComponent extends React.Component<IConnectedProps> {
public render(): JSX.Element {
return (
<React.Suspense fallback={<Spinner/>}>
<React.Fragment>
<div>
... a bunch of controls using translated text
</div>
<div>{activeUserName}</div>
</React.Fragment>
</React.Suspense>
);
}
}
const mapStateToProps = (state: ICoreRootState) : IConnectedProps => ({
activeUserName: userSelectors.getDisplayName(state),
});
export const LandingPage = connect(mapStateToProps)(LandingPageComponent);
Versions des packages installés:
react version: 16.8.4
react-redux version: 5.1.1
react-i18next version: 10.6.0
Ce que j'ai essayé:
1) J'obtiens l'erreur ci-dessous lorsque j'utilise withTranslation, WithTranslation comme suit:
export class LandingPageComponent extends React.Component<IConnectedProps & WithTranslation> {...}
export const LandingPage = connect(mapStateToProps)(withTranslation()(LandingPageComponent));
Erreur:
The above error occurred in the <withI18nextTranslation(LandingPageComponent)> component:
in withI18nextTranslation(LandingPageComponent) (created by Connect(withI18nextTranslation(LandingPageComponent)))
in Connect(withI18nextTranslation(LandingPageComponent))
in Route
in t
in Connect(t) (at App.tsx:49)
in Switch (at App.tsx:45)
in App (at src/index.tsx:14)
in Router (created by ConnectedRouter)
in ConnectedRouter (created by Connect(ConnectedRouter))
in Connect(ConnectedRouter) (at src/index.tsx:13)
in Provider (at src/index.tsx:12)
2) J'obtiens l'erreur ci-dessous lorsque j'utilise withTranslation, WithTranslation comme suit:
export class LandingPageComponent extends React.Component<IConnectedProps & WithTranslation> {...}
export const LandingPage = withTranslation()(connect(mapStateToProps)(LandingPageComponent));
Erreur:
index.js:1446 The above error occurred in the <withI18nextTranslation(Connect(LandingPageComponent))> component:
in withI18nextTranslation(Connect(LandingPageComponent))
in Route
in t
in Connect(t) (at App.tsx:49)
in Switch (at App.tsx:45)
in App (at src/index.tsx:14)
in Router (created by ConnectedRouter)
in ConnectedRouter (created by Connect(ConnectedRouter))
in Connect(ConnectedRouter) (at src/index.tsx:13)
in Provider (at src/index.tsx:12)
3) Je ne peux pas utiliser useTranslation car les hooks ne sont pas autorisés à être utilisés dans une classe.
J'ai également essayé ce qui suit:
... a bunch of imports
interface ILogoutButtonProps {
userName?: string;
}
interface IConnectedHandlers {
readonly logout: any;
readonly Push: any;
}
class InnerLogoutComponent extends React.Component<IButtonProps & IConnectedHandlers & ILogoutButtonProps & WithTranslation, {}> {
public render() {
const {userName, onClick, logout: Logout, Push: Push, ...buttonProps} = this.props;
const logoutText = this.props.i18n.t(StringNames.logout);
const buttonText = userName ? logoutText + " " + userName : logoutText;
return (
<Button {...buttonProps} text={buttonText} onClick={this.handleClick}/>
);
}
private handleClick = (event: React.MouseEvent<HTMLElement>) : void => {
this.props.logout()
.then(() => this.props.Push(LoginPaths.verifyUser));
}
}
const InnerLogoutTranslatedComponent = withTranslation()(InnerLogoutComponent);
class LogoutComponentInternal extends React.Component<IButtonProps & IConnectedHandlers & ILogoutButtonProps, {}> {
public render () {
return (
<InnerLogoutTranslatedComponent {...this.props}/>
);
}
}
export const LogoutComponent = connect(null,{logout, Push})(LogoutComponentInternal);
mais j'obtiens l'erreur suivante:
Hooks can only be called inside the body of a function component.
Merci d'avance...
Dans notre projet, nous utilisons avec succès ceci:
import { compose } from 'redux';
import { withNamespaces } from 'react-i18next';
import { connect } from 'react-redux';
...
export default compose(withNamespaces('translation'), connect(mapStateToProps))(ComponentName);
Avec cela, nous nous connectons à Redux avec mapStateToProps et nous avons traductions.
J'utilise SSR avec RazzleJS et dans mon cas, cela fonctionne parfaitement bien. J'ai connecté mes connect
et withTranslation
comme ceci:
export default connect(mapStateToProps,mapDispatchToProps)(withTranslation()(Component));
Cela fonctionne pour moi:
export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(Component));
J'ai en fait du mal à déterminer dans quel ordre vous enveloppez vos composants dans des HOC. Dans le projet sur lequel je travaille actuellement, nous enveloppons comme withNamespaces(connect(withStyles(component)))
, ce qui fonctionne très bien (withNamespaces
est essentiellement le même que withTranslations
). Nous avons rencontré des problèmes lors de la tentative de connexion d'un composant traduit, vous rencontrez peut-être les mêmes problèmes en ce moment. Voici donc notre façon de procéder:
Vous avez un composant "normal" comme
type InjectedProps = StateProps & ExternalProps & MyComponentsTranslations
export class MyComponent extends React.Component<InjectedProps> {
...
}
(Remarque: la procédure fonctionne exactement de la même manière avec les composants fonctionnels)
vous pouvez const MyConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(MyComponent)
et enfin vous faites
import {WithNamespaces, withNamespaces} from "react-i18next"
export const LocalizedMyComponent = withNamespaces()(
({t,...rest}): WithNamepsaces) => (
<MyConnectedComponent translations={{ put translations here }} {...rest} />
)
)
Maintenant, l'astuce est que nous définissons un interface MyComponentsTranslations {}
Où nous mettons toutes les traductions ou les fonctions de traduction requises (dans le cas de pluriels). MyComponentsTranslations
est ajouté au InjectedProps
pour les rendre disponibles dans le composant d'origine.
Vous pouvez toujours simplement injecter la fonction t
- de i18n dans vos composants, mais dans mon projet actuel, nous avons décidé qu'il est beaucoup plus propre de
Faites-moi savoir si cela fonctionne pour vous.
De plus, pour rendre le tout un peu plus élégant, vous pouvez utiliser ces aides:
export interface Translations<T> {
translations: T
}
export const createTranslations = <T>(translations: T): Translations<T> => ({
translations,
})
Cela vous permet de définir
type InjectedProps = StateProps & Translations<MyComponentTranslations>
et dans le withNamespace
hoc:
<MyConnectedComponent {...createTranslations<MyComponentTranslations>({ put translations here })} {...rest} />
Dans mon cas, je l'ai corrigé en faisant:
export default withTranslation(null, {withRef: true})(MyComponent);
withRef
est false
par défaut.
Source: https://github.com/i18next/react-i18next/blob/master/src/withTranslation.js