From 8c53008c8f018ea4fd69975a879856283be50e7b Mon Sep 17 00:00:00 2001 From: joshunrau Date: Fri, 5 Jun 2026 10:08:42 -0400 Subject: [PATCH 1/2] add translations to TMB_MOT --- .../TMB_MOT/TestMyBrain.12.18.min.js | 5 - lib/interactive/TMB_MOT/index.ts | 26 +++- lib/interactive/TMB_MOT/render.js | 132 ++++++++---------- lib/interactive/TMB_MOT/snap.0.5.1.min.js | 4 - lib/interactive/TMB_MOT/translator.ts | 114 +++++++++++++++ 5 files changed, 190 insertions(+), 91 deletions(-) create mode 100644 lib/interactive/TMB_MOT/translator.ts diff --git a/lib/interactive/TMB_MOT/TestMyBrain.12.18.min.js b/lib/interactive/TMB_MOT/TestMyBrain.12.18.min.js index bdd2350..6616145 100644 --- a/lib/interactive/TMB_MOT/TestMyBrain.12.18.min.js +++ b/lib/interactive/TMB_MOT/TestMyBrain.12.18.min.js @@ -56,7 +56,6 @@ function showFrame() { for ( tmbObjs.frames.length || (tmbObjs.frames = document.getElementsByTagName('div')), t = tmbObjs.frames.length; t--; - ) ((e = n.indexOf(tmbObjs.frames[t].id) > -1 ? 'block' : 'none'), tmbObjs.frames[t].style.display !== e && (tmbObjs.frames[t].style.display = e)); @@ -70,7 +69,6 @@ function showFrameClass() { for ( tmbObjs.frames.length || (tmbObjs.frames = document.getElementsByTagName('div')), t = tmbObjs.frames.length; t--; - ) ((e = n.indexOf(tmbObjs.frames[t].className) > -1 ? 'block' : 'none'), tmbObjs.frames[t].style.display !== e && (tmbObjs.frames[t].style.display = e)); @@ -517,7 +515,6 @@ function imagePreLoad(e, t) { (t.addEventListener('load', c, !0), t.addEventListener('error', c, !0), (t.id = e), (t.src = e)); }; l > 0; - ) (l--, d(n.shift())); } @@ -3362,7 +3359,6 @@ var saveTextAs = s = void 0 === a ? n : a >> 0, u = 0 > s ? Math.max(n + s, 0) : Math.min(s, n); u > i; - ) ((t[i] = e), i++); return t; @@ -3472,7 +3468,6 @@ var zen = tmbObjs, r = n.length, o = (window.console = window.console || {}); r--; - ) ((e = n[r]), o[e] || (o[e] = t)); })(), diff --git a/lib/interactive/TMB_MOT/index.ts b/lib/interactive/TMB_MOT/index.ts index 5ed9afd..c76eec4 100644 --- a/lib/interactive/TMB_MOT/index.ts +++ b/lib/interactive/TMB_MOT/index.ts @@ -22,8 +22,11 @@ const staticAssets = { export default defineInstrument({ kind: 'INTERACTIVE', - language: 'en', - tags: ['TestMyBrain'], + language: ['en', 'fr'], + tags: { + en: ['TestMyBrain'], + fr: ['TestMyBrain'] + }, internal: { edition: 1, name: 'TMB_MOT' @@ -43,16 +46,27 @@ export default defineInstrument({ }, render, html, - staticAssets + staticAssets, + enableLanguageLock: true, + enableLanguageSelect: true }, clientDetails: { estimatedDuration: 1, - instructions: ['Instructions will be presented on screen in the task.'] + instructions: { + en: ['Instructions will be presented on screen in the task.'], + fr: ["Les instructions seront présentées à l'écran pendant la tâche."] + } }, details: { - description: 'An attention task that measures the ability to track multiple moving objects simultaneously.', + description: { + en: 'An attention task that measures the ability to track multiple moving objects simultaneously.', + fr: 'Une tâche attentionnelle qui mesure la capacité à suivre simultanément plusieurs objets en mouvement.' + }, license: 'LGPL-3.0', - title: 'TMB Multiple Object Tracking' + title: { + en: 'TMB Multiple Object Tracking', + fr: 'TMB Suivi d’objets multiples' + } }, measures: {}, validationSchema: z.any() diff --git a/lib/interactive/TMB_MOT/render.js b/lib/interactive/TMB_MOT/render.js index 4e4e811..732470d 100644 --- a/lib/interactive/TMB_MOT/render.js +++ b/lib/interactive/TMB_MOT/render.js @@ -1,7 +1,19 @@ // @ts-nocheck /* eslint-disable */ +import { translator } from './translator.ts'; + export function render(done) { + translator.init(); + + function tFormat(key, vars) { + var s = translator.t(key); + if (vars) { + for (var k in vars) s = s.replace(new RegExp('\\{' + k + '\\}', 'g'), vars[k]); + } + return s; + } + var circle = []; // Array of SVG circles objects var happy = []; // array of happy targets var sad = []; // array of sad targets @@ -54,15 +66,17 @@ export function render(done) { function beginNoPractice() { showAlert( "

' + + translator.t('optionalPractice.intro') + + '

' + "

', - 'Click here to continue', + translator.t('buttons.clickContinue'), function () { practiceChoice = document.getElementById('practice').value; setFrameSequence(); @@ -356,7 +370,7 @@ export function render(done) { if (frame.type === 'test') { // update the score score++; - getID('textRight').innerHTML = 'Score ' + score; + getID('textRight').innerHTML = translator.t('trial.score') + ' ' + score; } } } @@ -406,7 +420,8 @@ export function render(done) { nextTrial(); }, 1500); } else if (frame.type === 'practice') { - var msg = '



You got ' + targetClicks + ' of ' + numTargets + ' dots correct.


'; + var msg = + '



' + tFormat('trial.youGot', { hits: targetClicks, total: numTargets }) + '


'; // deal with practice errors if (targetClicks < numTargets) { @@ -415,12 +430,7 @@ export function render(done) { // rewind the trials chain by one frameSequence.unshift(frame); - msg = - "

Let's try again.

" + - 'When the movement stops,
' + - 'click the ' + - numTargets + - ' dots that flashed.


'; + msg = '

' + tFormat('trial.tryAgain', { n: numTargets }) + '


'; practiceErr++; } @@ -430,7 +440,7 @@ export function render(done) { setTimeout(function () { showAlert( msg, - 'Click here to continue', + translator.t('buttons.clickContinue'), function () { showFrame('null'); nextTrial(); @@ -462,8 +472,8 @@ export function render(done) { // update and show the trial counter and score if (trialCount === 6 || demo === 'true') trialCount = 0; trialCount++; - getID('textLeft').innerHTML = trialCount + ' of 6'; - getID('textRight').innerHTML = 'Score ' + score; + getID('textLeft').innerHTML = tFormat('trial.trialOf', { n: trialCount }); + getID('textRight').innerHTML = translator.t('trial.score') + ' ' + score; } // then set the motion scheduler @@ -511,7 +521,7 @@ export function render(done) { // subtract any points they got before timing out if (frame.type === 'test') { score = score - targetClicks; - getID('textRight').innerHTML = 'Score ' + score; + getID('textRight').innerHTML = translator.t('trial.score') + ' ' + score; } // if we are debugging, log the results @@ -521,10 +531,8 @@ export function render(done) { frameSequence.unshift(frame); showAlert( - 'You took too long to respond!

' + - 'Remember:
once the movement stops,
' + - 'click the dots that flashed.


', - 'Click here to retry', + translator.t('trial.tookTooLong') + '


', + translator.t('buttons.clickRetry'), function () { showFrame('null'); nextTrial(); @@ -541,8 +549,8 @@ export function render(done) { timestamp = now(); if (frame.type === 'practice') - getID('textMiddle').innerHTML = 'Click the ' + numTargets + ' dots that flashed!'; - else if (frame.type === 'test') getID('textMiddle').innerHTML = 'Click ' + numTargets + ' dots'; + getID('textMiddle').innerHTML = tFormat('trial.clickFlashedPractice', { n: numTargets }); + else if (frame.type === 'test') getID('textMiddle').innerHTML = tFormat('trial.clickDots', { n: numTargets }); } else setTimeout(function () { nextTrial(); @@ -611,7 +619,7 @@ export function render(done) { if (frame.type === 'begin') showAlert( frame.message, - 'Click here for instructions', + translator.t('buttons.clickInstructions'), function () { nextTrial(); }, @@ -621,7 +629,7 @@ export function render(done) { else if (frame.type === 'message') showAlert( frame.message, - 'Click here to continue', + translator.t('buttons.clickContinue'), function () { showFrame('null'); nextTrial(); @@ -679,59 +687,31 @@ export function render(done) { function setFrameSequence() { var testMessage = { - begin: '

Splitting Your Attention

' + '

', + begin: '

' + translator.t('instructions.title') + '

' + '

', instruction1: - '

Instructions:

' + + '

' + + translator.t('instructions.heading') + + '

' + '

' + - '
Keep track of the dots that flash,
' + - 'they have green smiles behind them.


', + '
' + + translator.t('instructions.keepTrack') + + '


', practice2: - '

Instructions:

' + - 'Next time, when the movement stops,
' + - 'click the 2 dots that flashed.

' + - 'The other dots have
' + - 'red sad faces behind them.
' + + '

' + + translator.t('instructions.heading') + + '

' + + translator.t('instructions.practiceClickTwo') + + '
' + '
' + - 'Try not to click on those.

', - practice3: '


Good!

' + "Now we'll do the same thing with
" + '3 flashing dots.

', - targets3: - '

Great!

' + - "Now we'll do 6 more with 3 dots.
" + - 'Motion is slow at first, then gets faster.
' + - 'This will be the first of 3 parts.

' + - 'When you lose track of dots, just guess.
' + - 'Your score will be the total number of
' + - 'green smiles that you click.

', - targets3_noPrac: - 'The first part of the test has 3 flashing dots.
' + - 'Motion is slow at first, then gets faster.
' + - 'This will be the first of 3 parts.

' + - 'When you lose track of dots, just guess.
' + - 'Your score will be the total number of
' + - 'green smiles that you click.

', - targets4: - '
Excellent!

' + - 'You have finished the first part of this test.
' + - '' + - 'There are two parts left.

' + - 'The next part has 4 flashing dots.
' + - 'Motion is slow at first, then gets faster.

' + - 'When you lose track of dots, just guess.
' + - 'Every smile you click adds to your score!

', - targets5: - '
Outstanding!

' + - 'Now there is only one part left!

' + - 'The final part has 5 flashing dots!
' + - 'Motion is slow at first, then gets faster.

' + - 'When you lose track of dots, just guess.
' + - 'Every smile you click adds to your score!

', - emaTargets5: - 'You will do this task
' + - 'with 5 flashing dots!
' + - 'Motion is slow at first, then gets faster.

' + - 'When you lose track of dots, just guess.
' + - 'Every smile you click adds to your score!

', - noprac: 'Remember:

' + 'Click on the dots with the green
' + 'smiley faces behind them.

' + translator.t('instructions.tryNotToClick') + + '

', + practice3: '


' + translator.t('instructions.good3Dots') + '

', + targets3: '

' + translator.t('instructions.targets3') + '

', + targets3_noPrac: translator.t('instructions.targets3NoPrac') + '

', + targets4: '
' + translator.t('instructions.targets4') + '

', + targets5: '
' + translator.t('instructions.targets5') + '

', + emaTargets5: translator.t('instructions.emaTargets5') + '

', + noprac: translator.t('instructions.noprac') + '

' }; // set the random generator's seed diff --git a/lib/interactive/TMB_MOT/snap.0.5.1.min.js b/lib/interactive/TMB_MOT/snap.0.5.1.min.js index b246e3e..b892d9e 100644 --- a/lib/interactive/TMB_MOT/snap.0.5.1.min.js +++ b/lib/interactive/TMB_MOT/snap.0.5.1.min.js @@ -1440,7 +1440,6 @@ k = g.toTransformString(), l = m(g) == m(this.matrix) ? m(b.transform) : k; 'svg' != e.type && (e = e.parent()); - ) i.push(h(e)); for (d = i.length; d--; ) j.add(i[d]); @@ -2134,7 +2133,6 @@ return (b.normalize && b.normalize(), b); }; c.firstChild; - ) c.removeChild(c.firstChild); for (var f = d(a); f.firstChild; ) c.appendChild(f.firstChild); @@ -3411,7 +3409,6 @@ }, k = 0; 1e6 >= g && !k; - ) { for (var l = 0, n = d.length; n > l; l++) { var o = j(l); @@ -3781,7 +3778,6 @@ }, r = i.length; r--; - ) !(function (b) { ((a[b] = f[b] = diff --git a/lib/interactive/TMB_MOT/translator.ts b/lib/interactive/TMB_MOT/translator.ts new file mode 100644 index 0000000..2ad9f4b --- /dev/null +++ b/lib/interactive/TMB_MOT/translator.ts @@ -0,0 +1,114 @@ +import { Translator } from '/runtime/v1/@opendatacapture/runtime-core'; + +export const translator = new Translator({ + translations: { + optionalPractice: { + intro: { + en: 'You are about to take:
TMB Multiple Object Tracking.

If you have taken this test before,
please choose whether to:', + fr: 'Vous êtes sur le point de passer :
TMB Suivi d’objets multiples.

Si vous avez déjà passé ce test,
veuillez choisir :' + }, + skip: { + en: 'Skip the practice trials', + fr: 'Sauter les essais d’entraînement' + }, + retake: { + en: 'Re-take the practice trials', + fr: 'Refaire les essais d’entraînement' + } + }, + buttons: { + clickContinue: { + en: 'Click here to continue', + fr: 'Cliquez ici pour continuer' + }, + clickInstructions: { + en: 'Click here for instructions', + fr: 'Cliquez ici pour les instructions' + }, + clickRetry: { + en: 'Click here to retry', + fr: 'Cliquez ici pour réessayer' + } + }, + trial: { + score: { + en: 'Score', + fr: 'Score' + }, + trialOf: { + en: '{n} of 6', + fr: '{n} sur 6' + }, + youGot: { + en: 'You got {hits} of {total} dots correct.', + fr: 'Vous avez identifié correctement {hits} points sur {total}.' + }, + tryAgain: { + en: 'Let’s try again.

When the movement stops,
click the {n} dots that flashed.', + fr: 'Essayons à nouveau.

Lorsque le mouvement s’arrête,
cliquez sur les {n} points qui ont clignoté.' + }, + tookTooLong: { + en: 'You took too long to respond!

Remember:
once the movement stops,
click the dots that flashed.', + fr: 'Vous avez mis trop de temps à répondre !

Rappel :
une fois le mouvement arrêté,
cliquez sur les points qui ont clignoté.' + }, + clickFlashedPractice: { + en: 'Click the {n} dots that flashed!', + fr: 'Cliquez sur les {n} points qui ont clignoté !' + }, + clickDots: { + en: 'Click {n} dots', + fr: 'Cliquez sur {n} points' + } + }, + instructions: { + title: { + en: 'Splitting Your Attention', + fr: 'Diviser votre attention' + }, + heading: { + en: 'Instructions:', + fr: 'Instructions :' + }, + keepTrack: { + en: 'Keep track of the dots that flash,
they have green smiles behind them.', + fr: 'Suivez les points qui clignotent,
ils ont un sourire vert derrière eux.' + }, + practiceClickTwo: { + en: 'Next time, when the movement stops,
click the 2 dots that flashed.

The other dots have
red sad faces behind them.', + fr: 'La prochaine fois, lorsque le mouvement s’arrête,
cliquez sur les 2 points qui ont clignoté.

Les autres points ont
un visage triste rouge derrière eux.' + }, + tryNotToClick: { + en: 'Try not to click on those.', + fr: 'Essayez de ne pas cliquer sur ceux-là.' + }, + good3Dots: { + en: 'Good!

Now we’ll do the same thing with
3 flashing dots.', + fr: 'Bien !

Nous allons maintenant faire la même chose avec
3 points clignotants.' + }, + targets3: { + en: 'Great!

Now we’ll do 6 more with 3 dots.
Motion is slow at first, then gets faster.
This will be the first of 3 parts.

When you lose track of dots, just guess.
Your score will be the total number of
green smiles that you click.', + fr: 'Super !

Nous allons maintenant en faire 6 autres avec 3 points.
Le mouvement est lent au début, puis s’accélère.
Ce sera la première des 3 parties.

Lorsque vous perdez les points de vue, devinez simplement.
Votre score sera le nombre total de
sourires verts sur lesquels vous cliquez.' + }, + targets3NoPrac: { + en: 'The first part of the test has 3 flashing dots.
Motion is slow at first, then gets faster.
This will be the first of 3 parts.

When you lose track of dots, just guess.
Your score will be the total number of
green smiles that you click.', + fr: 'La première partie du test comporte 3 points clignotants.
Le mouvement est lent au début, puis s’accélère.
Ce sera la première des 3 parties.

Lorsque vous perdez les points de vue, devinez simplement.
Votre score sera le nombre total de
sourires verts sur lesquels vous cliquez.' + }, + targets4: { + en: 'Excellent!

You have finished the first part of this test.
There are two parts left.

The next part has 4 flashing dots.
Motion is slow at first, then gets faster.

When you lose track of dots, just guess.
Every smile you click adds to your score!', + fr: 'Excellent !

Vous avez terminé la première partie de ce test.
Il reste deux parties.

La partie suivante comporte 4 points clignotants.
Le mouvement est lent au début, puis s’accélère.

Lorsque vous perdez les points de vue, devinez simplement.
Chaque sourire sur lequel vous cliquez augmente votre score !' + }, + targets5: { + en: 'Outstanding!

Now there is only one part left!

The final part has 5 flashing dots!
Motion is slow at first, then gets faster.

When you lose track of dots, just guess.
Every smile you click adds to your score!', + fr: 'Remarquable !

Il ne reste plus qu’une partie !

La dernière partie comporte 5 points clignotants !
Le mouvement est lent au début, puis s’accélère.

Lorsque vous perdez les points de vue, devinez simplement.
Chaque sourire sur lequel vous cliquez augmente votre score !' + }, + emaTargets5: { + en: 'You will do this task
with 5 flashing dots!
Motion is slow at first, then gets faster.

When you lose track of dots, just guess.
Every smile you click adds to your score!', + fr: 'Vous ferez cette tâche
avec 5 points clignotants !
Le mouvement est lent au début, puis s’accélère.

Lorsque vous perdez les points de vue, devinez simplement.
Chaque sourire sur lequel vous cliquez augmente votre score !' + }, + noprac: { + en: 'Remember:

Click on the dots with the green
smiley faces behind them.', + fr: 'Rappel :

Cliquez sur les points ayant un
visage souriant vert derrière eux.' + } + } + } +}); From cd3e42491f624fc28827ad3f4b13d5e3e02d2d4b Mon Sep 17 00:00:00 2001 From: joshunrau Date: Fri, 5 Jun 2026 10:36:44 -0400 Subject: [PATCH 2/2] add translations for TMB_LN_SWITCHING --- .../TMB_LN_SWITCHING/TestMyBrain.12.18.min.js | 5 -- lib/interactive/TMB_LN_SWITCHING/index.ts | 27 ++++-- lib/interactive/TMB_LN_SWITCHING/render.js | 86 ++++++++++-------- .../TMB_LN_SWITCHING/translator.ts | 90 +++++++++++++++++++ 4 files changed, 157 insertions(+), 51 deletions(-) create mode 100644 lib/interactive/TMB_LN_SWITCHING/translator.ts diff --git a/lib/interactive/TMB_LN_SWITCHING/TestMyBrain.12.18.min.js b/lib/interactive/TMB_LN_SWITCHING/TestMyBrain.12.18.min.js index 0df5e7f..a37ffbb 100644 --- a/lib/interactive/TMB_LN_SWITCHING/TestMyBrain.12.18.min.js +++ b/lib/interactive/TMB_LN_SWITCHING/TestMyBrain.12.18.min.js @@ -56,7 +56,6 @@ function showFrame() { for ( tmbObjs.frames.length || (tmbObjs.frames = document.getElementsByTagName('div')), t = tmbObjs.frames.length; t--; - ) ((e = n.indexOf(tmbObjs.frames[t].id) > -1 ? 'block' : 'none'), tmbObjs.frames[t].style.display !== e && (tmbObjs.frames[t].style.display = e)); @@ -70,7 +69,6 @@ function showFrameClass() { for ( tmbObjs.frames.length || (tmbObjs.frames = document.getElementsByTagName('div')), t = tmbObjs.frames.length; t--; - ) ((e = n.indexOf(tmbObjs.frames[t].className) > -1 ? 'block' : 'none'), tmbObjs.frames[t].style.display !== e && (tmbObjs.frames[t].style.display = e)); @@ -517,7 +515,6 @@ function imagePreLoad(e, t) { (t.addEventListener('load', c, !0), t.addEventListener('error', c, !0), (t.id = e), (t.src = e)); }; l > 0; - ) (l--, d(n.shift())); } @@ -3362,7 +3359,6 @@ var saveTextAs = s = void 0 === a ? n : a >> 0, u = 0 > s ? Math.max(n + s, 0) : Math.min(s, n); u > i; - ) ((t[i] = e), i++); return t; @@ -3472,7 +3468,6 @@ var zen = tmbObjs, r = n.length, o = (window.console = window.console || {}); r--; - ) ((e = n[r]), o[e] || (o[e] = t)); })(), diff --git a/lib/interactive/TMB_LN_SWITCHING/index.ts b/lib/interactive/TMB_LN_SWITCHING/index.ts index c278d52..f6c4130 100644 --- a/lib/interactive/TMB_LN_SWITCHING/index.ts +++ b/lib/interactive/TMB_LN_SWITCHING/index.ts @@ -33,8 +33,11 @@ const staticAssets = { export default defineInstrument({ kind: 'INTERACTIVE', - language: 'en', - tags: ['TestMyBrain'], + language: ['en', 'fr'], + tags: { + en: ['TestMyBrain'], + fr: ['TestMyBrain'] + }, internal: { edition: 1, name: 'TMB_LN_SWITCHING' @@ -53,17 +56,27 @@ export default defineInstrument({ }, html, render, - staticAssets + staticAssets, + enableLanguageLock: true, + enableLanguageSelect: true }, clientDetails: { estimatedDuration: 1, - instructions: ['Instructions will be presented on screen in the task.'] + instructions: { + en: ['Instructions will be presented on screen in the task.'], + fr: ["Les instructions seront présentées à l'écran pendant la tâche."] + } }, details: { - description: - 'A task switching test that evaluates cognitive flexibility by alternating between letter and number categorization.', + description: { + en: 'A task switching test that evaluates cognitive flexibility by alternating between letter and number categorization.', + fr: 'Un test d’alternance de tâches qui évalue la flexibilité cognitive en alternant entre la catégorisation de lettres et de chiffres.' + }, license: 'LGPL-3.0', - title: 'Letter/Number Switching' + title: { + en: 'Letter/Number Switching', + fr: 'Alternance lettres/chiffres' + } }, measures: {}, validationSchema: z diff --git a/lib/interactive/TMB_LN_SWITCHING/render.js b/lib/interactive/TMB_LN_SWITCHING/render.js index 95d8eb0..582a4a4 100644 --- a/lib/interactive/TMB_LN_SWITCHING/render.js +++ b/lib/interactive/TMB_LN_SWITCHING/render.js @@ -1,7 +1,19 @@ // @ts-nocheck /* eslint-disable */ +import { translator } from './translator.ts'; + export function render(onComplete) { + translator.init(); + + function tFormat(key, vars) { + var s = translator.t(key); + if (vars) { + for (var k in vars) s = s.replace(new RegExp('\\{' + k + '\\}', 'g'), vars[k]); + } + return s; + } + var testVersion; // version identifier for this test var images = []; // images to load var chain; // chain of timeouts for stimulus presentation @@ -60,17 +72,18 @@ export function render(onComplete) { // and repeating the trial if (~frame.type.indexOf('practice') && !correct) { errorMessage = - 'Your target was the ' + - frame.judgement + - ' ' + - frame.target + - ':
' + + tFormat('practiceError.target', { + judgement: translator.t('judgement.' + frame.judgement), + target: frame.target + }) + + '
' + (frame.response === 'R' - ? 'you should have clicked
' + 'the right button.

' - : 'you should have clicked
' + 'the left button.

'); + ? translator.t('practiceError.shouldRight') + : translator.t('practiceError.shouldLeft')) + + '

'; showAlert( errorMessage, - 'Click here to retry', + translator.t('buttons.clickRetry'), function () { frameSequence.unshift(frame); showFrame('null'); @@ -89,8 +102,8 @@ export function render(onComplete) { frameSequence.unshift(frame); showAlert( - 'Please respond as quickly as you can.

' + 'Click the left or right button.

', - 'Click here to retry', + translator.t('timeout.message') + '

', + translator.t('buttons.clickRetry'), function () { showFrame('null'); setTimeout(function () { @@ -117,7 +130,7 @@ export function render(onComplete) { if (frame.type === 'begin') showAlert( frame.message, - 'Click here for instructions', + translator.t('buttons.clickInstructions'), function () { nextTrial(); }, @@ -127,7 +140,7 @@ export function render(onComplete) { else if (frame.type === 'message') showAlert( frame.message, - 'Click here to continue', + translator.t('buttons.clickContinue'), function () { showFrame('null'); nextTrial(); @@ -141,7 +154,9 @@ export function render(onComplete) { function () { requestAnimationFrame(function () { getID('sequence').innerHTML = frame.LN; - getID('judgement').innerHTML = frame.judgement.toString().toUpperCase(); + getID('judgement').innerHTML = frame.judgement + ? translator.t('judgement.' + frame.judgement).toUpperCase() + : ''; showFrame(null); }); }, @@ -244,40 +259,33 @@ export function render(onComplete) { // for a single trial/frame function setFrameSequence() { var TestMessage; + var instructionsHeading = '

' + translator.t('instructions.heading') + '

'; TestMessage = { - begin: '

Letter/Number Switching

' + "Title

", + begin: '

' + translator.t('instructions.title') + '

' + "Title

", instructions: [ - '

Instructions

' + + instructionsHeading + "Instructions

" + - 'Here your job is to report
' + - 'either the number or the letter
' + - 'in this letter/number pair.

', - '

Instructions

' + + translator.t('instructions.step1') + + '

', + instructionsHeading + "Instructions

" + - 'The word above the letter-number pair
' + - 'tells you what to report
' + - "(here it's the number).

", - '

Instructions

' + + translator.t('instructions.step2') + + '

', + instructionsHeading + "Instructions

" + - 'To report the number 1, you click
' + - 'the button that has that number (left).

', - '

Instructions

' + + translator.t('instructions.step3') + + '

', + instructionsHeading + "Instructions

" + - 'To report the letter z, you click
' + - 'the button that has that letter (right).

', - '

Instructions

' + + translator.t('instructions.step4') + + '

', + instructionsHeading + "Instructions

" + - "Let's do some practice.

", - 'Excellent!
' + 'You have completed the practice.

' + "Now let's do more.

" + translator.t('instructions.letsPractice') + + '

', + translator.t('instructions.excellent') + '

' ], - test: [ - 'Remember!

' + - 'Look at the word on top, then
' + - 'click the button that has
' + - 'the letter or number in the pair below.

' + - 'Please try to be QUICK,
' + - 'but also ACCURATE.

' - ] + test: [translator.t('test.remember') + '

'] }; // type of frame to display diff --git a/lib/interactive/TMB_LN_SWITCHING/translator.ts b/lib/interactive/TMB_LN_SWITCHING/translator.ts new file mode 100644 index 0000000..382d932 --- /dev/null +++ b/lib/interactive/TMB_LN_SWITCHING/translator.ts @@ -0,0 +1,90 @@ +import { Translator } from '/runtime/v1/@opendatacapture/runtime-core'; + +export const translator = new Translator({ + translations: { + buttons: { + clickContinue: { + en: 'Click here to continue', + fr: 'Cliquez ici pour continuer' + }, + clickInstructions: { + en: 'Click here for instructions', + fr: 'Cliquez ici pour les instructions' + }, + clickRetry: { + en: 'Click here to retry', + fr: 'Cliquez ici pour réessayer' + } + }, + judgement: { + letter: { + en: 'letter', + fr: 'lettre' + }, + number: { + en: 'number', + fr: 'chiffre' + } + }, + practiceError: { + target: { + en: 'Your target was the {judgement} {target}:', + fr: 'Votre cible était : {judgement} {target}' + }, + shouldRight: { + en: 'you should have clicked
the right button.', + fr: 'vous auriez dû cliquer
sur le bouton de droite.' + }, + shouldLeft: { + en: 'you should have clicked
the left button.', + fr: 'vous auriez dû cliquer
sur le bouton de gauche.' + } + }, + timeout: { + message: { + en: 'Please respond as quickly as you can.

Click the left or right button.', + fr: 'Veuillez répondre aussi vite que possible.

Cliquez sur le bouton de gauche ou de droite.' + } + }, + instructions: { + title: { + en: 'Letter/Number Switching', + fr: 'Alternance lettres/chiffres' + }, + heading: { + en: 'Instructions', + fr: 'Instructions' + }, + step1: { + en: 'Here your job is to report
either the number or the letter
in this letter/number pair.', + fr: 'Ici, votre tâche est de rapporter
soit le chiffre, soit la lettre
de cette paire lettre/chiffre.' + }, + step2: { + en: 'The word above the letter-number pair
tells you what to report
(here it’s the number).', + fr: 'Le mot au-dessus de la paire lettre-chiffre
vous indique quoi rapporter
(ici, c’est le chiffre).' + }, + step3: { + en: 'To report the number 1, you click
the button that has that number (left).', + fr: 'Pour rapporter le chiffre 1, vous cliquez
sur le bouton qui contient ce chiffre (gauche).' + }, + step4: { + en: 'To report the letter z, you click
the button that has that letter (right).', + fr: 'Pour rapporter la lettre z, vous cliquez
sur le bouton qui contient cette lettre (droite).' + }, + letsPractice: { + en: 'Let’s do some practice.', + fr: 'Faisons quelques essais d’entraînement.' + }, + excellent: { + en: 'Excellent!
You have completed the practice.

Now let’s do more.', + fr: 'Excellent !
Vous avez terminé l’entraînement.

Passons à la suite.' + } + }, + test: { + remember: { + en: 'Remember!

Look at the word on top, then
click the button that has
the letter or number in the pair below.

Please try to be QUICK,
but also ACCURATE.', + fr: 'Rappel !

Regardez le mot en haut, puis
cliquez sur le bouton qui contient
la lettre ou le chiffre de la paire ci-dessous.

Essayez d’être RAPIDE,
mais aussi PRÉCIS.' + } + } + } +});