@contractspec/module.learning-journey 3.7.6 → 3.7.10

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.
Files changed (44) hide show
  1. package/README.md +65 -188
  2. package/dist/browser/contracts/index.js +148 -148
  3. package/dist/browser/contracts/models.js +1 -1
  4. package/dist/browser/contracts/onboarding.js +5 -5
  5. package/dist/browser/contracts/operations.js +4 -4
  6. package/dist/browser/engines/index.js +173 -173
  7. package/dist/browser/engines/xp.js +18 -18
  8. package/dist/browser/events.js +1 -1
  9. package/dist/browser/i18n/catalogs/index.js +18 -18
  10. package/dist/browser/i18n/index.js +26 -26
  11. package/dist/browser/i18n/locale.js +2 -2
  12. package/dist/browser/i18n/messages.js +18 -18
  13. package/dist/browser/index.js +336 -335
  14. package/dist/contracts/index.d.ts +2 -2
  15. package/dist/contracts/index.js +148 -148
  16. package/dist/contracts/models.js +1 -1
  17. package/dist/contracts/onboarding.js +5 -5
  18. package/dist/contracts/operations.js +4 -4
  19. package/dist/engines/index.d.ts +1 -1
  20. package/dist/engines/index.js +173 -173
  21. package/dist/engines/xp.js +18 -18
  22. package/dist/events.js +1 -1
  23. package/dist/i18n/catalogs/index.d.ts +1 -1
  24. package/dist/i18n/catalogs/index.js +18 -18
  25. package/dist/i18n/index.d.ts +7 -7
  26. package/dist/i18n/index.js +26 -26
  27. package/dist/i18n/locale.d.ts +1 -1
  28. package/dist/i18n/locale.js +2 -2
  29. package/dist/i18n/messages.js +18 -18
  30. package/dist/index.d.ts +3 -3
  31. package/dist/index.js +336 -335
  32. package/dist/node/contracts/index.js +148 -148
  33. package/dist/node/contracts/models.js +1 -1
  34. package/dist/node/contracts/onboarding.js +5 -5
  35. package/dist/node/contracts/operations.js +4 -4
  36. package/dist/node/engines/index.js +173 -173
  37. package/dist/node/engines/xp.js +18 -18
  38. package/dist/node/events.js +1 -1
  39. package/dist/node/i18n/catalogs/index.js +18 -18
  40. package/dist/node/i18n/index.js +26 -26
  41. package/dist/node/i18n/locale.js +2 -2
  42. package/dist/node/i18n/messages.js +18 -18
  43. package/dist/node/index.js +336 -335
  44. package/package.json +7 -7
@@ -192,6 +192,161 @@ class SRSEngine {
192
192
  }
193
193
  var srsEngine = new SRSEngine;
194
194
 
195
+ // src/engines/streak.ts
196
+ var DEFAULT_STREAK_CONFIG = {
197
+ timezone: "UTC",
198
+ freezesPerMonth: 2,
199
+ maxFreezes: 5,
200
+ gracePeriodHours: 4
201
+ };
202
+
203
+ class StreakEngine {
204
+ config;
205
+ constructor(config = {}) {
206
+ this.config = { ...DEFAULT_STREAK_CONFIG, ...config };
207
+ }
208
+ update(state, now = new Date) {
209
+ const todayDate = this.getDateString(now);
210
+ const result = {
211
+ state: { ...state },
212
+ streakMaintained: false,
213
+ streakLost: false,
214
+ freezeUsed: false,
215
+ newStreak: false,
216
+ daysMissed: 0
217
+ };
218
+ if (!state.lastActivityDate) {
219
+ result.state.currentStreak = 1;
220
+ result.state.longestStreak = Math.max(1, state.longestStreak);
221
+ result.state.lastActivityAt = now;
222
+ result.state.lastActivityDate = todayDate;
223
+ result.newStreak = true;
224
+ result.streakMaintained = true;
225
+ return result;
226
+ }
227
+ if (state.lastActivityDate === todayDate) {
228
+ result.state.lastActivityAt = now;
229
+ result.streakMaintained = true;
230
+ return result;
231
+ }
232
+ const daysSinceActivity = this.getDaysBetween(state.lastActivityDate, todayDate);
233
+ if (daysSinceActivity === 1) {
234
+ result.state.currentStreak = state.currentStreak + 1;
235
+ result.state.longestStreak = Math.max(result.state.currentStreak, state.longestStreak);
236
+ result.state.lastActivityAt = now;
237
+ result.state.lastActivityDate = todayDate;
238
+ result.streakMaintained = true;
239
+ return result;
240
+ }
241
+ result.daysMissed = daysSinceActivity - 1;
242
+ const freezesNeeded = result.daysMissed;
243
+ if (freezesNeeded <= state.freezesRemaining) {
244
+ result.state.freezesRemaining = state.freezesRemaining - freezesNeeded;
245
+ result.state.freezeUsedAt = now;
246
+ result.state.currentStreak = state.currentStreak + 1;
247
+ result.state.longestStreak = Math.max(result.state.currentStreak, state.longestStreak);
248
+ result.state.lastActivityAt = now;
249
+ result.state.lastActivityDate = todayDate;
250
+ result.freezeUsed = true;
251
+ result.streakMaintained = true;
252
+ return result;
253
+ }
254
+ result.streakLost = true;
255
+ result.state.currentStreak = 1;
256
+ result.state.lastActivityAt = now;
257
+ result.state.lastActivityDate = todayDate;
258
+ result.newStreak = true;
259
+ return result;
260
+ }
261
+ checkStatus(state, now = new Date) {
262
+ if (!state.lastActivityDate) {
263
+ return {
264
+ isActive: false,
265
+ willExpireAt: null,
266
+ canUseFreeze: false,
267
+ daysUntilExpiry: 0
268
+ };
269
+ }
270
+ const todayDate = this.getDateString(now);
271
+ const daysSinceActivity = this.getDaysBetween(state.lastActivityDate, todayDate);
272
+ if (daysSinceActivity === 0) {
273
+ const tomorrow = this.addDays(now, 1);
274
+ tomorrow.setHours(23, 59, 59, 999);
275
+ return {
276
+ isActive: true,
277
+ willExpireAt: tomorrow,
278
+ canUseFreeze: state.freezesRemaining > 0,
279
+ daysUntilExpiry: 1
280
+ };
281
+ }
282
+ if (daysSinceActivity === 1) {
283
+ const endOfDay = new Date(now);
284
+ endOfDay.setHours(23 + this.config.gracePeriodHours, 59, 59, 999);
285
+ return {
286
+ isActive: true,
287
+ willExpireAt: endOfDay,
288
+ canUseFreeze: state.freezesRemaining > 0,
289
+ daysUntilExpiry: 0
290
+ };
291
+ }
292
+ const missedDays = daysSinceActivity - 1;
293
+ return {
294
+ isActive: missedDays <= state.freezesRemaining,
295
+ willExpireAt: null,
296
+ canUseFreeze: missedDays <= state.freezesRemaining,
297
+ daysUntilExpiry: -missedDays
298
+ };
299
+ }
300
+ useFreeze(state, now = new Date) {
301
+ if (state.freezesRemaining <= 0) {
302
+ return null;
303
+ }
304
+ return {
305
+ ...state,
306
+ freezesRemaining: state.freezesRemaining - 1,
307
+ freezeUsedAt: now
308
+ };
309
+ }
310
+ awardMonthlyFreezes(state) {
311
+ return {
312
+ ...state,
313
+ freezesRemaining: Math.min(state.freezesRemaining + this.config.freezesPerMonth, this.config.maxFreezes)
314
+ };
315
+ }
316
+ getInitialState() {
317
+ return {
318
+ currentStreak: 0,
319
+ longestStreak: 0,
320
+ lastActivityAt: null,
321
+ lastActivityDate: null,
322
+ freezesRemaining: this.config.freezesPerMonth,
323
+ freezeUsedAt: null
324
+ };
325
+ }
326
+ getMilestones(currentStreak) {
327
+ const milestones = [3, 7, 14, 30, 60, 90, 180, 365, 500, 1000];
328
+ const achieved = milestones.filter((m) => currentStreak >= m);
329
+ const next = milestones.find((m) => currentStreak < m) ?? null;
330
+ return { achieved, next };
331
+ }
332
+ getDateString(date) {
333
+ const year = date.getFullYear();
334
+ const month = String(date.getMonth() + 1).padStart(2, "0");
335
+ const day = String(date.getDate()).padStart(2, "0");
336
+ return `${year}-${month}-${day}`;
337
+ }
338
+ getDaysBetween(dateStr1, dateStr2) {
339
+ const date1 = new Date(dateStr1);
340
+ const date2 = new Date(dateStr2);
341
+ const diffTime = date2.getTime() - date1.getTime();
342
+ return Math.floor(diffTime / (1000 * 60 * 60 * 24));
343
+ }
344
+ addDays(date, days) {
345
+ return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
346
+ }
347
+ }
348
+ var streakEngine = new StreakEngine;
349
+
195
350
  // src/i18n/catalogs/en.ts
196
351
  import { defineTranslation } from "@contractspec/lib.contracts-spec/translations";
197
352
  var enMessages = defineTranslation({
@@ -233,18 +388,18 @@ var enMessages = defineTranslation({
233
388
  }
234
389
  });
235
390
 
236
- // src/i18n/catalogs/fr.ts
391
+ // src/i18n/catalogs/es.ts
237
392
  import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
238
- var frMessages = defineTranslation2({
393
+ var esMessages = defineTranslation2({
239
394
  meta: {
240
395
  key: "learning-journey.messages",
241
396
  version: "1.0.0",
242
397
  domain: "learning-journey",
243
- description: "XP source labels (French)",
398
+ description: "XP source labels (Spanish)",
244
399
  owners: ["platform"],
245
400
  stability: "experimental"
246
401
  },
247
- locale: "fr",
402
+ locale: "es",
248
403
  fallback: "en",
249
404
  messages: {
250
405
  "xp.source.base": {
@@ -252,40 +407,40 @@ var frMessages = defineTranslation2({
252
407
  description: "XP breakdown label for base XP"
253
408
  },
254
409
  "xp.source.scoreBonus": {
255
- value: "Bonus de score",
410
+ value: "Bonificación por puntuación",
256
411
  description: "XP breakdown label for score-based bonus"
257
412
  },
258
413
  "xp.source.perfectScore": {
259
- value: "Score parfait",
414
+ value: "Puntuación perfecta",
260
415
  description: "XP breakdown label for perfect score bonus"
261
416
  },
262
417
  "xp.source.firstAttempt": {
263
- value: "Premier essai",
418
+ value: "Primer intento",
264
419
  description: "XP breakdown label for first attempt bonus"
265
420
  },
266
421
  "xp.source.retryPenalty": {
267
- value: "Pénalité de réessai",
422
+ value: "Penalización por reintento",
268
423
  description: "XP breakdown label for retry penalty"
269
424
  },
270
425
  "xp.source.streakBonus": {
271
- value: "Bonus de série",
426
+ value: "Bonificación por racha",
272
427
  description: "XP breakdown label for streak bonus"
273
428
  }
274
429
  }
275
430
  });
276
431
 
277
- // src/i18n/catalogs/es.ts
432
+ // src/i18n/catalogs/fr.ts
278
433
  import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
279
- var esMessages = defineTranslation3({
434
+ var frMessages = defineTranslation3({
280
435
  meta: {
281
436
  key: "learning-journey.messages",
282
437
  version: "1.0.0",
283
438
  domain: "learning-journey",
284
- description: "XP source labels (Spanish)",
439
+ description: "XP source labels (French)",
285
440
  owners: ["platform"],
286
441
  stability: "experimental"
287
442
  },
288
- locale: "es",
443
+ locale: "fr",
289
444
  fallback: "en",
290
445
  messages: {
291
446
  "xp.source.base": {
@@ -293,23 +448,23 @@ var esMessages = defineTranslation3({
293
448
  description: "XP breakdown label for base XP"
294
449
  },
295
450
  "xp.source.scoreBonus": {
296
- value: "Bonificación por puntuación",
451
+ value: "Bonus de score",
297
452
  description: "XP breakdown label for score-based bonus"
298
453
  },
299
454
  "xp.source.perfectScore": {
300
- value: "Puntuación perfecta",
455
+ value: "Score parfait",
301
456
  description: "XP breakdown label for perfect score bonus"
302
457
  },
303
458
  "xp.source.firstAttempt": {
304
- value: "Primer intento",
459
+ value: "Premier essai",
305
460
  description: "XP breakdown label for first attempt bonus"
306
461
  },
307
462
  "xp.source.retryPenalty": {
308
- value: "Penalización por reintento",
463
+ value: "Pénalité de réessai",
309
464
  description: "XP breakdown label for retry penalty"
310
465
  },
311
466
  "xp.source.streakBonus": {
312
- value: "Bonificación por racha",
467
+ value: "Bonus de série",
313
468
  description: "XP breakdown label for streak bonus"
314
469
  }
315
470
  }
@@ -506,161 +661,6 @@ function getXpSourceLabel(source, locale) {
506
661
  return i18nKey ? i18n.t(i18nKey) : source;
507
662
  }
508
663
  var xpEngine = new XPEngine;
509
-
510
- // src/engines/streak.ts
511
- var DEFAULT_STREAK_CONFIG = {
512
- timezone: "UTC",
513
- freezesPerMonth: 2,
514
- maxFreezes: 5,
515
- gracePeriodHours: 4
516
- };
517
-
518
- class StreakEngine {
519
- config;
520
- constructor(config = {}) {
521
- this.config = { ...DEFAULT_STREAK_CONFIG, ...config };
522
- }
523
- update(state, now = new Date) {
524
- const todayDate = this.getDateString(now);
525
- const result = {
526
- state: { ...state },
527
- streakMaintained: false,
528
- streakLost: false,
529
- freezeUsed: false,
530
- newStreak: false,
531
- daysMissed: 0
532
- };
533
- if (!state.lastActivityDate) {
534
- result.state.currentStreak = 1;
535
- result.state.longestStreak = Math.max(1, state.longestStreak);
536
- result.state.lastActivityAt = now;
537
- result.state.lastActivityDate = todayDate;
538
- result.newStreak = true;
539
- result.streakMaintained = true;
540
- return result;
541
- }
542
- if (state.lastActivityDate === todayDate) {
543
- result.state.lastActivityAt = now;
544
- result.streakMaintained = true;
545
- return result;
546
- }
547
- const daysSinceActivity = this.getDaysBetween(state.lastActivityDate, todayDate);
548
- if (daysSinceActivity === 1) {
549
- result.state.currentStreak = state.currentStreak + 1;
550
- result.state.longestStreak = Math.max(result.state.currentStreak, state.longestStreak);
551
- result.state.lastActivityAt = now;
552
- result.state.lastActivityDate = todayDate;
553
- result.streakMaintained = true;
554
- return result;
555
- }
556
- result.daysMissed = daysSinceActivity - 1;
557
- const freezesNeeded = result.daysMissed;
558
- if (freezesNeeded <= state.freezesRemaining) {
559
- result.state.freezesRemaining = state.freezesRemaining - freezesNeeded;
560
- result.state.freezeUsedAt = now;
561
- result.state.currentStreak = state.currentStreak + 1;
562
- result.state.longestStreak = Math.max(result.state.currentStreak, state.longestStreak);
563
- result.state.lastActivityAt = now;
564
- result.state.lastActivityDate = todayDate;
565
- result.freezeUsed = true;
566
- result.streakMaintained = true;
567
- return result;
568
- }
569
- result.streakLost = true;
570
- result.state.currentStreak = 1;
571
- result.state.lastActivityAt = now;
572
- result.state.lastActivityDate = todayDate;
573
- result.newStreak = true;
574
- return result;
575
- }
576
- checkStatus(state, now = new Date) {
577
- if (!state.lastActivityDate) {
578
- return {
579
- isActive: false,
580
- willExpireAt: null,
581
- canUseFreeze: false,
582
- daysUntilExpiry: 0
583
- };
584
- }
585
- const todayDate = this.getDateString(now);
586
- const daysSinceActivity = this.getDaysBetween(state.lastActivityDate, todayDate);
587
- if (daysSinceActivity === 0) {
588
- const tomorrow = this.addDays(now, 1);
589
- tomorrow.setHours(23, 59, 59, 999);
590
- return {
591
- isActive: true,
592
- willExpireAt: tomorrow,
593
- canUseFreeze: state.freezesRemaining > 0,
594
- daysUntilExpiry: 1
595
- };
596
- }
597
- if (daysSinceActivity === 1) {
598
- const endOfDay = new Date(now);
599
- endOfDay.setHours(23 + this.config.gracePeriodHours, 59, 59, 999);
600
- return {
601
- isActive: true,
602
- willExpireAt: endOfDay,
603
- canUseFreeze: state.freezesRemaining > 0,
604
- daysUntilExpiry: 0
605
- };
606
- }
607
- const missedDays = daysSinceActivity - 1;
608
- return {
609
- isActive: missedDays <= state.freezesRemaining,
610
- willExpireAt: null,
611
- canUseFreeze: missedDays <= state.freezesRemaining,
612
- daysUntilExpiry: -missedDays
613
- };
614
- }
615
- useFreeze(state, now = new Date) {
616
- if (state.freezesRemaining <= 0) {
617
- return null;
618
- }
619
- return {
620
- ...state,
621
- freezesRemaining: state.freezesRemaining - 1,
622
- freezeUsedAt: now
623
- };
624
- }
625
- awardMonthlyFreezes(state) {
626
- return {
627
- ...state,
628
- freezesRemaining: Math.min(state.freezesRemaining + this.config.freezesPerMonth, this.config.maxFreezes)
629
- };
630
- }
631
- getInitialState() {
632
- return {
633
- currentStreak: 0,
634
- longestStreak: 0,
635
- lastActivityAt: null,
636
- lastActivityDate: null,
637
- freezesRemaining: this.config.freezesPerMonth,
638
- freezeUsedAt: null
639
- };
640
- }
641
- getMilestones(currentStreak) {
642
- const milestones = [3, 7, 14, 30, 60, 90, 180, 365, 500, 1000];
643
- const achieved = milestones.filter((m) => currentStreak >= m);
644
- const next = milestones.find((m) => currentStreak < m) ?? null;
645
- return { achieved, next };
646
- }
647
- getDateString(date) {
648
- const year = date.getFullYear();
649
- const month = String(date.getMonth() + 1).padStart(2, "0");
650
- const day = String(date.getDate()).padStart(2, "0");
651
- return `${year}-${month}-${day}`;
652
- }
653
- getDaysBetween(dateStr1, dateStr2) {
654
- const date1 = new Date(dateStr1);
655
- const date2 = new Date(dateStr2);
656
- const diffTime = date2.getTime() - date1.getTime();
657
- return Math.floor(diffTime / (1000 * 60 * 60 * 24));
658
- }
659
- addDays(date, days) {
660
- return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
661
- }
662
- }
663
- var streakEngine = new StreakEngine;
664
664
  export {
665
665
  xpEngine,
666
666
  streakEngine,
@@ -39,18 +39,18 @@ var enMessages = defineTranslation({
39
39
  }
40
40
  });
41
41
 
42
- // src/i18n/catalogs/fr.ts
42
+ // src/i18n/catalogs/es.ts
43
43
  import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
44
- var frMessages = defineTranslation2({
44
+ var esMessages = defineTranslation2({
45
45
  meta: {
46
46
  key: "learning-journey.messages",
47
47
  version: "1.0.0",
48
48
  domain: "learning-journey",
49
- description: "XP source labels (French)",
49
+ description: "XP source labels (Spanish)",
50
50
  owners: ["platform"],
51
51
  stability: "experimental"
52
52
  },
53
- locale: "fr",
53
+ locale: "es",
54
54
  fallback: "en",
55
55
  messages: {
56
56
  "xp.source.base": {
@@ -58,40 +58,40 @@ var frMessages = defineTranslation2({
58
58
  description: "XP breakdown label for base XP"
59
59
  },
60
60
  "xp.source.scoreBonus": {
61
- value: "Bonus de score",
61
+ value: "Bonificación por puntuación",
62
62
  description: "XP breakdown label for score-based bonus"
63
63
  },
64
64
  "xp.source.perfectScore": {
65
- value: "Score parfait",
65
+ value: "Puntuación perfecta",
66
66
  description: "XP breakdown label for perfect score bonus"
67
67
  },
68
68
  "xp.source.firstAttempt": {
69
- value: "Premier essai",
69
+ value: "Primer intento",
70
70
  description: "XP breakdown label for first attempt bonus"
71
71
  },
72
72
  "xp.source.retryPenalty": {
73
- value: "Pénalité de réessai",
73
+ value: "Penalización por reintento",
74
74
  description: "XP breakdown label for retry penalty"
75
75
  },
76
76
  "xp.source.streakBonus": {
77
- value: "Bonus de série",
77
+ value: "Bonificación por racha",
78
78
  description: "XP breakdown label for streak bonus"
79
79
  }
80
80
  }
81
81
  });
82
82
 
83
- // src/i18n/catalogs/es.ts
83
+ // src/i18n/catalogs/fr.ts
84
84
  import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
85
- var esMessages = defineTranslation3({
85
+ var frMessages = defineTranslation3({
86
86
  meta: {
87
87
  key: "learning-journey.messages",
88
88
  version: "1.0.0",
89
89
  domain: "learning-journey",
90
- description: "XP source labels (Spanish)",
90
+ description: "XP source labels (French)",
91
91
  owners: ["platform"],
92
92
  stability: "experimental"
93
93
  },
94
- locale: "es",
94
+ locale: "fr",
95
95
  fallback: "en",
96
96
  messages: {
97
97
  "xp.source.base": {
@@ -99,23 +99,23 @@ var esMessages = defineTranslation3({
99
99
  description: "XP breakdown label for base XP"
100
100
  },
101
101
  "xp.source.scoreBonus": {
102
- value: "Bonificación por puntuación",
102
+ value: "Bonus de score",
103
103
  description: "XP breakdown label for score-based bonus"
104
104
  },
105
105
  "xp.source.perfectScore": {
106
- value: "Puntuación perfecta",
106
+ value: "Score parfait",
107
107
  description: "XP breakdown label for perfect score bonus"
108
108
  },
109
109
  "xp.source.firstAttempt": {
110
- value: "Primer intento",
110
+ value: "Premier essai",
111
111
  description: "XP breakdown label for first attempt bonus"
112
112
  },
113
113
  "xp.source.retryPenalty": {
114
- value: "Penalización por reintento",
114
+ value: "Pénalité de réessai",
115
115
  description: "XP breakdown label for retry penalty"
116
116
  },
117
117
  "xp.source.streakBonus": {
118
- value: "Bonificación por racha",
118
+ value: "Bonus de série",
119
119
  description: "XP breakdown label for streak bonus"
120
120
  }
121
121
  }
@@ -2,8 +2,8 @@
2
2
  var LEARNING_JOURNEY_OWNERS = ["modules.learning-journey"];
3
3
 
4
4
  // src/events.ts
5
- import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
6
5
  import { defineEvent } from "@contractspec/lib.contracts-spec";
6
+ import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
7
7
  var CoursePublishedPayload = defineSchemaModel({
8
8
  name: "CoursePublishedEventPayload",
9
9
  description: "Payload when a course is published",
@@ -39,18 +39,18 @@ var enMessages = defineTranslation({
39
39
  }
40
40
  });
41
41
 
42
- // src/i18n/catalogs/fr.ts
42
+ // src/i18n/catalogs/es.ts
43
43
  import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
44
- var frMessages = defineTranslation2({
44
+ var esMessages = defineTranslation2({
45
45
  meta: {
46
46
  key: "learning-journey.messages",
47
47
  version: "1.0.0",
48
48
  domain: "learning-journey",
49
- description: "XP source labels (French)",
49
+ description: "XP source labels (Spanish)",
50
50
  owners: ["platform"],
51
51
  stability: "experimental"
52
52
  },
53
- locale: "fr",
53
+ locale: "es",
54
54
  fallback: "en",
55
55
  messages: {
56
56
  "xp.source.base": {
@@ -58,40 +58,40 @@ var frMessages = defineTranslation2({
58
58
  description: "XP breakdown label for base XP"
59
59
  },
60
60
  "xp.source.scoreBonus": {
61
- value: "Bonus de score",
61
+ value: "Bonificación por puntuación",
62
62
  description: "XP breakdown label for score-based bonus"
63
63
  },
64
64
  "xp.source.perfectScore": {
65
- value: "Score parfait",
65
+ value: "Puntuación perfecta",
66
66
  description: "XP breakdown label for perfect score bonus"
67
67
  },
68
68
  "xp.source.firstAttempt": {
69
- value: "Premier essai",
69
+ value: "Primer intento",
70
70
  description: "XP breakdown label for first attempt bonus"
71
71
  },
72
72
  "xp.source.retryPenalty": {
73
- value: "Pénalité de réessai",
73
+ value: "Penalización por reintento",
74
74
  description: "XP breakdown label for retry penalty"
75
75
  },
76
76
  "xp.source.streakBonus": {
77
- value: "Bonus de série",
77
+ value: "Bonificación por racha",
78
78
  description: "XP breakdown label for streak bonus"
79
79
  }
80
80
  }
81
81
  });
82
82
 
83
- // src/i18n/catalogs/es.ts
83
+ // src/i18n/catalogs/fr.ts
84
84
  import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
85
- var esMessages = defineTranslation3({
85
+ var frMessages = defineTranslation3({
86
86
  meta: {
87
87
  key: "learning-journey.messages",
88
88
  version: "1.0.0",
89
89
  domain: "learning-journey",
90
- description: "XP source labels (Spanish)",
90
+ description: "XP source labels (French)",
91
91
  owners: ["platform"],
92
92
  stability: "experimental"
93
93
  },
94
- locale: "es",
94
+ locale: "fr",
95
95
  fallback: "en",
96
96
  messages: {
97
97
  "xp.source.base": {
@@ -99,23 +99,23 @@ var esMessages = defineTranslation3({
99
99
  description: "XP breakdown label for base XP"
100
100
  },
101
101
  "xp.source.scoreBonus": {
102
- value: "Bonificación por puntuación",
102
+ value: "Bonus de score",
103
103
  description: "XP breakdown label for score-based bonus"
104
104
  },
105
105
  "xp.source.perfectScore": {
106
- value: "Puntuación perfecta",
106
+ value: "Score parfait",
107
107
  description: "XP breakdown label for perfect score bonus"
108
108
  },
109
109
  "xp.source.firstAttempt": {
110
- value: "Primer intento",
110
+ value: "Premier essai",
111
111
  description: "XP breakdown label for first attempt bonus"
112
112
  },
113
113
  "xp.source.retryPenalty": {
114
- value: "Penalización por reintento",
114
+ value: "Pénalité de réessai",
115
115
  description: "XP breakdown label for retry penalty"
116
116
  },
117
117
  "xp.source.streakBonus": {
118
- value: "Bonificación por racha",
118
+ value: "Bonus de série",
119
119
  description: "XP breakdown label for streak bonus"
120
120
  }
121
121
  }