Skip to content

Commit 8e0db80

Browse files
Config message approach for translations.
1 parent 54e7d87 commit 8e0db80

File tree

5 files changed

+54
-24
lines changed

5 files changed

+54
-24
lines changed

src/board/buttons.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,14 @@ export class Button {
1414
constructor(
1515
private id: "buttonA" | "buttonB",
1616
private element: SVGElement,
17-
label: string,
17+
private label: () => string,
1818
private onChange: (change: Partial<State>) => void
1919
) {
2020
this._presses = 0;
2121
this.state = new RangeSensor(id, 0, 1, 0, undefined);
2222

2323
this.element.setAttribute("role", "button");
2424
this.element.setAttribute("tabindex", "0");
25-
this.element.ariaLabel = label;
2625
this.element.style.cursor = "pointer";
2726

2827
this.keyListener = (e) => {
@@ -64,6 +63,10 @@ export class Button {
6463
this.element.addEventListener("mouseleave", this.mouseLeaveListener);
6564
}
6665

66+
updateTranslations() {
67+
this.element.ariaLabel = this.label();
68+
}
69+
6770
setValue(value: any) {
6871
this.setValueInternal(value, false);
6972
}

src/board/i18n.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/board/index.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
import { DataLogging } from "./data-logging";
1313
import { Display } from "./display";
1414
import { FileSystem } from "./fs";
15-
import { formattedMessage } from "./i18n";
1615
import { Microphone } from "./microphone";
1716
import { Pin } from "./pins";
1817
import { Radio } from "./radio";
@@ -57,6 +56,22 @@ export class Board {
5756

5857
private epoch: number | undefined;
5958

59+
// The language and translations can be changed via the "config" message.
60+
private language: string = "en";
61+
private translations: Record<string, string> = {
62+
"button-a": "Button A",
63+
"button-b": "Button B",
64+
"touch-logo": "Touch logo",
65+
"start-simulator": "Start simulator",
66+
};
67+
formattedMessage = ({ id }: { id: string }): string => {
68+
const result = this.translations[id];
69+
if (!result) {
70+
console.trace(`No string for code ${id}`);
71+
}
72+
return result ?? id;
73+
};
74+
6075
constructor(
6176
public operations: WebAssemblyOperations,
6277
private notifications: Notifications,
@@ -71,13 +86,13 @@ export class Board {
7186
new Button(
7287
"buttonA",
7388
this.svg.querySelector("#ButtonA")!,
74-
formattedMessage({ id: "button-a" }),
89+
() => this.formattedMessage({ id: "button-a" }),
7590
onChange
7691
),
7792
new Button(
7893
"buttonB",
7994
this.svg.querySelector("#ButtonB")!,
80-
formattedMessage({ id: "button-b" }),
95+
() => this.formattedMessage({ id: "button-b" }),
8196
onChange
8297
),
8398
];
@@ -86,7 +101,7 @@ export class Board {
86101
"pinLogo",
87102
{
88103
element: this.svg.querySelector("#Logo")!,
89-
label: formattedMessage({ id: "touch-logo" }),
104+
label: () => this.formattedMessage({ id: "touch-logo" }),
90105
},
91106
onChange
92107
);
@@ -118,13 +133,29 @@ export class Board {
118133

119134
this.stoppedOverlay = document.querySelector(".play-button-container")!;
120135
this.playButton = document.querySelector(".play-button")!;
121-
this.playButton.ariaLabel = formattedMessage({ id: "start-simulator" });
122136
this.initializePlayButton();
123137
// We start stopped.
124138
this.displayStoppedState();
125139
this.playButton.addEventListener("click", () =>
126140
this.notifications.onRequestFlash()
127141
);
142+
143+
this.updateTranslationsInternal();
144+
}
145+
146+
updateTranslations(language: string, translations: Record<string, string>) {
147+
this.language = language;
148+
this.translations = translations;
149+
this.updateTranslationsInternal();
150+
}
151+
152+
private updateTranslationsInternal() {
153+
document.documentElement.lang = this.language;
154+
this.playButton.ariaLabel = this.formattedMessage({
155+
id: "start-simulator",
156+
});
157+
this.buttons.forEach((b) => b.updateTranslations());
158+
this.pins.forEach((b) => b.updateTranslations());
128159
}
129160

130161
getState(): State {
@@ -392,6 +423,11 @@ export const createMessageListener = (board: Board) => (e: MessageEvent) => {
392423
if (e.source === window.parent) {
393424
const { data } = e;
394425
switch (data.kind) {
426+
case "config": {
427+
const { language, translations } = data;
428+
board.updateTranslations(language, translations);
429+
break;
430+
}
395431
case "flash": {
396432
const { filesystem } = data;
397433
if (!isFileSystem(filesystem)) {

src/board/pins.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export class Pin {
1212

1313
constructor(
1414
private id: "pin0" | "pin1" | "pin2" | "pinLogo",
15-
private ui: { element: SVGElement; label: string },
15+
private ui: { element: SVGElement; label: () => string } | null,
1616
private onChange: (changes: Partial<State>) => void
1717
) {
1818
this.state = new RangeSensor(id, 0, 1, 0, undefined);
@@ -21,7 +21,6 @@ export class Pin {
2121
const { element, label } = this.ui;
2222
element.setAttribute("role", "button");
2323
element.setAttribute("tabindex", "0");
24-
element.ariaLabel = label;
2524
element.style.cursor = "pointer";
2625
}
2726

@@ -99,6 +98,12 @@ export class Pin {
9998
return !!this.state.value;
10099
}
101100

101+
updateTranslations() {
102+
if (this.ui) {
103+
this.ui.element.ariaLabel = this.ui.label();
104+
}
105+
}
106+
102107
render() {
103108
if (this.ui) {
104109
const fill = !!this.state.value ? "red" : "url(#an)";

src/simulator.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html>
2+
<html lang="en">
33
<head>
44
<title>Simulator</title>
55
<meta charset="UTF-8" />

0 commit comments

Comments
 (0)