Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set up internationalization of the front end with i18next (fixed diff on Github) #675

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ee0fb51
Install i18n and react-i18n
guergana Dec 1, 2024
3776f7d
Run npm upgrade
guergana Dec 1, 2024
923b8db
Basic setup and example
guergana Dec 1, 2024
b85e5b5
Update case for button
guergana Dec 1, 2024
414b669
Uncomment test to see if it works on CI
guergana Dec 1, 2024
8e8d6a4
Add external translation files
guergana Dec 1, 2024
985c95b
Add translations for WelcomeBanner
guergana Dec 1, 2024
712f613
Install packages to manage electron main renderer translations
guergana Dec 1, 2024
db31afa
Organize files
guergana Dec 1, 2024
ae7fd70
Capitalize text to pass e2e tests
guergana Dec 1, 2024
10586f5
Organize files
guergana Dec 2, 2024
6ae5c82
Translate main application layouts
guergana Dec 2, 2024
5a7b1ef
Add translations to all dialogs
guergana Dec 2, 2024
a92b34a
Add dom.iteratable to fix TS error
guergana Dec 2, 2024
7442587
Install i18n and react-i18n
guergana Dec 1, 2024
1dff552
Run npm upgrade
guergana Dec 1, 2024
301fba7
Basic setup and example
guergana Dec 1, 2024
2ccb821
Update case for button
guergana Dec 1, 2024
e8b1ee3
Uncomment test to see if it works on CI
guergana Dec 1, 2024
c631d1f
Add external translation files
guergana Dec 1, 2024
c2370d7
Add translations for WelcomeBanner
guergana Dec 1, 2024
3b0d5fe
Install packages to manage electron main renderer translations
guergana Dec 1, 2024
ae65111
Organize files
guergana Dec 1, 2024
923ec22
Capitalize text to pass e2e tests
guergana Dec 1, 2024
3740d96
Organize files
guergana Dec 2, 2024
f6fc213
Translate main application layouts
guergana Dec 2, 2024
3aabf01
Add translations to all dialogs
guergana Dec 2, 2024
cdfc3bd
Add dom.iteratable to fix TS error
guergana Dec 2, 2024
2becbc2
Fix merge and translate new dialogs
guergana Dec 2, 2024
00bfd3e
Merge branch '355-i18n-breakdown' of https://github.com/okfn/opendata…
guergana Dec 2, 2024
586fde3
Translate files for context menu, tabular data menu and missing
guergana Dec 2, 2024
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
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 @@ -13,6 +13,7 @@ import File from '../Controllers/File'
import Table from '../Controllers/Table'
import Text from '../Controllers/Text'
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 @@ -34,16 +35,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 @@ -71,6 +73,7 @@ function FileContent() {
}

function EmptyContent() {
const { t } = useTranslation()
return (
<StyledCard>
<StyledCardContent>
Expand All @@ -85,7 +88,7 @@ function EmptyContent() {
paddingBottom: '8px',
}}
>
The ODE supports Excel & csv files
{t('ODE-supports-CSV-Excel-files')}
</Typography>
<Button
sx={{
Expand All @@ -101,7 +104,7 @@ function EmptyContent() {
aria-label="accept"
onClick={() => store.openDialog('fileUpload')}
>
Upload your data
{t('upload-your-data')}
</Button>
<Typography
sx={{
Expand All @@ -111,15 +114,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
6 changes: 3 additions & 3 deletions client/components/Application/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import * as store from '@client/store'
import { AssistantDialog } from './Dialogs/Assistant'
import CloseWithUnsavedChangesDialog from './Dialogs/CloseWithUnsavedChanges'
import ConfigDialog from './Dialogs/Config'
import { CreateFolderDialog } from './Dialogs/CreateFolder'
import { CreateFolderDialog } from './Dialogs/CreateFolder/index'
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
Loading