From 92f5d1a7f5f9e7cc3eeac6a9659ef701bd2c4786 Mon Sep 17 00:00:00 2001
From: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com>
Date: Mon, 5 Jul 2021 00:38:41 +0700
Subject: [PATCH] fix(client): set the correct language to the HTML lang
attribute (#42729)
---
...{react-i18nextMock.js => react-i18next.js} | 0
.../components/app-mount-notifier.test.tsx | 52 +++++++++++++++++++
client/src/components/app-mount-notifier.ts | 27 ----------
client/src/components/app-mount-notifier.tsx | 38 ++++++++++++++
jest.config.js | 1 -
5 files changed, 90 insertions(+), 28 deletions(-)
rename client/src/__mocks__/{react-i18nextMock.js => react-i18next.js} (100%)
create mode 100644 client/src/components/app-mount-notifier.test.tsx
delete mode 100644 client/src/components/app-mount-notifier.ts
create mode 100644 client/src/components/app-mount-notifier.tsx
diff --git a/client/src/__mocks__/react-i18nextMock.js b/client/src/__mocks__/react-i18next.js
similarity index 100%
rename from client/src/__mocks__/react-i18nextMock.js
rename to client/src/__mocks__/react-i18next.js
diff --git a/client/src/components/app-mount-notifier.test.tsx b/client/src/components/app-mount-notifier.test.tsx
new file mode 100644
index 0000000000..ababbe5a39
--- /dev/null
+++ b/client/src/components/app-mount-notifier.test.tsx
@@ -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(
+
+
+ App content
} />
+
+
+ );
+ };
+
+ 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
+ );
+ });
+ }
+ );
+});
diff --git a/client/src/components/app-mount-notifier.ts b/client/src/components/app-mount-notifier.ts
deleted file mode 100644
index 2bcd979747..0000000000
--- a/client/src/components/app-mount-notifier.ts
+++ /dev/null
@@ -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) =>
- bindActionCreators({ appMount }, dispatch);
-
-type AppMountNotifierProps = {
- appMount: () => void;
- render: () => ReactNode;
-};
-
-class AppMountNotifier extends Component {
- static displayName = 'AppMountNotifier';
-
- componentDidMount() {
- return this.props.appMount();
- }
- render() {
- return this.props.render();
- }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(AppMountNotifier);
diff --git a/client/src/components/app-mount-notifier.tsx b/client/src/components/app-mount-notifier.tsx
new file mode 100644
index 0000000000..f3d6830fec
--- /dev/null
+++ b/client/src/components/app-mount-notifier.tsx
@@ -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 (
+ <>
+
+ {render()}
+ >
+ );
+};
+
+AppMountNotifier.displayName = 'AppMountNotifier';
+
+export default connect(null, mapDispatchToProps)(AppMountNotifier);
diff --git a/jest.config.js b/jest.config.js
index ed27610807..6b9bae0cde 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -10,7 +10,6 @@ module.exports = {
'/client/src/__mocks__/styleMock.js',
// CSS Modules - match files that end with 'module.css'
'\\.module\\.css$': 'identity-obj-proxy',
- 'react-i18next': '/client/src/__mocks__/react-i18nextMock.js',
'^lodash-es$': 'lodash'
},
globals: {