Skip to content

Commit

Permalink
Add first example implementation of basic translation
Browse files Browse the repository at this point in the history
  • Loading branch information
jansim committed Jul 27, 2023
1 parent 8f0075b commit 663f90a
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
53 changes: 53 additions & 0 deletions packages/jspsych/src/JsPsych.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ export class JsPsych {
// of jsPsych
webaudio_context: AudioContext = null;

/**
* the currently active locale (if specified)
*/
locale: string | undefined = undefined;

internal = {
/**
* this flag is used to determine whether we are in a scope where
Expand Down Expand Up @@ -117,10 +122,15 @@ export class JsPsych {
override_safe_mode: false,
case_sensitive_responses: false,
extensions: [],
translations: {},
locale: undefined,
fallback_locale: undefined,
...options,
};
this.opts = options;

this.locale = this.opts.locale;

autoBind(this); // so we can pass JsPsych methods as callbacks and `this` remains the JsPsych instance

this.webaudio_context =
Expand Down Expand Up @@ -379,6 +389,49 @@ export class JsPsych {
return this.timeline.allTimelineVariables();
}

setLocale(locale: string) {
this.locale = locale;
}

translate(key: string) {
// TODO: This should support string processing + maybe more i18n features

// First pass at translation using the current locale
const locale = this.locale;
if (locale) {
const translation = this.searchTranslation(locale, key);
if (translation !== undefined) {
return translation;
}
}
// Second pass using the fallback_locale
const fallbackLocale = this.opts.fallback_locale;
if (fallbackLocale) {
const translation = this.searchTranslation(fallbackLocale, key);
if (translation !== undefined) {
return translation;
}
}
// If nothing is found, default to return the original translation key
return key;
}

private searchTranslation(locale: string, key: string) {
// First search for translations on the trial itself
if (
this.current_trial.translations &&
locale in this.current_trial.translations &&
key in this.current_trial.translations[locale]
) {
return this.current_trial.translations[locale][key];
}
// Then search for global translations
if (locale in this.opts.translations && key in this.opts.translations?.[locale]) {
return this.opts.translations[locale][key];
}
return undefined;
}

addNodeToEndOfTimeline(new_timeline, preload_callback?) {
this.timeline.insert(new_timeline);
}
Expand Down
73 changes: 73 additions & 0 deletions packages/jspsych/tests/core/i18n.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
import { pressKey, startTimeline } from "@jspsych/test-utils";

import { initJsPsych } from "../../src";

describe("translations are correctly fetched", () => {
test("when drawing from the global translations", async () => {
const jsPsych = initJsPsych({
locale: "de",
translations: {
de: {
"Hello World!": "Hallo Welt!",
},
},
});
const { getHTML } = await startTimeline(
[
{
type: htmlKeyboardResponse,
stimulus: () => jsPsych.translate("Hello World!"),
on_finish: () => {
jsPsych.setLocale("en");
},
},
{
type: htmlKeyboardResponse,
stimulus: () => jsPsych.translate("Hello World!"),
},
],
jsPsych
);

expect(getHTML()).toMatch("Hallo Welt!");
pressKey("a");
expect(getHTML()).toMatch("Hello World!");
});

test("when drawing from trial-level translations", async () => {
const jsPsych = initJsPsych({
locale: "de",
});
const { getHTML } = await startTimeline(
[
{
type: htmlKeyboardResponse,
stimulus: () => jsPsych.translate("Hello World!"),
translations: {
de: {
"Hello World!": "Hallo Welt!",
},
},
on_finish: () => {
jsPsych.setLocale("en");
},
},
{
type: htmlKeyboardResponse,
stimulus: () => jsPsych.translate("Hello World!"),
translations: {
de: {
"Hello World!": "Hallo Welt!",
},
},
},
],
jsPsych
);

expect(getHTML()).toMatch("Hallo Welt!");
pressKey("a");
expect(getHTML()).toMatch("Hello World!");
});
});

0 comments on commit 663f90a

Please sign in to comment.