WIP: locale

This commit is contained in:
Paulo Gustavo Veiga 2021-02-12 18:00:54 -08:00
parent db6da3d75e
commit d57cec6f80
6 changed files with 76 additions and 24 deletions

View File

@ -89,6 +89,9 @@
"export.document": { "export.document": {
"defaultMessage": "Mindmap Tools: Export your mindmap in thirdparty mindmap tool formats" "defaultMessage": "Mindmap Tools: Export your mindmap in thirdparty mindmap tool formats"
}, },
"export.document-label": {
"defaultMessage": "Document: Export your mindmap in a self-contained document ready to share"
},
"export.image": { "export.image": {
"defaultMessage": "Image: Get a graphic representation of your map including all colors and shapes." "defaultMessage": "Image: Get a graphic representation of your map including all colors and shapes."
}, },
@ -96,7 +99,7 @@
"defaultMessage": "Export" "defaultMessage": "Export"
}, },
"export.warning": { "export.warning": {
"defaultMessage": "Exporting to Image (SVG,PNG,JPEG )is available only in the editor toolbar." "defaultMessage": "Exporting to Image (SVG,PNG,JPEG,PDF) is only available in the editor toolbar."
}, },
"footer.aboutus": { "footer.aboutus": {
"defaultMessage": "About Us" "defaultMessage": "About Us"
@ -197,6 +200,12 @@
"info.title": { "info.title": {
"defaultMessage": "Info" "defaultMessage": "Info"
}, },
"language.change": {
"defaultMessage": "Change Language"
},
"languange.help": {
"defaultMessage": "Help to Translate"
},
"login.desc": { "login.desc": {
"defaultMessage": "Log into your account" "defaultMessage": "Log into your account"
}, },

View File

@ -59,9 +59,11 @@ export type AccountInfo = {
firstName: string; firstName: string;
lastName: string; lastName: string;
email: string; email: string;
language: string; language: LocaleCode;
} }
export type LocaleCode = 'en' | 'es' | 'fr' | 'de';
interface Client { interface Client {
importMap(model: ImportMapInfo): Promise<number> importMap(model: ImportMapInfo): Promise<number>
createMap(map: BasicMapInfo): Promise<number>; createMap(map: BasicMapInfo): Promise<number>;
@ -70,6 +72,7 @@ interface Client {
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>; renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
fetchAllMaps(): Promise<MapInfo[]>; fetchAllMaps(): Promise<MapInfo[]>;
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>; duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>;
updateAccountLanguage(locale: LocaleCode): Promise<void>;
updateStarred(id: number, starred: boolean): Promise<void>; updateStarred(id: number, starred: boolean): Promise<void>;
updateMapToPublic(id: number, starred: boolean): Promise<void>; updateMapToPublic(id: number, starred: boolean): Promise<void>;

View File

@ -1,5 +1,5 @@
import { Language } from '@material-ui/icons'; import { Language } from '@material-ui/icons';
import Client, { AccountInfo, BasicMapInfo, ChangeHistory, ImportMapInfo, Label, MapInfo, NewUser} from '..'; import Client, { AccountInfo, BasicMapInfo, ChangeHistory, ImportMapInfo, Label, LocaleCode, MapInfo, NewUser } from '..';
class MockClient implements Client { class MockClient implements Client {
private maps: MapInfo[] = []; private maps: MapInfo[] = [];
private labels: Label[] = []; private labels: Label[] = [];
@ -34,16 +34,23 @@ class MockClient implements Client {
]; ];
} }
updateAccountLanguage(locale: LocaleCode): Promise<void> {
localStorage.setItem('locale', locale);
return Promise.resolve();
}
importMap(model: ImportMapInfo): Promise<number> { importMap(model: ImportMapInfo): Promise<number> {
return Promise.resolve(10); return Promise.resolve(10);
} }
fetchAccountInfo(): Promise<AccountInfo> { fetchAccountInfo(): Promise<AccountInfo> {
const locale: LocaleCode | null = localStorage.getItem('locale') as LocaleCode;
return Promise.resolve({ return Promise.resolve({
firstName: 'Costme', firstName: 'Costme',
lastName: 'Fulanito', lastName: 'Fulanito',
email: 'test@example.com', email: 'test@example.com',
language: 'en' language: locale ? locale : 'en'
}); });
} }
deleteMaps(ids: number[]): Promise<void> { deleteMaps(ids: number[]): Promise<void> {

View File

@ -1,5 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label, ChangeHistory, AccountInfo, ImportMapInfo } from '..'; import Client, { ErrorInfo, MapInfo, BasicMapInfo, NewUser, Label, ChangeHistory, AccountInfo, ImportMapInfo, LocaleCode } from '..';
export default class RestClient implements Client { export default class RestClient implements Client {
private baseUrl: string; private baseUrl: string;
@ -9,6 +9,11 @@ export default class RestClient implements Client {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.sessionExpired = sessionExpired; this.sessionExpired = sessionExpired;
} }
updateAccountLanguage(locale: LocaleCode): Promise<void> {
throw "Method not implemented";
}
importMap(model: ImportMapInfo): Promise<number> { importMap(model: ImportMapInfo): Promise<number> {
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => { const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
axios.post(this.baseUrl + `/c/restful/maps?title=${model.title}&description=${model.description ? model.description : ''}`, axios.post(this.baseUrl + `/c/restful/maps?title=${model.title}&description=${model.description ? model.description : ''}`,
@ -22,7 +27,8 @@ export default class RestClient implements Client {
reject(errorInfo); reject(errorInfo);
}); });
} }
return new Promise(handler); } return new Promise(handler);
}
fetchAccountInfo(): Promise<AccountInfo> { fetchAccountInfo(): Promise<AccountInfo> {
const handler = (success: (account: AccountInfo) => void, reject: (error: ErrorInfo) => void) => { const handler = (success: (account: AccountInfo) => void, reject: (error: ErrorInfo) => void) => {
@ -33,11 +39,12 @@ export default class RestClient implements Client {
} }
).then(response => { ).then(response => {
const account = response.data; const account = response.data;
const locale: LocaleCode | null = account.locale;
success({ success({
lastName: account.lastName ? account.lastName : '', lastName: account.lastName ? account.lastName : '',
firstName: account.fistName ? account.fistName : '', firstName: account.fistName ? account.fistName : '',
email: account.email, email: account.email,
language: "en" language: locale ? locale : 'en'
}); });
}).catch(error => { }).catch(error => {
const errorInfo = this.parseResponseOnError(error.response); const errorInfo = this.parseResponseOnError(error.response);

View File

@ -115,7 +115,7 @@ const ExportDialog = (props: ExportDialogProps) => {
className={classes.label} className={classes.label}
value="document" value="document"
control={<Radio color="primary" />} control={<Radio color="primary" />}
label={intl.formatMessage({ id: "export.document", defaultMessage: "Document: Export your mindmap in a self-contained document ready to share" })} label={intl.formatMessage({ id: "export.document-label", defaultMessage: "Document: Export your mindmap in a self-contained document ready to share" })}
color="secondary" /> color="secondary" />
{exportGroup == 'document' && {exportGroup == 'document' &&
(<Select onChange={handleOnExportFormatChange} (<Select onChange={handleOnExportFormatChange}

View File

@ -1,18 +1,31 @@
import { Button, Divider, Link, ListItemIcon, Menu, MenuItem, Tooltip } from '@material-ui/core'; import { Button, Divider, Menu, MenuItem, Tooltip } from '@material-ui/core';
import { ExitToAppOutlined, SettingsApplicationsOutlined, TranslateTwoTone } from '@material-ui/icons'; import { TranslateTwoTone } from '@material-ui/icons';
import React from "react"; import React from "react";
import { FormattedMessage } from "react-intl"; import { useMutation, useQuery, useQueryClient } from "react-query";
import { useQuery } from "react-query"; import Client, { ErrorInfo, AccountInfo, LocaleCode } from "../../../client";
import Client, { ErrorInfo, AccountInfo } from "../../../client";
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { activeInstance } from '../../../redux/clientSlice'; import { activeInstance } from '../../../redux/clientSlice';
import { FormattedMessage, useIntl } from 'react-intl';
const localeToStr = new Map<LocaleCode, string>([["en", "English"], ["es", "Español"], ["fr", "Français"], ["de", "Deutsch"]]);
const LanguageMenu = () => { const LanguageMenu = () => {
const queryClient = useQueryClient();
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl); const open = Boolean(anchorEl);
const intl = useIntl();
const mutation = useMutation((locale: LocaleCode) => client.updateAccountLanguage(locale),
{
onSuccess: () => {
queryClient.invalidateQueries('account')
handleClose();
}
}
);
const handleMenu = (event: React.MouseEvent<HTMLElement>) => { const handleMenu = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
@ -22,13 +35,18 @@ const LanguageMenu = () => {
setAnchorEl(null); setAnchorEl(null);
}; };
const handleOnClick = (event: React.MouseEvent<HTMLElement>) => {
const localeCode = event.target['id'];
mutation.mutate(localeCode);
}
const { data } = useQuery<unknown, ErrorInfo, AccountInfo>('account', () => { const { data } = useQuery<unknown, ErrorInfo, AccountInfo>('account', () => {
return client.fetchAccountInfo(); return client.fetchAccountInfo();
}); });
return ( return (
<span> <span>
<Tooltip title="Change Language"> <Tooltip title={intl.formatMessage({ id: 'language.change', defaultMessage: 'Change Language' })}>
<Button <Button
size="small" size="small"
variant="outlined" variant="outlined"
@ -37,7 +55,7 @@ const LanguageMenu = () => {
onClick={handleMenu} onClick={handleMenu}
startIcon={<TranslateTwoTone />} startIcon={<TranslateTwoTone />}
> >
{data?.language == "en" ? "English" : "Español"} {localeToStr.get(data?.language ? data?.language : 'en')}
</Button> </Button>
</Tooltip> </Tooltip>
<Menu id="appbar-language" <Menu id="appbar-language"
@ -55,17 +73,25 @@ const LanguageMenu = () => {
horizontal: 'right', horizontal: 'right',
}} }}
> >
<MenuItem onClick={handleClose}> <MenuItem onClick={handleOnClick} id="en">
English {localeToStr.get('en')}
</MenuItem> </MenuItem>
<MenuItem onClick={handleClose}> <MenuItem onClick={handleOnClick} id="es">
Español {localeToStr.get('es')}
</MenuItem> </MenuItem>
<MenuItem onClick={handleOnClick} id="fr">
{localeToStr.get('fr')}
</MenuItem>
<MenuItem onClick={handleOnClick} id="de">
{localeToStr.get('de')}
</MenuItem>
<Divider /> <Divider />
<MenuItem onClick={handleClose}>
Help to Translate <MenuItem onClick={handleOnClick}>
<FormattedMessage id="language.help" defaultMessage=" Help to Translate" />
</MenuItem> </MenuItem>
</Menu> </Menu>
</span>); </span>);