fix(client): set the correct language to the HTML lang attribute (#42729)
This commit is contained in:
52
client/src/components/app-mount-notifier.test.tsx
Normal file
52
client/src/components/app-mount-notifier.test.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { i18nextCodes } from '../../../config/i18n/all-langs';
|
||||
import AppMountNotifier from './app-mount-notifier';
|
||||
import { createStore } from '../redux/createStore';
|
||||
import i18nTestConfig from '../../i18n/configForTests';
|
||||
|
||||
jest.mock('react-ga');
|
||||
jest.unmock('react-i18next');
|
||||
|
||||
type Language = [string, string];
|
||||
|
||||
const store = createStore();
|
||||
|
||||
// Create a nested array for languages
|
||||
const languages = Object.keys(i18nextCodes).map(
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-unsafe-return */
|
||||
// @ts-ignore
|
||||
// TODO: convert `all-langs.js` to TypeScript
|
||||
(key): Language => [i18nextCodes[key], key]
|
||||
);
|
||||
|
||||
describe('AppMountNotifier', () => {
|
||||
const setup = (lang: string) => {
|
||||
i18nTestConfig.language = lang;
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<I18nextProvider i18n={i18nTestConfig}>
|
||||
<AppMountNotifier render={() => <p>App content</p>} />
|
||||
</I18nextProvider>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
test.each(languages)(
|
||||
'should set the lang attribute to %s if the language is %s',
|
||||
async langCode => {
|
||||
setup(langCode);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(document.querySelector('html')).toHaveAttribute(
|
||||
'lang',
|
||||
langCode
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
import { Component, ReactNode } from 'react';
|
||||
import { AnyAction, bindActionCreators, Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { appMount } from '../redux';
|
||||
|
||||
const mapStateToProps = () => ({});
|
||||
const mapDispatchToProps = (dispatch: Dispatch<AnyAction>) =>
|
||||
bindActionCreators({ appMount }, dispatch);
|
||||
|
||||
type AppMountNotifierProps = {
|
||||
appMount: () => void;
|
||||
render: () => ReactNode;
|
||||
};
|
||||
|
||||
class AppMountNotifier extends Component<AppMountNotifierProps> {
|
||||
static displayName = 'AppMountNotifier';
|
||||
|
||||
componentDidMount() {
|
||||
return this.props.appMount();
|
||||
}
|
||||
render() {
|
||||
return this.props.render();
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AppMountNotifier);
|
38
client/src/components/app-mount-notifier.tsx
Normal file
38
client/src/components/app-mount-notifier.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { bindActionCreators, Dispatch } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { appMount } from '../redux';
|
||||
|
||||
interface AppMountNotifierProps {
|
||||
render: () => React.ReactNode;
|
||||
appMount: () => void;
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch) =>
|
||||
bindActionCreators({ appMount }, dispatch);
|
||||
|
||||
const AppMountNotifier = ({
|
||||
render,
|
||||
appMount
|
||||
}: AppMountNotifierProps): JSX.Element => {
|
||||
useEffect(() => {
|
||||
appMount();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet htmlAttributes={{ lang: i18n.language }} />
|
||||
{render()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
AppMountNotifier.displayName = 'AppMountNotifier';
|
||||
|
||||
export default connect(null, mapDispatchToProps)(AppMountNotifier);
|
@ -10,7 +10,6 @@ module.exports = {
|
||||
'<rootDir>/client/src/__mocks__/styleMock.js',
|
||||
// CSS Modules - match files that end with 'module.css'
|
||||
'\\.module\\.css$': 'identity-obj-proxy',
|
||||
'react-i18next': '<rootDir>/client/src/__mocks__/react-i18nextMock.js',
|
||||
'^lodash-es$': 'lodash'
|
||||
},
|
||||
globals: {
|
||||
|
Reference in New Issue
Block a user