React-reduxに接続されたコンポーネントでreact-i18nextを使用したいのですが、どうすればよいかわかりません。
接続コンポーネントの例を示すためにコードを簡略化しました。
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);
インストールされているパッケージのバージョン:
react version: 16.8.4
react-redux version: 5.1.1
react-i18next version: 10.6.0
私が試したこと:
1)withTranslation、WithTranslationを次のように使用すると、以下のエラーが発生します。
export class LandingPageComponent extends React.Component<IConnectedProps & WithTranslation> {...}
export const LandingPage = connect(mapStateToProps)(withTranslation()(LandingPageComponent));
エラー:
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)withTranslation、WithTranslationを次のように使用すると、以下のエラーが発生します。
export class LandingPageComponent extends React.Component<IConnectedProps & WithTranslation> {...}
export const LandingPage = withTranslation()(connect(mapStateToProps)(LandingPageComponent));
エラー:
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)クラス内でのフックの使用が許可されていないため、useTranslationを使用できません。
私は次のことも試しました:
... 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);
しかし、私は次のエラーを受け取ります:
Hooks can only be called inside the body of a function component.
前もって感謝します...
私たちのプロジェクトでは、これをうまく利用しています。
import { compose } from 'redux';
import { withNamespaces } from 'react-i18next';
import { connect } from 'react-redux';
...
export default compose(withNamespaces('translation'), connect(mapStateToProps))(ComponentName);
これにより、ReduxにmapStateToPropsで接続し、translationsができます。
私はRazzleJSでSSRを使用しており、私の場合は完全に正常に動作しています。私はconnect
とwithTranslation
を次のように接続しました:
export default connect(mapStateToProps,mapDispatchToProps)(withTranslation()(Component));
これは私にとってはうまくいきます:
export default withTranslation()(connect(mapStateToProps, mapDispatchToProps)(Component));
コンポーネントをHOCでラップする順序を決定するのに実際に問題があります。私が現在取り組んでいるプロジェクトでは、withNamespaces(connect(withStyles(component)))
のようにラップします。これは非常にうまく機能します(withNamespaces
は基本的にwithTranslations
と同じです)。翻訳されたコンポーネントを接続しようとしたときに問題が発生しました。現在同じ問題が発生している可能性があります。それで、これが私たちのやり方です:
あなたはのような「通常の」コンポーネントを持っています
_type InjectedProps = StateProps & ExternalProps & MyComponentsTranslations
export class MyComponent extends React.Component<InjectedProps> {
...
}
_
(注:手順は機能コンポーネントとまったく同じように機能します)
できますconst MyConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(MyComponent)
そして最後に、あなたは
_import {WithNamespaces, withNamespaces} from "react-i18next"
export const LocalizedMyComponent = withNamespaces()(
({t,...rest}): WithNamepsaces) => (
<MyConnectedComponent translations={{ put translations here }} {...rest} />
)
)
_
ここでの秘訣は、必要なすべての翻訳または翻訳関数(複数形の場合)を配置する_interface MyComponentsTranslations {}
_を定義することです。 MyComponentsTranslations
がInjectedProps
に追加され、元のコンポーネントで使用できるようになります。
あなたはいつでもi18nのt
関数をコンポーネントに注入することができますが、私の現在のプロジェクトでは、
これで問題が解決するかどうかお知らせください。
また、全体を少しエレガントにするために、次のヘルパーを使用できます。
_export interface Translations<T> {
translations: T
}
export const createTranslations = <T>(translations: T): Translations<T> => ({
translations,
})
_
これにより、
_type InjectedProps = StateProps & Translations<MyComponentTranslations>
_
withNamespace
hoc:
_<MyConnectedComponent {...createTranslations<MyComponentTranslations>({ put translations here })} {...rest} />
_
私の場合、次のようにして修正しました:
export default withTranslation(null, {withRef: true})(MyComponent);
withRef
はデフォルトでfalse
です。
ソース: https://github.com/i18next/react-i18next/blob/master/src/withTranslation.js