Skip to content

Commit

Permalink
Set up internationalization of the front end with i18next (#662)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: roll <[email protected]>
  • Loading branch information
guergana and roll authored Dec 3, 2024
1 parent 1073780 commit 426ba61
Show file tree
Hide file tree
Showing 29 changed files with 368 additions and 292 deletions.
14 changes: 9 additions & 5 deletions client/components/Application/Browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FileTree from '../Parts/Trees/File'
import Button from '@mui/material/Button'
import * as store from '@client/store'
import createFolderIcon from '../../assets/create_folder_icon.svg'
import { useTranslation, Trans } from 'react-i18next'

export default function Browser() {
const files = store.useStore((state) => state.files)
Expand All @@ -24,15 +25,17 @@ function DefaultBrowser() {
const files = store.useStore((state) => state.files)
const event = store.useStore((state) => state.event)

const { t } = useTranslation()

return (
<ErrorBoundary
fallback={
<Box sx={{ color: '#555' }}>
<strong>Failed to open the project</strong>. Please{' '}
<Trans i18nKey="failed-open-project" components={{ 1: <strong /> }} />{' '}
<a href="https://github.com/okfn/opendataeditor/issues" target="_blank">
create an issue
{t('create-an-issue')}
</a>{' '}
sharing the project details <small>(if possible)</small>
<Trans i18nKey="sharing-contents-if-possible" components={{ 1: <small /> }} />
</Box>
}
>
Expand All @@ -42,7 +45,7 @@ function DefaultBrowser() {
startIcon={<img src={createFolderIcon} alt="" />}
onClick={() => store.openDialog('addEmptyFolder')}
>
Create folder
{t('create-folder')}
</Button>
<FileTree
files={files}
Expand All @@ -59,5 +62,6 @@ function EmptyBrowser() {
}

function LoadingBrowser() {
return <SpinnerCard message="Loading" />
const { t } = useTranslation()
return <SpinnerCard message={t('loading')} />
}
18 changes: 11 additions & 7 deletions client/components/Application/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import emptyContentScreenImg from '../../assets/empty_screen.png'
import File from '../Controllers/File'
import Table from '../Controllers/Table'
import SpinnerCard from '../Parts/Cards/Spinner'
import { useTranslation, Trans } from 'react-i18next'

export default function Content() {
const record = store.useStore((state) => state.record)
Expand All @@ -33,16 +34,17 @@ function FileContent() {
if (!record) return null

const Controller = CONTROLLERS[record.type] || File
const { t } = useTranslation()

return (
<ErrorBoundary
fallback={
<Box sx={{ padding: 2.5, color: '#555' }}>
<strong>Failed to open the file</strong>. Please{' '}
<Trans i18nKey="failed-open-project" components={{ 1: <strong /> }} />{' '}
<a href="https://github.com/okfn/opendataeditor/issues" target="_blank">
create an issue
{t('create-an-issue')}
</a>{' '}
sharing the file contents <small>(if possible)</small>
<Trans i18nKey="sharing-contents-if-possible" components={{ 1: <small /> }} />
</Box>
}
>
Expand Down Expand Up @@ -70,6 +72,7 @@ function FileContent() {
}

function EmptyContent() {
const { t } = useTranslation()
return (
<StyledCard>
<StyledCardContent>
Expand All @@ -84,7 +87,7 @@ function EmptyContent() {
paddingBottom: '8px',
}}
>
The ODE supports Excel & csv files
{t('ODE-supports-CSV-Excel-files')}
</Typography>
<Button
sx={{
Expand All @@ -100,7 +103,7 @@ function EmptyContent() {
aria-label="accept"
onClick={() => store.openDialog('fileUpload')}
>
Upload your data
{t('upload-your-data')}
</Button>
<Typography
sx={{
Expand All @@ -110,15 +113,16 @@ function EmptyContent() {
fontSize: '12px',
}}
>
You can also add links to online tables
{t('links-online-tables')}
</Typography>
</StyledCardContent>
</StyledCard>
)
}

function LoadingContent() {
return <SpinnerCard message="Loading" />
const { t } = useTranslation()
return <SpinnerCard message={t('loading')} />
}

// We still need to cover here and in the settings "chart" type and some other types
Expand Down
4 changes: 2 additions & 2 deletions client/components/Application/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { CreateFolderDialog } from './Dialogs/CreateFolder'
import { DeleteFileDialog } from './Dialogs/DeleteFile'
import OpenLocationDialog from './Dialogs/OpenLocation'
import PublishDialog from './Dialogs/Publish'
import { RenameFileDialog } from './Dialogs/RenameFile'
import { SaveChangesDialog } from './Dialogs/SaveChanges'
import { RenameFileDialog } from './Dialogs/RenameFile/index'
import { SaveChangesDialog } from './Dialogs/SaveChanges/index'
import UnsavedChangesDialog from './Dialogs/UnsavedChanges'
import { UploadFileDialog } from './Dialogs/UploadFile'
import WelcomeBannerDialog from './Dialogs/WelcomeBanner'
Expand Down
32 changes: 18 additions & 14 deletions client/components/Application/Dialogs/Assistant/Assistant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as React from 'react'
import { PropsWithChildren } from 'react'
import Markdown from 'react-markdown'
import * as store from './store'
import { useTranslation } from 'react-i18next'

const DEFAULT_PROMPT = `
suggest improvements to the names of the columns in the table
Expand Down Expand Up @@ -37,37 +38,37 @@ export function AssistantDialog() {
}

function TermsStepDialog() {
const { t } = useTranslation()
return (
<StepDialog
label="Confirm"
cancelLabel="Cancel"
label={t('confirm')}
cancelLabel={t('cancel')}
transitionDuration={{ exit: 0 }}
onConfirm={store.acceptTerms}
>
If you proceed, the Open Data Editor will only share the names of the columns in
your table to suggest improvements to the titles and descriptions associated with
them. Do you want to proceed?
{t('assistant-step-dialog')}
</StepDialog>
)
}

function CredsStepDialog() {
const [key, setKey] = React.useState('')
const { t } = useTranslation()

return (
<StepDialog
label="Confirm"
cancelLabel="Cancel"
label={t('confirm')}
cancelLabel={t('cancel')}
confirmDisabled={!key}
transitionDuration={0}
onConfirm={() => store.setApiKey({ key })}
>
<Stack spacing={1}>
<Box>Please enter your OpenAI API key:</Box>
<Box>{t('enter-openAI-key')}</Box>
<StyledTextField
fullWidth
autoFocus
label="OpenAI API Key"
label={t('open-AI-key')}
variant="outlined"
value={key}
inputProps={{ spellCheck: false }}
Expand Down Expand Up @@ -96,17 +97,18 @@ function CredsStepDialog() {

function PromptStepDialog() {
const [prompt, setPrompt] = React.useState(DEFAULT_PROMPT)
const { t } = useTranslation()

return (
<StepDialog
label="Confirm"
cancelLabel="Cancel"
label={t('confirm')}
cancelLabel={t('cancel')}
confirmDisabled={!prompt}
transitionDuration={0}
onConfirm={() => store.setPromptAndFetchResult({ prompt })}
>
<Stack spacing={1}>
<Box>Please enter your prompt to the AI assistant:</Box>
<Box>{t('AI-assistant-enter-prompt')}</Box>
<StyledTextField
autoFocus
value={prompt}
Expand All @@ -124,10 +126,11 @@ function PromptStepDialog() {

function ResultStepDialog() {
const state = store.useState()
const { t } = useTranslation()

return (
<StepDialog
label="OK"
label={t('ok')}
disabled={state.progress?.blocking}
transitionDuration={{ enter: 0 }}
onConfirm={store.closeDialog}
Expand All @@ -148,11 +151,12 @@ function StepDialog(
transitionDuration?: number | { enter?: number; exit?: number }
}>
) {
const { t } = useTranslation()
return (
<TwoButtonDialog
open={true}
maxWidth="md"
title="AI Assistant"
title={t('AI-assistant')}
Icon={AutoFixHighIcon}
label={props.label}
disabled={props.disabled}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import DangerousIcon from '@mui/icons-material/Dangerous'
import TwoButtonDialog from '../../Parts/Dialogs/TwoButton'
import * as store from '@client/store'
import { useTranslation } from 'react-i18next'

export default function CloseWithUnsavedChangesDialog() {
const onSave = async () => {
Expand All @@ -13,14 +14,16 @@ export default function CloseWithUnsavedChangesDialog() {
store.closeDesktopApp()
}

const { t } = useTranslation()

return (
<TwoButtonDialog
open={true}
title="Unsaved Changes"
cancelLabel="Discard"
label="Save"
title={t('unsaved-changes')}
cancelLabel={t('discard')}
label={t('save')}
Icon={DangerousIcon}
description="There are unsaved changes. Please, click save or cancel."
description={t('unsaved-changes-dialog-description')}
onCancel={onDiscard}
onConfirm={onSave}
disableClosing={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { LinearProgress } from '@client/components/Progress'
import * as appStore from '@client/store'
import * as React from 'react'
import * as store from './store'
import { useTranslation } from 'react-i18next'

export function CreateFolderDialog() {
const folderPath = appStore.useStore(appStore.getFolderPath)
Expand All @@ -13,13 +14,15 @@ export function CreateFolderDialog() {
store.resetState()
}, [dialog])

const { t } = useTranslation()

return (
<InputDialog
open={true}
value={folderPath}
title="Create new folder"
label="Create"
placholder="Name of the new folder"
title={t('create-new-folder')}
label={t('create')}
placholder={t('name-new-folder')}
onCancel={store.closeDialog}
onConfirm={store.createFolder}
>
Expand Down
13 changes: 8 additions & 5 deletions client/components/Application/Dialogs/DeleteFile/DeleteFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@ import { LinearProgress } from '@client/components/Progress'
import * as appStore from '@client/store'
import * as React from 'react'
import * as store from './store'
import { useTranslation } from 'react-i18next'

export function DeleteFileDialog() {
const isFolder = appStore.useStore(appStore.getIsFolder)
const dialog = appStore.useStore((state) => state.dialog)
const { progress } = store.useState()

const { t } = useTranslation()
const fileOrFolder = isFolder ? t('folder') : t('file')

React.useEffect(() => {
store.resetState()
}, [dialog])

const title = isFolder ? 'Delete Folder' : 'Delete File'
const description = !progress
? `Are you sure you want to delete this ${isFolder ? 'folder' : 'file'}?`
? t('are-you-sure-delete-filefolder', { fileOrFolder })
: undefined

return (
<TwoButtonDialog
open={true}
title={title}
title={t('delete-fileFolder', { fileOrFolder })}
description={description}
label="Delete"
label={t('delete')}
hoverBgButtonColor="OKFNRed600"
cancelLabel="No"
cancelLabel={t('no')}
onCancel={store.closeDialog}
onConfirm={store.deleteFile}
>
Expand Down
Loading

0 comments on commit 426ba61

Please sign in to comment.