Version Fix and Locale Updates (#3626)
This commit is contained in:
parent
b644022f30
commit
a6ccae5849
15 changed files with 360 additions and 58 deletions
|
@ -3,3 +3,10 @@ export interface Language {
|
|||
title: string;
|
||||
}
|
||||
|
||||
export interface KavitaLocale {
|
||||
fileName: string; // isoCode aka what maps to the file on disk and what transloco loads
|
||||
renderName: string;
|
||||
translationCompletion: number;
|
||||
isRtL: boolean;
|
||||
hash: string;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import {Action} from "./action-factory.service";
|
|||
import {CoverImageSize} from "../admin/_models/cover-image-size";
|
||||
import {LicenseInfo} from "../_models/kavitaplus/license-info";
|
||||
import {LicenseService} from "./license.service";
|
||||
import {LocalizationService} from "./localization.service";
|
||||
|
||||
export enum Role {
|
||||
Admin = 'Admin',
|
||||
|
@ -48,6 +49,7 @@ export class AccountService {
|
|||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly licenseService = inject(LicenseService);
|
||||
private readonly localizationService = inject(LocalizationService);
|
||||
|
||||
baseUrl = environment.apiUrl;
|
||||
userKey = 'kavita-user';
|
||||
|
@ -168,6 +170,8 @@ export class AccountService {
|
|||
}
|
||||
|
||||
setCurrentUser(user?: User, refreshConnections = true) {
|
||||
|
||||
const isSameUser = this.currentUser === user;
|
||||
if (user) {
|
||||
user.roles = [];
|
||||
const roles = this.getDecodedToken(user.token).role;
|
||||
|
@ -197,7 +201,9 @@ export class AccountService {
|
|||
// But that really messes everything up
|
||||
this.messageHub.stopHubConnection();
|
||||
this.messageHub.createHubConnection(this.currentUser);
|
||||
this.licenseService.hasValidLicense().subscribe();
|
||||
if (!isSameUser) {
|
||||
this.licenseService.hasValidLicense().subscribe();
|
||||
}
|
||||
this.startRefreshTokenTimer();
|
||||
}
|
||||
}
|
||||
|
@ -316,6 +322,8 @@ export class AccountService {
|
|||
|
||||
// Update the locale on disk (for logout and compact-number pipe)
|
||||
localStorage.setItem(AccountService.localeKey, this.currentUser.preferences.locale);
|
||||
this.localizationService.refreshTranslations(this.currentUser.preferences.locale);
|
||||
|
||||
}
|
||||
return settings;
|
||||
}), takeUntilDestroyed(this.destroyRef));
|
||||
|
|
|
@ -1,18 +1,36 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {environment} from "../../environments/environment";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import {Language} from "../_models/metadata/language";
|
||||
import {KavitaLocale, Language} from "../_models/metadata/language";
|
||||
import {ReplaySubject, tap} from "rxjs";
|
||||
import {TranslocoService} from "@jsverse/transloco";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LocalizationService {
|
||||
|
||||
private readonly translocoService = inject(TranslocoService);
|
||||
|
||||
baseUrl = environment.apiUrl;
|
||||
|
||||
private readonly localeSubject = new ReplaySubject<KavitaLocale[]>(1);
|
||||
public readonly locales$ = this.localeSubject.asObservable();
|
||||
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
|
||||
getLocales() {
|
||||
return this.httpClient.get<Language[]>(this.baseUrl + 'locale');
|
||||
return this.httpClient.get<KavitaLocale[]>(this.baseUrl + 'locale').pipe(tap(locales => {
|
||||
this.localeSubject.next(locales);
|
||||
}));
|
||||
}
|
||||
|
||||
refreshTranslations(lang: string) {
|
||||
|
||||
// Clear the cached translation
|
||||
localStorage.removeItem(`@@TRANSLOCO_PERSIST_TRANSLATIONS/${lang}`);
|
||||
|
||||
// Reload the translation
|
||||
return this.translocoService.load(lang);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,12 @@ import {SideNavComponent} from './sidenav/_components/side-nav/side-nav.componen
|
|||
import {NavHeaderComponent} from "./nav/_components/nav-header/nav-header.component";
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import {ServerService} from "./_services/server.service";
|
||||
import {OutOfDateModalComponent} from "./announcements/_components/out-of-date-modal/out-of-date-modal.component";
|
||||
import {PreferenceNavComponent} from "./sidenav/preference-nav/preference-nav.component";
|
||||
import {Breakpoint, UtilityService} from "./shared/_services/utility.service";
|
||||
import {TranslocoService} from "@jsverse/transloco";
|
||||
import {User} from "./_models/user";
|
||||
import {VersionService} from "./_services/version.service";
|
||||
import {LicenseService} from "./_services/license.service";
|
||||
import {LocalizationService} from "./_services/localization.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
@ -36,8 +35,9 @@ import {LicenseService} from "./_services/license.service";
|
|||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
protected readonly Breakpoint = Breakpoint;
|
||||
|
||||
|
||||
transitionState$!: Observable<boolean>;
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly offcanvas = inject(NgbOffcanvas);
|
||||
|
@ -53,8 +53,9 @@ export class AppComponent implements OnInit {
|
|||
private readonly translocoService = inject(TranslocoService);
|
||||
private readonly versionService = inject(VersionService); // Needs to be injected to run background job
|
||||
private readonly licenseService = inject(LicenseService);
|
||||
private readonly localizationService = inject(LocalizationService);
|
||||
|
||||
protected readonly Breakpoint = Breakpoint;
|
||||
transitionState$!: Observable<boolean>;
|
||||
|
||||
|
||||
constructor(ratingConfig: NgbRatingConfig, modalConfig: NgbModalConfig) {
|
||||
|
@ -112,6 +113,7 @@ export class AppComponent implements OnInit {
|
|||
this.setDocHeight();
|
||||
this.setCurrentUser();
|
||||
this.themeService.setColorScape('');
|
||||
this.localizationService.getLocales().subscribe(); // This will cache the localizations on startup
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
</ng-template>
|
||||
<ng-template #edit>
|
||||
<select class="form-select" aria-describedby="global-header" formControlName="locale">
|
||||
@for(opt of locales; track opt.title) {
|
||||
<option [value]="opt.isoCode">{{opt.title | titlecase}}</option>
|
||||
@for(opt of locales; track opt.renderName) {
|
||||
<option [value]="opt.fileName">{{opt.renderName | titlecase}} ({{opt.translationCompletion | number:'1.0-1'}}%)</option>
|
||||
}
|
||||
</select>
|
||||
</ng-template>
|
||||
|
|
|
@ -21,7 +21,7 @@ import {LocalizationService} from "../../_services/localization.service";
|
|||
import {bookColorThemes} from "../../book-reader/_components/reader-settings/reader-settings.component";
|
||||
import {FormControl, FormGroup, ReactiveFormsModule} from "@angular/forms";
|
||||
import {User} from "../../_models/user";
|
||||
import {Language} from "../../_models/metadata/language";
|
||||
import {KavitaLocale, Language} from "../../_models/metadata/language";
|
||||
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
|
||||
import {debounceTime, distinctUntilChanged, filter, forkJoin, switchMap, tap} from "rxjs";
|
||||
import {take} from "rxjs/operators";
|
||||
|
@ -35,7 +35,7 @@ import {
|
|||
NgbAccordionDirective, NgbAccordionHeader,
|
||||
NgbAccordionItem, NgbTooltip
|
||||
} from "@ng-bootstrap/ng-bootstrap";
|
||||
import {AsyncPipe, NgStyle, NgTemplateOutlet, TitleCasePipe} from "@angular/common";
|
||||
import {AsyncPipe, DecimalPipe, NgStyle, NgTemplateOutlet, TitleCasePipe} from "@angular/common";
|
||||
import {ColorPickerModule} from "ngx-color-picker";
|
||||
import {SettingTitleComponent} from "../../settings/_components/setting-title/setting-title.component";
|
||||
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
|
||||
|
@ -76,7 +76,8 @@ import {LicenseService} from "../../_services/license.service";
|
|||
PdfSpreadModePipe,
|
||||
PdfThemePipe,
|
||||
PdfScrollModePipe,
|
||||
AsyncPipe
|
||||
AsyncPipe,
|
||||
DecimalPipe
|
||||
],
|
||||
templateUrl: './manage-user-preferences.component.html',
|
||||
styleUrl: './manage-user-preferences.component.scss',
|
||||
|
@ -112,7 +113,7 @@ export class ManageUserPreferencesComponent implements OnInit {
|
|||
|
||||
|
||||
fontFamilies: Array<string> = [];
|
||||
locales: Array<Language> = [{title: 'English', isoCode: 'en'}];
|
||||
locales: Array<KavitaLocale> = [];
|
||||
|
||||
settingsForm: FormGroup = new FormGroup({});
|
||||
user: User | undefined = undefined;
|
||||
|
@ -120,7 +121,7 @@ export class ManageUserPreferencesComponent implements OnInit {
|
|||
get Locale() {
|
||||
if (!this.settingsForm.get('locale')) return 'English';
|
||||
|
||||
return this.locales.filter(l => l.isoCode === this.settingsForm.get('locale')!.value)[0].title;
|
||||
return this.locales.filter(l => l.fileName === this.settingsForm.get('locale')!.value)[0].renderName;
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,7 +129,7 @@ export class ManageUserPreferencesComponent implements OnInit {
|
|||
this.fontFamilies = this.bookService.getFontFamilies().map(f => f.title);
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.localizationService.getLocales().subscribe(res => {
|
||||
this.localizationService.locales$.subscribe(res => {
|
||||
this.locales = res;
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
|
|
|
@ -30,6 +30,7 @@ import {LazyLoadImageModule} from "ng-lazyload-image";
|
|||
import {getSaver, SAVER} from "./app/_providers/saver.provider";
|
||||
import {distinctUntilChanged} from "rxjs/operators";
|
||||
import {APP_BASE_HREF, PlatformLocation} from "@angular/common";
|
||||
import {provideTranslocoDefaultLocale} from "@jsverse/transloco-locale/lib/transloco-locale.providers";
|
||||
|
||||
const disableAnimations = !('animate' in document.documentElement);
|
||||
|
||||
|
@ -112,7 +113,9 @@ const translocoOptions = {
|
|||
missingHandler: {
|
||||
useFallbackTranslation: true,
|
||||
allowEmpty: false,
|
||||
logMissingKey: true
|
||||
},
|
||||
failedRetries: 2,
|
||||
} as TranslocoConfig
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue