Commit 63a19a6b authored by Konstantin Schulz's avatar Konstantin Schulz
Browse files

test module now has improved timers, exercise structure and evaluation

parent e7e5bd25
......@@ -13,13 +13,13 @@ const routes: Routes = [
{ path: 'preview', loadChildren: './preview/preview.module#PreviewPageModule' },
{ path: 'kwic', loadChildren: './kwic/kwic.module#KwicPageModule' },
{ path: 'ranking', loadChildren: './ranking/ranking.module#RankingPageModule' },
{ path: 'feedback', loadChildren: './feedback/feedback.module#FeedbackPageModule' },
{ path: 'change-language', loadChildren: './change-language/change-language.module#ChangeLanguagePageModule' }, { path: 'info', loadChildren: './info/info.module#InfoPageModule' },
{ path: 'sources', loadChildren: './sources/sources.module#SourcesPageModule' },
{ path: 'imprint', loadChildren: './imprint/imprint.module#ImprintPageModule' },
{ path: 'test', loadChildren: './test/test.module#TestPageModule' },
{ path: 'confirm-cancel', loadChildren: './confirm-cancel/confirm-cancel.module#ConfirmCancelPageModule' },
{ path: 'change-language', loadChildren: './change-language/change-language.module#ChangeLanguagePageModule' },
{ path: 'info', loadChildren: './info/info.module#InfoPageModule' },
{ path: 'sources', loadChildren: './sources/sources.module#SourcesPageModule' },
{ path: 'imprint', loadChildren: './imprint/imprint.module#ImprintPageModule' },
{ path: 'test', loadChildren: './test/test.module#TestPageModule' },
{ path: 'confirm-cancel', loadChildren: './confirm-cancel/confirm-cancel.module#ConfirmCancelPageModule' },
];
@NgModule({
......
import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule} from '@angular/forms';
import {Routes, RouterModule} from '@angular/router';
import {IonicModule} from '@ionic/angular';
import {FeedbackPage} from './feedback.page';
import {TranslateModule} from "@ngx-translate/core";
const routes: Routes = [
{
path: '',
component: FeedbackPage
}
];
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RouterModule.forChild(routes),
TranslateModule.forChild(),
],
declarations: [FeedbackPage]
})
export class FeedbackPageModule {
}
<ion-header>
<ion-toolbar>
<div class="toolbar-left">
<ion-back-button icon="arrow-round-back" defaultHref="home"></ion-back-button>
<ion-title>{{ 'MACHINA_CALLIDA' | translate }}</ion-title>
</div>
<div class="toolbar-right">
<ion-spinner *ngIf="HelperService.isLoading"></ion-spinner>
<button (click)="HelperService.goToHomePage(navCtrl)">
<ion-icon name="home"></ion-icon>
</button>
</div>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-grid>
<ion-row>
<ion-col>
<h1>{{ 'FEEDBACK' | translate }}</h1>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<!--suppress HtmlUnknownTarget -->
<a href="{{HelperService.config['developerMailTo']}}">{{ 'EMAIL' | translate }}</a>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FeedbackPage } from './feedback.page';
describe('FeedbackPage', () => {
let component: FeedbackPage;
let fixture: ComponentFixture<FeedbackPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FeedbackPage ],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FeedbackPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, OnDestroy} from '@angular/core';
import {NavController} from "@ionic/angular";
import {HelperService} from '../helper.service';
import {XAPIevent} from "src/app/models/xAPIevent";
import {TranslateService} from "@ngx-translate/core";
declare var H5P: any;
// dirty hack to prevent H5P access errors after resize events
window.onresize = () => {
/* tslint:disable:prefer-const */
/* tslint:disable:no-shadowed-variable */
let H5P: any;
/* tslint:enable:prefer-const */
/* tslint:enable:no-shadowed-variable */
};
@Component({
selector: 'app-feedback',
templateUrl: './feedback.page.html',
styleUrls: ['./feedback.page.scss'],
})
export class FeedbackPage implements OnDestroy {
Array = Array;
HelperService = HelperService;
public currentExercise: string = "";
public exercises: string[] = ["voc_list_1", "voc_list_2", "voc_list_3", "voc_list_4", "voc_list_5", "fill_blanks_1", "nonH5P_1", "multi_choice_1", "multi_choice_2", "multi_choice_3", "multi_choice_4", "multi_choice_5", "multi_choice_6", "multi_choice_7", "multi_choice_8", "fill_blanks_2", "fill_blanks_3", "fill_blanks_4", "fill_blanks_5", "multi_choice_9", "fill_blanks_6", "multi_choice_10", "multi_choice_11", "multi_choice_12", "multi_choice_13"];
constructor(public navCtrl: NavController, public translate: TranslateService) {
H5P.externalDispatcher.on('xAPI', (event: XAPIevent) => {
// results are only available when a task has been completed/answered, not in the "attempted" or "interacted" stages
if (event.data.statement.verb.id === HelperService.config["xAPIverbIDanswered"] && event.data.statement.result) {
// TODO: SAVE THIS SCORE BY SENDING IT TO THE BACKEND? OR WRITE THE WHOLE STATEMENT?
// console.log(event.data.statement.result.score.scaled);
const iframe: HTMLIFrameElement = <HTMLIFrameElement>document.getElementById("h5p-iframe-1");
const checkbox: HTMLInputElement = <HTMLInputElement>iframe.contentWindow.document.getElementById("known");
if (checkbox) {
const isVocabularyKnown: boolean = checkbox.checked;
}
this.showNextExercise(this.exercises.indexOf(this.currentExercise) + 1);
}
});
}
public initH5P(exerciseType: string) {
// dirty hack to get H5P going without explicit button click on the new page
setTimeout(() => {
(($) => {
$(() => {
$('.h5p-container').empty().h5p({
frameJs: 'assets/dist/js/h5p-standalone-frame.min.js',
frameCss: 'assets/dist/styles/h5p.css',
h5pContent: 'assets/h5p/' + exerciseType
});
});
})(H5P.jQuery);
}, 50);
}
ngOnDestroy() {
H5P.externalDispatcher.off('xAPI');
}
showNextExercise(newIndex: number) {
let oldIndex = this.exercises.indexOf(this.currentExercise);
let navLinks: HTMLCollection = document.getElementById("exerciseNav").children;
if (oldIndex > -1) {
// TODO: move highlighting & navigation to the results page
navLinks[oldIndex].children[0].classList.remove("highlight");
if (this.currentExercise.startsWith("nonH5P")) {
document.getElementById("h5p-row").classList.remove("hide");
}
}
this.currentExercise = this.exercises[newIndex];
navLinks[this.exercises.indexOf(this.currentExercise)].children[0].classList.add("highlight");
if (this.currentExercise.startsWith("nonH5P")) {
document.getElementById("h5p-row").classList.add("hide");
return;
}
let fileName: string = this.currentExercise.split("_").slice(-1) + "_" + this.translate.currentLang + ".json";
let exerciseType = this.currentExercise.split("_").slice(0, 2).join("_");
const baseUrl: string = location.protocol.concat('//').concat(window.location.host);
window.localStorage.setItem(HelperService.config['localStorageKeyH5P'], baseUrl + "/assets/h5p/" + exerciseType + "/content/" + fileName);
if (exerciseType.startsWith("voc_list")) {
exerciseType = "fill_blanks";
}
this.initH5P(exerciseType);
}
}
......@@ -11,9 +11,6 @@
<button (click)="changeLanguage($event).then()">
<img src="{{'assets/imgs/' + translate.currentLang + '.svg'}}" width="50px" height="30px">
</button>
<!--<button (click)="HelperService.goToFeedbackPage(navCtrl)">
<ion-icon name="help-circle"></ion-icon>
</button>-->
</div>
</ion-toolbar>
</ion-header>
......
import {CorpusMC} from 'src/app/models/corpusMC';
import {TextRange} from 'src/app/models/textRange';
import {Author} from 'src/app/models/author';
export class ApplicationState {
public currentCorpus: CorpusMC;
......
export class ExercisePart {
public durationSeconds: number;
public exercises: string[];
public startIndex: number;
constructor(init?: Partial<ExercisePart>) {
Object.assign(this, init);
}
}
......@@ -6,7 +6,6 @@
<div class="toolbar-right">
<ion-spinner *ngIf="HelperService.isLoading"></ion-spinner>
<span id="timer"></span>
<!-- HelperService.goToHomePage(navCtrl)-->
<button (click)="exit($event).then()">
<ion-icon name="close-circle"></ion-icon>
</button>
......@@ -15,19 +14,26 @@
</ion-header>
<ion-content padding>
<ion-grid style="text-align:left;">
<ion-grid>
<ion-row>
<ion-col>
{{ 'TEST_MODULE_GO_TO_EXERCISE' | translate}}
<ion-label>{{ 'TEST_MODULE_GO_TO_EXERCISE' | translate}}</ion-label>
<ion-select (ionChange)="showNextExercise(+selectedExerciseIndex -1)"
[(ngModel)]="selectedExerciseIndex" name="selectedExerciseIndex">
<ion-select-option *ngFor="let number of Array.from(Array(getExerciseCount()).keys())">
{{number + 1}}
</ion-select-option>
</ion-select>
</ion-col>
<ion-col id="exerciseNav">
<a *ngFor="let number of Array.from(Array(exercises.length).keys())" (click)="showNextExercise(number)">
<span>{{number + 1}}</span>&nbsp;
</a>
</ion-row>
<ion-row *ngIf="!results?.length">
<ion-col>
<ion-label>{{ 'TEST_MODULE_PROGRESS_PART' | translate }} {{getCurrentExercisePartIndex() + 1}}</ion-label>
<ion-progress-bar value="{{progressBarValue}}"></ion-progress-bar>
</ion-col>
</ion-row>
<!-- step 1: intro-->
<div *ngIf="currentExercise == 'nonH5P_1'">
<div *ngIf="currentExerciseIndex == 0">
<ion-row>
<ion-col>
<h4>{{ 'UNIT_INTRO_TITLE' | translate }}</h4>
......@@ -98,21 +104,15 @@
<!-- step 3: read the text and answer questions, preparing the exercise unit, 10min -->
<!-- step 4: fill in the gap exercise or learn voc, 15min -->
<!-- step 5: repeat the voc test, 5min -->
<div>
<ion-row id="h5p-row">
<ion-col>
<div class="h5p-container"></div>
</ion-col>
</ion-row>
<!--<ion-row style="text-align:right;">
<ion-col>
<ion-button (click)="showNextExercise()">{{ "BUTTON_CONTINUE" | translate}}</ion-button>
</ion-col>
</ion-row>-->
</div>
<ion-row id="h5p-row">
<ion-col>
<div class="h5p-container"></div>
</ion-col>
</ion-row>
<a id="evaluateNgIf"></a>
<!-- step 6: show results -->
<div *ngIf="currentExercise == 'nonH5P_2'">
<div *ngIf="results?.length">
<ion-row>
<ion-col>
<ion-card>
......@@ -130,47 +130,41 @@
<ion-item>
<ion-icon name="walk" slot="start"></ion-icon>
<ion-label>Ergebnis Üben:</ion-label>
<div *ngIf="testType == TestType.cloze; else list">{{results[2][0]}} von {{results[2][1]}}
Lücken wurden richtig ergänzt.
<div *ngIf="testType == TestType.cloze; else list">
{{results[2][0]}} von {{results[2][1]}} Lücken wurden richtig ergänzt.
</div>
<ng-template #list>
<!-- TODO: ADD RESULTS FOR LIST LEARNING -->
<!-- <div>{{results[2][0]}} von {{results[2][1]}} Wörtern wurden gelernt. Davon wurden ... Wörter-->
<!-- als "Kann ich" markiert.-->
<!-- </div>-->
{{results[2][0]}} von {{results[2][1]}} Wörtern wurden gelernt. Davon
wurden {{knownCount[0]}} Wörter als "Kann ich" markiert.
</ng-template>
</ion-item>
<ion-item>
<ion-icon name="pulse" slot="start"></ion-icon>
<ion-label>Ergebnis Wortschatztest:</ion-label>
... von ... Aufgaben wurden richtig bearbeitet.<br>
Veränderung gegenüber dem 1. Diagnosetest: ...%
{{results[3][0]}} von {{results[3][1]}} Aufgaben wurden richtig bearbeitet.<br>
Veränderung gegenüber dem 1.
Diagnosetest: {{ ((results[0][0] - results[3][0]) / (results[0][0] > 0 ? results[0][0] : 1)) * -100 }}
%
</ion-item>
<!--<ion-item>
<ion-icon name="medal" slot="start"></ion-icon>
<ion-label>Rang im Highscore:</ion-label>
Platz ... von ... Teilnehmern
</ion-item>-->
</ion-card>
</ion-col>
</ion-row>
<ion-row>
<ion-toolbar>
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button (click)="HelperService.goToAuthorPage(navCtrl)">
<ion-icon name="walk"></ion-icon>
<ion-label>{{ 'EXERCISE_GENERATE' | translate }}</ion-label>
</ion-tab-button>
<ion-tab-button (click)="HelperService.goToTestPage(navCtrl)">
<!-- Link doesn't work-->
<ion-icon name="school"></ion-icon>
<ion-label>{{ 'TEST_REPEAT' | translate }}</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-toolbar>
</ion-row>
</div>
</ion-grid>
</ion-content>
<ion-footer *ngIf="results?.length">
<ion-toolbar>
<ion-tabs>
<ion-tab-bar slot="bottom">
<ion-tab-button (click)="HelperService.goToAuthorPage(navCtrl)">
<ion-icon name="walk"></ion-icon>
<ion-label>{{ 'EXERCISE_GENERATE' | translate }}</ion-label>
</ion-tab-button>
<ion-tab-button (click)="reset()">
<ion-icon name="school"></ion-icon>
<ion-label>{{ 'TEST_REPEAT' | translate }}</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-toolbar>
</ion-footer>
ion-grid {
text-align: left;
}
ion-select {
max-width: 100px;
}
This diff is collapsed.
......@@ -88,7 +88,7 @@
"shouldNotCheck": "Should not have been checked",
"noInput": "Please answer before viewing the solution"
},
"question": "<p>Choose words that belong to the word field \"government\":<\/p>\n",
"question": "<p>Choose words that belong to the word field \"city\":<\/p>\n",
"behaviour": {
"enableRetry": false,
"enableSolutionsButton": true,
......@@ -134,4 +134,3 @@
}
]
}
\ No newline at end of file
{"questions": ["<p><h4>diligens, ntis </h4> *careful : careful*</p>"], "showSolutions": "Show solutions", "tryAgain": "Try again", "text": "<p>Give a translation.</p><br><p><label><input type=\"checkbox\" id=\"known\"> I already know this.</label></p>\n", "checkAnswer": "Check", "notFilledOut": "Please fill in all blanks", "behaviour": {"enableSolutionsButton": true, "autoCheck": false, "caseSensitive": false, "showSolutionsRequiresInput": false, "separateLines": false, "enableRetry": false, "disableImageZooming": true, "confirmCheckDialog": false, "confirmRetryDialog": false, "acceptSpellingErrors": false, "enableCheckButton": true}, "answerIsCorrect": "&#039;:ans&#039; is correct", "answerIsWrong": "&#039;:ans&#039; is wrong", "answeredCorrectly": "Answered correctly", "answeredIncorrectly": "Answered incorrectly", "solutionLabel": "Correct answer:", "inputLabel": "Blank input @num of @total", "inputHasTipLabel": "Tip available", "tipLabel": "Tip", "confirmCheck": {"header": "Finish ?", "body": "Are you sure you wish to finish ?", "cancelLabel": "Cancel", "confirmLabel": "Finish"}, "confirmRetry": {"header": "Retry ?", "body": "Are you sure you wish to retry ?", "cancelLabel": "Cancel", "confirmLabel": "Confirm"}, "overallFeedback": [{"from": 0, "to": 100, "feedback": "You got @score of @total blanks correct."}], "scoreBarLabel": "You got :num out of :total points"}
\ No newline at end of file
{
"questions": [
"<p><h4>diligens, ntis </h4> *careful : careful*</p>"
],
"showSolutions": "Show solutions",
"tryAgain": "Try again",
"text": "<p>Give a translation.</p><br><p><label><input type=\"checkbox\" id=\"known\"> I already know this.</label></p>\n",
"checkAnswer": "Check",
"notFilledOut": "Please fill in all blanks",
"behaviour": {
"enableSolutionsButton": true,
"autoCheck": false,
"caseSensitive": false,
"showSolutionsRequiresInput": false,
"separateLines": false,
"enableRetry": false,
"disableImageZooming": true,
"confirmCheckDialog": false,
"confirmRetryDialog": false,
"acceptSpellingErrors": false,
"enableCheckButton": true
},
"answerIsCorrect": "&#039;:ans&#039; is correct",
"answerIsWrong": "&#039;:ans&#039; is wrong",
"answeredCorrectly": "Answered correctly",
"answeredIncorrectly": "Answered incorrectly",
"solutionLabel": "Correct answer:",
"inputLabel": "Blank input @num of @total",
"inputHasTipLabel": "Tip available",
"tipLabel": "Tip",
"confirmCheck": {
"header": "Finish ?",
"body": "Are you sure you wish to finish ?",
"cancelLabel": "Cancel",
"confirmLabel": "Finish"
},
"confirmRetry": {
"header": "Retry ?",
"body": "Are you sure you wish to retry ?",
"cancelLabel": "Cancel",
"confirmLabel": "Confirm"
},
"overallFeedback": [
{
"from": 0,
"to": 100,
"feedback": "You got @score of @total blanks correct."
}
],
"scoreBarLabel": "You got :num out of :total points"
}
{"questions": ["<p><h4>custodia, ae, f. </h4> *guard : guard*</p>"], "showSolutions": "Show solutions", "tryAgain": "Try again", "text": "<p>Give a translation.</p><br><p><label><input type=\"checkbox\" id=\"known\"> I already know this.</label></p>\n", "checkAnswer": "Check", "notFilledOut": "Please fill in all blanks", "behaviour": {"enableSolutionsButton": true, "autoCheck": false, "caseSensitive": false, "showSolutionsRequiresInput": false, "separateLines": false, "enableRetry": false, "disableImageZooming": true, "confirmCheckDialog": false, "confirmRetryDialog": false, "acceptSpellingErrors": false, "enableCheckButton": true}, "answerIsCorrect": "&#039;:ans&#039; is correct", "answerIsWrong": "&#039;:ans&#039; is wrong", "answeredCorrectly": "Answered correctly", "answeredIncorrectly": "Answered incorrectly", "solutionLabel": "Correct answer:", "inputLabel": "Blank input @num of @total", "inputHasTipLabel": "Tip available", "tipLabel": "Tip", "confirmCheck": {"header": "Finish ?", "body": "Are you sure you wish to finish ?", "cancelLabel": "Cancel", "confirmLabel": "Finish"}, "confirmRetry": {"header": "Retry ?", "body": "Are you sure you wish to retry ?", "cancelLabel": "Cancel", "confirmLabel": "Confirm"}, "overallFeedback": [{"from": 0, "to": 100, "feedback": "You got @score of @total blanks correct."}], "scoreBarLabel": "You got :num out of :total points"}
\ No newline at end of file
{
"questions": [
"<p><h4>custodia, ae, f. </h4> *guard : guard*</p>"
],
"showSolutions": "Show solutions",
"tryAgain": "Try again",
"text": "<p>Give a translation.</p><br><p><label><input type=\"checkbox\" id=\"known\"> I already know this.</label></p>\n",
"checkAnswer": "Check",
"notFilledOut": "Please fill in all blanks",
"behaviour": {
"enableSolutionsButton": true,
"autoCheck": false,
"caseSensitive": false,
"showSolutionsRequiresInput": false,
"separateLines": false,
"enableRetry": false,
"disableImageZooming": true,
"confirmCheckDialog": false,
"confirmRetryDialog": false,
"acceptSpellingErrors": false,
"enableCheckButton": true
},
"answerIsCorrect": "&#039;:ans&#039; is correct",
"answerIsWrong": "&#039;:ans&#039; is wrong",
"answeredCorrectly": "Answered correctly",
"answeredIncorrectly": "Answered incorrectly",
"solutionLabel": "Correct answer:",
"inputLabel": "Blank input @num of @total",
"inputHasTipLabel": "Tip available",
"tipLabel": "Tip",
"confirmCheck": {
"header": "Finish ?",
"body": "Are you sure you wish to finish ?",
"cancelLabel": "Cancel",
"confirmLabel": "Finish"
},
"confirmRetry": {
"header": "Retry ?",
"body": "Are you sure you wish to retry ?",
"cancelLabel": "Cancel",
"confirmLabel": "Confirm"
},
"overallFeedback": [
{
"from": 0,
"to": 100,
"feedback": "You got @score of @total blanks correct."
}
],
"scoreBarLabel": "You got :num out of :total points"
}
{"questions": ["<p><h4>praestare, o, stiti </h4> *outperform : outperform*</p>"], "showSolutions": "Show solutions", "tryAgain": "Try again", "text": "<p>Give a translation.</p><br><p><label><input type=\"checkbox\" id=\"known\"> I already know this.</label></p>\n", "checkAnswer": "Check", "notFilledOut": "Please fill in all blanks", "behaviour": {"enableSolutionsButton": true, "autoCheck": false, "caseSensitive": false, "showSolutionsRequiresInput": false, "separateLines": false, "enableRetry": false, "disableImageZooming": true, "confirmCheckDialog": false, "confirmRetryDialog": false, "acceptSpellingErrors": false, "enableCheckButton": true}, "answerIsCorrect": "&#039;:ans&#039; is correct", "answerIsWrong": "&#039;:ans&#039; is wrong", "answeredCorrectly": "Answered correctly", "answeredIncorrectly": "Answered incorrectly", "solutionLabel": "Correct answer:", "inputLabel": "Blank input @num of @total", "inputHasTipLabel": "Tip available", "tipLabel": "Tip", "confirmCheck": {"header": "Finish ?", "body": "Are you sure you wish to finish ?", "cancelLabel": "Cancel", "confirmLabel": "Finish"}, "confirmRetry": {"header": "Retry ?", "body": "Are you sure you wish to retry ?", "cancelLabel": "Cancel", "confirmLabel": "Confirm"}, "overallFeedback": [{"from": 0, "to": 100, "feedback": "You got @score of @total blanks correct."}], "scoreBarLabel": "You got :num out of :total points"}
\ No newline at end of file
{
"questions": [
"<p><h4>praestare, o, stiti </h4> *outperform : outperform*</p>"
],
"showSolutions": "Show solutions",
"tryAgain": "Try again",
"text": "<p>Give a translation.</p><br><p><label><input type=\"checkbox\" id=\"known\"> I already know this.</label></p>\n",
"checkAnswer": "Check",
"notFilledOut": "Please fill in all blanks",
"behaviour": {
"enableSolutionsButton": true,
"autoCheck": false,
"caseSensitive": false,
"showSolutionsRequiresInput": false,
"separateLines": false,
"enableRetry": false,
"disableImageZooming": true,
"confirmCheckDialog": false,
"confirmRetryDialog": false,
"acceptSpellingErrors": false,
"enableCheckButton": true
},
"answerIsCorrect": "&#039;:ans&#039; is correct",
"answerIsWrong": "&#039;:ans&#039; is wrong",
"answeredCorrectly": "Answered correctly",
"answeredIncorrectly": "Answered incorrectly",
"solutionLabel": "Correct answer:",
"inputLabel": "Blank input @num of @total",
"inputHasTipLabel": "Tip available",
"tipLabel": "Tip",
"confirmCheck": {
"header": "Finish ?",
"body": "Are you sure you wish to finish ?",
"cancelLabel": "Cancel",
"confirmLabel": "Finish"
},
"confirmRetry": {
"header": "Retry ?",
"body": "Are you sure you wish to retry ?",
"cancelLabel": "Cancel",
"confirmLabel": "Confirm"
},
"overallFeedback": [
{
"from": 0,
"to": 100,
"feedback": "You got @score of @total blanks correct."
}
],
"scoreBarLabel": "You got :num out of :total points"
}
......@@ -130,6 +130,7 @@
"TEST": "Lerneinheit",
"TEST_MODULE_EXERCISE_NUMBER": "Übungsnummer",
"TEST_MODULE_GO_TO_EXERCISE": "Gehe zu Übung",
"TEST_MODULE_PROGRESS_PART": "Fortschritt: Teil",
"TEST_REPEAT": "Test wiederholen",
"TEXT_SHOW_OOV": "Unbekannte Vokabeln markieren",
"TEXT_TOO_LONG": "Text zu lang, max. Wortzahl: ",
......
......@@ -130,6 +130,7 @@
"TEST": "Learning unit",
"TEST_MODULE_EXERCISE_NUMBER": "Exercise number",
"TEST_MODULE_GO_TO_EXERCISE": "Go to exercise",
"TEST_MODULE_PROGRESS_PART": "Progress: Part",
"TEST_REPEAT": "Repeat test",
"TEXT_SHOW_OOV": "Highlight unknown vocabulary",
"TEXT_TOO_LONG": "Text too long, max. word count: ",
......