Skip to content

Commit 8af14e9

Browse files
authored
feat: Prepare for multilingual support (#357)
* Add fallback to each route Not sure if this causes any side effects * Move action texts for basic recommendations to translation file * Run prettier * Add component to support line breaks (\n) in translations * Replace custom component by simple css style * Remove unnecessary white space * Move texts for charts to translation file * Move texts for contact behavior to translation file * Open links in new tab * Set rel to noopener * Move texts for credits to translation file * Move texts for faqs to translation file * Add missing attributes (target, rel) to links * Run prettier * Move texts for imprint to translation file * Move texts for legal information to translation file * Move texts for privacy to translation file * Move texts for rki to translation file * Move texts for symptom level to translation file * Move texts for risk recommendation to translation file * Move texts for cov map feature info to translation file * Run prettier * Add fallback component to routes of embedded app * Move texts for welcome to common translation file * Move texts for install promt to common translation file * Move texts for lazy error to common translation file * Move text for copying to clipboard to common translation file * Move texts for welcome info to common translation file * Run prettier * Add suspense with fallback to installPromt
1 parent eb2af17 commit 8af14e9

27 files changed

+657
-608
lines changed

apps/official/components/CovMapFeatureInfo.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import ContactsLowIcon from "../static/images/contacts-low.svg";
2424
import ContactsMediumIcon from "../static/images/contacts-medium.svg";
2525
import SymptomsLowIcon from "../static/images/symptoms-low.svg";
2626
import { usePathPreservingQueryChange } from "app-config/components/customHistoryHooks";
27+
import { useTranslation } from "react-i18next";
2728

2829
const useStyles = makeStyles<Theme, { fullScreen: boolean }>((theme) => ({
2930
action: {
@@ -148,19 +149,21 @@ export const CovMapFeatureInfo = ({ rawData }: FeatureInfoProps) => {
148149
);
149150

150151
const ContactsIcon = ({ score }: { score: ContactScore }) => {
152+
const { t } = useTranslation("translation");
153+
151154
switch (score) {
152155
case ContactScore.Low:
153156
return (
154157
<div className={center}>
155158
<ContactsLowIcon />
156-
<Typography variant="body2">reduziert</Typography>
159+
<Typography variant="body2">{t("contacts-indicator.reduced")}</Typography>
157160
</div>
158161
);
159162
case ContactScore.Medium:
160163
return (
161164
<div className={center}>
162165
<ContactsMediumIcon />
163-
<Typography variant="body2">erhöht</Typography>
166+
<Typography variant="body2">{t("contacts-indicator.increased")}</Typography>
164167
</div>
165168
);
166169
default:

apps/official/components/basic-recommendations/BasicRecommendations.tsx

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import HygieneIcon from "../../static/images/hand-washing.svg";
1313
import MaskIcon from "../../static/images/mask.svg";
1414
import VentilationIcon from "../../static/images/fresh-air.svg";
1515
import RegionalIcon from "../../static/images/checklist.svg";
16-
import { ActionTexts } from "../../static/texts/ActionTexts";
1716
import { NavigationTitle } from "app-config/components/NavigationTitle";
17+
import { useTranslation } from "react-i18next";
1818

1919
const useStyles = makeStyles({
2020
teaser: {
@@ -35,11 +35,14 @@ const useStyles = makeStyles({
3535
textAlign: "left",
3636
fontWeight: "bold",
3737
},
38+
multiLineText: {
39+
whiteSpace: "break-spaces",
40+
},
3841
});
3942

4043
const CountyTeaser = ({ county, url }: { county: string; url: string }): JSX.Element => {
4144
const classes = useStyles();
42-
const teaser = `${ActionTexts.COUNTY_TEASER_1}${county}${ActionTexts.COUNTY_TEASER_2}`;
45+
const { t } = useTranslation("translation");
4346

4447
return (
4548
<Button href={url} target="_blank" disableRipple>
@@ -48,7 +51,7 @@ const CountyTeaser = ({ county, url }: { county: string; url: string }): JSX.Ele
4851
<Grid container direction="row" alignItems="center" spacing={2}>
4952
<Grid item xs={10}>
5053
<Typography variant="body1" className={classes.leftText}>
51-
{teaser}
54+
{t("basic-recommendations.county-teaser", { county })}
5255
</Typography>
5356
</Grid>
5457
<Grid item xs={2}>
@@ -63,11 +66,13 @@ const CountyTeaser = ({ county, url }: { county: string; url: string }): JSX.Ele
6366

6467
const FinalTeaser = (): JSX.Element => {
6568
const classes = useStyles();
69+
const { t } = useTranslation("translation");
70+
6671
return (
6772
<Card className={classes.teaser}>
6873
<CardContent>
69-
<Typography variant="body1" className={classes.leftText}>
70-
{ActionTexts.FINAL_TEASER}
74+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
75+
{t("basic-recommendations.final-teaser")}
7176
</Typography>
7277
</CardContent>
7378
</Card>
@@ -76,16 +81,18 @@ const FinalTeaser = (): JSX.Element => {
7681

7782
const Intro = (): JSX.Element => {
7883
const classes = useStyles();
84+
const { t } = useTranslation("translation");
85+
7986
return (
8087
<Grid container direction="column" spacing={4}>
8188
<Grid item>
8289
<Typography variant="body1" className={classes.leftText}>
83-
{ActionTexts.INTRO_TEASER_1}
90+
{t("basic-recommendations.intro-teaser-1")}
8491
</Typography>
8592
</Grid>
8693
<Grid item>
8794
<Typography variant="body1" className={classes.subHeader}>
88-
{ActionTexts.INTRO_TEASER_2}
95+
{t("basic-recommendations.intro-teaser-2")}
8996
</Typography>
9097
</Grid>
9198
</Grid>
@@ -94,6 +101,8 @@ const Intro = (): JSX.Element => {
94101

95102
const ContactSection = (): JSX.Element => {
96103
const classes = useStyles();
104+
const { t } = useTranslation("translation");
105+
97106
return (
98107
<div>
99108
<Grid container direction="row">
@@ -102,19 +111,21 @@ const ContactSection = (): JSX.Element => {
102111
</Grid>
103112
<Grid item xs={9}>
104113
<Typography variant="h1" className={classes.leftText}>
105-
{ActionTexts.CONTACT_HEADLINE}
114+
{t("basic-recommendations.contact.headline")}
106115
</Typography>
107116
</Grid>
108117
</Grid>
109-
<Typography variant="body1" className={classes.leftText}>
110-
{ActionTexts.CONTACT_TEXT}
118+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
119+
{t("basic-recommendations.contact.text")}
111120
</Typography>
112121
</div>
113122
);
114123
};
115124

116125
const DistanceSection = (): JSX.Element => {
117126
const classes = useStyles();
127+
const { t } = useTranslation("translation");
128+
118129
return (
119130
<div>
120131
<Grid container direction="row">
@@ -123,19 +134,21 @@ const DistanceSection = (): JSX.Element => {
123134
</Grid>
124135
<Grid item xs={9}>
125136
<Typography variant="h1" className={classes.leftText}>
126-
{ActionTexts.DISTANCE_HEADLINE}
137+
{t("basic-recommendations.distance.headline")}
127138
</Typography>
128139
</Grid>
129140
</Grid>
130-
<Typography variant="body1" className={classes.leftText}>
131-
{ActionTexts.DISTANCE_TEXT}
141+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
142+
{t("basic-recommendations.distance.text")}
132143
</Typography>
133144
</div>
134145
);
135146
};
136147

137148
const MaskSection = (): JSX.Element => {
138149
const classes = useStyles();
150+
const { t } = useTranslation("translation");
151+
139152
return (
140153
<div>
141154
<Grid container direction="row">
@@ -144,19 +157,21 @@ const MaskSection = (): JSX.Element => {
144157
</Grid>
145158
<Grid item xs={9}>
146159
<Typography variant="h1" className={classes.leftText}>
147-
{ActionTexts.MASK_HEADLINE}
160+
{t("basic-recommendations.mask.headline")}
148161
</Typography>
149162
</Grid>
150163
</Grid>
151-
<Typography variant="body1" className={classes.leftText}>
152-
{ActionTexts.MASK_TEXT}
164+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
165+
{t("basic-recommendations.mask.text")}
153166
</Typography>
154167
</div>
155168
);
156169
};
157170

158171
const VentilationSection = (): JSX.Element => {
159172
const classes = useStyles();
173+
const { t } = useTranslation();
174+
160175
return (
161176
<div>
162177
<Grid container direction="row">
@@ -165,19 +180,21 @@ const VentilationSection = (): JSX.Element => {
165180
</Grid>
166181
<Grid item xs={9}>
167182
<Typography variant="h1" className={classes.leftText}>
168-
{ActionTexts.VENTILATION_HEADLINE}
183+
{t("basic-recommendations.ventilation.headline")}
169184
</Typography>
170185
</Grid>
171186
</Grid>
172-
<Typography variant="body1" className={classes.leftText}>
173-
{ActionTexts.VENTILATION_TEXT}
187+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
188+
{t("basic-recommendations.ventilation.text")}
174189
</Typography>
175190
</div>
176191
);
177192
};
178193

179194
const HygieneSection = (): JSX.Element => {
180195
const classes = useStyles();
196+
const { t } = useTranslation();
197+
181198
return (
182199
<div>
183200
<Grid container direction="row">
@@ -186,19 +203,20 @@ const HygieneSection = (): JSX.Element => {
186203
</Grid>
187204
<Grid item xs={9}>
188205
<Typography variant="h1" className={classes.leftText}>
189-
{ActionTexts.HYGIENE_HEADLINE}
206+
{t("basic-recommendations.hygiene.headline")}
190207
</Typography>
191208
</Grid>
192209
</Grid>
193-
<Typography variant="body1" className={classes.leftText}>
194-
{ActionTexts.HYGIENE_TEXT}
210+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
211+
{t("basic-recommendations.hygiene.text")}
195212
</Typography>
196213
</div>
197214
);
198215
};
199216

200217
const RegionalSection = (): JSX.Element => {
201218
const classes = useStyles();
219+
const { t } = useTranslation();
202220
return (
203221
<div>
204222
<Grid container direction="row">
@@ -207,12 +225,12 @@ const RegionalSection = (): JSX.Element => {
207225
</Grid>
208226
<Grid item xs={9}>
209227
<Typography variant="h1" className={classes.leftText}>
210-
{ActionTexts.REGIONAL_HEADLINE}
228+
{t("basic-recommendations.regional.headline")}
211229
</Typography>
212230
</Grid>
213231
</Grid>
214-
<Typography variant="body1" className={classes.leftText}>
215-
{ActionTexts.REGIONAL_TEXT}
232+
<Typography variant="body1" className={`${classes.leftText} ${classes.multiLineText}`}>
233+
{t("basic-recommendations.regional.text")}
216234
</Typography>
217235
</div>
218236
);
@@ -245,12 +263,13 @@ function loadDistrictData(location): DistrictData | undefined {
245263
export const BasicRecommendations = (): JSX.Element => {
246264
const location = useLocation();
247265
const districtData = loadDistrictData(location);
266+
const { t } = useTranslation("translation");
248267

249268
return (
250269
<>
251270
<main className="sections">
252271
<section>
253-
<NavigationTitle title={ActionTexts.TITLE} backToExpandedFeatureInfo={true} />
272+
<NavigationTitle title={t("basic-recommendations.title")} backToExpandedFeatureInfo={true} />
254273
</section>
255274
<section>
256275
{districtData !== undefined ? (

apps/official/components/pages/Charts.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { AppApi } from "../../../../src/state/app";
77

88
import { formatUTCDate } from "../../../../src/lib/formatUTCDate";
99
import { NavigationTitle } from "app-config/components/NavigationTitle";
10+
import { useTranslation } from "react-i18next";
1011

1112
export const Charts = () => {
1213
const dispatch = useThunkDispatch();
14+
const { t } = useTranslation("translation");
1315
const currentDate = useSelector((state: State) => state.app.currentDate);
1416
const dateKey = formatUTCDate(currentDate);
1517
const dataUrl =
@@ -43,7 +45,7 @@ export const Charts = () => {
4345
justifyContent: "center",
4446
}}
4547
>
46-
<NavigationTitle title={"Deutschlandweite Graphen"} />
48+
<NavigationTitle title={t("pages.charts")} />
4749
<div style={{ width: "100%", height: "calc(100vh - 150px)" }}>
4850
<ResponsiveContainer>
4951
<LineChart
@@ -67,15 +69,15 @@ export const Charts = () => {
6769
dataKey={"CI"}
6870
stroke="#8884d8"
6971
strokeWidth="4px"
70-
name="Kontaktindex C"
72+
name={t("charts.contact-index") as string}
7173
/>
7274
<Line
7375
yAxisId="right"
7476
type="monotone"
7577
dataKey={"R"}
7678
stroke="#f01a8d"
7779
strokeWidth="4px"
78-
name="Reproduktionszahl R"
80+
name={t("charts.reproduction-rate") as string}
7981
/>
8082
</LineChart>
8183
</ResponsiveContainer>

apps/official/components/pages/ContactBehavior.tsx

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,40 @@
11
import React from "react";
22
import Typography from "@material-ui/core/Typography";
33
import { NavigationTitle } from "app-config/components/NavigationTitle";
4+
import { Trans, useTranslation } from "react-i18next";
45

56
const ContactBehavior = () => {
7+
const { t } = useTranslation("translation");
8+
69
return (
710
<main className="sections">
811
<section>
9-
<NavigationTitle title="Kontaktverhalten" backToExpandedFeatureInfo={true} />
12+
<NavigationTitle title={t("pages.contact-behavior")} backToExpandedFeatureInfo={true} />
1013
</section>
1114

1215
<section>
13-
<Typography>Was ist das Kontaktverhalten und warum ist es wichtig?</Typography>
14-
<Typography>
15-
Das Virus wird von Mensch zu Mensch übertragen. Indem wir Kontakte reduzieren, können wir es dem Virus
16-
erschweren, sich in der Bevölkerung zu verbreiten. Dabei ist der{" "}
17-
<a href="https://www.rki.de/DE/Content/InfAZ/N/Neuartiges_Coronavirus/Projekte_RKI/R-Wert-Erlaeuterung.pdf?__blob=publicationFile">
18-
R-Wert
19-
</a>{" "}
20-
ist eine wichtige Maßzahl, mit der wir beurteilen können, ob wir es dem Virus schwer genug gemacht haben.
21-
</Typography>
22-
<Typography>
23-
Der R-Wert besagt, wie viele Personen von einer infizierten Person im Durchschnitt angesteckt werden. Wenn der
24-
R-Wert 1 beträgt, bedeutet dies, dass eine infizierte Person im Schnitt nur eine weitere ansteckt. Ziel ist
25-
es, durch Maßnahmen einen R Wert unter 1 zu erreichen, d.h., dass eine infizierte Person im Durchschnitt
26-
weniger als eine weitere Person ansteckt. Ein R-Wert oberhalb von 1 führt dagegen zu einer Kettenreaktion mit
27-
einem unkontrollierten Anstieg der Fallzahlen. Der R-Wert hängt einerseits von der Biologie des Virus ab ("wie
28-
ansteckungsfähig ist das Virus?"), andererseits von unserem Kontaktverhalten ("auf wie viele Personen treffe
29-
ich?"). Während wir die Biologie des Virus nicht ändern können, können wir durch unser Kontaktverhalten einen
30-
großen Einfluss auf das Infektionsgeschehen nehmen. Indem wir unsere Kontakte reduzieren, können wir es auch
31-
einem hoch ansteckenden Virus so schwer machen, eine weitere Person zu infizieren, dass der R-Wert unter 1
32-
sinkt.
33-
</Typography>
34-
<Typography>
35-
Das Problem des R-Werts ist es, dass er das Infektionsgeschehen mit mehreren Tage Verzögerung abbildet, da er
36-
aus der Zahl der bestätigten Infektionen berechnet wird. Dies erscheint auch logisch, wenn man bedenkt, dass
37-
man nach einer Ansteckung mit dem Coronavirus nicht sofort Symptome entwickelt und auch das Ergebnis eines
38-
Labortests mit mehreren Tagen Verzögerung dem Robert-Koch-Institut mitgeteilt wird. Der R-Wert ist somit immer
39-
ein Blick in die Vergangenheit.
40-
</Typography>
16+
<Typography>{t("contact-behavior.intro")}</Typography>
4117
<Typography>
42-
Unsere Gruppe hat ein{" "}
43-
<a href="https://www.medrxiv.org/content/10.1101/2020.10.02.20188136v2">
44-
Modell für das Kontaktverhalten auf Basis von GPS Daten
45-
</a>{" "}
46-
entwickelt. Über die Berechnung eines sogenannten Kontakt-Index können wir den R-Wert vorhersagen. Der Vorteil
47-
vom Kontakt-Index ist nun, dass er fast ohne Verzögerung berechnet werden kann.
18+
<Trans i18nKey="contact-behavior.text-1">
19+
part-0
20+
<a href={t("contact-behavior.external-explanation-reproduction-rate")} target="_blank" rel="noopener">
21+
link-title
22+
</a>
23+
part-2
24+
</Trans>
4825
</Typography>
26+
<Typography>{t("contact-behavior.text-2")}</Typography>
27+
<Typography>{t("contact-behavior.text-3")}</Typography>
4928
<Typography>
50-
Von einem erhöhten Kontaktverhalten sprechen wir, wenn unser Modell voraussagt, dass in einer Region so viele
51-
Kontakte vorhanden sind, dass sich das Virus leicht ausbreiten kann und wir davon ausgehen, dass der R-Wert
52-
über 1 liegen wird.
29+
<Trans i18nKey="contact-behavior.text-4">
30+
part-0
31+
<a href="https://www.medrxiv.org/content/10.1101/2020.10.02.20188136v2" target="_blank" rel="noopener">
32+
Modell für das Kontaktverhalten auf Basis von GPS Daten
33+
</a>
34+
part-2
35+
</Trans>
5336
</Typography>
37+
<Typography>{t("contact-behavior.text-5")}</Typography>
5438
</section>
5539
</main>
5640
);

0 commit comments

Comments
 (0)