Localization (and language chooser)...
This commit is contained in:
parent
653574025e
commit
5822198f92
|
@ -29,7 +29,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { mapActions } from '../../store/map';
|
import { mapActions } from '../../store/map';
|
||||||
import { SettingsState } from '../../store/settings';
|
import { SettingsState } from '../../store/settings';
|
||||||
|
|
||||||
import i18n from '../../i18n/index';
|
import i18n, { setI18nLanguage } from '../../i18n/index';
|
||||||
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -37,6 +37,13 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GpxRecord: React.FC<{}> = () => {
|
const GpxRecord: React.FC<{}> = () => {
|
||||||
|
|
||||||
|
const language = useSelector(
|
||||||
|
(state: { settings: SettingsState }) => state.settings.language
|
||||||
|
);
|
||||||
|
|
||||||
|
setI18nLanguage(language);
|
||||||
|
|
||||||
const db = useDB();
|
const db = useDB();
|
||||||
|
|
||||||
const [isRecording, setIsRecording] = useState(false);
|
const [isRecording, setIsRecording] = useState(false);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Fragment, useEffect, useRef } from 'react';
|
import React, { Fragment, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { useDB } from 'react-pouchdb';
|
import { useDB } from 'react-pouchdb';
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import {
|
||||||
IonList,
|
IonList,
|
||||||
IonListHeader,
|
IonListHeader,
|
||||||
IonModal,
|
IonModal,
|
||||||
|
IonSelect,
|
||||||
|
IonSelectOption,
|
||||||
IonTitle,
|
IonTitle,
|
||||||
IonToolbar,
|
IonToolbar,
|
||||||
} from '@ionic/react';
|
} from '@ionic/react';
|
||||||
|
@ -22,7 +24,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { settingsActions, SettingsState } from '../../store/settings';
|
import { settingsActions, SettingsState } from '../../store/settings';
|
||||||
import uri from '../../lib/ids';
|
import uri from '../../lib/ids';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import i18n from '../../i18n/index';
|
import i18n, { setI18nLanguage } from '../../i18n/index';
|
||||||
|
|
||||||
const Settings: React.FC<{}> = () => {
|
const Settings: React.FC<{}> = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -66,18 +68,18 @@ const Settings: React.FC<{}> = () => {
|
||||||
};
|
};
|
||||||
settingsFromRedux();
|
settingsFromRedux();
|
||||||
}
|
}
|
||||||
|
setLocalLanguage(settingsState.language);
|
||||||
}, [db, settingsState]);
|
}, [db, settingsState]);
|
||||||
|
|
||||||
|
const [localLanguage, setLocalLanguage] = useState(settingsState.language);
|
||||||
|
|
||||||
|
const languageSelect = useRef<HTMLIonSelectElement>(null);
|
||||||
const pseudo = useRef<HTMLIonInputElement>(null);
|
const pseudo = useRef<HTMLIonInputElement>(null);
|
||||||
const minTimeInterval = useRef<HTMLIonInputElement>(null);
|
const minTimeInterval = useRef<HTMLIonInputElement>(null);
|
||||||
const minDistance = useRef<HTMLIonInputElement>(null);
|
const minDistance = useRef<HTMLIonInputElement>(null);
|
||||||
|
|
||||||
const modal = useRef<HTMLIonModalElement>(null);
|
const modal = useRef<HTMLIonModalElement>(null);
|
||||||
|
|
||||||
const dismiss = () => {
|
|
||||||
modal.current?.dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
dispatch(
|
dispatch(
|
||||||
settingsActions.saveSettings({
|
settingsActions.saveSettings({
|
||||||
|
@ -88,11 +90,19 @@ const Settings: React.FC<{}> = () => {
|
||||||
minTimeInterval: minTimeInterval.current?.value,
|
minTimeInterval: minTimeInterval.current?.value,
|
||||||
minDistance: minDistance.current?.value,
|
minDistance: minDistance.current?.value,
|
||||||
},
|
},
|
||||||
|
language: languageSelect.current?.value,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
dismiss();
|
dismiss();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setI18nLanguage(localLanguage);
|
||||||
|
|
||||||
|
const dismiss = () => {
|
||||||
|
modal.current?.dismiss();
|
||||||
|
setLocalLanguage(settingsState.language);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<IonButton id='open-SettingsDialog'>
|
<IonButton id='open-SettingsDialog'>
|
||||||
|
@ -112,6 +122,27 @@ const Settings: React.FC<{}> = () => {
|
||||||
</IonButtons>
|
</IonButtons>
|
||||||
</IonToolbar>
|
</IonToolbar>
|
||||||
<IonContent>
|
<IonContent>
|
||||||
|
<IonList lines='full' class='ion-no-margin'>
|
||||||
|
<IonListHeader lines='full'>
|
||||||
|
<IonLabel>{i18n.language}</IonLabel>
|
||||||
|
</IonListHeader>
|
||||||
|
<IonItem>
|
||||||
|
<IonLabel>{i18n.colonize(i18n.language)} </IonLabel>
|
||||||
|
<IonSelect
|
||||||
|
placeholder={i18n.languageSelect.placeHolder}
|
||||||
|
ref={languageSelect}
|
||||||
|
value={localLanguage}
|
||||||
|
interface='popover'
|
||||||
|
onIonChange={(ev) => setLocalLanguage(ev.detail.value)}
|
||||||
|
>
|
||||||
|
{i18n.languageSelect.choices.map((choice) => (
|
||||||
|
<IonSelectOption key={choice.value} value={choice.value}>
|
||||||
|
{choice.label}
|
||||||
|
</IonSelectOption>
|
||||||
|
))}
|
||||||
|
</IonSelect>
|
||||||
|
</IonItem>
|
||||||
|
</IonList>
|
||||||
<IonList lines='full' class='ion-no-margin'>
|
<IonList lines='full' class='ion-no-margin'>
|
||||||
<IonListHeader lines='full'>
|
<IonListHeader lines='full'>
|
||||||
<IonLabel>{i18n.user}</IonLabel>
|
<IonLabel>{i18n.user}</IonLabel>
|
||||||
|
|
|
@ -16,13 +16,20 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { enterAnimation, leaveAnimation } from '../../lib/animation';
|
import { enterAnimation, leaveAnimation } from '../../lib/animation';
|
||||||
import { mapActions, MapState } from '../../store/map';
|
import { mapActions, MapState } from '../../store/map';
|
||||||
import { tileProviders } from './tile';
|
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 TileServerChooserDialog: React.FC<{}> = () => {
|
||||||
const tileProvider = useSelector(
|
const tileProvider = useSelector(
|
||||||
(state: { map: MapState }) => state.map.scope.tileProvider
|
(state: { map: MapState }) => state.map.scope.tileProvider
|
||||||
) as keyof typeof tileProviders;
|
) as keyof typeof tileProviders;
|
||||||
|
|
||||||
|
const language = useSelector(
|
||||||
|
(state: { settings: SettingsState }) => state.settings.language
|
||||||
|
);
|
||||||
|
|
||||||
|
setI18nLanguage(language);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const modal = useRef<HTMLIonModalElement>(null);
|
const modal = useRef<HTMLIonModalElement>(null);
|
||||||
|
|
|
@ -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 phoneRoute from '../../theme/icons/font-gis/svg/routing/uEB08-phone-route-nons.svg';
|
||||||
import GpxImport from './gpx-import';
|
import GpxImport from './gpx-import';
|
||||||
import GpxExport from './GpxExport';
|
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 TrackBrowser: React.FC<{}> = () => {
|
||||||
const gpxes = useFind({
|
const gpxes = useFind({
|
||||||
|
@ -38,6 +40,13 @@ const TrackBrowser: React.FC<{}> = () => {
|
||||||
modal.current?.dismiss();
|
modal.current?.dismiss();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const language = useSelector(
|
||||||
|
(state: { settings: SettingsState }) => state.settings.language
|
||||||
|
);
|
||||||
|
|
||||||
|
setI18nLanguage(language);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<IonButton id='track-browser-button'>
|
<IonButton id='track-browser-button'>
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Fragment } from 'react';
|
|
||||||
import LocalizedStrings from 'react-localization';
|
import LocalizedStrings from 'react-localization';
|
||||||
|
|
||||||
const strings = new LocalizedStrings({
|
const strings = new LocalizedStrings({
|
||||||
|
@ -9,6 +8,7 @@ const strings = new LocalizedStrings({
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
close: 'Close',
|
close: 'Close',
|
||||||
settings: 'Settings',
|
settings: 'Settings',
|
||||||
|
language: 'Language',
|
||||||
user: 'User',
|
user: 'User',
|
||||||
pseudo: 'Pseudo',
|
pseudo: 'Pseudo',
|
||||||
geolocation: 'Geolocation',
|
geolocation: 'Geolocation',
|
||||||
|
@ -38,6 +38,15 @@ const strings = new LocalizedStrings({
|
||||||
|
|
||||||
chooseYourMap: 'Choose your map',
|
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',
|
tracks: 'Tracks',
|
||||||
},
|
},
|
||||||
fr: {
|
fr: {
|
||||||
|
@ -47,6 +56,7 @@ const strings = new LocalizedStrings({
|
||||||
cancel: 'Annuler',
|
cancel: 'Annuler',
|
||||||
close: 'Fermer',
|
close: 'Fermer',
|
||||||
settings: 'Paramètres',
|
settings: 'Paramètres',
|
||||||
|
language: 'Langue',
|
||||||
user: 'Utilisateur',
|
user: 'Utilisateur',
|
||||||
pseudo: 'Pseudo',
|
pseudo: 'Pseudo',
|
||||||
geolocation: 'Géolocalisation',
|
geolocation: 'Géolocalisation',
|
||||||
|
@ -86,8 +96,25 @@ const strings = new LocalizedStrings({
|
||||||
|
|
||||||
chooseYourMap: 'Choisissez votre carte',
|
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',
|
tracks: 'Traces',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default strings;
|
export default strings;
|
||||||
|
|
||||||
|
export const setI18nLanguage = (language: string) => {
|
||||||
|
if (language === undefined || language === 'auto') {
|
||||||
|
strings.setLanguage(strings.getInterfaceLanguage());
|
||||||
|
} else {
|
||||||
|
strings.setLanguage(language);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ export interface SettingsState {
|
||||||
minTimeInterval: number;
|
minTimeInterval: number;
|
||||||
minDistance: number;
|
minDistance: number;
|
||||||
};
|
};
|
||||||
|
language: 'auto'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initialSettingsState: SettingsState = {
|
export const initialSettingsState: SettingsState = {
|
||||||
|
@ -20,6 +21,7 @@ export const initialSettingsState: SettingsState = {
|
||||||
minTimeInterval: 15000,
|
minTimeInterval: 15000,
|
||||||
minDistance: 10,
|
minDistance: 10,
|
||||||
},
|
},
|
||||||
|
language: 'auto',
|
||||||
};
|
};
|
||||||
|
|
||||||
const settingsSlice = createSlice({
|
const settingsSlice = createSlice({
|
||||||
|
|
Loading…
Reference in New Issue