Skip to content

Commit bae3d38

Browse files
authored
Merge pull request #6 from sharedferret/localization
Localization
2 parents 80ae54e + 17588e0 commit bae3d38

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2811
-889
lines changed

package-lock.json

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lynn",
3-
"version": "26.0.0",
3+
"version": "27.0.0",
44
"private": true,
55
"dependencies": {
66
"@date-io/dayjs": "^2.16.0",
@@ -14,6 +14,8 @@
1414
"dayjs": "^1.11.7",
1515
"eorzea-time": "^3.0.0",
1616
"i18next": "^25.2.1",
17+
"i18next-browser-languagedetector": "^8.2.0",
18+
"i18next-resources-to-backend": "^1.2.1",
1719
"leaflet": "^1.9.4",
1820
"leaflet-draw": "^1.0.4",
1921
"lynn-eorzea-weather": "^3.3.0",
30.8 KB
Loading
File renamed without changes.

src/App.jsx

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import './App.css';
22
import { Helmet } from 'react-helmet';
33
import React, { useEffect } from 'react';
4+
import { I18nextProvider } from 'react-i18next';
45

56
import createTheme from '@mui/material/styles/createTheme';
67
import ThemeProvider from '@mui/material/styles/ThemeProvider';
@@ -10,6 +11,8 @@ import {
1011
useParams,
1112
} from 'react-router-dom';
1213

14+
import i18n from './i18n';
15+
1316
import MainPageComponent from './MainPageComponent';
1417
import ForecastMainComponent from './forecast/ForecastMainComponent';
1518
import BAMainComponent from './ba/BAMainComponent';
@@ -375,23 +378,22 @@ function App() {
375378
});
376379

377380
return (
378-
<ColorModeContext.Provider value={colorMode}>
379-
<ThemeProvider theme={theme}>
380-
<Helmet>
381-
<title>FFXIV Field Operations Assistant - forays.info</title>
382-
<meta name="description" content="A collection of tools for Final Fantasy XIV side content created by Lynn Kaneko @ Exodus" />
383-
<meta property="og:title" content="forays.info" />
384-
<meta property="og:url" content="https://forays.info/" />
385-
<meta property="og:image" content="https://forays.info/logo.png" />
386-
<meta property="og:description" content="A collection of tools for Final Fantasy XIV side content created by Lynn Kaneko @ Exodus" />
387-
<meta property="og:site_name" content="forays.info" />
388-
<meta name="twitter:card" content="summary" />
389-
<meta name="twitter:creator" content="@reflexyui" />
390-
</Helmet>
391-
<RouterProvider router={router} />
392-
</ThemeProvider>
393-
</ColorModeContext.Provider>
394-
381+
<I18nextProvider i18n={i18n}>
382+
<ColorModeContext.Provider value={colorMode}>
383+
<ThemeProvider theme={theme}>
384+
<Helmet>
385+
<title>FFXIV Field Operations Assistant - forays.info</title>
386+
<meta name="description" content="A collection of tools for Final Fantasy XIV side content created by Lynn Kaneko @ Exodus" />
387+
<meta property="og:title" content="forays.info" />
388+
<meta property="og:url" content="https://forays.info/" />
389+
<meta property="og:image" content="https://forays.info/logo.png" />
390+
<meta property="og:description" content="A collection of tools for Final Fantasy XIV side content created by Lynn Kaneko @ Exodus" />
391+
<meta property="og:site_name" content="forays.info" />
392+
</Helmet>
393+
<RouterProvider router={router} />
394+
</ThemeProvider>
395+
</ColorModeContext.Provider>
396+
</I18nextProvider>
395397
);
396398
}
397399

src/FooterComponent.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import SvgIcon from '@mui/material/SvgIcon';
77
import Typography from '@mui/material/Typography';
88
import GitHubIcon from '@mui/icons-material/GitHub';
99
import { useNavigate } from 'react-router-dom';
10+
import { useTranslation } from 'react-i18next';
1011

1112
export default function FooterComponent({ includePadding = true }) {
1213
const navigate = useNavigate();
14+
const { t } = useTranslation('common');
15+
1316
return (
1417
<Box width="100%">
1518
<Stack
@@ -21,9 +24,7 @@ export default function FooterComponent({ includePadding = true }) {
2124
alignItems="center"
2225
>
2326
<Typography variant="subtitle2" fontSize={12} maxWidth={600} textAlign="left">
24-
FINAL FANTASY XIV © 2010 - 2025 SQUARE ENIX CO., LTD. FINAL FANTASY, FINAL FANTASY
25-
XIV, and FFXIV are registered trademarks or trademarks of Square Enix Holdings Co.,
26-
Ltd. All material used under license.
27+
{t('footer.copyright')}
2728
</Typography>
2829
<Box flexGrow={1} />
2930
<Stack direction="row">
@@ -72,7 +73,7 @@ export default function FooterComponent({ includePadding = true }) {
7273
}}
7374
>
7475
<Typography variant="subtitle2" fontSize={12} pl={1} pr={1}>
75-
{`Version ${process.env.REACT_APP_VERSION}`}
76+
{t('footer.version', { ver: process.env.REACT_APP_VERSION })}
7677
</Typography>
7778
</Button>
7879
</Stack>

src/MainPageComponent.jsx

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import Paper from '@mui/material/Paper';
44
import Stack from '@mui/material/Stack';
55
import Typography from '@mui/material/Typography';
66
import { Helmet } from 'react-helmet';
7+
import { useTranslation, Trans } from 'react-i18next';
78

89
export default function MainPageComponent() {
10+
const { t } = useTranslation('common');
11+
912
function getSiteName() {
1013
const host = window.location.hostname;
1114

@@ -84,46 +87,44 @@ export default function MainPageComponent() {
8487
<Paper elevation={3}>
8588
<Stack p={5} spacing={2}>
8689
<Typography textAlign="left" fontSize={textSize}>
87-
Welcome to
88-
{' '}
89-
{getSiteName()}
90-
, a home for tools to help with Final Fantasy XIV side
91-
content - including the Occult Crescent (Forked Tower), Eureka (The Baldesion
92-
Arsenal), and Bozja (Delubrum Reginae Savage). Find out how to build and gather
93-
materials for Lost Actions and Logos Actions, what to bring for The Baldesion
94-
Arsenal or Delubrum Reginae Savage runs, when the next Cassie or Crab spawn is,
95-
and more!
90+
<Trans i18nKey="main.intro.p1" ns="common" values={{ sitename: getSiteName() }} />
9691
</Typography>
9792
<Typography textAlign="left" fontSize={textSize}>
98-
Looking for a group to run Forked Tower, BA, or DRS with? Most of the content on this site
99-
was designed for runs on
100-
{' '}
101-
<a
102-
href="https://discord.gg/thehelplines"
103-
target="_blank"
104-
rel="noreferrer"
105-
>
106-
The Help Lines
107-
108-
</a>
109-
{' '}
110-
on Primal.
93+
<Trans
94+
i18nKey="main.intro.p2"
95+
ns="common"
96+
components={[
97+
<a
98+
href="https://discord.gg/thehelplines"
99+
target="_blank"
100+
rel="noreferrer"
101+
>
102+
The Help Lines
103+
</a>,
104+
]}
105+
/>
111106
</Typography>
112107
<Typography textAlign="left" fontSize={textSize}>
113-
Built by Lynn Kaneko @ Exodus. Issues/suggestions? You can reach out to me
114-
on Discord (@lynnkaneko).
108+
<Trans i18nKey="main.intro.p3" ns="common" />
115109
</Typography>
116110
<Typography textAlign="left" fontSize={textSize}>
117-
Home page artwork by
118-
{' '}
119-
<a
120-
href={pageTheme.imageCreditLink}
121-
target="_blank"
122-
rel="noreferrer"
123-
>
124-
{pageTheme.imageCredit}
125-
!
126-
</a>
111+
<Trans
112+
i18nKey="main.intro.p4"
113+
ns="common"
114+
components={[
115+
<a
116+
href={pageTheme.imageCreditLink}
117+
target="_blank"
118+
rel="noreferrer"
119+
>
120+
{pageTheme.imageCredit}
121+
!
122+
</a>,
123+
]}
124+
values={{
125+
artist: pageTheme.imageCredit,
126+
}}
127+
/>
127128
</Typography>
128129
</Stack>
129130
</Paper>
@@ -148,13 +149,11 @@ export default function MainPageComponent() {
148149
<meta name="twitter:card" content="summary" />
149150
<meta name="twitter:creator" content="@reflexyui" />
150151
<title>
151-
{getSiteName()}
152-
{' '}
153-
- FFXIV Field Operations Assistant
152+
{t('main.header.title', { sitename: getSiteName() })}
154153
</title>
155154
</Helmet>
156155
<Box>
157-
<Typography variant="h3" fontWeight={700}>FFXIV Field Operations Assistant</Typography>
156+
<Typography variant="h3" fontWeight={700}><Trans i18nKey="main.title" ns="common" /></Typography>
158157
</Box>
159158
<Box pl={5} sx={{ display: { xs: 'none', md: 'block' } }}>
160159
<Stack direction="row">

src/SettingsPopoverComponent.jsx

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useCallback } from 'react';
2+
import { useTranslation } from 'react-i18next';
23

34
import Box from '@mui/material/Box';
45
import Button from '@mui/material/Button';
@@ -8,16 +9,36 @@ import DialogContent from '@mui/material/DialogContent';
89
import DialogContentText from '@mui/material/DialogContentText';
910
import DialogTitle from '@mui/material/DialogTitle';
1011
import Stack from '@mui/material/Stack';
11-
import ToggleButton from '@mui/material/ToggleButton';
12-
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
1312
import Typography from '@mui/material/Typography';
1413

1514
import SettingsApplicationsIcon from '@mui/icons-material/SettingsApplications';
15+
import {
16+
FormControlLabel, Radio, RadioGroup,
17+
} from '@mui/material';
18+
import { changeLanguage } from './i18n';
1619
import UniversalisRegionPicker from './UniversalisRegionPicker';
1720

1821
export default function SettingsPopoverComponent({ setColorMode }) {
22+
const { t } = useTranslation('common');
1923
const [open, setOpen] = React.useState(false);
2024

25+
/**
26+
const getFlag = () => {
27+
const language = localStorage.getItem('i18nextLng').substring(0, 2);
28+
29+
switch (language) {
30+
case 'fr':
31+
return '🇫🇷';
32+
case 'de':
33+
return '🇩🇪';
34+
case 'jp':
35+
return '🇯🇵';
36+
default:
37+
return '🇨🇦';
38+
}
39+
};
40+
*/
41+
2142
const handleSettingsButtonClick = () => {
2243
setOpen(true);
2344
};
@@ -38,13 +59,15 @@ export default function SettingsPopoverComponent({ setColorMode }) {
3859
onClick={(e) => handleSettingsButtonClick(e)}
3960
>
4061
<SettingsApplicationsIcon sx={{ color: 'white' }} />
62+
{ /* <Typography fontWeight={600} fontSize={16}>{getFlag()}</Typography> */ }
4163
<Box>
42-
<Typography color="#fff" fontWeight={600} fontSize={16}>Settings</Typography>
64+
<Typography color="#fff" fontWeight={600} fontSize={16}>{t('settings.title')}</Typography>
4365
</Box>
4466
</Stack>
4567
);
4668

4769
const [theme, setTheme] = React.useState(localStorage.getItem('theme'));
70+
const [language, setLanguage] = React.useState(localStorage.getItem('language') || 'en');
4871

4972
const handleThemeChange = useCallback((event, newTheme) => {
5073
if (newTheme) {
@@ -54,40 +77,55 @@ export default function SettingsPopoverComponent({ setColorMode }) {
5477
}
5578
}, [localStorage, setTheme]);
5679

80+
const handleLanguageChange = useCallback((event, newLanguage) => {
81+
if (newLanguage) {
82+
setLanguage(newLanguage);
83+
changeLanguage(newLanguage);
84+
}
85+
}, [setLanguage, changeLanguage]);
86+
5787
return (
5888
<>
5989
<Box flexGrow={1}>
6090
{settingsButton}
6191
</Box>
6292
<Dialog open={open} onClose={handleClose}>
63-
<DialogTitle>Settings</DialogTitle>
93+
<DialogTitle>{t('settings.title')}</DialogTitle>
6494
<DialogContent>
65-
<DialogContentText>Site Theme</DialogContentText>
66-
<ToggleButtonGroup
95+
<DialogContentText>{t('settings.theme_title')}</DialogContentText>
96+
<RadioGroup
97+
row
6798
value={theme}
6899
exclusive
69100
onChange={handleThemeChange}
70101
>
71-
<ToggleButton value="light">
72-
Light
73-
</ToggleButton>
74-
<ToggleButton value="dark">
75-
Dark
76-
</ToggleButton>
77-
<ToggleButton value="system">
78-
System
79-
</ToggleButton>
80-
</ToggleButtonGroup>
81-
<DialogContentText pt={2}>Universalis Region</DialogContentText>
102+
<FormControlLabel value="light" control={<Radio />} label={t('settings.themes.light')} />
103+
<FormControlLabel value="dark" control={<Radio />} label={t('settings.themes.dark')} />
104+
<FormControlLabel value="system" control={<Radio />} label={t('settings.themes.system')} />
105+
</RadioGroup>
106+
107+
<DialogContentText pt={2}>{t('settings.language_title')}</DialogContentText>
108+
109+
<RadioGroup
110+
row
111+
value={language}
112+
onChange={handleLanguageChange}
113+
>
114+
<FormControlLabel value="en" control={<Radio />} label="🇨🇦 English" />
115+
<FormControlLabel value="fr" control={<Radio />} disabled label="🇫🇷 Français" />
116+
<FormControlLabel value="de" control={<Radio />} label="🇩🇪 Deutsch" />
117+
<FormControlLabel value="jp" control={<Radio />} disabled label="🇯🇵 日本語" />
118+
</RadioGroup>
119+
120+
<DialogContentText pt={2}>{t('settings.universalis_region_title')}</DialogContentText>
82121
<UniversalisRegionPicker />
83122
</DialogContent>
84123
<DialogActions>
85124
<Button onClick={handleClose}>
86-
Close
125+
{t('common.close')}
87126
</Button>
88127
</DialogActions>
89128
</Dialog>
90129
</>
91-
92130
);
93131
}

0 commit comments

Comments
 (0)