Skip to content

Commit

Permalink
change labels of region selector
Browse files Browse the repository at this point in the history
torn between changing the labels of the dropdowns when translating and
having a separate page body for Bengali and English. Leaning towards
having separate pages, this will require the pages to be kept to parity
and will not be very DRY but keeps the language selection by className
simple and maintains a good UX. This is DRY vs KISS moment
  • Loading branch information
JavaRip committed Jun 14, 2024
1 parent 5c1b8e2 commit e526f7b
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 39 deletions.
30 changes: 5 additions & 25 deletions frontEnd2024/functions/iarsenic-react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {
Staining,
StainingGuide,
Result,
PrivacyPolicy,
} from './pages';
import config from './config';
import { navigate } from 'wouter/use-browser-location';
import PrivacyPolicy from './pages/PrivacyPolicy';
import LanguageSelector from './utils/LanguageSelector';

const Theme = {
theme: createTheme({
Expand All @@ -25,28 +26,7 @@ const Theme = {
})
};

function changeLanguage(language: 'english' | 'bengali') {
localStorage.setItem('language', language);

document.body.className = language;
}

function setLanguage() {
if (localStorage.getItem('language')) {
if (localStorage.getItem('language') === 'english') {
changeLanguage('english');
} else if (localStorage.getItem('language') === 'bengali') {
changeLanguage('bengali');
} else {
console.error(`invalid language option ${localStorage.getItem('language')}`);
localStorage.removeItem('language');
}
} else {
changeLanguage('english');
}
}

setLanguage();
LanguageSelector.init();

function App() {
return (
Expand Down Expand Up @@ -84,7 +64,7 @@ function App() {
src={`${config.basePath}/british.png`}
/>
}
onClick={() => changeLanguage('english')}
onClick={() => LanguageSelector.set('english')}
/>

<Button
Expand All @@ -94,7 +74,7 @@ function App() {
src={`${config.basePath}/bangladesh.jpg`}
/>
}
onClick={() => changeLanguage('bengali')}
onClick={() => LanguageSelector.set('bengali')}
/>
</Box>
</Stack>
Expand Down
113 changes: 100 additions & 13 deletions frontEnd2024/functions/iarsenic-react/src/pages/Region/Region.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Typography, Autocomplete, TextField, Button, Stack } from "@mui/material";
import { Typography, Autocomplete, TextField, Button, Stack, CircularProgress } from "@mui/material";
import config from "../../config";
import { useEffect, useState } from "react";
import { navigate } from "wouter/use-browser-location";
import { DropdownDistrict, DropdownDivision, DropdownUnion, DropdownUpazila } from "../../types";
import { DropdownDistrict, DropdownDivision, DropdownUnion, DropdownUpazila, RegionTranslations } from "../../types";
import PredictorsStorage from "../../utils/PredictorsStorage";
import LanguageSelector from "../../utils/LanguageSelector";

export default function Region(): JSX.Element {
const [language, setLanguage] = useState<'english' | 'bengali'>();
const [translations, setTranslations] = useState<RegionTranslations>();
const [dropdownData, setDropdownData] = useState<DropdownDivision[]>([]);
const [selectedDivision, setSelectedDivision] = useState<DropdownDivision | null>(null);
const [selectedDistrict, setSelectedDistrict] = useState<DropdownDistrict | null>(null);
Expand All @@ -27,6 +30,7 @@ export default function Region(): JSX.Element {
async function fetchDropdownData() {
const response = await fetch(`${config.basePath}/model5/dropdown-data.json`);
const data = await response.json();

setDropdownData(data);
}

Expand All @@ -43,10 +47,33 @@ export default function Region(): JSX.Element {
return !Object.values(newErrors).some(value => value);
}

async function fetchTranslations() {
const response = await fetch(`${config.basePath}/region-translations.json`);
const data = await response.json();

setTranslations(data);
}

useEffect(() => {
fetchDropdownData();
setLanguage(LanguageSelector.get());
}, []);

useEffect(() => {
if (language === 'bengali') {
fetchTranslations();
}

}, [language]);

if ((!language || !dropdownData) || (language === 'bengali' && !translations)) {
return (
<Stack alignContent='center' justifyContent='center'>
<CircularProgress />
</Stack>
);
}

return (
<>
<Typography alignSelf='center' variant="h4">Region</Typography>
Expand All @@ -62,10 +89,22 @@ export default function Region(): JSX.Element {
setSelectedUnion(null);
setErrors(e => ({ ...e, division: false }));
}}
getOptionLabel={(option) => option.division}
getOptionLabel={(option) => {
if (language === 'english') return option.division;
if (!translations) throw new Error('Translations not loaded');
return translations.Districts[option.division];
}}
renderInput={(params) => {
const label = (() => {
if (language === 'english') return "Division";
if (!translations) throw new Error('Translations not loaded');
return translations.Divisions['Division'];
})();

return (
<TextField {...params} label="Division"
<TextField
{...params}
label={label}
error={errors.division}
helperText={errors.division ? 'Please select a division' : ''}
/>
Expand All @@ -82,10 +121,22 @@ export default function Region(): JSX.Element {
setSelectedUnion(null);
setErrors(e => ({ ...e, district: false }));
}}
getOptionLabel={(option) => option.district}
getOptionLabel={(option) => {
if (language === 'english') return option.district;
if (!translations) throw new Error('Translations not loaded');
return translations.Districts[option.district];
}}
renderInput={(params) => {
const label = (() => {
if (language === 'english') return "District";
if (!translations) throw new Error('Translations not loaded');
return translations.Districts['District'];
})();

return (
<TextField {...params} label="District"
<TextField
{...params}
label={label}
error={errors.district}
helperText={errors.district ? 'Please select a district' : ''}
disabled={!selectedDivision}
Expand All @@ -102,10 +153,22 @@ export default function Region(): JSX.Element {
setSelectedUnion(null);
setErrors(e => ({ ...e, upazila: false }));
}}
getOptionLabel={(option) => option.upazila}
getOptionLabel={(option) => {
if (language === 'english') return option.upazila;
if (!translations) throw new Error('Translations not loaded');
return translations.Upazilas[option.upazila];
}}
renderInput={(params) => {
const label = (() => {
if (language === 'english') return "Upazila";
if (!translations) throw new Error('Translations not loaded');
return translations.Districts['Upazila'];
})();

return (
<TextField {...params} label="Upazila"
<TextField
{...params}
label={label}
error={errors.upazila}
helperText={errors.upazila ? 'Please select an upazila' : ''}
disabled={!selectedDistrict}
Expand All @@ -121,10 +184,22 @@ export default function Region(): JSX.Element {
setSelectedUnion(newValue);
setErrors(e => ({ ...e, union: false }));
}}
getOptionLabel={(option) => option.union}
getOptionLabel={(option) => {
if (language === 'english') return option.union;
if (!translations) throw new Error('Translations not loaded');
return translations.Unions[option.union];
}}
renderInput={(params) => {
return (
<TextField {...params} label="Union"
const label = (() => {
if (language === 'english') return "Union";
if (!translations) throw new Error('Translations not loaded');
return translations.Unions['Union'];
})();

return (
<TextField
{...params}
label={label}
error={errors.union}
helperText={errors.union ? 'Please select a union' : ''}
disabled={!selectedUpazila}
Expand All @@ -140,10 +215,22 @@ export default function Region(): JSX.Element {
setSelectedMouza(newValue);
setErrors(e => ({ ...e, mouza: false }));
}}
getOptionLabel={(mouza) => mouza}
getOptionLabel={(option) => {
if (language === 'english') return option;
if (!translations) throw new Error('Translations not loaded');
return translations.Mouzas[option];
}}
renderInput={(params) => {
const label = (() => {
if (language === 'english') return "Mouza";
if (!translations) throw new Error('Translations not loaded');
return translations.Mouzas['Mouza'];
})();

return (
<TextField {...params} label="Mouza"
<TextField
{...params}
label={label}
error={errors.mouza}
helperText={errors.mouza ? 'Please select a mouza' : ''}
disabled={!selectedUnion}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,11 @@ export default function Result(): JSX.Element {
});
}

// 1. load user entered predictor data - no dpendencies
useEffect(loadPredictors, []);

// 2. load model data - depends on predictors to download predictions for
// this district only
useEffect(() => {
if (!predictors) {
return;
Expand All @@ -120,6 +123,7 @@ export default function Result(): JSX.Element {
fetchModelData(predictors.regionKey.division, predictors.regionKey.district);
}, [predictors]);

// 3. get output message - depends on model data for prediction
useEffect(() => {
if (!modelData) {
console.error('attempting to produce estimate without model data');
Expand Down
3 changes: 2 additions & 1 deletion frontEnd2024/functions/iarsenic-react/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export { default as Region } from './Region';
export { default as Review } from './Review';
export { default as Staining } from './Staining';
export { default as StainingGuide } from './StainingGuide';
export { default as Result } from './Result';
export { default as Result } from './Result';
export { default as PrivacyPolicy } from './PrivacyPolicy';
19 changes: 19 additions & 0 deletions frontEnd2024/functions/iarsenic-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,22 @@ export type ModelData = {
}
}
}

// key is english region name, value is bengali
export type RegionTranslations = {
"Divisions": {
[key: string]: string
},
"Districts": {
[key: string]: string
},
"Upazilas": {
[key: string]: string
},
"Unions": {
[key: string]: string
},
"Mouzas": {
[key: string]: string
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export default class LanguageSelector {
static dataKey: string = 'language';

static init = () => {
const language = LanguageSelector.get();
document.body.className = language;
};

static get = (): 'english' | 'bengali' => {
const language = localStorage.getItem(this.dataKey) || 'english';

if (language !== 'english' && language !== 'bengali') {
throw new Error(`Invalid language in local storage ${language}`);
}

return language;
};

static set = (language: 'english' | 'bengali') => {
localStorage.setItem(LanguageSelector.dataKey, language);

document.body.className = language;
};
}

0 comments on commit e526f7b

Please sign in to comment.