@@ -12,7 +12,6 @@ import {
12
12
import { DataLogging } from "./data-logging" ;
13
13
import { Display } from "./display" ;
14
14
import { FileSystem } from "./fs" ;
15
- import { formattedMessage } from "./i18n" ;
16
15
import { Microphone } from "./microphone" ;
17
16
import { Pin } from "./pins" ;
18
17
import { Radio } from "./radio" ;
@@ -57,6 +56,22 @@ export class Board {
57
56
58
57
private epoch : number | undefined ;
59
58
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
+
60
75
constructor (
61
76
public operations : WebAssemblyOperations ,
62
77
private notifications : Notifications ,
@@ -71,13 +86,13 @@ export class Board {
71
86
new Button (
72
87
"buttonA" ,
73
88
this . svg . querySelector ( "#ButtonA" ) ! ,
74
- formattedMessage ( { id : "button-a" } ) ,
89
+ ( ) => this . formattedMessage ( { id : "button-a" } ) ,
75
90
onChange
76
91
) ,
77
92
new Button (
78
93
"buttonB" ,
79
94
this . svg . querySelector ( "#ButtonB" ) ! ,
80
- formattedMessage ( { id : "button-b" } ) ,
95
+ ( ) => this . formattedMessage ( { id : "button-b" } ) ,
81
96
onChange
82
97
) ,
83
98
] ;
@@ -86,7 +101,7 @@ export class Board {
86
101
"pinLogo" ,
87
102
{
88
103
element : this . svg . querySelector ( "#Logo" ) ! ,
89
- label : formattedMessage ( { id : "touch-logo" } ) ,
104
+ label : ( ) => this . formattedMessage ( { id : "touch-logo" } ) ,
90
105
} ,
91
106
onChange
92
107
) ;
@@ -118,13 +133,29 @@ export class Board {
118
133
119
134
this . stoppedOverlay = document . querySelector ( ".play-button-container" ) ! ;
120
135
this . playButton = document . querySelector ( ".play-button" ) ! ;
121
- this . playButton . ariaLabel = formattedMessage ( { id : "start-simulator" } ) ;
122
136
this . initializePlayButton ( ) ;
123
137
// We start stopped.
124
138
this . displayStoppedState ( ) ;
125
139
this . playButton . addEventListener ( "click" , ( ) =>
126
140
this . notifications . onRequestFlash ( )
127
141
) ;
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 ( ) ) ;
128
159
}
129
160
130
161
getState ( ) : State {
@@ -392,6 +423,11 @@ export const createMessageListener = (board: Board) => (e: MessageEvent) => {
392
423
if ( e . source === window . parent ) {
393
424
const { data } = e ;
394
425
switch ( data . kind ) {
426
+ case "config" : {
427
+ const { language, translations } = data ;
428
+ board . updateTranslations ( language , translations ) ;
429
+ break ;
430
+ }
395
431
case "flash" : {
396
432
const { filesystem } = data ;
397
433
if ( ! isFileSystem ( filesystem ) ) {
0 commit comments