@@ -17,6 +17,81 @@ let user_gave_up = false; // True if user ever gave up before user solved it
1717
1818let startTime = Date . now ( ) ;
1919
20+ // Current language
21+ let lang ;
22+
23+ const resources = {
24+ en : {
25+ translation : {
26+ already_correct : 'The answer is already correct!' ,
27+ congrats : 'Congratulations! Your answer is correct!' ,
28+ congrats_all : 'Great work! All your answers are correct!' ,
29+ expecting : "We were expecting an answer like this:\n{0}" ,
30+ give_up_title : 'Give up and show an answer.' ,
31+ hint_title : 'Provide a hint given current attempt.' ,
32+ no_hints : 'Sorry, there are no hints for this lab.' ,
33+ no_matching_hint : 'Sorry, I cannot find a hint that matches your attempt.' ,
34+ reset_title : 'Reset initial state (throwing away current attempt).' ,
35+ try_harder : "Try harder! Don't give up so soon. Current time spent (in seconds): {0}" ,
36+ }
37+ } ,
38+ ja : {
39+ translation : {
40+ already_correct : '答えはすでに正しいです!' ,
41+ congrats : '「おめでとうございます!」あなたの答えは正解です!' ,
42+ congrats_all : '素晴らしい仕事でした!あなたの答えはすべて正解です!' ,
43+ expecting : "次のような答えを期待していました:\n{0}" ,
44+ give_up_title : '諦めて答えを示してください。' ,
45+ hint_title : '現在の試行に関するヒントを提供します。' ,
46+ no_hints : '申し訳ありませんが、このラボにはヒントがありません。' ,
47+ no_matching_hint : '申し訳ありませんが、あなたの試みに一致するヒントが見つかりません。' ,
48+ reset_title : '初期状態をリセットします (現在の試行を破棄します)。' ,
49+ try_harder : '「もっと頑張ってください! すぐに諦めないでください。現在の所要時間 (秒): {0}」' ,
50+ }
51+ } ,
52+ }
53+
54+ // Create a "format" method to simplify internationalization.
55+ // Use as: "Demo {0} result"".format(name);
56+ // https://www.geeksforgeeks.org/what-are-the-equivalent-of-printf-string-format-in-javascript/
57+ String . prototype . format = function ( ) {
58+ const args = arguments ;
59+ return this . replace ( / { ( \d + ) } / g, function ( match , number ) {
60+ return typeof args [ number ] != 'undefined'
61+ ? args [ number ]
62+ : match ;
63+ } ) ;
64+ } ;
65+
66+ // Retrieve translation for given key from resources.
67+ function t ( key ) {
68+ let result = resources [ lang ] [ 'translation' ] [ key ] ;
69+
70+ if ( result === undefined ) {
71+ result = resources [ 'en' ] [ 'translation' ] [ key ] ;
72+ }
73+ return result ;
74+ }
75+
76+ // Retrieve translation from object for given field
77+ function retrieve_t ( obj , field ) {
78+ let result = obj [ field + "_" + lang ] ;
79+
80+ if ( result === undefined ) {
81+ result = obj [ field ] ;
82+ }
83+ return result ;
84+ }
85+
86+ function determine_locale ( ) {
87+ let lang = document . documentElement . lang ;
88+ if ( ! lang ) {
89+ lang = 'en' ;
90+ }
91+ return lang ;
92+ }
93+
94+
2095// This array contains the default pattern preprocessing commands, in order.
2196// We process every pattern through these (in order) to create a final regex
2297// to be used to match a pattern.
@@ -197,7 +272,7 @@ function calcOneMatch(attempt, index = 0, correct = correctRe) {
197272 */
198273function calcMatch ( attempt , correct = correctRe ) {
199274 if ( ! correct ) { // Defensive test, should never happen.
200- alert ( 'Internal failure, correct value not defined or empty.' ) ;
275+ alert ( 'Error: Internal failure, correct value not defined or empty.' ) ;
201276 return false ;
202277 }
203278 for ( let i = 0 ; i < correct . length ; i ++ ) {
@@ -344,9 +419,9 @@ function runCheck() {
344419 setTimeout ( function ( ) {
345420 let congrats_text ;
346421 if ( correctRe . length > 1 ) {
347- congrats_text = 'Great work! All your answers are correct!' ;
422+ congrats_text = t ( 'congrats' ) ;
348423 } else {
349- congrats_text = 'Congratulations! Your answer is correct!' ;
424+ congrats_text = t ( 'congrats_all' ) ;
350425 }
351426 alert ( congrats_text ) ;
352427 } , 100 ) ;
@@ -366,10 +441,10 @@ function findHint(attempt, validIndexes = undefined) {
366441 hint . presentRe . test ( attempt [ hint . index ] ) ) &&
367442 ( ! hint . absentRe ||
368443 ! hint . absentRe . test ( attempt [ hint . index ] ) ) ) {
369- return hint . text ;
444+ return retrieve_t ( hint , ' text' ) ;
370445 }
371446 } ;
372- return 'Sorry, I cannot find a hint that matches your attempt.' ;
447+ return t ( 'no_matching_hint' ) ;
373448}
374449
375450/** Show a hint to the user. */
@@ -378,9 +453,9 @@ function showHint(e) {
378453 // alert(`Form id = ${e.target.form.id}`);
379454 let attempt = retrieveAttempt ( ) ;
380455 if ( calcMatch ( attempt , correctRe ) ) {
381- alert ( 'The answer is already correct!' ) ;
456+ alert ( t ( 'already_correct' ) ) ;
382457 } else if ( ! hints ) {
383- alert ( 'Sorry, there are no hints for this lab.' ) ;
458+ alert ( t ( 'no_hints' ) ) ;
384459 } else {
385460 let validIndexes = findIndexes ( e . target . form ) ;
386461 alert ( findHint ( attempt , validIndexes ) ) ;
@@ -393,7 +468,7 @@ function showAnswer(e) {
393468 if ( ! user_solved ) {
394469 user_gave_up = true ;
395470 }
396- alert ( `We were expecting an answer like this:\n ${ goodAnswer } ` ) ;
471+ alert ( t ( ' expecting' ) . format ( goodAnswer ) ) ;
397472}
398473
399474// "Give up" only shows the answer after this many seconds have elapsed.
@@ -403,7 +478,7 @@ function maybeShowAnswer(e) {
403478 let currentTime = Date . now ( ) ;
404479 let elapsedTime = ( currentTime - startTime ) / 1000 ; // in seconds
405480 if ( elapsedTime < MIN_DELAY_TIME ) {
406- alert ( "Try harder! Don't give up so soon. Current time spent (in seconds): " + elapsedTime ) ;
481+ alert ( t ( 'try_harder' ) . format ( elapsedTime . toString ( ) ) ) ;
407482 } else {
408483 showAnswer ( e ) ;
409484 }
@@ -431,7 +506,7 @@ function processHints(requestedHints) {
431506
432507 // Hints must only contain these fields, since we ignore the rest.
433508 const allowedHintFields = new Set (
434- [ 'present' , 'absent' , 'text' , 'examples' , 'index' ,
509+ [ 'present' , 'absent' , 'text' , 'text_ja' , ' examples', 'index' ,
435510 'preprocessing' ] ) ;
436511
437512 // Process each hint
@@ -662,6 +737,9 @@ function initPage() {
662737 // Run a selftest on page load, to prevent later problems
663738 runSelftest ( ) ;
664739
740+ // Set current locale
741+ lang = determine_locale ( ) ;
742+
665743 // Set up user interaction for all attempts.
666744 let current = 0 ;
667745 while ( true ) {
@@ -673,19 +751,19 @@ function initPage() {
673751 for ( let hintButton of document . querySelectorAll ( "button.hintButton" ) ) {
674752 hintButton . addEventListener ( 'click' , ( e ) => { showHint ( e ) ; } ) ;
675753 if ( ! hintButton . title ) {
676- hintButton . title = 'Provide a hint given current attempt.' ;
754+ hintButton . title = t ( 'hint_title' ) ;
677755 }
678756 }
679757 for ( let resetButton of document . querySelectorAll ( "button.resetButton" ) ) {
680758 resetButton . addEventListener ( 'click' , ( e ) => { resetForm ( e ) ; } ) ;
681759 if ( ! resetButton . title ) {
682- resetButton . title = 'Reset initial state (throwing away current attempt).' ;
760+ resetButton . title = t ( 'reset_title' ) ;
683761 }
684762 }
685763 for ( let giveUpButton of document . querySelectorAll ( "button.giveUpButton" ) ) {
686764 giveUpButton . addEventListener ( 'click' , ( e ) => { maybeShowAnswer ( e ) ; } ) ;
687765 if ( ! giveUpButton . title ) {
688- giveUpButton . title = 'Give up and show an answer.' ;
766+ giveUpButton . title = t ( 'give_up_title' ) ;
689767 }
690768 }
691769 if ( info . debug ) {
0 commit comments