@mintplayer/ng-spark-auth 0.0.1 → 0.0.2

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, signal, computed, Injectable, makeEnvironmentProviders, Component } from '@angular/core';
2
+ import { InjectionToken, inject, signal, computed, Injectable, Pipe, makeEnvironmentProviders, Component } from '@angular/core';
3
3
  import { HttpClient, withInterceptors, withXsrfConfiguration } from '@angular/common/http';
4
4
  import { switchMap, tap } from 'rxjs';
5
5
  import { Router, RouterLink, ActivatedRoute } from '@angular/router';
@@ -76,6 +76,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
76
76
  args: [{ providedIn: 'root' }]
77
77
  }], ctorParameters: () => [] });
78
78
 
79
+ class SparkAuthTranslationService {
80
+ http = inject(HttpClient);
81
+ translationsMap = signal({}, ...(ngDevMode ? [{ debugName: "translationsMap" }] : []));
82
+ constructor() {
83
+ this.http.get('/spark/translations').subscribe(t => {
84
+ this.translationsMap.set(t);
85
+ });
86
+ }
87
+ t(key) {
88
+ const ts = this.translationsMap()[key];
89
+ if (!ts)
90
+ return key;
91
+ const lang = localStorage.getItem('spark-lang') ?? navigator.language?.split('-')[0] ?? 'en';
92
+ return ts[lang] ?? ts['en'] ?? Object.values(ts)[0] ?? key;
93
+ }
94
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkAuthTranslationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
95
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkAuthTranslationService, providedIn: 'root' });
96
+ }
97
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkAuthTranslationService, decorators: [{
98
+ type: Injectable,
99
+ args: [{ providedIn: 'root' }]
100
+ }], ctorParameters: () => [] });
101
+
102
+ class TranslateKeyPipe {
103
+ translation = inject(SparkAuthTranslationService);
104
+ transform(key) {
105
+ return this.translation.t(key);
106
+ }
107
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TranslateKeyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
108
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.5", ngImport: i0, type: TranslateKeyPipe, isStandalone: true, name: "t", pure: false });
109
+ }
110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: TranslateKeyPipe, decorators: [{
111
+ type: Pipe,
112
+ args: [{ name: 't', pure: false, standalone: true }]
113
+ }] });
114
+
79
115
  const sparkAuthInterceptor = (req, next) => {
80
116
  const config = inject(SPARK_AUTH_CONFIG);
81
117
  const router = inject(Router);
@@ -175,24 +211,24 @@ class SparkAuthBarComponent {
175
211
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.5", type: SparkAuthBarComponent, isStandalone: true, selector: "spark-auth-bar", ngImport: i0, template: `
176
212
  @if (authService.isAuthenticated()) {
177
213
  <span class="me-2">{{ authService.user()?.userName }}</span>
178
- <button class="btn btn-outline-light btn-sm" (click)="onLogout()">Logout</button>
214
+ <button class="btn btn-outline-light btn-sm" (click)="onLogout()">{{ 'authLogout' | t }}</button>
179
215
  } @else {
180
- <a class="btn btn-outline-light btn-sm" [routerLink]="config.loginUrl">Login</a>
216
+ <a class="btn btn-outline-light btn-sm" [routerLink]="config.loginUrl">{{ 'authLogin' | t }}</a>
181
217
  }
182
- `, isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
218
+ `, isInline: true, dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }] });
183
219
  }
184
220
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkAuthBarComponent, decorators: [{
185
221
  type: Component,
186
222
  args: [{
187
223
  selector: 'spark-auth-bar',
188
224
  standalone: true,
189
- imports: [RouterLink],
225
+ imports: [RouterLink, TranslateKeyPipe],
190
226
  template: `
191
227
  @if (authService.isAuthenticated()) {
192
228
  <span class="me-2">{{ authService.user()?.userName }}</span>
193
- <button class="btn btn-outline-light btn-sm" (click)="onLogout()">Logout</button>
229
+ <button class="btn btn-outline-light btn-sm" (click)="onLogout()">{{ 'authLogout' | t }}</button>
194
230
  } @else {
195
- <a class="btn btn-outline-light btn-sm" [routerLink]="config.loginUrl">Login</a>
231
+ <a class="btn btn-outline-light btn-sm" [routerLink]="config.loginUrl">{{ 'authLogin' | t }}</a>
196
232
  }
197
233
  `,
198
234
  }]
@@ -204,6 +240,7 @@ class SparkLoginComponent {
204
240
  router = inject(Router);
205
241
  route = inject(ActivatedRoute);
206
242
  config = inject(SPARK_AUTH_CONFIG);
243
+ translation = inject(SparkAuthTranslationService);
207
244
  routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
208
245
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
209
246
  errorMessage = signal('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
@@ -233,7 +270,7 @@ class SparkLoginComponent {
233
270
  });
234
271
  }
235
272
  else {
236
- this.errorMessage.set('Invalid email or password.');
273
+ this.errorMessage.set(this.translation.t('authInvalidCredentials'));
237
274
  }
238
275
  },
239
276
  });
@@ -243,7 +280,7 @@ class SparkLoginComponent {
243
280
  <div class="d-flex justify-content-center">
244
281
  <div class="card" style="width: 100%; max-width: 400px;">
245
282
  <div class="card-body">
246
- <h3 class="card-title text-center mb-4">Login</h3>
283
+ <h3 class="card-title text-center mb-4">{{ 'authLogin' | t }}</h3>
247
284
 
248
285
  @if (errorMessage()) {
249
286
  <div class="alert alert-danger" role="alert">{{ errorMessage() }}</div>
@@ -252,7 +289,7 @@ class SparkLoginComponent {
252
289
  <bs-form>
253
290
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
254
291
  <div class="mb-3">
255
- <label for="email" class="form-label">Email</label>
292
+ <label for="email" class="form-label">{{ 'authEmail' | t }}</label>
256
293
  <input
257
294
  type="text"
258
295
  id="email"
@@ -262,7 +299,7 @@ class SparkLoginComponent {
262
299
  </div>
263
300
 
264
301
  <div class="mb-3">
265
- <label for="password" class="form-label">Password</label>
302
+ <label for="password" class="form-label">{{ 'authPassword' | t }}</label>
266
303
  <input
267
304
  type="password"
268
305
  id="password"
@@ -272,7 +309,7 @@ class SparkLoginComponent {
272
309
  </div>
273
310
 
274
311
  <div class="mb-3">
275
- <bs-toggle-button [type]="'checkbox'" formControlName="rememberMe" [name]="'rememberMe'">Remember me</bs-toggle-button>
312
+ <bs-toggle-button [type]="'checkbox'" formControlName="rememberMe" [name]="'rememberMe'">{{ 'authRememberMe' | t }}</bs-toggle-button>
276
313
  </div>
277
314
 
278
315
  <button
@@ -283,33 +320,33 @@ class SparkLoginComponent {
283
320
  @if (loading()) {
284
321
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
285
322
  }
286
- Login
323
+ {{ 'authLogin' | t }}
287
324
  </button>
288
325
  </form>
289
326
  </bs-form>
290
327
 
291
328
  <div class="mt-3 text-center">
292
- <a [routerLink]="routePaths.register">Create an account</a>
329
+ <a [routerLink]="routePaths.register">{{ 'authCreateAccount' | t }}</a>
293
330
  </div>
294
331
  <div class="mt-2 text-center">
295
- <a [routerLink]="routePaths.forgotPassword">Forgot password?</a>
332
+ <a [routerLink]="routePaths.forgotPassword">{{ 'authForgotPassword' | t }}</a>
296
333
  </div>
297
334
  </div>
298
335
  </div>
299
336
  </div>
300
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "ngmodule", type: BsToggleButtonModule }, { kind: "component", type: i3.BsToggleButtonComponent, selector: "bs-toggle-button", inputs: ["type", "isToggled", "name", "value", "group"], outputs: ["isToggledChange"] }, { kind: "directive", type: i3.BsToggleButtonValueAccessor, selector: "bs-toggle-button" }] });
337
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "ngmodule", type: BsToggleButtonModule }, { kind: "component", type: i3.BsToggleButtonComponent, selector: "bs-toggle-button", inputs: ["type", "isToggled", "name", "value", "group"], outputs: ["isToggledChange"] }, { kind: "directive", type: i3.BsToggleButtonValueAccessor, selector: "bs-toggle-button" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }] });
301
338
  }
302
339
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkLoginComponent, decorators: [{
303
340
  type: Component,
304
341
  args: [{
305
342
  selector: 'spark-login',
306
343
  standalone: true,
307
- imports: [ReactiveFormsModule, RouterLink, BsFormModule, BsToggleButtonModule],
344
+ imports: [ReactiveFormsModule, RouterLink, BsFormModule, BsToggleButtonModule, TranslateKeyPipe],
308
345
  template: `
309
346
  <div class="d-flex justify-content-center">
310
347
  <div class="card" style="width: 100%; max-width: 400px;">
311
348
  <div class="card-body">
312
- <h3 class="card-title text-center mb-4">Login</h3>
349
+ <h3 class="card-title text-center mb-4">{{ 'authLogin' | t }}</h3>
313
350
 
314
351
  @if (errorMessage()) {
315
352
  <div class="alert alert-danger" role="alert">{{ errorMessage() }}</div>
@@ -318,7 +355,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
318
355
  <bs-form>
319
356
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
320
357
  <div class="mb-3">
321
- <label for="email" class="form-label">Email</label>
358
+ <label for="email" class="form-label">{{ 'authEmail' | t }}</label>
322
359
  <input
323
360
  type="text"
324
361
  id="email"
@@ -328,7 +365,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
328
365
  </div>
329
366
 
330
367
  <div class="mb-3">
331
- <label for="password" class="form-label">Password</label>
368
+ <label for="password" class="form-label">{{ 'authPassword' | t }}</label>
332
369
  <input
333
370
  type="password"
334
371
  id="password"
@@ -338,7 +375,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
338
375
  </div>
339
376
 
340
377
  <div class="mb-3">
341
- <bs-toggle-button [type]="'checkbox'" formControlName="rememberMe" [name]="'rememberMe'">Remember me</bs-toggle-button>
378
+ <bs-toggle-button [type]="'checkbox'" formControlName="rememberMe" [name]="'rememberMe'">{{ 'authRememberMe' | t }}</bs-toggle-button>
342
379
  </div>
343
380
 
344
381
  <button
@@ -349,16 +386,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
349
386
  @if (loading()) {
350
387
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
351
388
  }
352
- Login
389
+ {{ 'authLogin' | t }}
353
390
  </button>
354
391
  </form>
355
392
  </bs-form>
356
393
 
357
394
  <div class="mt-3 text-center">
358
- <a [routerLink]="routePaths.register">Create an account</a>
395
+ <a [routerLink]="routePaths.register">{{ 'authCreateAccount' | t }}</a>
359
396
  </div>
360
397
  <div class="mt-2 text-center">
361
- <a [routerLink]="routePaths.forgotPassword">Forgot password?</a>
398
+ <a [routerLink]="routePaths.forgotPassword">{{ 'authForgotPassword' | t }}</a>
362
399
  </div>
363
400
  </div>
364
401
  </div>
@@ -379,6 +416,7 @@ class SparkTwoFactorComponent {
379
416
  router = inject(Router);
380
417
  route = inject(ActivatedRoute);
381
418
  config = inject(SPARK_AUTH_CONFIG);
419
+ translation = inject(SparkAuthTranslationService);
382
420
  routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
383
421
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
384
422
  errorMessage = signal('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
@@ -395,7 +433,9 @@ class SparkTwoFactorComponent {
395
433
  const isRecovery = this.useRecoveryCode();
396
434
  const code = isRecovery ? this.form.value.recoveryCode : this.form.value.code;
397
435
  if (!code?.trim()) {
398
- this.errorMessage.set(isRecovery ? 'Please enter a recovery code.' : 'Please enter the 6-digit code.');
436
+ this.errorMessage.set(isRecovery
437
+ ? this.translation.t('authEnterRecoveryCodeError')
438
+ : this.translation.t('authEnterCodeError'));
399
439
  return;
400
440
  }
401
441
  this.loading.set(true);
@@ -410,7 +450,7 @@ class SparkTwoFactorComponent {
410
450
  },
411
451
  error: () => {
412
452
  this.loading.set(false);
413
- this.errorMessage.set('Invalid code. Please try again.');
453
+ this.errorMessage.set(this.translation.t('authInvalidCode'));
414
454
  },
415
455
  });
416
456
  }
@@ -419,7 +459,7 @@ class SparkTwoFactorComponent {
419
459
  <div class="d-flex justify-content-center">
420
460
  <div class="card" style="width: 100%; max-width: 400px;">
421
461
  <div class="card-body">
422
- <h3 class="card-title text-center mb-4">Two-Factor Authentication</h3>
462
+ <h3 class="card-title text-center mb-4">{{ 'authTwoFactorTitle' | t }}</h3>
423
463
 
424
464
  @if (errorMessage()) {
425
465
  <div class="alert alert-danger" role="alert">{{ errorMessage() }}</div>
@@ -429,25 +469,25 @@ class SparkTwoFactorComponent {
429
469
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
430
470
  @if (!useRecoveryCode()) {
431
471
  <div class="mb-3">
432
- <label for="code" class="form-label">Authentication Code</label>
472
+ <label for="code" class="form-label">{{ 'authCode' | t }}</label>
433
473
  <input
434
474
  type="text"
435
475
  id="code"
436
476
  formControlName="code"
437
477
  autocomplete="one-time-code"
438
478
  maxlength="6"
439
- placeholder="Enter 6-digit code"
479
+ [placeholder]="'authEnterCode' | t"
440
480
  />
441
481
  </div>
442
482
  } @else {
443
483
  <div class="mb-3">
444
- <label for="recoveryCode" class="form-label">Recovery Code</label>
484
+ <label for="recoveryCode" class="form-label">{{ 'authRecoveryCode' | t }}</label>
445
485
  <input
446
486
  type="text"
447
487
  id="recoveryCode"
448
488
  formControlName="recoveryCode"
449
489
  autocomplete="off"
450
- placeholder="Enter recovery code"
490
+ [placeholder]="'authEnterRecoveryCode' | t"
451
491
  />
452
492
  </div>
453
493
  }
@@ -460,7 +500,7 @@ class SparkTwoFactorComponent {
460
500
  @if (loading()) {
461
501
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
462
502
  }
463
- Verify
503
+ {{ 'authVerify' | t }}
464
504
  </button>
465
505
  </form>
466
506
  </bs-form>
@@ -468,31 +508,31 @@ class SparkTwoFactorComponent {
468
508
  <div class="mt-3 text-center">
469
509
  <button class="btn btn-link" (click)="toggleRecoveryCode()">
470
510
  @if (useRecoveryCode()) {
471
- Use authentication code instead
511
+ {{ 'authUseAuthCode' | t }}
472
512
  } @else {
473
- Use a recovery code instead
513
+ {{ 'authUseRecoveryCode' | t }}
474
514
  }
475
515
  </button>
476
516
  </div>
477
517
  <div class="mt-2 text-center">
478
- <a [routerLink]="routePaths.login">Back to login</a>
518
+ <a [routerLink]="routePaths.login">{{ 'authBackToLogin' | t }}</a>
479
519
  </div>
480
520
  </div>
481
521
  </div>
482
522
  </div>
483
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }] });
523
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }] });
484
524
  }
485
525
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkTwoFactorComponent, decorators: [{
486
526
  type: Component,
487
527
  args: [{
488
528
  selector: 'spark-two-factor',
489
529
  standalone: true,
490
- imports: [ReactiveFormsModule, RouterLink, BsFormModule],
530
+ imports: [ReactiveFormsModule, RouterLink, BsFormModule, TranslateKeyPipe],
491
531
  template: `
492
532
  <div class="d-flex justify-content-center">
493
533
  <div class="card" style="width: 100%; max-width: 400px;">
494
534
  <div class="card-body">
495
- <h3 class="card-title text-center mb-4">Two-Factor Authentication</h3>
535
+ <h3 class="card-title text-center mb-4">{{ 'authTwoFactorTitle' | t }}</h3>
496
536
 
497
537
  @if (errorMessage()) {
498
538
  <div class="alert alert-danger" role="alert">{{ errorMessage() }}</div>
@@ -502,25 +542,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
502
542
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
503
543
  @if (!useRecoveryCode()) {
504
544
  <div class="mb-3">
505
- <label for="code" class="form-label">Authentication Code</label>
545
+ <label for="code" class="form-label">{{ 'authCode' | t }}</label>
506
546
  <input
507
547
  type="text"
508
548
  id="code"
509
549
  formControlName="code"
510
550
  autocomplete="one-time-code"
511
551
  maxlength="6"
512
- placeholder="Enter 6-digit code"
552
+ [placeholder]="'authEnterCode' | t"
513
553
  />
514
554
  </div>
515
555
  } @else {
516
556
  <div class="mb-3">
517
- <label for="recoveryCode" class="form-label">Recovery Code</label>
557
+ <label for="recoveryCode" class="form-label">{{ 'authRecoveryCode' | t }}</label>
518
558
  <input
519
559
  type="text"
520
560
  id="recoveryCode"
521
561
  formControlName="recoveryCode"
522
562
  autocomplete="off"
523
- placeholder="Enter recovery code"
563
+ [placeholder]="'authEnterRecoveryCode' | t"
524
564
  />
525
565
  </div>
526
566
  }
@@ -533,7 +573,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
533
573
  @if (loading()) {
534
574
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
535
575
  }
536
- Verify
576
+ {{ 'authVerify' | t }}
537
577
  </button>
538
578
  </form>
539
579
  </bs-form>
@@ -541,14 +581,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
541
581
  <div class="mt-3 text-center">
542
582
  <button class="btn btn-link" (click)="toggleRecoveryCode()">
543
583
  @if (useRecoveryCode()) {
544
- Use authentication code instead
584
+ {{ 'authUseAuthCode' | t }}
545
585
  } @else {
546
- Use a recovery code instead
586
+ {{ 'authUseRecoveryCode' | t }}
547
587
  }
548
588
  </button>
549
589
  </div>
550
590
  <div class="mt-2 text-center">
551
- <a [routerLink]="routePaths.login">Back to login</a>
591
+ <a [routerLink]="routePaths.login">{{ 'authBackToLogin' | t }}</a>
552
592
  </div>
553
593
  </div>
554
594
  </div>
@@ -575,6 +615,7 @@ class SparkRegisterComponent {
575
615
  fb = inject(FormBuilder);
576
616
  authService = inject(SparkAuthService);
577
617
  router = inject(Router);
618
+ translation = inject(SparkAuthTranslationService);
578
619
  routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
579
620
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
580
621
  errorMessage = signal('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
@@ -608,7 +649,7 @@ class SparkRegisterComponent {
608
649
  this.errorMessage.set(err.error.detail);
609
650
  }
610
651
  else {
611
- this.errorMessage.set('Registration failed. Please try again.');
652
+ this.errorMessage.set(this.translation.t('authRegistrationFailed'));
612
653
  }
613
654
  },
614
655
  });
@@ -618,7 +659,7 @@ class SparkRegisterComponent {
618
659
  <div class="d-flex justify-content-center">
619
660
  <div class="card" style="width: 100%; max-width: 400px;">
620
661
  <div class="card-body">
621
- <h3 class="card-title text-center mb-4">Register</h3>
662
+ <h3 class="card-title text-center mb-4">{{ 'authRegister' | t }}</h3>
622
663
 
623
664
  @if (errorMessage()) {
624
665
  <div class="alert alert-danger" role="alert">{{ errorMessage() }}</div>
@@ -627,7 +668,7 @@ class SparkRegisterComponent {
627
668
  <bs-form>
628
669
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
629
670
  <div class="mb-3">
630
- <label for="email" class="form-label">Email</label>
671
+ <label for="email" class="form-label">{{ 'authEmail' | t }}</label>
631
672
  <input
632
673
  type="email"
633
674
  id="email"
@@ -635,12 +676,12 @@ class SparkRegisterComponent {
635
676
  autocomplete="email"
636
677
  />
637
678
  @if (form.get('email')?.touched && form.get('email')?.hasError('email')) {
638
- <div class="text-danger mt-1">Please enter a valid email address.</div>
679
+ <div class="text-danger mt-1">{{ 'authInvalidEmail' | t }}</div>
639
680
  }
640
681
  </div>
641
682
 
642
683
  <div class="mb-3">
643
- <label for="password" class="form-label">Password</label>
684
+ <label for="password" class="form-label">{{ 'authPassword' | t }}</label>
644
685
  <input
645
686
  type="password"
646
687
  id="password"
@@ -650,7 +691,7 @@ class SparkRegisterComponent {
650
691
  </div>
651
692
 
652
693
  <div class="mb-3">
653
- <label for="confirmPassword" class="form-label">Confirm Password</label>
694
+ <label for="confirmPassword" class="form-label">{{ 'authConfirmPassword' | t }}</label>
654
695
  <input
655
696
  type="password"
656
697
  id="confirmPassword"
@@ -658,7 +699,7 @@ class SparkRegisterComponent {
658
699
  autocomplete="new-password"
659
700
  />
660
701
  @if (form.touched && form.hasError('passwordMismatch')) {
661
- <div class="text-danger mt-1">Passwords do not match.</div>
702
+ <div class="text-danger mt-1">{{ 'authPasswordMismatch' | t }}</div>
662
703
  }
663
704
  </div>
664
705
 
@@ -670,31 +711,31 @@ class SparkRegisterComponent {
670
711
  @if (loading()) {
671
712
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
672
713
  }
673
- Register
714
+ {{ 'authRegister' | t }}
674
715
  </button>
675
716
  </form>
676
717
  </bs-form>
677
718
 
678
719
  <div class="mt-3 text-center">
679
- <span>Already have an account? </span>
680
- <a [routerLink]="routePaths.login">Login</a>
720
+ <span>{{ 'authAlreadyHaveAccount' | t }} </span>
721
+ <a [routerLink]="routePaths.login">{{ 'authLogin' | t }}</a>
681
722
  </div>
682
723
  </div>
683
724
  </div>
684
725
  </div>
685
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }] });
726
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }] });
686
727
  }
687
728
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkRegisterComponent, decorators: [{
688
729
  type: Component,
689
730
  args: [{
690
731
  selector: 'spark-register',
691
732
  standalone: true,
692
- imports: [ReactiveFormsModule, RouterLink, BsFormModule],
733
+ imports: [ReactiveFormsModule, RouterLink, BsFormModule, TranslateKeyPipe],
693
734
  template: `
694
735
  <div class="d-flex justify-content-center">
695
736
  <div class="card" style="width: 100%; max-width: 400px;">
696
737
  <div class="card-body">
697
- <h3 class="card-title text-center mb-4">Register</h3>
738
+ <h3 class="card-title text-center mb-4">{{ 'authRegister' | t }}</h3>
698
739
 
699
740
  @if (errorMessage()) {
700
741
  <div class="alert alert-danger" role="alert">{{ errorMessage() }}</div>
@@ -703,7 +744,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
703
744
  <bs-form>
704
745
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
705
746
  <div class="mb-3">
706
- <label for="email" class="form-label">Email</label>
747
+ <label for="email" class="form-label">{{ 'authEmail' | t }}</label>
707
748
  <input
708
749
  type="email"
709
750
  id="email"
@@ -711,12 +752,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
711
752
  autocomplete="email"
712
753
  />
713
754
  @if (form.get('email')?.touched && form.get('email')?.hasError('email')) {
714
- <div class="text-danger mt-1">Please enter a valid email address.</div>
755
+ <div class="text-danger mt-1">{{ 'authInvalidEmail' | t }}</div>
715
756
  }
716
757
  </div>
717
758
 
718
759
  <div class="mb-3">
719
- <label for="password" class="form-label">Password</label>
760
+ <label for="password" class="form-label">{{ 'authPassword' | t }}</label>
720
761
  <input
721
762
  type="password"
722
763
  id="password"
@@ -726,7 +767,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
726
767
  </div>
727
768
 
728
769
  <div class="mb-3">
729
- <label for="confirmPassword" class="form-label">Confirm Password</label>
770
+ <label for="confirmPassword" class="form-label">{{ 'authConfirmPassword' | t }}</label>
730
771
  <input
731
772
  type="password"
732
773
  id="confirmPassword"
@@ -734,7 +775,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
734
775
  autocomplete="new-password"
735
776
  />
736
777
  @if (form.touched && form.hasError('passwordMismatch')) {
737
- <div class="text-danger mt-1">Passwords do not match.</div>
778
+ <div class="text-danger mt-1">{{ 'authPasswordMismatch' | t }}</div>
738
779
  }
739
780
  </div>
740
781
 
@@ -746,14 +787,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
746
787
  @if (loading()) {
747
788
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
748
789
  }
749
- Register
790
+ {{ 'authRegister' | t }}
750
791
  </button>
751
792
  </form>
752
793
  </bs-form>
753
794
 
754
795
  <div class="mt-3 text-center">
755
- <span>Already have an account? </span>
756
- <a [routerLink]="routePaths.login">Login</a>
796
+ <span>{{ 'authAlreadyHaveAccount' | t }} </span>
797
+ <a [routerLink]="routePaths.login">{{ 'authLogin' | t }}</a>
757
798
  </div>
758
799
  </div>
759
800
  </div>
@@ -771,6 +812,7 @@ var sparkRegister_component = /*#__PURE__*/Object.freeze({
771
812
  class SparkForgotPasswordComponent {
772
813
  fb = inject(FormBuilder);
773
814
  authService = inject(SparkAuthService);
815
+ translation = inject(SparkAuthTranslationService);
774
816
  routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
775
817
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
776
818
  errorMessage = signal('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
@@ -790,12 +832,12 @@ class SparkForgotPasswordComponent {
790
832
  this.authService.forgotPassword(email).subscribe({
791
833
  next: () => {
792
834
  this.loading.set(false);
793
- this.successMessage.set('If an account with that email exists, we\'ve sent a password reset link.');
835
+ this.successMessage.set(this.translation.t('authForgotPasswordSuccess'));
794
836
  },
795
837
  error: () => {
796
838
  this.loading.set(false);
797
839
  // Don't reveal whether the email exists
798
- this.successMessage.set('If an account with that email exists, we\'ve sent a password reset link.');
840
+ this.successMessage.set(this.translation.t('authForgotPasswordSuccess'));
799
841
  },
800
842
  });
801
843
  }
@@ -804,7 +846,7 @@ class SparkForgotPasswordComponent {
804
846
  <div class="d-flex justify-content-center">
805
847
  <div class="card" style="width: 100%; max-width: 400px;">
806
848
  <div class="card-body">
807
- <h3 class="card-title text-center mb-4">Forgot Password</h3>
849
+ <h3 class="card-title text-center mb-4">{{ 'authForgotPasswordTitle' | t }}</h3>
808
850
 
809
851
  @if (successMessage()) {
810
852
  <div class="alert alert-success" role="alert">{{ successMessage() }}</div>
@@ -816,13 +858,13 @@ class SparkForgotPasswordComponent {
816
858
 
817
859
  @if (!successMessage()) {
818
860
  <p class="text-muted mb-3">
819
- Enter your email address and we will send you a link to reset your password.
861
+ {{ 'authForgotPasswordDescription' | t }}
820
862
  </p>
821
863
 
822
864
  <bs-form>
823
865
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
824
866
  <div class="mb-3">
825
- <label for="email" class="form-label">Email</label>
867
+ <label for="email" class="form-label">{{ 'authEmail' | t }}</label>
826
868
  <input
827
869
  type="email"
828
870
  id="email"
@@ -839,31 +881,31 @@ class SparkForgotPasswordComponent {
839
881
  @if (loading()) {
840
882
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
841
883
  }
842
- Send Reset Link
884
+ {{ 'authSendResetLink' | t }}
843
885
  </button>
844
886
  </form>
845
887
  </bs-form>
846
888
  }
847
889
 
848
890
  <div class="mt-3 text-center">
849
- <a [routerLink]="routePaths.login">Back to login</a>
891
+ <a [routerLink]="routePaths.login">{{ 'authBackToLogin' | t }}</a>
850
892
  </div>
851
893
  </div>
852
894
  </div>
853
895
  </div>
854
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }] });
896
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }] });
855
897
  }
856
898
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkForgotPasswordComponent, decorators: [{
857
899
  type: Component,
858
900
  args: [{
859
901
  selector: 'spark-forgot-password',
860
902
  standalone: true,
861
- imports: [ReactiveFormsModule, RouterLink, BsFormModule],
903
+ imports: [ReactiveFormsModule, RouterLink, BsFormModule, TranslateKeyPipe],
862
904
  template: `
863
905
  <div class="d-flex justify-content-center">
864
906
  <div class="card" style="width: 100%; max-width: 400px;">
865
907
  <div class="card-body">
866
- <h3 class="card-title text-center mb-4">Forgot Password</h3>
908
+ <h3 class="card-title text-center mb-4">{{ 'authForgotPasswordTitle' | t }}</h3>
867
909
 
868
910
  @if (successMessage()) {
869
911
  <div class="alert alert-success" role="alert">{{ successMessage() }}</div>
@@ -875,13 +917,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
875
917
 
876
918
  @if (!successMessage()) {
877
919
  <p class="text-muted mb-3">
878
- Enter your email address and we will send you a link to reset your password.
920
+ {{ 'authForgotPasswordDescription' | t }}
879
921
  </p>
880
922
 
881
923
  <bs-form>
882
924
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
883
925
  <div class="mb-3">
884
- <label for="email" class="form-label">Email</label>
926
+ <label for="email" class="form-label">{{ 'authEmail' | t }}</label>
885
927
  <input
886
928
  type="email"
887
929
  id="email"
@@ -898,14 +940,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
898
940
  @if (loading()) {
899
941
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
900
942
  }
901
- Send Reset Link
943
+ {{ 'authSendResetLink' | t }}
902
944
  </button>
903
945
  </form>
904
946
  </bs-form>
905
947
  }
906
948
 
907
949
  <div class="mt-3 text-center">
908
- <a [routerLink]="routePaths.login">Back to login</a>
950
+ <a [routerLink]="routePaths.login">{{ 'authBackToLogin' | t }}</a>
909
951
  </div>
910
952
  </div>
911
953
  </div>
@@ -933,6 +975,7 @@ class SparkResetPasswordComponent {
933
975
  authService = inject(SparkAuthService);
934
976
  router = inject(Router);
935
977
  route = inject(ActivatedRoute);
978
+ translation = inject(SparkAuthTranslationService);
936
979
  routePaths = inject(SPARK_AUTH_ROUTE_PATHS);
937
980
  loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
938
981
  errorMessage = signal('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
@@ -947,7 +990,7 @@ class SparkResetPasswordComponent {
947
990
  this.email = this.route.snapshot.queryParamMap.get('email') ?? '';
948
991
  this.code = this.route.snapshot.queryParamMap.get('code') ?? '';
949
992
  if (!this.email || !this.code) {
950
- this.errorMessage.set('Invalid password reset link. Please request a new one.');
993
+ this.errorMessage.set(this.translation.t('authInvalidResetLink'));
951
994
  }
952
995
  }
953
996
  onSubmit() {
@@ -956,7 +999,7 @@ class SparkResetPasswordComponent {
956
999
  return;
957
1000
  }
958
1001
  if (!this.email || !this.code) {
959
- this.errorMessage.set('Invalid password reset link. Please request a new one.');
1002
+ this.errorMessage.set(this.translation.t('authInvalidResetLink'));
960
1003
  return;
961
1004
  }
962
1005
  this.loading.set(true);
@@ -966,7 +1009,7 @@ class SparkResetPasswordComponent {
966
1009
  this.authService.resetPassword(this.email, this.code, newPassword).subscribe({
967
1010
  next: () => {
968
1011
  this.loading.set(false);
969
- this.successMessage.set('Your password has been reset successfully.');
1012
+ this.successMessage.set(this.translation.t('authResetSuccess'));
970
1013
  },
971
1014
  error: (err) => {
972
1015
  this.loading.set(false);
@@ -974,7 +1017,7 @@ class SparkResetPasswordComponent {
974
1017
  this.errorMessage.set(err.error.detail);
975
1018
  }
976
1019
  else {
977
- this.errorMessage.set('Failed to reset password. The link may have expired.');
1020
+ this.errorMessage.set(this.translation.t('authResetFailed'));
978
1021
  }
979
1022
  },
980
1023
  });
@@ -984,13 +1027,13 @@ class SparkResetPasswordComponent {
984
1027
  <div class="d-flex justify-content-center">
985
1028
  <div class="card" style="width: 100%; max-width: 400px;">
986
1029
  <div class="card-body">
987
- <h3 class="card-title text-center mb-4">Reset Password</h3>
1030
+ <h3 class="card-title text-center mb-4">{{ 'authResetPassword' | t }}</h3>
988
1031
 
989
1032
  @if (successMessage()) {
990
1033
  <div class="alert alert-success" role="alert">
991
1034
  {{ successMessage() }}
992
1035
  <div class="mt-2">
993
- <a [routerLink]="routePaths.login">Go to login</a>
1036
+ <a [routerLink]="routePaths.login">{{ 'authGoToLogin' | t }}</a>
994
1037
  </div>
995
1038
  </div>
996
1039
  }
@@ -1003,7 +1046,7 @@ class SparkResetPasswordComponent {
1003
1046
  <bs-form>
1004
1047
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
1005
1048
  <div class="mb-3">
1006
- <label for="newPassword" class="form-label">New Password</label>
1049
+ <label for="newPassword" class="form-label">{{ 'authNewPassword' | t }}</label>
1007
1050
  <input
1008
1051
  type="password"
1009
1052
  id="newPassword"
@@ -1013,7 +1056,7 @@ class SparkResetPasswordComponent {
1013
1056
  </div>
1014
1057
 
1015
1058
  <div class="mb-3">
1016
- <label for="confirmPassword" class="form-label">Confirm Password</label>
1059
+ <label for="confirmPassword" class="form-label">{{ 'authConfirmPassword' | t }}</label>
1017
1060
  <input
1018
1061
  type="password"
1019
1062
  id="confirmPassword"
@@ -1021,7 +1064,7 @@ class SparkResetPasswordComponent {
1021
1064
  autocomplete="new-password"
1022
1065
  />
1023
1066
  @if (form.touched && form.hasError('passwordMismatch')) {
1024
- <div class="text-danger mt-1">Passwords do not match.</div>
1067
+ <div class="text-danger mt-1">{{ 'authPasswordMismatch' | t }}</div>
1025
1068
  }
1026
1069
  </div>
1027
1070
 
@@ -1033,37 +1076,37 @@ class SparkResetPasswordComponent {
1033
1076
  @if (loading()) {
1034
1077
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
1035
1078
  }
1036
- Reset Password
1079
+ {{ 'authResetPassword' | t }}
1037
1080
  </button>
1038
1081
  </form>
1039
1082
  </bs-form>
1040
1083
 
1041
1084
  <div class="mt-3 text-center">
1042
- <a [routerLink]="routePaths.login">Back to login</a>
1085
+ <a [routerLink]="routePaths.login">{{ 'authBackToLogin' | t }}</a>
1043
1086
  </div>
1044
1087
  }
1045
1088
  </div>
1046
1089
  </div>
1047
1090
  </div>
1048
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }] });
1091
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: BsFormModule }, { kind: "component", type: i2.BsFormComponent, selector: "bs-form", inputs: ["action", "method"], outputs: ["submitted"] }, { kind: "directive", type: i2.BsFormControlDirective, selector: "bs-form input:not(.no-form-control), bs-form textarea:not(.no-form-control)" }, { kind: "pipe", type: TranslateKeyPipe, name: "t" }] });
1049
1092
  }
1050
1093
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImport: i0, type: SparkResetPasswordComponent, decorators: [{
1051
1094
  type: Component,
1052
1095
  args: [{
1053
1096
  selector: 'spark-reset-password',
1054
1097
  standalone: true,
1055
- imports: [ReactiveFormsModule, RouterLink, BsFormModule],
1098
+ imports: [ReactiveFormsModule, RouterLink, BsFormModule, TranslateKeyPipe],
1056
1099
  template: `
1057
1100
  <div class="d-flex justify-content-center">
1058
1101
  <div class="card" style="width: 100%; max-width: 400px;">
1059
1102
  <div class="card-body">
1060
- <h3 class="card-title text-center mb-4">Reset Password</h3>
1103
+ <h3 class="card-title text-center mb-4">{{ 'authResetPassword' | t }}</h3>
1061
1104
 
1062
1105
  @if (successMessage()) {
1063
1106
  <div class="alert alert-success" role="alert">
1064
1107
  {{ successMessage() }}
1065
1108
  <div class="mt-2">
1066
- <a [routerLink]="routePaths.login">Go to login</a>
1109
+ <a [routerLink]="routePaths.login">{{ 'authGoToLogin' | t }}</a>
1067
1110
  </div>
1068
1111
  </div>
1069
1112
  }
@@ -1076,7 +1119,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
1076
1119
  <bs-form>
1077
1120
  <form [formGroup]="form" (ngSubmit)="onSubmit()">
1078
1121
  <div class="mb-3">
1079
- <label for="newPassword" class="form-label">New Password</label>
1122
+ <label for="newPassword" class="form-label">{{ 'authNewPassword' | t }}</label>
1080
1123
  <input
1081
1124
  type="password"
1082
1125
  id="newPassword"
@@ -1086,7 +1129,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
1086
1129
  </div>
1087
1130
 
1088
1131
  <div class="mb-3">
1089
- <label for="confirmPassword" class="form-label">Confirm Password</label>
1132
+ <label for="confirmPassword" class="form-label">{{ 'authConfirmPassword' | t }}</label>
1090
1133
  <input
1091
1134
  type="password"
1092
1135
  id="confirmPassword"
@@ -1094,7 +1137,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
1094
1137
  autocomplete="new-password"
1095
1138
  />
1096
1139
  @if (form.touched && form.hasError('passwordMismatch')) {
1097
- <div class="text-danger mt-1">Passwords do not match.</div>
1140
+ <div class="text-danger mt-1">{{ 'authPasswordMismatch' | t }}</div>
1098
1141
  }
1099
1142
  </div>
1100
1143
 
@@ -1106,13 +1149,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.5", ngImpor
1106
1149
  @if (loading()) {
1107
1150
  <span class="spinner-border spinner-border-sm me-1" role="status"></span>
1108
1151
  }
1109
- Reset Password
1152
+ {{ 'authResetPassword' | t }}
1110
1153
  </button>
1111
1154
  </form>
1112
1155
  </bs-form>
1113
1156
 
1114
1157
  <div class="mt-3 text-center">
1115
- <a [routerLink]="routePaths.login">Back to login</a>
1158
+ <a [routerLink]="routePaths.login">{{ 'authBackToLogin' | t }}</a>
1116
1159
  </div>
1117
1160
  }
1118
1161
  </div>
@@ -1132,5 +1175,5 @@ var sparkResetPassword_component = /*#__PURE__*/Object.freeze({
1132
1175
  * Generated bundle index. Do not edit.
1133
1176
  */
1134
1177
 
1135
- export { SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, SparkAuthBarComponent, SparkAuthService, SparkForgotPasswordComponent, SparkLoginComponent, SparkRegisterComponent, SparkResetPasswordComponent, SparkTwoFactorComponent, defaultSparkAuthConfig, provideSparkAuth, sparkAuthGuard, sparkAuthInterceptor, sparkAuthRoutes, withSparkAuth };
1178
+ export { SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, SparkAuthBarComponent, SparkAuthService, SparkAuthTranslationService, SparkForgotPasswordComponent, SparkLoginComponent, SparkRegisterComponent, SparkResetPasswordComponent, SparkTwoFactorComponent, TranslateKeyPipe, defaultSparkAuthConfig, provideSparkAuth, sparkAuthGuard, sparkAuthInterceptor, sparkAuthRoutes, withSparkAuth };
1136
1179
  //# sourceMappingURL=mintplayer-ng-spark-auth.mjs.map