From 2cfe84ae5174d719588b63d57aa65bceb0ea74c6 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Mon, 26 Jun 2023 23:38:50 -0400 Subject: [PATCH 1/5] extract i18next init to separate file To avoid cluttering app.js more than necessary, I am extracting the logic to initialize i18next to a new file called i18nextInit.ts, which just performs the same initialization logic and exports the initialized instance of i18next. In tsconfig.json, `resolveJsonModule` was set `true` so that the JSON translation files can be imported in TypeScript. --- tsconfig.json | 1 + www/js/app.js | 35 ++--------------------------------- www/js/i18nextInit.ts | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 www/js/i18nextInit.ts diff --git a/tsconfig.json b/tsconfig.json index 14493a462..3f9007f40 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "module": "es6", "target": "es5", "esModuleInterop": true, + "resolveJsonModule": true, "jsx": "react", "allowJs": true, "moduleResolution": "node" diff --git a/www/js/app.js b/www/js/app.js index 0a19886c8..367c25582 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -13,9 +13,6 @@ import 'angular-translate-loader-static-files'; import 'moment'; import 'moment-timezone'; -import i18next from 'i18next'; -import { initReactI18next } from 'react-i18next'; - import 'ionic-toast'; import 'ionic-datepicker'; import 'angular-simple-logger'; @@ -23,36 +20,8 @@ import 'angular-simple-logger'; import '../manual_lib/ionic/js/ionic.js'; import '../manual_lib/ionic/js/ionic-angular.js'; - -import en from '../i18n/en.json'; -import es from '../../locales/es/i18n/es.json'; -import fr from '../../locales/fr/i18n/fr.json'; -import it from '../../locales/it/i18n/it.json'; -const langs = { en, es, fr, it }; - -let resources = {}; -for (const [lang, json] of Object.entries(langs)) { - resources[lang] = { translation: json } -} - -const locales = !navigator?.length ? [navigator.language] : navigator.languages; -let detectedLang; -locales.forEach(locale => { - const lang = locale.trim().split(/-|_/)[0]; - if (Object.keys(langs).includes(lang)) { - detectedLang = lang; - } -}); - -i18next.use(initReactI18next) - .init({ - debug: true, - resources, - lng: detectedLang, - fallbackLng: 'en' -}); - -window.i18next = i18next; +import initializedI18next from './i18nextInit'; +window.i18next = initializedI18next; import 'ng-i18next'; angular.module('emission', ['ionic', 'jm.i18next', diff --git a/www/js/i18nextInit.ts b/www/js/i18nextInit.ts new file mode 100644 index 000000000..268d28c8d --- /dev/null +++ b/www/js/i18nextInit.ts @@ -0,0 +1,36 @@ +/* Initializes i18next with en, es, fr, and it translations, and uses the language + detected by the browser with en as a fallback. + Exports the initialized instance of i18next. */ + +import i18next from 'i18next'; +import { initReactI18next } from 'react-i18next'; + +import en from '../i18n/en.json'; +import es from '../../locales/es/i18n/es.json'; +import fr from '../../locales/fr/i18n/fr.json'; +import it from '../../locales/it/i18n/it.json'; +const langs = { en, es, fr, it }; + +let resources = {}; +for (const [lang, json] of Object.entries(langs)) { + resources[lang] = { translation: json } +} + +const locales = navigator?.languages?.length ? navigator.languages : [navigator.language]; +let detectedLang; +locales.forEach(locale => { + const lang = locale.trim().split(/-|_/)[0]; + if (Object.keys(langs).includes(lang)) { + detectedLang = lang; + } +}); + +i18next.use(initReactI18next) + .init({ + debug: true, + resources, + lng: detectedLang, + fallbackLng: 'en' + }); + +export default i18next; From 700e0aa87633a4eb3d506d071eccf456ca2fd46b Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 27 Jun 2023 01:05:47 -0400 Subject: [PATCH 2/5] TripCard: remove unused imports and alias windowDimensions 'width' as 'windowWidth' for readability/clarity --- www/js/diary/cards/TripCard.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/www/js/diary/cards/TripCard.tsx b/www/js/diary/cards/TripCard.tsx index a411f1704..3b1a0d566 100644 --- a/www/js/diary/cards/TripCard.tsx +++ b/www/js/diary/cards/TripCard.tsx @@ -5,13 +5,12 @@ */ import React, { useEffect, useState } from "react"; -import { angularize, getAngularService } from "../../angular-react-helper"; +import { getAngularService } from "../../angular-react-helper"; import { View, useWindowDimensions, StyleSheet } from 'react-native'; -import { Card, Divider, IconButton, PaperProvider, Text, useTheme } from 'react-native-paper'; +import { Divider, IconButton, Text } from 'react-native-paper'; import { object } from "prop-types"; import LeafletView from "../../components/LeafletView"; import { useTranslation } from "react-i18next"; -import TimestampBadge from "./TimestampBadge"; import MultilabelButtonGroup from "../../survey/multilabel/MultiLabelButtonGroup"; import UserInputButton from "../../survey/enketo/UserInputButton"; import useAppConfig from "../../useAppConfig"; @@ -24,7 +23,7 @@ import { useNavigation } from "@react-navigation/native"; const TripCard = ({ trip }) => { const { t } = useTranslation(); - const { height, width } = useWindowDimensions(); + const { width: windowWidth } = useWindowDimensions(); const { appConfig, loading } = useAppConfig(); const navigation = useNavigation(); @@ -66,7 +65,7 @@ const TripCard = ({ trip }) => { + style={[{minHeight: windowWidth / 2}, mapStyle]} /> {trip.percentages?.map?.((pct, i) => ( From b0c710f6b2e694625032d69dd712b45c7586f58f Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 27 Jun 2023 01:33:45 -0400 Subject: [PATCH 3/5] LabelDetails: use key on direct child of .map The `key` prop needs to go on the here because that is the element being repeated; not the IconButton. --- www/js/diary/LabelDetailsScreen.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/js/diary/LabelDetailsScreen.tsx b/www/js/diary/LabelDetailsScreen.tsx index 032a88713..e44e5497b 100644 --- a/www/js/diary/LabelDetailsScreen.tsx +++ b/www/js/diary/LabelDetailsScreen.tsx @@ -75,8 +75,8 @@ const LabelScreenDetails = ({ route, navigation }) => { {trip.percentages?.map?.((pct, i) => ( - - + {pct.pct}% From 7ad16ed178f1fb12ac3caab57487b0ff35ae8c04 Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 27 Jun 2023 01:46:45 -0400 Subject: [PATCH 4/5] fix filters always init on "All Trips" The filter state that is applied initially should be the first one in the list. This updates FilterSelect to reflect that. --- www/js/diary/list/FilterSelect.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/www/js/diary/list/FilterSelect.tsx b/www/js/diary/list/FilterSelect.tsx index 48e5a078f..5d962a803 100644 --- a/www/js/diary/list/FilterSelect.tsx +++ b/www/js/diary/list/FilterSelect.tsx @@ -12,14 +12,17 @@ import { array, number } from "prop-types"; const FilterSelect = ({ filters, setFilters, numListDisplayed, numListTotal }) => { const { t } = useTranslation(); - const [selectedFilter, setSelectedFilter] = useState('show-all'); + const [selectedFilter, setSelectedFilter] = useState(); useEffect(() => { - setSelectedFilter(filters?.find(f => f.state)?.key); - }, []); + if (!selectedFilter) { + setSelectedFilter(filters?.find(f => f.state)?.key); + } + }, [filters]); useEffect(() => { - if (selectedFilter === 'show-all') { + if (!selectedFilter) return; + if (selectedFilter == 'show-all') { setFilters(filters.map(f => ({ ...f, state: false }))); } else { setFilters(filters.map(f => { From 7534f86af94ca95ebe62cfd7d3a020d97a92cace Mon Sep 17 00:00:00 2001 From: Jack Greenlee Date: Tue, 27 Jun 2023 03:00:25 -0400 Subject: [PATCH 5/5] dynamicConfig: fix error message translation This was made translatable in 36a1aaf5c38058339b4a1661dcf6fd3e24e77d76, but I overwrote it when I merged with 14e8a67866ccd624070728ff6d55d6b362542ff3 and I must have incorrectly resolved the merge conflicts for this line in particular. --- www/js/config/dynamic_config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/config/dynamic_config.js b/www/js/config/dynamic_config.js index c1136704d..1f858a2b0 100644 --- a/www/js/config/dynamic_config.js +++ b/www/js/config/dynamic_config.js @@ -267,7 +267,7 @@ angular.module('emission.config.dynamic', ['emission.plugin.logger']) $rootScope.$apply(() => dc.saveAndNotifyConfigReady(existingConfig)); } }).catch((err) => { - Logger.displayError('Error loading config on app start', err) + Logger.displayError(i18next.t('config.loading-config-app-start', err)) }); }; $ionicPlatform.ready().then(function() {