Skip to content

Commit

Permalink
add i18next and config for i18n
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Robinson <merobi@gmail.com>
  • Loading branch information
merobi-hub committed Nov 21, 2022
1 parent 0f857c5 commit 3745a7e
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 17 deletions.
5 changes: 4 additions & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
"redux": "^4.0.1",
"redux-logger": "^3.0.6",
"redux-saga": "^1.0.2",
"webpack-merge": "^4.2.1"
"webpack-merge": "^4.2.1",
"i18next": "^22.0.6",
"i18next-browser-languagedetector": "^7.0.1",
"react-i18next": "^12.0.0"
},
"devDependencies": {
"@types/classnames": "^2.2.10",
Expand Down
4 changes: 3 additions & 1 deletion web/src/components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import MqText from '../core/text/MqText'
import NamespaceSelect from '../namespace-select/NamespaceSelect'
import React, { ReactElement } from 'react'
import Search from '../search/Search'
import { useTranslation } from 'react-i18next'

const styles = (theme: Theme) => {
return createStyles({
Expand Down Expand Up @@ -40,6 +41,7 @@ const styles = (theme: Theme) => {
type HeaderProps = WithStyles<typeof styles>

const Header = (props: HeaderProps): ReactElement => {
const { t } = useTranslation();
const { classes } = props
return (
<AppBar position='fixed' elevation={0} className={classes.appBar}>
Expand All @@ -53,7 +55,7 @@ const Header = (props: HeaderProps): ReactElement => {
<NamespaceSelect />
<Box ml={2}>
<MqText link href={API_DOCS_URL}>
API Docs
{t('header.docs_link')}
</MqText>
</Box>
</Box>
Expand Down
12 changes: 7 additions & 5 deletions web/src/components/jobs/JobDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import MqText from '../core/text/MqText'
import RunInfo from './RunInfo'
import RunStatus from './RunStatus'
import Runs from './Runs'
import { useTranslation } from 'react-i18next'

const styles = ({ spacing }: ITheme) => {
return createStyles({
Expand Down Expand Up @@ -52,6 +53,7 @@ const JobDetailPage: FunctionComponent<IProps> = props => {
const handleChange = (event: ChangeEvent, newValue: SetStateAction<number>) => {
setTab(newValue)
}
const { t } = useTranslation()

useEffect(() => {
fetchRuns(job.name, job.namespace)
Expand Down Expand Up @@ -82,13 +84,13 @@ const JobDetailPage: FunctionComponent<IProps> = props => {
>
<Box mb={2} display={'flex'} justifyContent={'space-between'} alignItems={'center'}>
<Tabs value={tab} onChange={handleChange} textColor='primary' indicatorColor='primary'>
<Tab label='LATEST RUN' disableRipple={true} />
<Tab label='RUN HISTORY' disableRipple={true} />
<Tab label={t('jobs.latest_tab')} disableRipple={true} />
<Tab label={t('jobs.history_tab')} disableRipple={true} />
</Tabs>
<Box display={'flex'} alignItems={'center'}>
<Box mr={1}>
<Button variant='outlined' color='primary' target={'_blank'} href={job.location}>
Location
{t('jobs.location')}
</Button>
</Box>
<IconButton onClick={() => history.push('/')}>
Expand Down Expand Up @@ -116,8 +118,8 @@ const JobDetailPage: FunctionComponent<IProps> = props => {
) : (
!job.latestRun && (
<MqEmpty
title={'No Run Information Available'}
body={'Try adding some runs for this job.'}
title={t('jobs.empty_title')}
body={t('jobs.empty_body')}
/>
)
)
Expand Down
4 changes: 3 additions & 1 deletion web/src/components/jobs/RunInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import MqCode from '../core/code/MqCode'
import MqJson from '../core/code/MqJson'
import MqText from '../core/text/MqText'
import React, { FunctionComponent } from 'react'
import { useTranslation } from 'react-i18next'

interface RunInfoProps {
run: Run
}

const RunInfo: FunctionComponent<RunInfoProps> = props => {
const { run } = props
const { t } = useTranslation()

return (
<Box mt={2}>
Expand All @@ -26,7 +28,7 @@ const RunInfo: FunctionComponent<RunInfoProps> = props => {
{run.facets && (
<Box mt={2}>
<Box mb={1}>
<MqText subheading>FACETS</MqText>
<MqText subheading>{t('jobs.runinfo_subhead')}</MqText>
</Box>
<MqJson code={run.facets} />
</Box>
Expand Down
6 changes: 4 additions & 2 deletions web/src/components/jobs/Runs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import React, { FunctionComponent, SetStateAction } from 'react'
import RunInfo from './RunInfo'
import RunStatus from './RunStatus'
import transitions from '@material-ui/core/styles/transitions'
import { useTranslation } from 'react-i18next'

const RUN_COLUMNS = ['ID', 'STATE', 'CREATED AT', 'STARTED AT', 'ENDED AT', 'DURATION']

Expand Down Expand Up @@ -54,8 +55,9 @@ interface RunsProps {

const Runs: FunctionComponent<RunsProps & WithStyles<typeof styles>> = props => {
const { runs, facets, classes } = props
const { t } = useTranslation()
if (runs.length === 0) {
return <MqEmpty title={'No Runs Found'} body={'Try adding some runs for this job.'} />
return <MqEmpty title={'jobs.empty_title'} body={'jobs.empty_body'} />
}

const [infoView, setInfoView] = React.useState<Run | null>(null)
Expand Down Expand Up @@ -116,7 +118,7 @@ const Runs: FunctionComponent<RunsProps & WithStyles<typeof styles>> = props =>
{facets && (
<Box mt={2}>
<Box mb={1}>
<MqText subheading>FACETS</MqText>
<MqText subheading>{t('jobs.runs_subhead')}</MqText>
</Box>
<MqCode code={JSON.stringify(facets, null, '\t')} />
</Box>
Expand Down
6 changes: 4 additions & 2 deletions web/src/components/lineage/Lineage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import MqEmpty from '../core/empty/MqEmpty'
import MqText from '../core/text/MqText'
import Node from './components/node/Node'
import ParentSize from '@visx/responsive/lib/components/ParentSize'
import { useTranslation } from 'react-i18next'
import i18next from '../../i18n'

const BOTTOM_OFFSET = 8

Expand Down Expand Up @@ -159,9 +161,9 @@ class Lineage extends React.Component<LineageProps, LineageState> {
<Box className={classes.lineageContainer}>
{this.props.selectedNode === null && (
<Box display={'flex'} justifyContent={'center'} alignItems={'center'} pt={2}>
<MqEmpty title={'No node selected'}>
<MqEmpty title={i18next.t('lineage.empty_title')}>
<MqText subdued>
Try selecting a node through search or the jobs or datasets page.
{i18next.t('lineage.empty_body')}
</MqText>
</MqEmpty>
</Box>
Expand Down
10 changes: 6 additions & 4 deletions web/src/components/search/SearchPlaceholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { theme } from '../../helpers/theme'
import MqText from '../core/text/MqText'
import React from 'react'
import withStyles, { WithStyles } from '@material-ui/core/styles/withStyles'
import { useTranslation } from 'react-i18next';

const styles = (theme: Theme) =>
createStyles({
Expand All @@ -20,24 +21,25 @@ const styles = (theme: Theme) =>
})

const SearchPlaceholder: React.FC<WithStyles<typeof styles>> = ({ classes }) => {
const { t } = useTranslation();
return (
<Box className={classes.root}>
<Box display={'inline'}>
<MqText disabled inline>
{' '}
Search
{t('search.search')}
</MqText>{' '}
<MqText bold inline font={'mono'} color={theme.palette.common.white}>
{' '}
Jobs
{t('search.jobs')}
</MqText>{' '}
<MqText disabled inline>
{' '}
and
{t('search.and')}
</MqText>{' '}
<MqText bold inline font={'mono'} color={theme.palette.common.white}>
{' '}
Datasets
{t('search.datasets')}
</MqText>
</Box>
</Box>
Expand Down
1 change: 1 addition & 0 deletions web/src/for_i18n.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'i18next';
131 changes: 131 additions & 0 deletions web/src/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import i18n from 'i18next';
import { initReactI18next, useTranslation } from 'react-i18next';
// import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

i18n
// .use(Backend)
// detect user language
// learn more: https://github.com/i18next/i18next-browser-languageDetector
.use(LanguageDetector)
// pass the i18n instance to react-i18next.
.use(initReactI18next)
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
debug: true,
fallbackLng: 'en',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
resources: {
en: {
translation: {
// here we will place our translations...
header: {
docs_link: 'API Docs'
},
jobs: {
latest_tab: 'LATEST RUN',
history_tab: 'RUN HISTORY',
location: 'LOCATION',
empty_title: 'No Run Information Available',
empty_body: 'Try adding some runs for this job.',
runinfo_subhead: 'FACETS',
runs_subhead: 'FACETS'
},
search: {
search: 'Search',
jobs: 'Jobs',
and: 'and',
datasets: 'Datasets'
},
lineage: {
empty_title: 'No node selected',
empty_body: 'Try selecting a node through search or the jobs or datasets page.'
}
}
},
fr: {
translation: {
header: {
docs_link: 'API Docs'
},
jobs: {
latest_tab: 'DERNIÈRE COURSE',
history_tab: "HISTORIQUE D'EXECUTION",
location: 'EMPLACEMENT',
empty_title: 'Pas de Course les Informations Disponibles',
empty_body: "Essayez d'ajouter quelques exécutions pour ce travail.",
runinfo_subhead: 'FACETTES',
runs_subhead: 'FACETTES',
},
search: {
search: 'Recherche',
jobs: "d'Emplois",
and: 'et',
datasets: "d'Ensembles de Données"
},
lineage: {
empty_title: 'Aucun nœud sélectionné',
empty_body: 'Essayez de sélectionner un nœud via la recherche ou la page des travaux ou des ensembles de données.'
}
}
},
es: {
translation: {
header: {
docs_link: 'API Docs'
},
jobs: {
latest_tab: 'ÚLTIMA EJECUCIÓN',
history_tab: 'HISTORIAL DE EJECUCIONES',
location: 'UBICACIÓN',
empty_title: 'No hay Información de Ejecución Disponible',
empty_body: 'Intente agregar algunas ejecuciones para este trabajo.',
runinfo_subhead: 'FACETAS',
runs_subhead: 'FACETAS'
},
search: {
search: 'Buscar',
jobs: 'Trabajos',
and: 'y',
datasets: 'Conjuntos de Datos'
},
lineage: {
empty_title: 'Ningún nodo seleccionado',
empty_body: 'Intente seleccionar un nodo mediante la búsqueda o la página de trabajos o conjuntos de datos.'
}
}
},
pl: {
translation: {
header: {
docs_link: 'API Dokumenty'
},
jobs: {
latest_tab: 'OSTATNI BIEG',
history_tab: 'BIEGAĆ HISTORIA',
location: 'LOKALIZACJA',
empty_title: 'Brak dostępnych informacji o przebiegu',
empty_body: 'Spróbuj dodać kilka przebiegów dla tego zadania.',
runinfo_subhead: 'ASPECTY',
runs_subhead: 'ASPECTY'
},
search: {
search: 'Wyszukaj Oferty',
jobs: 'Pracy',
and: 'i',
datasets: 'Zestawy Danych'
},
lineage: {
empty_title: 'Nie wybrano węzła',
empty_body: 'Spróbuj wybrać węzeł za pomocą wyszukiwania lub strony zadań lub zestawów danych.'
}
}
}

}
});

export default i18n;
3 changes: 3 additions & 0 deletions web/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ import App from './components/App'
// fonts
import './index.css'

// i18n
import './i18n.js';

ReactDOM.render(<App />, document.getElementById('root'))
2 changes: 1 addition & 1 deletion web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"noImplicitAny": false,
"noImplicitThis": true,
"strictNullChecks": true,
"module": "commonjs",
Expand Down

0 comments on commit 3745a7e

Please sign in to comment.