@windward/games 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## Release [0.22.0] - 2025-08-28
4
+
5
+ * Merged in feature/LE-2036/update-core-package-v (pull request #252)
6
+ * Merged in feature/LE-1851-multiple-choice-block-feedback-l (pull request #251)
7
+ * Merged release/0.22.0 into feature/LE-1851-multiple-choice-block-feedback-l
8
+ * Merged in feature/LE-2036/word-jumble-gen (pull request #250)
9
+ * Merged in feature/LE-1851-multiple-choice-block-feedback-l (pull request #249)
10
+
11
+
12
+ ## Release [0.21.0] - 2025-07-29
13
+
14
+ * Merged in feature/LE-1912/sorting-game-generation (pull request #246)
15
+ * Merged in feature/LE-1913/matching-block (pull request #245)
16
+ * Merge branch 'release/0.21.0' into feature/LE-1913/matching-block
17
+ * Merge branch 'develop' into Feature/LE-1913/matching-block
18
+ * Merge branch 'develop' into feature/LE-1882/bucket-games
19
+
20
+
3
21
  ## Release [0.20.0] - 2025-06-25
4
22
 
5
23
  * Merged in feature/LE-1948/empty-bucket (pull request #242)
@@ -228,13 +228,14 @@
228
228
  </div>
229
229
  </template>
230
230
  <template #form="{ on, attrs }">
231
- <div v-bind="attrs" v-on="on">
231
+ <p v-bind="attrs" v-on="on">
232
232
  <TextViewer v-if="hint" v-model="hintText"></TextViewer>
233
233
  <TextViewer
234
234
  v-if="answerDescriptionModal"
235
235
  v-model="answerDescription"
236
+ class="dialog-text-viewer"
236
237
  ></TextViewer>
237
- </div>
238
+ </p>
238
239
  </template>
239
240
  </DialogBox>
240
241
  </v-carousel>
@@ -320,10 +321,14 @@ export default {
320
321
  onAnswerDescription(question, answer) {
321
322
  this.activeQuestion = question
322
323
  this.activeAnswer = answer
323
- //launches modal and displays anwer description
324
+ // launches modal and displays anwer description
324
325
  this.dialog = true
325
326
  this.answerDescriptionModal = true
326
- this.answerDescription = question.answer_description
327
+ if (question.metadata.config.single_feedback) {
328
+ this.answerDescription = question.answer_description
329
+ } else if (!_.isEmpty(answer.feedback)) {
330
+ this.answerDescription = answer.feedback
331
+ }
327
332
  },
328
333
  onChooseAnswer(answer, question) {
329
334
  // check to see if student already answered this question
@@ -467,13 +472,12 @@ export default {
467
472
  }
468
473
  )
469
474
  if (studentsQuestionResponse) {
470
- if (answer.correctAnswer === true && answer.chosen === true) {
471
- return 'mdi-information'
472
- } else if (
473
- answer.correctAnswer === true &&
474
- answer.chosen === false
475
+ if (
476
+ answer.chosen === true &&
477
+ (!_.isEmpty(answer.feedback) ||
478
+ question.metadata.config.single_feedback)
475
479
  ) {
476
- return 'mdi-information-outline'
480
+ return 'mdi-message-alert-outline'
477
481
  }
478
482
  }
479
483
  },
@@ -613,4 +617,7 @@ export default {
613
617
  min-width: 20% !important;
614
618
  margin-right: 16px;
615
619
  }
620
+ .dialog-text-viewer {
621
+ color: var(--v-primary-base);
622
+ }
616
623
  </style>
@@ -248,12 +248,28 @@
248
248
  indeterminate
249
249
  ></v-progress-circular>
250
250
  </div>
251
+ <v-container class="pa-4 mb-6">
252
+ <v-row>
253
+ <v-col cols="12">
254
+ <GenerateAIQuestionButton
255
+ :course="course"
256
+ :content="content"
257
+ :block="block"
258
+ question-type="matching_game"
259
+ :replace-existing-mode="replaceExisting"
260
+ @click:generate="onGeneratedMatchingGame"
261
+ ></GenerateAIQuestionButton>
262
+ </v-col>
263
+ </v-row>
264
+ </v-container>
251
265
  </div>
252
266
  </template>
253
267
 
254
268
  <script>
255
269
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
256
270
  import _ from 'lodash'
271
+ import { mapGetters } from 'vuex'
272
+ import { GenerateAIQuestionButton } from '@windward/core/utils'
257
273
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
258
274
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
259
275
  import Uuid from '~/helpers/Uuid'
@@ -266,6 +282,7 @@ export default {
266
282
  SortableExpansionPanel,
267
283
  ImageAssetSettings,
268
284
  BaseContentBlockSettings,
285
+ GenerateAIQuestionButton
269
286
  },
270
287
  beforeMount() {
271
288
  if (_.isEmpty(this.block)) {
@@ -326,8 +343,15 @@ export default {
326
343
  return {
327
344
  valid: true,
328
345
  loading: false,
346
+ replaceExisting: false,
329
347
  }
330
348
  },
349
+ computed: {
350
+ ...mapGetters({
351
+ course: 'course/get',
352
+ content: 'content/get',
353
+ }),
354
+ },
331
355
  mounted() {},
332
356
  methods: {
333
357
  onAddPrompt(index = 0) {
@@ -464,6 +488,129 @@ export default {
464
488
  // holder array now has new answer positions
465
489
  this.block.metadata.config.prompts = holderArray
466
490
  },
491
+ // Handler for receiving matching game data from GenerateAIQuestionButton
492
+ onGeneratedMatchingGame(activityData, replaceMode) {
493
+
494
+ this.loading = true
495
+ try {
496
+ // Process the activity data
497
+ if (activityData && activityData.metadata &&
498
+ activityData.metadata.config &&
499
+ activityData.metadata.config.answerObjects &&
500
+ activityData.metadata.config.prompts &&
501
+ Array.isArray(activityData.metadata.config.answerObjects) &&
502
+ Array.isArray(activityData.metadata.config.prompts)) {
503
+
504
+ if (replaceMode) {
505
+ // Replace mode: Clear existing answers and prompts
506
+ this.block.metadata.config.answerObjects.splice(0, this.block.metadata.config.answerObjects.length)
507
+ this.block.metadata.config.prompts.splice(0, this.block.metadata.config.prompts.length)
508
+
509
+ // Add all new answer objects and prompts
510
+ activityData.metadata.config.answerObjects.forEach((answerObj, index) => {
511
+ this.block.metadata.config.answerObjects.push({
512
+ id: index.toString(), // string id
513
+ display: answerObj.display || ''
514
+ })
515
+ })
516
+
517
+ // Add all prompts - following the exact pattern from BucketGameSettingsManager
518
+ activityData.metadata.config.prompts.forEach((promptArray, index) => {
519
+ this.block.metadata.config.prompts[index] = []
520
+ if (Array.isArray(promptArray)) {
521
+ promptArray.forEach(prompt => {
522
+ // Ensure the answer object reference is correct
523
+ const answerObj = this.block.metadata.config.answerObjects[index]
524
+ this.block.metadata.config.prompts[index].push({
525
+ id: index.toString(), // string id
526
+ textOrImage: prompt.textOrImage || 'text',
527
+ prompt: prompt.prompt || '',
528
+ matchExplanation: prompt.matchExplanation || this.$t('windward.games.components.settings.matching_game.form.correct_match'),
529
+ fileConfig: prompt.fileConfig || {
530
+ hideBackground: true,
531
+ },
532
+ answer: answerObj
533
+ })
534
+ })
535
+ }
536
+ })
537
+ } else {
538
+ // Merge mode: Add new terms and prompts to existing ones
539
+ // Check if there's only one empty answer (the default one created on init)
540
+ const hasOnlyEmptyAnswer = this.block.metadata.config.answerObjects.length === 1 &&
541
+ this.block.metadata.config.answerObjects[0].display === '';
542
+
543
+ if (hasOnlyEmptyAnswer) {
544
+ // If there's only one empty answer, replace it instead of merging
545
+ this.block.metadata.config.answerObjects.splice(0, 1);
546
+ this.block.metadata.config.prompts.splice(0, 1);
547
+ }
548
+
549
+ const existingAnswerCount = this.block.metadata.config.answerObjects.length
550
+
551
+ // Add new answer objects
552
+ activityData.metadata.config.answerObjects.forEach((answerObj, index) => {
553
+ const newIndex = existingAnswerCount + index
554
+ this.block.metadata.config.answerObjects.push({
555
+ id: newIndex.toString(), // string id
556
+ display: answerObj.display || ''
557
+ })
558
+ })
559
+
560
+ // Add new prompts
561
+ activityData.metadata.config.prompts.forEach((promptArray, index) => {
562
+ const adjustedIndex = existingAnswerCount + index
563
+ this.block.metadata.config.prompts[adjustedIndex] = []
564
+ if (Array.isArray(promptArray)) {
565
+ promptArray.forEach(prompt => {
566
+ const answerObj = this.block.metadata.config.answerObjects[adjustedIndex]
567
+ this.block.metadata.config.prompts[adjustedIndex].push({
568
+ id: adjustedIndex.toString(), // string id
569
+ textOrImage: prompt.textOrImage || 'text',
570
+ prompt: prompt.prompt || '',
571
+ matchExplanation: prompt.matchExplanation || this.$t('windward.games.components.settings.matching_game.form.correct_match'),
572
+ fileConfig: prompt.fileConfig || {
573
+ hideBackground: true,
574
+ },
575
+ answer: answerObj
576
+ })
577
+ })
578
+ }
579
+ })
580
+ }
581
+
582
+ // Update title and instructions if provided and we're in replace mode
583
+ if (replaceMode) {
584
+ if (activityData.metadata.config.title) {
585
+ this.block.metadata.config.title = activityData.metadata.config.title
586
+ }
587
+
588
+ if (activityData.metadata.config.instructions) {
589
+ this.block.metadata.config.instructions = activityData.metadata.config.instructions
590
+ }
591
+ }
592
+
593
+ this.$toast.success(
594
+ replaceMode
595
+ ? this.$t('windward.games.components.settings.matching_game.form.replaced_successfully')
596
+ : this.$t('windward.games.components.settings.matching_game.form.added_successfully'),
597
+ { duration: 3000 }
598
+ )
599
+ } else {
600
+ this.$toast.error(this.$t('windward.games.components.settings.matching_game.form.invalid_response'), {
601
+ duration: 5000
602
+ })
603
+ }
604
+ } catch (error) {
605
+ // Extract error message from the response
606
+ const errorMessage = error.message || 'Unknown error occurred'
607
+ this.$toast.error(`${this.$t('windward.games.components.settings.matching_game.form.failed_to_process')}: ${errorMessage}`, {
608
+ duration: 5000
609
+ })
610
+ } finally {
611
+ this.loading = false
612
+ }
613
+ }
467
614
  },
468
615
  }
469
616
  </script>
@@ -79,6 +79,20 @@
79
79
  :disabled="render"
80
80
  ></v-textarea>
81
81
  </v-container>
82
+ <v-container class="pa-4 mb-6">
83
+ <v-row>
84
+ <v-col cols="12">
85
+ <GenerateAIQuestionButton
86
+ :course="course"
87
+ :content="currentContent"
88
+ :block="block"
89
+ question-type="sorting_game"
90
+ :replace-existing-mode="replaceExisting"
91
+ @click:generate="onGeneratedSortingGame"
92
+ ></GenerateAIQuestionButton>
93
+ </v-col>
94
+ </v-row>
95
+ </v-container>
82
96
  <div v-if="loading" class="text-center">
83
97
  <v-progress-circular
84
98
  :size="70"
@@ -92,6 +106,8 @@
92
106
 
93
107
  <script>
94
108
  import _ from 'lodash'
109
+ import { mapGetters } from 'vuex'
110
+ import { GenerateAIQuestionButton } from '@windward/core/utils'
95
111
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
96
112
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
97
113
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
@@ -100,7 +116,7 @@ import Uuid from '~/helpers/Uuid'
100
116
  export default {
101
117
  name: 'SortingGameSettingsManager',
102
118
  extends: BaseContentSettings,
103
- components: { SortableExpansionPanel, BaseContentBlockSettings },
119
+ components: { SortableExpansionPanel, BaseContentBlockSettings, GenerateAIQuestionButton },
104
120
  beforeMount() {
105
121
  if (_.isEmpty(this.block)) {
106
122
  this.block = {}
@@ -148,6 +164,7 @@ export default {
148
164
  valid: true,
149
165
  dialog: false,
150
166
  loading: false,
167
+ replaceExisting: false,
151
168
  headers: [
152
169
  {
153
170
  text: 'Bucket Text',
@@ -159,6 +176,12 @@ export default {
159
176
  cursor: null,
160
177
  }
161
178
  },
179
+ computed: {
180
+ ...mapGetters({
181
+ course: 'course/get',
182
+ currentContent: 'content/get',
183
+ }),
184
+ },
162
185
  methods: {
163
186
  onAddElement() {
164
187
  this.block.metadata.config.answer.forEach((element) => {
@@ -179,6 +202,84 @@ export default {
179
202
  return (element.id = startingIndex)
180
203
  })
181
204
  },
205
+ onGeneratedSortingGame(activityData, replaceMode) {
206
+ this.loading = true
207
+ try {
208
+ // Process the activity data
209
+ if (activityData && activityData.metadata &&
210
+ activityData.metadata.config &&
211
+ activityData.metadata.config.answer &&
212
+ Array.isArray(activityData.metadata.config.answer)) {
213
+
214
+ // Save new items
215
+ const newItems = activityData.metadata.config.answer
216
+
217
+ if (replaceMode) {
218
+ // Replace mode: Clear existing items
219
+ this.block.metadata.config.answer.splice(0, this.block.metadata.config.answer.length)
220
+
221
+ // Add all new items - ensure they have the correct structure
222
+ newItems.forEach((item, index) => {
223
+ this.block.metadata.config.answer.push({
224
+ id: index,
225
+ value: item.value || '',
226
+ expand: false,
227
+ })
228
+ })
229
+ } else {
230
+ // Merge mode: Add new items to existing ones
231
+ const hasOnlyEmptyAnswer = this.block.metadata.config.answer.length === 1 &&
232
+ this.block.metadata.config.answer[0].value === ''
233
+
234
+ if (hasOnlyEmptyAnswer) {
235
+ // If there's only one empty answer, replace it instead of merging
236
+ this.block.metadata.config.answer.splice(0, 1)
237
+ }
238
+
239
+ let currentId = this.block.metadata.config.answer.length
240
+
241
+ newItems.forEach((item) => {
242
+ this.block.metadata.config.answer.push({
243
+ id: currentId,
244
+ value: item.value || '',
245
+ expand: false,
246
+ })
247
+ currentId += 1
248
+ })
249
+ }
250
+
251
+ // Update title and instructions if provided and we're in replace mode
252
+ if (replaceMode) {
253
+ if (activityData.metadata.config.title) {
254
+ this.block.metadata.config.title = activityData.metadata.config.title
255
+ }
256
+
257
+ if (activityData.metadata.config.instructions) {
258
+ this.block.metadata.config.instructions = activityData.metadata.config.instructions
259
+ }
260
+
261
+ // Update feedback if provided
262
+ if (activityData.metadata.config.feedback_correct) {
263
+ this.block.metadata.config.feedback_correct = activityData.metadata.config.feedback_correct
264
+ }
265
+ }
266
+
267
+ this.$toast.success(
268
+ replaceMode
269
+ ? this.$t('windward.games.components.settings.sorting_game.form.replaced_successfully')
270
+ : this.$t('windward.games.components.settings.sorting_game.form.added_successfully'),
271
+ { duration: 3000 }
272
+ )
273
+ } else {
274
+ throw new Error('activity.error.technical')
275
+ }
276
+ } catch (error) {
277
+ // Let the error bubble up to GenerateAIQuestionButton with proper error type
278
+ throw error
279
+ } finally {
280
+ this.loading = false
281
+ }
282
+ },
182
283
  },
183
284
  }
184
285
  </script>
@@ -119,10 +119,26 @@
119
119
  indeterminate
120
120
  ></v-progress-circular>
121
121
  </div>
122
+ <v-container class="pa-4 mb-6">
123
+ <v-row>
124
+ <v-col cols="12">
125
+ <GenerateAIQuestionButton
126
+ :course="course"
127
+ :content="currentContent"
128
+ :block="block"
129
+ question-type="word_jumble"
130
+ :replace-existing-mode="replaceExisting"
131
+ @click:generate="onGeneratedWordJumble"
132
+ ></GenerateAIQuestionButton>
133
+ </v-col>
134
+ </v-row>
135
+ </v-container>
122
136
  </div>
123
137
  </template>
124
138
  <script>
125
139
  import _ from 'lodash'
140
+ import { mapGetters } from 'vuex'
141
+ import { GenerateAIQuestionButton } from '@windward/core/utils'
126
142
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
127
143
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
128
144
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
@@ -133,6 +149,7 @@ export default {
133
149
  components: {
134
150
  SortableExpansionPanel,
135
151
  BaseContentBlockSettings,
152
+ GenerateAIQuestionButton,
136
153
  },
137
154
  beforeMount() {
138
155
  if (_.isEmpty(this.block)) {
@@ -173,8 +190,16 @@ export default {
173
190
  return {
174
191
  valid: true,
175
192
  loading: false,
193
+ replaceExisting: true,
176
194
  }
177
195
  },
196
+ computed: {
197
+
198
+ ...mapGetters({
199
+ course: 'course/get',
200
+ currentContent: 'content/get',
201
+ }),
202
+ },
178
203
  methods: {
179
204
  onBeforeSave() {
180
205
  this.block.metadata.config.words.forEach((element) => {
@@ -226,6 +251,73 @@ export default {
226
251
  this.block.metadata.config.currentWord =
227
252
  this.block.metadata.config.words.length - 1
228
253
  },
254
+ onGeneratedWordJumble(activityData, replaceMode) {
255
+ this.loading = true
256
+ try {
257
+ // Process the activity data
258
+ if (activityData && activityData.metadata &&
259
+ activityData.metadata.config &&
260
+ activityData.metadata.config.words &&
261
+ Array.isArray(activityData.metadata.config.words)) {
262
+
263
+ const newWords = activityData.metadata.config.words
264
+
265
+ if (replaceMode) { this.block.metadata.config.words.splice(0, this.block.metadata.config.words.length)
266
+ newWords.forEach(word => {
267
+ this.block.metadata.config.words.push({
268
+ id: word.id || this.block.metadata.config.words.length + 1,
269
+ value: word.value || '',
270
+ hint: word.hint || '',
271
+ shuffledWord: this.shuffle(word.value || '')
272
+ })
273
+ })
274
+ } else {
275
+ newWords.forEach(word => {
276
+ this.block.metadata.config.words.push({
277
+ id: this.block.metadata.config.words.length + 1,
278
+ value: word.value || '',
279
+ hint: word.hint || '',
280
+ shuffledWord: this.shuffle(word.value || '')
281
+ })
282
+ })
283
+ }
284
+
285
+ if (replaceMode && activityData.metadata.config.title) {
286
+ this.block.metadata.config.title = activityData.metadata.config.title
287
+ }
288
+
289
+ if (replaceMode) {
290
+ if (activityData.metadata.config.feedback_correct) {
291
+ this.block.metadata.config.feedback_correct = activityData.metadata.config.feedback_correct
292
+ }
293
+
294
+ if (activityData.metadata.config.feedback_incorrect) {
295
+ this.block.metadata.config.feedback_incorrect = activityData.metadata.config.feedback_incorrect
296
+ }
297
+ }
298
+
299
+ this.block.metadata.config.currentWord = 0
300
+
301
+ this.$toast.success(
302
+ replaceMode
303
+ ? this.$t('windward.games.components.settings.word_jumble.form.replaced_successfully')
304
+ : this.$t('windward.games.components.settings.word_jumble.form.added_successfully'),
305
+ { duration: 3000 }
306
+ )
307
+ } else {
308
+ this.$toast.error(this.$t('windward.games.components.settings.word_jumble.form.invalid_response'), {
309
+ duration: 5000
310
+ })
311
+ }
312
+ } catch (error) {
313
+ const errorMessage = error.message || 'Unknown error occurred'
314
+ this.$toast.error(`${this.$t('windward.games.components.settings.word_jumble.form.failed_to_process')}: ${errorMessage}`, {
315
+ duration: 5000
316
+ })
317
+ } finally {
318
+ this.loading = false
319
+ }
320
+ },
229
321
  },
230
322
  }
231
323
  </script>
@@ -7,6 +7,11 @@ export default {
7
7
  correct_match: 'This match is correct.',
8
8
  incorrect_match: 'That’s an incorrect match. Try again.',
9
9
  correct_match_label: 'Explanation of the correct match',
10
+ replace_existing: 'Replace Existing Matches',
11
+ added_successfully: 'Matches added successfully',
12
+ replaced_successfully: 'Matches replaced successfully',
13
+ invalid_response: 'Invalid response from AI generation',
14
+ failed_to_process: 'Failed to process AI response',
10
15
  feedback: {
11
16
  correct: 'feedback when correct',
12
17
  incorrect: 'feedback when incorrect',
@@ -5,4 +5,11 @@ export default {
5
5
  instructions: 'Drag each statement into the correct order. When you are finished, click the Check Your Answers button. Statements in the correct order will appear green, while statements not in the correct order will appear red.',
6
6
  feedback_correct_label: 'Explanation of the correct order',
7
7
  default_feedback_correct: 'That is the correct order.',
8
+ form: {
9
+ replace_existing: 'Replace existing items',
10
+ replaced_successfully: 'Items replaced successfully',
11
+ added_successfully: 'New items added successfully',
12
+ invalid_response: 'Invalid response from sorting game generation',
13
+ failed_to_process: 'Failed to process generated sorting game'
14
+ }
8
15
  }
@@ -9,4 +9,13 @@ export default {
9
9
  add: 'Add Word',
10
10
  feedback_correct: 'Feedback when correct',
11
11
  feedback_incorrect: 'Feedback when incorrect',
12
+
13
+ // AI generation keys in nested form structure
14
+ form: {
15
+ replace_existing: 'Replace existing words',
16
+ replaced_successfully: 'Words replaced successfully',
17
+ added_successfully: 'New words added successfully',
18
+ invalid_response: 'Invalid response from word jumble generation',
19
+ failed_to_process: 'Failed to process generated words'
20
+ }
12
21
  }
@@ -16,5 +16,10 @@ export default {
16
16
  char_count_less_then:
17
17
  'El número de caracteres para este campo debe ser menor que',
18
18
  },
19
+ replace_existing: 'Reemplazar coincidencias existentes',
20
+ added_successfully: 'Coincidencias añadidas correctamente',
21
+ replaced_successfully: 'Coincidencias reemplazadas correctamente',
22
+ invalid_response: 'Respuesta inválida de la generación de IA',
23
+ failed_to_process: 'Error al procesar la respuesta de IA'
19
24
  },
20
25
  }
@@ -5,4 +5,11 @@ export default {
5
5
  instructions: 'Arrastre cada declaración al orden correcto. Cuando haya terminado, haga clic en el botón Verifique sus respuestas. Las declaraciones en el orden correcto aparecerán en verde, mientras que las declaraciones que no estén en el orden correcto aparecerán en rojo.',
6
6
  feedback_correct_label: 'Explicación del orden correcto.',
7
7
  default_feedback_correct: 'Ese es el orden correcto.',
8
+ form: {
9
+ replace_existing: 'Reemplazar elementos existentes',
10
+ replaced_successfully: 'Elementos reemplazados exitosamente',
11
+ added_successfully: 'Nuevos elementos agregados exitosamente',
12
+ invalid_response: 'Respuesta inválida de la generación de juego de ordenamiento',
13
+ failed_to_process: 'Error al procesar el juego de ordenamiento generado'
14
+ }
8
15
  }
@@ -9,4 +9,13 @@ export default {
9
9
  add: 'Agregar palabra',
10
10
  feedback_correct: 'Comentarios cuando sea correcto',
11
11
  feedback_incorrect: 'Comentarios cuando sean incorrectos',
12
+
13
+ // AI generation keys in nested form structure
14
+ form: {
15
+ replace_existing: 'Reemplazar palabras existentes',
16
+ replaced_successfully: 'Palabras reemplazadas exitosamente',
17
+ added_successfully: 'Nuevas palabras añadidas exitosamente',
18
+ invalid_response: 'Respuesta inválida de la generación de revoltijo de palabras',
19
+ failed_to_process: 'Error al procesar las palabras generadas'
20
+ }
12
21
  }
@@ -16,5 +16,10 @@ export default {
16
16
  char_count_less_then:
17
17
  'Teckenantalet för detta fält måste vara mindre än',
18
18
  },
19
+ replace_existing: 'Ersätt befintliga matchningar',
20
+ added_successfully: 'Matchningar har lagts till',
21
+ replaced_successfully: 'Matchningar har ersatts',
22
+ invalid_response: 'Ogiltigt svar från AI-generering',
23
+ failed_to_process: 'Misslyckades med att bearbeta AI-svar'
19
24
  },
20
25
  }
@@ -5,4 +5,11 @@ export default {
5
5
  instructions: 'Dra varje påstående i rätt ordning. När du är klar klickar du på knappen Kontrollera dina svar. Påståenden i rätt ordning visas i grönt, medan påståenden som inte är i rätt ordning visas röda.',
6
6
  feedback_correct_label: 'Förklaring av rätt ordning',
7
7
  default_feedback_correct: 'Det är rätt ordning.',
8
+ form: {
9
+ replace_existing: 'Ersätt befintliga objekt',
10
+ replaced_successfully: 'Objekt ersatta framgångsrikt',
11
+ added_successfully: 'Nya objekt tillagda framgångsrikt',
12
+ invalid_response: 'Ogiltigt svar från sorteringsspelsgenerering',
13
+ failed_to_process: 'Misslyckades med att bearbeta genererat sorteringsspel'
14
+ }
8
15
  }
@@ -9,4 +9,13 @@ export default {
9
9
  add: 'Lägg till ord',
10
10
  feedback_correct: 'Återkoppling när korrekt',
11
11
  feedback_incorrect: 'Återkoppling när felaktig',
12
+
13
+ // AI generation keys in nested form structure
14
+ form: {
15
+ replace_existing: 'Ersätt befintliga ord',
16
+ replaced_successfully: 'Ord ersatta framgångsrikt',
17
+ added_successfully: 'Nya ord tillagda framgångsrikt',
18
+ invalid_response: 'Ogiltig respons från ordvirrvarr-generering',
19
+ failed_to_process: 'Misslyckades med att bearbeta genererade ord'
20
+ }
12
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/games",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Windward UI Plugin Games",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "license": "MIT",
22
22
  "homepage": "https://bitbucket.org/mindedge/windward-ui-plugin-games#readme",
23
23
  "dependencies": {
24
- "@windward/core": "^0.20.0",
24
+ "@windward/core": "^0.22.0",
25
25
  "eslint": "^8.11.0",
26
26
  "lodash": "^4.17.21",
27
27
  "prettier": "^2.6.0",