Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

feat: add i18n to app #9

Merged
merged 4 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .tx/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[main]
host = https://www.transifex.com

[o:open-edx:p:edx-platform:r:frontend-component-ai-translations]
file_filter = src/i18n/messages/<lang>.json
source_file = src/i18n/transifex_input.json
source_lang = en
type = KEYVALUEJSON
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export TRANSIFEX_RESOURCE = frontend-component-header-edx
transifex_resource = frontend-component-header-edx
export TRANSIFEX_RESOURCE = frontend-component-ai-translations
transifex_resource = frontend-component-ai-translations
transifex_langs = "ar,fr,es_419,zh_CN,pt,it,de,uk,ru,hi,fr_CA"

transifex_utils = ./node_modules/.bin/transifex-utils.js
Expand Down
312 changes: 216 additions & 96 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"scripts": {
"build": "make build",
"i18n_extract": "BABEL_ENV=i18n fedx-scripts babel src --quiet > /dev/null",
"i18n_extract": "fedx-scripts formatjs extract",
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
Expand Down Expand Up @@ -39,7 +39,9 @@
"@testing-library/react": "10.4.9",
"@testing-library/user-event": "^14.5.1",
"@wojtekmaj/enzyme-adapter-react-17": "0.8.0",
"babel-plugin-react-intl": "^8.2.25",
"enzyme": "3.11.0",
"glob": "7.2.0",
"husky": "8.0.3",
"jest": "29.7.0"
},
Expand Down
13 changes: 9 additions & 4 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useState } from 'react';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import {
ActionRow, Collapsible, Icon, IconButton, Image,
} from '@edx/paragon';
import { ChevronLeft, ChevronRight, Close } from '@edx/paragon/icons';
import PropTypes from 'prop-types';

import messages from './messages';
import XpertLogo from './XpertLogo';

const App = ({ setIsAiTranslations, closeTranscriptSettings }) => {
Expand All @@ -14,6 +16,7 @@ const App = ({ setIsAiTranslations, closeTranscriptSettings }) => {
translationsError: false,
view: '',
});
const intl = useIntl();

const handleAppState = (updatedData) => {
setAppState((previousState) => ({ ...previousState, ...updatedData }));
Expand Down Expand Up @@ -45,7 +48,9 @@ const App = ({ setIsAiTranslations, closeTranscriptSettings }) => {
>
<div className="d-flex flex-column justify-content-center">
<XpertLogo />
Get free translations
<h4 className="h4 free-transltions-text mt-2.5">
<FormattedMessage {...messages.getFreeTranslations} />
</h4>
<Image
src={googleTranslateImage}
className="flex-grow-0"
Expand All @@ -70,7 +75,7 @@ const App = ({ setIsAiTranslations, closeTranscriptSettings }) => {
size="sm"
iconAs={Icon}
src={ChevronLeft}
alt="back button to main transcript settings view"
alt={intl.formatMessage(messages.backButtonAlt)}
onClick={handleBackButton}
/>
<ActionRow.Spacer />
Expand All @@ -82,12 +87,12 @@ const App = ({ setIsAiTranslations, closeTranscriptSettings }) => {
setIsAiTranslations(false);
}}
src={Close}
alt="close settings"
alt={intl.formatMessage(messages.closeButtonAlt)}
data-testid="action-row-close-btn"
/>
</ActionRow>
<div className="d-flex flex-column" key="ai-translations-views">
Translations is not available
<FormattedMessage {...messages.translationsNotAvailable} />
</div>
</>
)}
Expand Down
56 changes: 33 additions & 23 deletions src/App.test.jsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
import * as React from 'react';
import { act, render, screen } from '@testing-library/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
// eslint-disable-next-line import/no-extraneous-dependencies
import userEvent from '@testing-library/user-event';

import App from './App';
import messages from './messages';

const courseId = 'Fake-ID';

describe('App', () => {
it('renders collapsible button', () => {
const onSetIsAiTranslations = jest.fn();
render(
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={() => {}}
courseId={courseId}
/>,
<IntlProvider locale="en">
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={() => {}}
courseId={courseId}
/>
</IntlProvider>,
);

expect(
screen.getByText(/Get free translations/),
screen.getByText(messages.getFreeTranslations.defaultMessage),
).toBeInTheDocument();
});

it('renders App component', async () => {
const onSetIsAiTranslations = jest.fn();

render(
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={() => {}}
/>,
<IntlProvider locale="en">
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={() => {}}
/>
</IntlProvider>,
);

userEvent.click(screen.getByTestId('app-entry-btn'));
Expand All @@ -40,41 +46,45 @@ describe('App', () => {
it('goes back to previous view', async () => {
const onSetIsAiTranslations = jest.fn();
render(
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={() => {}}
/>,
<IntlProvider locale="en">
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={() => {}}
/>
</IntlProvider>,
);

userEvent.click(
screen.getByText(/Get free translations/),
screen.getByText(messages.getFreeTranslations.defaultMessage),
);
expect(await screen.findByText(/Translations is not available/)).toBeInTheDocument();
expect(await screen.findByText(messages.translationsNotAvailable.defaultMessage)).toBeInTheDocument();
expect(await screen.findByTestId('action-row-back-btn')).toBeInTheDocument();

await act(async () => {
userEvent.click(screen.queryByTestId('action-row-back-btn'));
});

expect(onSetIsAiTranslations).toHaveBeenCalled();
expect(await screen.findByText(/Get free translations/)).toBeInTheDocument();
expect(await screen.findByText(messages.getFreeTranslations.defaultMessage)).toBeInTheDocument();
expect(screen.queryByText(/Get free translations is not available/)).not.toBeInTheDocument();
});

it('calls closeTranscriptSettings when close button is clicked', async () => {
const onSetIsAiTranslations = jest.fn();
const onCloseTranscriptSettings = jest.fn();
render(
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={onCloseTranscriptSettings}
/>,
<IntlProvider locale="en">
<App
setIsAiTranslations={onSetIsAiTranslations}
closeTranscriptSettings={onCloseTranscriptSettings}
/>
</IntlProvider>,
);

userEvent.click(
screen.getByText(/Get free translations/),
screen.getByText(messages.getFreeTranslations.defaultMessage),
);
expect(await screen.findByText(/Translations is not available/)).toBeInTheDocument();
expect(await screen.findByText(messages.translationsNotAvailable.defaultMessage)).toBeInTheDocument();
expect(await screen.findByTestId('action-row-close-btn')).toBeInTheDocument();

await userEvent.click(screen.queryByTestId('action-row-close-btn'));
Expand Down
38 changes: 38 additions & 0 deletions src/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { messages as paragonMessages } from '@edx/paragon';
import arMessages from './messages/ar.json';
import frMessages from './messages/fr.json';
import es419Messages from './messages/es_419.json';
import zhcnMessages from './messages/zh_CN.json';
import ptMessages from './messages/pt.json';
import itMessages from './messages/it.json';
import ukMessages from './messages/uk.json';
import deMessages from './messages/de.json';
import ruMessages from './messages/ru.json';
import hiMessages from './messages/hi.json';
import frCAMessages from './messages/fr_CA.json';
import dedeMessages from './messages/de_DE.json';
import ititMessages from './messages/it_IT.json';
import ptptMessages from './messages/pt_PT.json';
// no need to import en messages-- they are in the defaultMessage field

const appMessages = {
ar: arMessages,
'es-419': es419Messages,
fr: frMessages,
'zh-cn': zhcnMessages,
pt: ptMessages,
it: itMessages,
de: deMessages,
hi: hiMessages,
'fr-ca': frCAMessages,
ru: ruMessages,
uk: ukMessages,
'de-de': dedeMessages,
'it-it': ititMessages,
'pt-pt': ptptMessages,
};

export default [
paragonMessages,
appMessages,
];
23 changes: 23 additions & 0 deletions src/i18n/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import messages from './index';

describe('messages', () => {
it('contains app messages', () => {
expect(messages.length).toEqual(2);
const appMessages = messages[1];
const languages = Object.getOwnPropertyNames(appMessages);
expect(languages).toContainEqual('ar');
expect(languages).toContainEqual('es-419');
expect(languages).toContainEqual('fr');
expect(languages).toContainEqual('zh-cn');
expect(languages).toContainEqual('pt');
expect(languages).toContainEqual('it');
expect(languages).toContainEqual('de');
expect(languages).toContainEqual('hi');
expect(languages).toContainEqual('fr-ca');
expect(languages).toContainEqual('ru');
expect(languages).toContainEqual('uk');
expect(languages).toContainEqual('de-de');
expect(languages).toContainEqual('it-it');
expect(languages).toContainEqual('pt-pt');
});
});
1 change: 1 addition & 0 deletions src/i18n/messages/ar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/de_DE.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/es_419.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/fa_IR.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/fr_CA.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/hi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/it.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/it_IT.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/pt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/pt_PT.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/uk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions src/i18n/messages/zh_CN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
26 changes: 26 additions & 0 deletions src/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
getFreeTranslations: {
id: 'ai-translations.request.heading.top',
defaultMessage: 'Get free translations',
description: 'Translations heading available',
},
translationsNotAvailable: {
id: 'ai-translations.request.heading.bottom',
defaultMessage: 'Translations service is not available',
description: 'Translations heading not available',
},
backButtonAlt: {
id: 'ai-translations.icon.button.back.alt',
defaultMessage: 'Back button to main transcript settings view',
description: 'alt text for back icon button',
},
closeButtonAlt: {
id: 'ai-translations.icon.button.close.alt',
defaultMessage: 'Close settings',
description: 'alt text for close settings icon button',
},
});

export default messages;
Loading