Skip to content

Commit

Permalink
(#5 #14) Fixed web client ssr to stop throwing unmatched content erro…
Browse files Browse the repository at this point in the history
…rs on rehydration in the browser. and improved translation component code generally to be DRY (all possible locales are indicated in the graphql type system only now)
  • Loading branch information
zachsa committed Jul 12, 2022
1 parent e8d7aa0 commit 2a9e7b4
Show file tree
Hide file tree
Showing 9 changed files with 341 additions and 286 deletions.
1 change: 0 additions & 1 deletion web/chompfile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ ignore = [
'apollo-server-core',
'apollo-server-koa',
'koa-bodyparser',
'node-fetch',
'http-errors'
]

Expand Down
28 changes: 28 additions & 0 deletions web/client/modules/i18n/translate/form/_lazy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Translate from '..'
import DialogTitle from '@mui/material/DialogTitle'
import DialogContent from '@mui/material/DialogContent'
import DialogContentText from '@mui/material/DialogContentText'
import DialogActions from '@mui/material/DialogActions'
import Button from '@mui/material/Button'

export default ({ from }) => {
return (
<>
<DialogTitle>
<Translate contentId="Language translation" />
</DialogTitle>
<DialogContent dividers>
<DialogContentText gutterBottom>
<Translate contentId="suggest-translation" />:
</DialogContentText>
<DialogContentText gutterBottom>From: {from}</DialogContentText>
<DialogContentText gutterBottom>To: (TODO - this should be a text field)</DialogContentText>
</DialogContent>
<DialogActions>
<Button size="small" variant="contained">
TODO
</Button>
</DialogActions>
</>
)
}
28 changes: 7 additions & 21 deletions web/client/modules/i18n/translate/form/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,15 @@
import Translate from '..'
import { lazy, Suspense } from 'react'
import { Linear as Loading } from '../../../../components/loading'
import Dialog from '@mui/material/Dialog'
import DialogTitle from '@mui/material/DialogTitle'
import DialogContent from '@mui/material/DialogContent'
import DialogContentText from '@mui/material/DialogContentText'
import DialogActions from '@mui/material/DialogActions'
import Button from '@mui/material/Button'

const Form = lazy(() => import('./_lazy'))

export default ({ open, setOpen, from }) => {
return (
<Dialog onClose={() => setOpen(false)} open={open}>
<DialogTitle>
<Translate contentId="Language translation" />
</DialogTitle>
<DialogContent dividers>
<DialogContentText gutterBottom>
<Translate contentId="suggest-translation" />:
</DialogContentText>
<DialogContentText gutterBottom>From: {from}</DialogContentText>
<DialogContentText gutterBottom>To: (TODO - this should be a text field)</DialogContentText>
</DialogContent>
<DialogActions>
<Button size="small" variant="contained">
TODO
</Button>
</DialogActions>
<Suspense fallback={<Loading />}>
<Form from={from} />
</Suspense>
</Dialog>
)
}
76 changes: 37 additions & 39 deletions web/client/modules/i18n/translate/index.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,47 @@
import { useContext, useState } from 'react'
import { useContext, useState, useEffect, lazy, Suspense } from 'react'
import { ctx as i18nContext } from '../index'
import Box from '@mui/material/Box'
import { Translate } from '../../../components/icons'
import Form from './form'
import Icon from '@mui/material/Icon'
import Tooltip from '@mui/material/Tooltip'

const Form = lazy(() => import('./form'))

export default ({ contentId }) => {
const [open, setOpen] = useState(false)
const [isClient, setIsClient] = useState(false)
const { t, language } = useContext(i18nContext)
const { text, missing } = t(contentId, language)

if (missing) {
return (
<>
<Tooltip placement="top-end" title="Click to translate!">
<Box
onClick={() => setOpen(!open)}
sx={{
position: 'relative',
outline: theme => `thin dotted ${theme.palette.success.main}`,
cursor: 'pointer',
transition: theme => theme.transitions.create(['background-color']),
'&:hover': {
backgroundColor: theme => theme.palette.grey[100],
},
}}
>
<Icon
component={Translate}
sx={{
width: '0.65em',
height: '0.65em',
position: 'absolute',
right: 0,
top: 0,
}}
/>
{text}
</Box>
</Tooltip>
<Form from={text} open={open} setOpen={setOpen} />
</>
)
}
useEffect(() => {
setIsClient(true)
}, [])

return (
<>
<Box
component={'span'}
onClick={missing && isClient ? () => setOpen(!open) : () => null}
sx={
missing && isClient
? {
position: 'relative',
outline: theme => `thin dotted ${theme.palette.success.main}`,
cursor: 'pointer',
transition: theme => theme.transitions.create(['background-color']),
'&:hover': {
backgroundColor: theme => theme.palette.grey[100],
},
}
: {}
}
>
{text}
</Box>

return text
{/* CONTENT TRANSLATION */}
{missing && isClient && (
<Suspense fallback={null}>
<Form from={text} open={open} setOpen={setOpen} />
</Suspense>
)}
</>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,98 @@ import Tooltip from '@mui/material/Tooltip'
import { gql, useQuery } from '@apollo/client'
import Box from '@mui/material/Box'

const LANGUAGES = ['en']
const SelectLocale = ({ updateSetting, language, LANGUAGES }) => {
const { error, loading, data } = useQuery(
gql`
query locales($languages: [Language!]) {
locales(languages: $languages) {
id
... on Locale {
name
code
language
}
}
}
`,
{
variables: {
languages: LANGUAGES,
},
}
)

if (loading) {
return (
<Loading
sx={theme => ({
width: '100%',
mt: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
display: 'block',
width: 400,
},
})}
/>
)
}

const SelectLocale = memo(
({ updateSetting, language }) => {
if (error) {
throw error
}

return (
<Tooltip title="Select language" placement="left">
<ComboBox
getOptionLabel={option => option.name}
label="language"
autoHighlight
value={data.locales.find(option => option.language === language)}
onChange={(e, option) => updateSetting({ language: option.language })}
options={data.locales}
renderOption={(props, option) => (
<Box component="li" sx={{ '& > img': { mr: 2, flexShrink: 0 } }} {...props}>
<img
loading="lazy"
width="20"
src={`https://flagcdn.com/w20/${option.code.split('_')[1].toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${option.code.split('_')[1].toLowerCase()}.png 2x`}
alt=""
/>
{option.name}
</Box>
)}
/>
</Tooltip>
)
}

const Locales = memo(
props => {
const { error, loading, data } = useQuery(
gql`
query locales($languages: [Language!]) {
locales(languages: $languages) {
id
... on Locale {
query languageLocales($name: String!) {
__type(name: $name) {
enumValues {
name
code
language
}
}
}
`,
{
variables: {
languages: LANGUAGES,
name: 'Language',
},
}
)

if (loading) {
return (
<Loading
sx={theme => ({
sx={{
width: '100%',
mt: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
display: 'block',
width: 400,
},
})}
mt: theme => theme.spacing(2),
}}
/>
)
}
Expand All @@ -49,36 +106,13 @@ const SelectLocale = memo(
throw error
}

return (
<Tooltip title="Select language" placement="left">
<ComboBox
getOptionLabel={option => option.name}
label="language"
autoHighlight
value={data.locales.find(option => option.language === language)}
onChange={(e, option) => updateSetting({ language: option.language })}
options={data.locales}
renderOption={(props, option) => (
<Box component="li" sx={{ '& > img': { mr: 2, flexShrink: 0 } }} {...props}>
<img
loading="lazy"
width="20"
src={`https://flagcdn.com/w20/${option.code.split('_')[1].toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${option.code.split('_')[1].toLowerCase()}.png 2x`}
alt=""
/>
{option.name}
</Box>
)}
/>
</Tooltip>
)
return <SelectLocale LANGUAGES={data.__type.enumValues.map(({ name }) => name)} {...props} />
},
() => false
() => false // Needed for now - otherwise the dropdown has incorrect state
)

export default () => {
const { updateSetting, language } = useContext(siteSettingsContext)

return <SelectLocale updateSetting={updateSetting} language={language} />
return <Locales updateSetting={updateSetting} language={language} />
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@ const LanguageSettings = memo(

export default ({ forceLanguage }) => {
const { accepted } = useContext(siteSettingsContext)
return <LanguageSettings forceLanguage accepted={accepted} />
return <LanguageSettings forceLanguage={forceLanguage} accepted={accepted} />
}
Loading

0 comments on commit 2a9e7b4

Please sign in to comment.