Multi language questions
One of the most important features of rumbas is that it is easy to create different language versions of the same question.
Create a new rumbas project
- Create a new folder
multi_language_questions
for this tutorial. - Create a
.rumbasrc.yaml
file (with the right content) in this folder. - Create a
questions
folder in this folder. - Create an
exams
folder in this folder. - Create a
defaults
folder in this folder.
Translating the statement
Currently our question with variables is defined in yaml as follows:
---
type: normal
statement: How much is 9 * {a}?
advice: You could calculate 10 * {a} and then subtract {a}. This yields {a} * 10 - {a} = {a * 10} - {a} = {a*9}
parts:
- type: number_entry
prompt: Enter your answer in the inputbox
marks: 5
answer: a * 9
variables:
a: 3
Currently this question is only available in English. We want to make this question available in Dutch as well.
Let's take a look again at the structure of a questions.
Question
field | type | description |
---|---|---|
statement | Translation | The statement is a content area which appears at the top of the question, before any input boxes. Use the statement to set up the question and provide any information the student needs to answer it. |
advice | Translation | Advice is a content area which is shown when the student presses the Reveal button to reveal the question’s answers, or at the end of the exam. The advice area is normally used to present a worked solution to the question. |
parts | Array of QuestionPart | A question consists of one or more parts. Each part can have a different type to create elaborate questions. |
builtin_constants | BuiltinConstants | Specifies which constants are enabled. You might want to disable the constant e so it can be used as a variable in the questions. |
custom_constants | Array of CustomConstant | Custom constants that are used in your question. |
variables | Map from String to VariableRepresentation | The (ungrouped) variables that are used in this question. |
grouped_variables | "none" or Map from String to Map from String to VariableRepresentation | The (grouped) variables that are used in this question. This is a map from a group name to a map of variables. Should mainly be used to make it easier to template multiple variables at once. |
variables_test | VariablesTest | The test to which your variables should comply. Sometimes it’s hard to define randomised question variables so they’re guaranteed to produce a usable set of values. In these cases, it’s easier to state the condition you want the variables to satisfy, Variable values are generated until this condition passes.While this tool allows you to pick sets of variables that would be hard to generate constructively, it’s a random process so you must be aware that there’s a chance no suitable set of values will ever be found. |
functions | Map from String to Function | The functions that are used in this question |
preamble | Preamble | Specify custom javascript and css code that should be loaded. |
navigation | QuestionNavigation | Specify some navigation options for the question. |
extensions | Extensions | Use this to enable the extensions that are used in the question |
diagnostic_topic_names | Array of Translation | The names of the topics used in diagnostic exams that this question belongs to |
resources | Array of ResourcePath | The paths to the resources |
custom_part_types | Array of CustomPartTypeDefinitionPath | The custom part types used in this exam |
rulesets | Map from String to JMERulesetItem | The rulesets defined in this question. A “ruleset” defines a list of named simplification rules used to manipulate mathematical expressions. https://numbas-editor.readthedocs.io/en/latest/question/reference.html#rulesets |
We see that the statement
and advice
fields have the type Translation
.
Translation
One of the following items:
type | description |
---|---|
TranslationStruct | A structured translatable string with placeholders. |
FileString | A simple filestring. This implies that it can also just be a string. |
For now we will focus on the first option, the TranslationStruct
.
TranslationStruct
field | type | description |
---|---|---|
content | TranslationContent | The content with optional placeholders ({{placeholder-name}}). |
placeholders | Map from String to Translation | The values for the placeholders. It maps the placeholder-name to it's translatable value. The value for a placeholder can thus (if needed) be different for different locales. |
---
content: # the content of form TranslationContent
placeholders: {} # empty for now
Let's now have a look at TranslationContent
.
TranslationContent
One of the following items:
type | description |
---|---|
Map from String to FileString | Map from locale to content. You can use this to specify different content for different locales. |
FileString | A filestring. Possibly to a file that is placed in locale folders and is therefore localized. |
The first option is the most important for now. It says that we can specify different versions of the content in different languages by using a hash.
---
content:
en: english content
nl: dutch content
placeholders: {} # empty for now
Update the statement
, advice
and prompt
fields of the first_question_with_variables.yaml
question to make it available in Dutch as shown below.
---
type: normal
statement:
content:
en: How much is 9 * {a}?
nl: Hoeveel is 9 * {a}?
placeholders: {}
advice:
content:
en: You could calculate 10 * {a} and then subtract {a}. This yields {a} * 10 - {a} = {a * 10} - {a} = {a*9}
nl: Je kan 10 * {a} berekenen en dan {a} daarvan aftrekken. Dit geeft {a} * 10 - {a} = {a * 10} - {a} = {a*9}
placeholders: {}
parts:
- type: number_entry
prompt:
content:
en: Enter your answer in the inputbox
nl: Geef je antwoord in in het invulveld
placeholders: {}
marks: 5
answer: a * 9
variables:
a: 3
Take a good look at the output of the compilation. You should see that all successful compilations happened 'with locale en'.
---
- name: en # custom name
numbas_locale: en-GB # English (United Kingdom)
---
- name: en # custom name
numbas_locale: en-GB # English (United Kingdom)
- name: nl # custom name
numbas_locale: nl-NL # Dutch (The Netherlands)
You can access the dutch exams at http://localhost:8000/nl/exams/first_question_with_variables/
You can also find the dutch exam and english exam in the online demo.
Placeholders
If we look at statement
and advice
we see that some values (mostly math expressions) are language independant.
---
type: normal
statement:
content:
en: How much is 9 * {a}?
nl: Hoeveel is 9 * {a}?
placeholders: {}
advice:
content:
en: You could calculate 10 * {a} and then subtract {a}. This yields {a} * 10 - {a} = {a * 10} - {a} = {a*9}
nl: Je kan 10 * {a} berekenen en dan {a} daarvan aftrekken. Dit geeft {a} * 10 - {a} = {a * 10} - {a} = {a*9}
placeholders: {}
parts:
- type: number_entry
prompt:
content:
en: Enter your answer in the inputbox
nl: Geef je antwoord in in het invulveld
placeholders: {}
marks: 5
answer: a * 9
variables:
a: 3
This is where placeholders come in. Placeholders can be specified by name and then be used in the content
field by writing {name}
.
---
type: normal
statement:
content:
en: How much is {formula}?
nl: Hoeveel is {formula}?
placeholders:
formula: 9 * {a}
advice:
content:
en: You could calculate {times10} and then subtract {a}. This yields {result}
nl: Je kan {times10} berekenen en dan {a} daarvan aftrekken. Dit geeft {result}
placeholders:
times10: 10 * {a}
result: '{a} * 10 - {a} = {a * 10} - {a} = {a*9}'
parts:
- type: number_entry
prompt:
content:
en: Enter your answer in the inputbox
nl: Geef je antwoord in in het invulveld
placeholders: {}
marks: 5
answer: a * 9
variables:
a: 3
Recompile all exams. You should see no difference but there are less chances to have different formulas in the different languages.
You can also use the placeholders the other way around. This is mainly useful when almost the whole string is maths and some small parts need to be translated. This might not work for all languages due to different grammar rules etc. For example:
---
content: "{command} $5x^2-10$."
placeholders:
command:
content:
nl: Ontbind in factoren
en: Factorize
placeholders: {}
Locale Folders
It might happen that you want to use the same text in different questions or exams. This is where the FileString
type comes in.
Translation
One of the following items:
type | description |
---|---|
TranslationStruct | A structured translatable string with placeholders. |
FileString | A simple filestring. This implies that it can also just be a string. |
Let's take a look at the FileString
type.
FileString
One of the following items:
type | description |
---|---|
String | A string of the form file:<filepath> where filepath is the relative path (within the exams or questions folder) to a file containing content. This content can be localized by placing it in locale folders. e.g. file:examples/basic-explanation.html will search for files in folders with following form: questions/examples/locale-<localename>/basic-explanation.html If a file isn't found for a specific locale, questions/examples/basic-explanation.html will be used. |
String | A literal string. |
A filestring is thus one of the following:
- A string that starts with
file:
followed by a path to a file - Another string that is interpreted literally as text.
In the first option, it is possible to use locale folders to specify different versions of the file for different locales.
Using the FileString
type in combination with locale folders gives us a powerful mechanism to reuse text in different questions and exams.
This yields following yaml code for the question
---
type: normal
statement:
content: how-much.html
placeholders:
formula: 9 * {a}
advice:
content:
en: You could calculate {times10} and then subtract {a}. This yields {result}
nl: Je kan {times10} berekenen en dan {a} daarvan aftrekken. Dit geeft {result}
placeholders:
times10: 10 * {a}
result: '{a} * 10 - {a} = {a * 10} - {a} = {a*9}'
parts:
- type: number_entry
prompt:
content:
en: Enter your answer in the inputbox
nl: Geef je antwoord in in het invulveld
placeholders: {}
marks: 5
answer: a * 9
variables:
a: 3
And questions/locale-nl/how-much.html
file:
Hoeveel is {formula}?
And questions/locale-en/how-much.html
file:
How much is {formula}?