From 5822198f92495788ed9312cfecf4f788d407f729 Mon Sep 17 00:00:00 2001 From: evlist Date: Sat, 8 Oct 2022 17:33:32 +0200 Subject: [PATCH] Localization (and language chooser)... --- src/components/map/GpxRecord.tsx | 9 +++- src/components/map/Settings.tsx | 43 ++++++++++++++++--- .../map/TileServerChooserDialog.tsx | 9 +++- src/components/map/TracksBrowser.tsx | 11 ++++- src/i18n/index.tsx | 29 ++++++++++++- src/store/settings.ts | 2 + 6 files changed, 93 insertions(+), 10 deletions(-) diff --git a/src/components/map/GpxRecord.tsx b/src/components/map/GpxRecord.tsx index dd2701b..e821355 100644 --- a/src/components/map/GpxRecord.tsx +++ b/src/components/map/GpxRecord.tsx @@ -29,7 +29,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { mapActions } from '../../store/map'; import { SettingsState } from '../../store/settings'; -import i18n from '../../i18n/index'; +import i18n, { setI18nLanguage } from '../../i18n/index'; declare global { @@ -37,6 +37,13 @@ declare global { } const GpxRecord: React.FC<{}> = () => { + + const language = useSelector( + (state: { settings: SettingsState }) => state.settings.language + ); + + setI18nLanguage(language); + const db = useDB(); const [isRecording, setIsRecording] = useState(false); diff --git a/src/components/map/Settings.tsx b/src/components/map/Settings.tsx index 3cd86dc..c7c4504 100644 --- a/src/components/map/Settings.tsx +++ b/src/components/map/Settings.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useEffect, useRef } from 'react'; +import React, { Fragment, useEffect, useRef, useState } from 'react'; import { useDB } from 'react-pouchdb'; @@ -13,6 +13,8 @@ import { IonList, IonListHeader, IonModal, + IonSelect, + IonSelectOption, IonTitle, IonToolbar, } from '@ionic/react'; @@ -22,7 +24,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { settingsActions, SettingsState } from '../../store/settings'; import uri from '../../lib/ids'; import _ from 'lodash'; -import i18n from '../../i18n/index'; +import i18n, { setI18nLanguage } from '../../i18n/index'; const Settings: React.FC<{}> = () => { const dispatch = useDispatch(); @@ -66,18 +68,18 @@ const Settings: React.FC<{}> = () => { }; settingsFromRedux(); } + setLocalLanguage(settingsState.language); }, [db, settingsState]); + const [localLanguage, setLocalLanguage] = useState(settingsState.language); + + const languageSelect = useRef(null); const pseudo = useRef(null); const minTimeInterval = useRef(null); const minDistance = useRef(null); const modal = useRef(null); - const dismiss = () => { - modal.current?.dismiss(); - }; - const save = () => { dispatch( settingsActions.saveSettings({ @@ -88,11 +90,19 @@ const Settings: React.FC<{}> = () => { minTimeInterval: minTimeInterval.current?.value, minDistance: minDistance.current?.value, }, + language: languageSelect.current?.value, }) ); dismiss(); }; + setI18nLanguage(localLanguage); + + const dismiss = () => { + modal.current?.dismiss(); + setLocalLanguage(settingsState.language); + }; + return ( @@ -112,6 +122,27 @@ const Settings: React.FC<{}> = () => { + + + {i18n.language} + + + {i18n.colonize(i18n.language)} + setLocalLanguage(ev.detail.value)} + > + {i18n.languageSelect.choices.map((choice) => ( + + {choice.label} + + ))} + + + {i18n.user} diff --git a/src/components/map/TileServerChooserDialog.tsx b/src/components/map/TileServerChooserDialog.tsx index 976b5cd..e1248a1 100644 --- a/src/components/map/TileServerChooserDialog.tsx +++ b/src/components/map/TileServerChooserDialog.tsx @@ -16,13 +16,20 @@ import { useDispatch, useSelector } from 'react-redux'; import { enterAnimation, leaveAnimation } from '../../lib/animation'; import { mapActions, MapState } from '../../store/map'; import { tileProviders } from './tile'; -import i18n from '../../i18n/index'; +import i18n, { setI18nLanguage } from '../../i18n/index'; +import { SettingsState } from '../../store/settings'; const TileServerChooserDialog: React.FC<{}> = () => { const tileProvider = useSelector( (state: { map: MapState }) => state.map.scope.tileProvider ) as keyof typeof tileProviders; + const language = useSelector( + (state: { settings: SettingsState }) => state.settings.language + ); + + setI18nLanguage(language); + const dispatch = useDispatch(); const modal = useRef(null); diff --git a/src/components/map/TracksBrowser.tsx b/src/components/map/TracksBrowser.tsx index 4a46870..bd2b7a1 100644 --- a/src/components/map/TracksBrowser.tsx +++ b/src/components/map/TracksBrowser.tsx @@ -21,7 +21,9 @@ import { enterAnimation, leaveAnimation } from '../../lib/animation'; import phoneRoute from '../../theme/icons/font-gis/svg/routing/uEB08-phone-route-nons.svg'; import GpxImport from './gpx-import'; import GpxExport from './GpxExport'; -import i18n from '../../i18n/index'; +import i18n, { setI18nLanguage } from '../../i18n/index'; +import { useSelector } from 'react-redux'; +import { SettingsState } from '../../store/settings'; const TrackBrowser: React.FC<{}> = () => { const gpxes = useFind({ @@ -38,6 +40,13 @@ const TrackBrowser: React.FC<{}> = () => { modal.current?.dismiss(); }; + const language = useSelector( + (state: { settings: SettingsState }) => state.settings.language + ); + + setI18nLanguage(language); + + return ( diff --git a/src/i18n/index.tsx b/src/i18n/index.tsx index fd445ba..d5b9441 100644 --- a/src/i18n/index.tsx +++ b/src/i18n/index.tsx @@ -1,4 +1,3 @@ -import { Fragment } from 'react'; import LocalizedStrings from 'react-localization'; const strings = new LocalizedStrings({ @@ -9,6 +8,7 @@ const strings = new LocalizedStrings({ cancel: 'Cancel', close: 'Close', settings: 'Settings', + language: 'Language', user: 'User', pseudo: 'Pseudo', geolocation: 'Geolocation', @@ -38,6 +38,15 @@ const strings = new LocalizedStrings({ chooseYourMap: 'Choose your map', + languageSelect: { + placeHolder: 'Select your language', + choices: [ + { value: 'auto', label: 'Automatic' }, + { value: 'en', label: 'English' }, + { value: 'fr', label: 'Français' }, + ], + }, + tracks: 'Tracks', }, fr: { @@ -47,6 +56,7 @@ const strings = new LocalizedStrings({ cancel: 'Annuler', close: 'Fermer', settings: 'Paramètres', + language: 'Langue', user: 'Utilisateur', pseudo: 'Pseudo', geolocation: 'Géolocalisation', @@ -86,8 +96,25 @@ const strings = new LocalizedStrings({ chooseYourMap: 'Choisissez votre carte', + languageSelect: { + placeHolder: 'Selectionner votre langue', + choices: [ + { value: 'auto', label: 'Automatique' }, + { value: 'fr', label: 'Français' }, + { value: 'en', label: 'English' }, + ], + }, + tracks: 'Traces', }, }); export default strings; + +export const setI18nLanguage = (language: string) => { + if (language === undefined || language === 'auto') { + strings.setLanguage(strings.getInterfaceLanguage()); + } else { + strings.setLanguage(language); + } +}; diff --git a/src/store/settings.ts b/src/store/settings.ts index 3b17dba..20541e9 100644 --- a/src/store/settings.ts +++ b/src/store/settings.ts @@ -9,6 +9,7 @@ export interface SettingsState { minTimeInterval: number; minDistance: number; }; + language: 'auto' } export const initialSettingsState: SettingsState = { @@ -20,6 +21,7 @@ export const initialSettingsState: SettingsState = { minTimeInterval: 15000, minDistance: 10, }, + language: 'auto', }; const settingsSlice = createSlice({