Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions docs/plugins/translate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# plugin-translate

This plugin enables dynamic language selection during a jsPsych experiment using the i18next translation framework. It can either prompt participants to choose a language from a dropdown menu or automatically switch to a specified locale. Language resources can be supplied directly, and selected language data is saved for each trial. This plugin is useful for multi-language studies, international deployments, or experiments requiring runtime translation changes.

The first `jsPsychPluginTranslate` trial in the timeline will set up (initialize) the translations. After that trial runs, you can access the translations throughout the rest of the experiment.

1. **Initialize translations with a `jsPsychPluginTranslate` trial.** This trial must include the translation resources and a default/initial language. It can prompt the participant to choose their language, or just set the language directly.

2. **Use the translations during the experiment.** After initializing translations with a `jsPsychPluginTranslate` trial, you can use the `jsPsychPluginTranslate` [class methods](#class-methods) in other parts of your experiment to retrieve translated text from the translation resources, based on the current locale. You can also change and retrieve the current locale at any point after initialization.

## Parameters

In addition to the [parameters available in all plugins](https://www.jspsych.org/latest/overview/plugins#parameters-available-in-all-plugins), this plugin accepts the following parameters. Parameters with a default value of `undefined` must be specified. Other parameters can be left unspecified if the default value is acceptable.

| Parameter | Type | Default Value | Description |
| ---------------------- | ------------ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `stimulus` | HTML\_STRING | `null` | HTML content shown to participants when selecting a language. Only displayed if `set_locale` is not set. Useful for presenting instructions or prompts. |
| `resources` | OBJECT | `null` | An object containing i18next-compatible language resources. Must be provided if i18next is not already initialized. Should be structured as `{ en: { translation: {...} }, de: { translation: {...} } }`. |
| `set_locale` | STRING | `null` | If provided, the plugin switches immediately to this locale without displaying a language selection interface. Must be a valid locale code. |
| `button_text` | STRING | "Next" | The label for the confirmation button shown when prompting for language selection. |
| `language_name_locale` | STRING | "en" | The locale to use for displaying language names in the dropdown menu. For example, "de" would display "Deutsch", "Englisch", etc.

## Class Methods

This plugin exposes these static methods on the `jsPsychPluginTranslate` class:

* `t(key, options)` — access i18next translation directly.
* `setLocale(locale)` — change language programmatically.
* `language()` — returns current language.
* `languages()` — returns supported languages.
* `resolvedLanguage()` — returns resolved language from i18next.

After the translations have been initialized with a `jsPsychPluginTranslate` trial, these methods can be used in the experiment code to retrieve a translated string (`t`), change the language (`setLocale`), and get the current language settings (`language`/`languages`/`resolvedLanguage`).

!!! info
The `jsPsychPluginTranslate` methods must be called _after_ translations have been initialized with a `jsPsychPluginTranslate` trial, so they should be used inside a function, such as in a [dynamic parameter](../overview/dynamic-parameters/) or in an [event-related callback function](../overview/events/).

## Data Generated

In addition to the [default data collected by all plugins](https://www.jspsych.org/latest/overview/plugins#data-collected-by-all-plugins), this plugin collects the following data for each trial:

| Name | Type | Value |
| -------- | ------ | -------------------------------------------------------------------- |
| `locale` | STRING | The locale selected or set during the trial, e.g., "en", "de", "es". |

## Install

Using the CDN-hosted JavaScript file:

```js
<script src="https://unpkg.com/@jspsych/plugin-translate@VERSION_HERE"></script>
```

Using the JavaScript file downloaded from a GitHub release dist archive:

```js
<script src="jspsych/plugin-translate.js"></script>
```

Using NPM:

```
npm install @jspsych/plugin-translate
```
```js
import jsPsychTranslate from '@jspsych/plugin-translate';
```

## Examples

### Initialize translations and prompt the participant to choose a language

This example will show the stimulus and a dropdown menu with all locale (language) options listed in the resources. The language names that correspond to the locale codes will be shown according to the 'language_name_locale' value (in this case, "English" for "en" and "German" for "de"). After the participant selects a language and clicks the next button, translations will be initialized and the language will be set to the participant's response.

```javascript
const init_user_set_language = {
type: jsPsychTranslate,
stimulus: "<p>Please choose your language:</p>",
resources: {
en: { translation: { greeting: "Hello!" } },
de: { translation: { greeting: "Hallo!" } }
},
button_text: "Continue",
language_name_locale: "en"
};
```

After this `init_user_set_language` trial runs, calling `jsPsychTranslate.t` with a key from the resources (e.g. "greeting") will return the translated string based on the locale set by the participant.

```javascript
const translated_greeting = {
type: jsPsychHtmlKeyboardResponse,
stimulus: () => jsPsychPluginTranslate.t("greeting")
};
```

Note that this uses a dynamic parameter for the `stimulus` because `jsPsychTranslate.t` can only be called after the translations have been initialized with a `jsPsychPluginTranslate` trial.

The `translated_greeting` trial will show "Hello!" as the stimulus if the participant selected English, or "Hallo!" if the participant selected German.

### Initialize translations and set locale without prompt

This example will intialize translations and set the language to German, without displaying anything to the participant.

```javascript
const init_set_language = {
type: jsPsychTranslate,
set_locale: "de",
resources: {
en: { translation: { greeting: "Hello!" } },
de: { translation: { greeting: "Hallo!" } }
}
};
```

After this `init_set_language` trial runs, you can call `jsPsychTranslate.t` to retrive a translated string from the resources, based on the `set_locale` value. In this example the language is set to German, so the `translated_greeting` trial below would show "Hallo!" as the stimulus.

```javascript
const translated_greeting = {
type: jsPsychHtmlKeyboardResponse,
stimulus: () => jsPsychPluginTranslate.t("greeting")
};
```

Note that this uses a dynamic parameter for the `stimulus` because `jsPsychTranslate.t` can only be called after the translations have been initialized with a `jsPsychPluginTranslate` trial.

### After initialization, change the locale without user prompt

The translation resources only need to be defined the first time you run the trial. After that, you can change the language during the experiment with a trial that just sets the `set_locale` value.

```javascript
const change_language = {
type: jsPsychTranslate,
set_locale: "es"
};
```

After this `change_language` trial runs, any text that is retrieved using `jsPsychTranslate.t` will return the Spanish (es) translations.
81 changes: 81 additions & 0 deletions examples/jspsych-translate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html>
<head>
<title>jsPsychTranslate Example</title>
<script src="../packages/jspsych/dist/index.browser.js"></script>
<script src="../packages/plugin-translate/dist/index.browser.js"></script>
<script src="https://unpkg.com/@jspsych/[email protected]"></script>
<link rel="stylesheet" href="../packages/jspsych/css/jspsych.css" />
</head>
<body></body>
<script>
const jsPsych = initJsPsych({
on_finish: function () {
jsPsych.data.displayData();
},
});

// allow participant to choose the language
const chooseLanguage = {
type: jsPsychPluginTranslate,
stimulus: "<p>Please choose your language:</p>",
resources: {
en: { translation: { greeting: "Hello!" } },
de: { translation: { greeting: "Hallo!" } },
es: { translation: { greeting: "Hola!" } },
},
button_text: "Continue",
language_name_locale: "en",
};

const hello = {
type: jsPsychHtmlButtonResponse,
stimulus: () =>
`<p style="font-size:48px;">${jsPsychPluginTranslate.t(
"greeting"
)}</p>`,
choices: ["Next"],
};

const transition = {
type: jsPsychHtmlButtonResponse,
stimulus: "Now the text will silently change to Spanish.",
choices: ["Next"],
};

// silently set the language without notifying participant
const silentlySetLanguage = {
type: jsPsychPluginTranslate,
set_locale: "de",
resources: {
en: { translation: { greeting: "Hello!" } },
de: { translation: { greeting: "Hallo!" } },
},
};

// silently change the language without notifying participant
const silentlyChangeLanguage = {
type: jsPsychPluginTranslate,
set_locale: "es",
};

const hello_again = {
type: jsPsychHtmlButtonResponse,
stimulus: () =>
`<p style="font-size:48px;">${jsPsychPluginTranslate.t(
"greeting"
)}</p>`,
choices: ["Next"],
};

const timeline = [
chooseLanguage,
hello,
transition,
silentlyChangeLanguage,
hello_again,
];

jsPsych.run(timeline);
</script>
</html>
68 changes: 55 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 41 additions & 0 deletions packages/plugin-translate/CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Courtney B. Hilton" # Replace with last name
given-names: "Courtney B. Hilton" # Replace with first name
name-particle: "Courtney B. Hilton" # Replace with name particle(s)
orcid: "https://orcid.org/0000-0000-0000-0000" # Replace with ORCID
# More authors can be listed here in the same format as above
contact: # Contact person for this extension
- family-names: "Courtney B. Hilton"
given-names: "Courtney B. Hilton"
email: "{email}" # Replace with contact person's email
orcid: "https://orcid.org/0000-0000-0000-0000" # Replace with contact person's ORCID
title: "jsPsychPluginTranslate"
version: 0.0.0
doi: 10.5281/zenodo.1234 # Replace with DOI
date-released: 2000-01-01
url: "{softwareUrl}" # Replace with URL to this extension

# If you wish to cite a paper on this extension instead, you can use the following template:
preferred-citation:
authors:
- family-names: "Courtney B. Hilton"
given-names: "Courtney B. Hilton"
name-particle: "Courtney B. Hilton"
orcid: "https://orcid.org/0000-0000-0000-0000"
# More authors can be listed here in the same format as above
date-published: 2023-05-11
doi: 10.21105/joss.12345
issn: 1234-5678
issue: 01
journal: Journal for Open Source Software
publisher:
name: Open Journals
start: 0001
title: "{title}"
type: article # Other options include: book, pamphlet, conference-paper...
url: "{linkToPublicationInJournal}"
volume: 1

# More information on the preffered-citation CFF format can be found at https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files#citing-something-other-than-software
Loading