Skip to content

Commit b65fdfa

Browse files
Add "config" message for translation (#44)
1 parent 6c3eebf commit b65fdfa

File tree

4 files changed

+74
-25
lines changed

4 files changed

+74
-25
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/index.ts

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ export class Board {
5858

5959
private epoch: number | undefined;
6060

61+
// The language and translations can be changed via the "config" message.
62+
private language: string = "en";
63+
private translations: Record<string, string> = {
64+
"button-a": "Button A",
65+
"button-b": "Button B",
66+
"touch-logo": "Touch logo",
67+
"start-simulator": "Start simulator",
68+
};
69+
formattedMessage = ({ id }: { id: string }): string => {
70+
const result = this.translations[id];
71+
if (!result) {
72+
console.trace(`No string for code ${id}`);
73+
}
74+
return result ?? id;
75+
};
76+
6177
constructor(
6278
public operations: WebAssemblyOperations,
6379
private notifications: Notifications,
@@ -72,26 +88,28 @@ export class Board {
7288
new Button(
7389
"buttonA",
7490
this.svg.querySelector("#ButtonA")!,
75-
"button A",
91+
() => this.formattedMessage({ id: "button-a" }),
7692
onChange
7793
),
7894
new Button(
7995
"buttonB",
8096
this.svg.querySelector("#ButtonB")!,
81-
"button B",
97+
() => this.formattedMessage({ id: "button-b" }),
8298
onChange
8399
),
84100
];
85101
this.pins = Array(33);
86102
this.pins[MICROBIT_HAL_PIN_FACE] = new Pin(
87103
"pinLogo",
88-
this.svg.querySelector("#Logo")!,
89-
"logo",
104+
{
105+
element: this.svg.querySelector("#Logo")!,
106+
label: () => this.formattedMessage({ id: "touch-logo" }),
107+
},
90108
onChange
91109
);
92-
this.pins[MICROBIT_HAL_PIN_P0] = new Pin("pin0", null, "pin 0", onChange);
93-
this.pins[MICROBIT_HAL_PIN_P1] = new Pin("pin1", null, "pin 1", onChange);
94-
this.pins[MICROBIT_HAL_PIN_P2] = new Pin("pin2", null, "pin 2", onChange);
110+
this.pins[MICROBIT_HAL_PIN_P0] = new Pin("pin0", null, onChange);
111+
this.pins[MICROBIT_HAL_PIN_P1] = new Pin("pin1", null, onChange);
112+
this.pins[MICROBIT_HAL_PIN_P2] = new Pin("pin2", null, onChange);
95113
this.audio = new Audio();
96114
this.temperature = new RangeSensor("temperature", -5, 50, 21, "°C");
97115
this.accelerometer = new Accelerometer(onChange);
@@ -123,6 +141,23 @@ export class Board {
123141
this.playButton.addEventListener("click", () =>
124142
this.notifications.onRequestFlash()
125143
);
144+
145+
this.updateTranslationsInternal();
146+
}
147+
148+
updateTranslations(language: string, translations: Record<string, string>) {
149+
this.language = language;
150+
this.translations = translations;
151+
this.updateTranslationsInternal();
152+
}
153+
154+
private updateTranslationsInternal() {
155+
document.documentElement.lang = this.language;
156+
this.playButton.ariaLabel = this.formattedMessage({
157+
id: "start-simulator",
158+
});
159+
this.buttons.forEach((b) => b.updateTranslations());
160+
this.pins.forEach((b) => b.updateTranslations());
126161
}
127162

128163
getState(): State {
@@ -499,6 +534,11 @@ export const createMessageListener = (board: Board) => (e: MessageEvent) => {
499534
if (e.source === window.parent) {
500535
const { data } = e;
501536
switch (data.kind) {
537+
case "config": {
538+
const { language, translations } = data;
539+
board.updateTranslations(language, translations);
540+
break;
541+
}
502542
case "flash": {
503543
const { filesystem } = data;
504544
if (!isFileSystem(filesystem)) {

src/board/pins.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ export class Pin {
1212

1313
constructor(
1414
private id: "pin0" | "pin1" | "pin2" | "pinLogo",
15-
private element: SVGElement | null,
16-
label: string,
15+
private ui: { element: SVGElement; label: () => string } | null,
1716
private onChange: (changes: Partial<State>) => void
1817
) {
1918
this.state = new RangeSensor(id, 0, 1, 0, undefined);
2019

21-
if (this.element) {
22-
this.element.setAttribute("role", "button");
23-
this.element.setAttribute("tabindex", "0");
24-
this.element.ariaLabel = label;
25-
this.element.style.cursor = "pointer";
20+
if (this.ui) {
21+
const { element, label } = this.ui;
22+
element.setAttribute("role", "button");
23+
element.setAttribute("tabindex", "0");
24+
element.style.cursor = "pointer";
2625
}
2726

2827
this.keyListener = (e) => {
@@ -57,12 +56,13 @@ export class Pin {
5756
}
5857
};
5958

60-
if (this.element) {
61-
this.element.addEventListener("mousedown", this.mouseDownListener);
62-
this.element.addEventListener("mouseup", this.mouseUpListener);
63-
this.element.addEventListener("keydown", this.keyListener);
64-
this.element.addEventListener("keyup", this.keyListener);
65-
this.element.addEventListener("mouseleave", this.mouseLeaveListener);
59+
if (this.ui) {
60+
const { element } = this.ui;
61+
element.addEventListener("mousedown", this.mouseDownListener);
62+
element.addEventListener("mouseup", this.mouseUpListener);
63+
element.addEventListener("keydown", this.keyListener);
64+
element.addEventListener("keyup", this.keyListener);
65+
element.addEventListener("mouseleave", this.mouseLeaveListener);
6666
}
6767
}
6868

@@ -98,10 +98,16 @@ export class Pin {
9898
return !!this.state.value;
9999
}
100100

101+
updateTranslations() {
102+
if (this.ui) {
103+
this.ui.element.ariaLabel = this.ui.label();
104+
}
105+
}
106+
101107
render() {
102-
if (this.element) {
108+
if (this.ui) {
103109
const fill = !!this.state.value ? "red" : "url(#an)";
104-
this.element.querySelectorAll("path").forEach((p) => {
110+
this.ui.element.querySelectorAll("path").forEach((p) => {
105111
p.style.fill = fill;
106112
});
107113
}

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)