Localization - First Pass (#2174)

* Started designing the backend localization service

* Worked in Transloco for initial PoC

* Worked in Transloco for initial PoC

* Translated the login screen

* translated dashboard screen

* Started work on the backend

* Fixed a logic bug

* translated edit-user screen

* Hooked up the backend for having a locale property.

* Hooked up the ability to view the available locales and switch to them.

* Made the localization service languages be derived from what's in langs/ directory.

* Fixed up localization switching

* Switched when we check for a license on UI bootstrap

* Tweaked some code

* Fixed the bug where dashboard wasn't loading and made it so language switching is working.

* Fixed a bug on dashboard with languagePath

* Converted user-scrobble-history.component.html

* Converted spoiler.component.html

* Converted review-series-modal.component.html

* Converted review-card-modal.component.html

* Updated the readme

* Translated using Weblate (English)

Currently translated at 100.0% (54 of 54 strings)

Translation: Kavita/ui
Translate-URL: https://hosted.weblate.org/projects/kavita/ui/en/

* Converted review-card.component.html

* Deleted dead component

* Converted want-to-read.component.html

* Added translation using Weblate (Korean)

* Translated using Weblate (Spanish)

Currently translated at 40.7% (22 of 54 strings)

Translation: Kavita/ui
Translate-URL: https://hosted.weblate.org/projects/kavita/ui/es/

* Translated using Weblate (Korean)

Currently translated at 62.9% (34 of 54 strings)

Translation: Kavita/ui
Translate-URL: https://hosted.weblate.org/projects/kavita/ui/ko/

* Converted user-preferences.component.html

* Translated using Weblate (Korean)

Currently translated at 92.5% (50 of 54 strings)

Translation: Kavita/ui
Translate-URL: https://hosted.weblate.org/projects/kavita/ui/ko/

* Converted user-holds.component.html

* Converted theme-manager.component.html

* Converted restriction-selector.component.html

* Converted manage-devices.component.html

* Converted edit-device.component.html

* Converted change-password.component.html

* Converted change-email.component.html

* Converted change-age-restriction.component.html

* Converted api-key.component.html

* Converted anilist-key.component.html

* Converted typeahead.component.html

* Converted user-stats-info-cards.component.html

* Converted user-stats.component.html

* Converted top-readers.component.html

* Converted some pipes and ensure translation is loaded before the app.

* Finished all but one pipe for localization

* Converted directory-picker.component.html

* Converted library-access-modal.component.html

* Converted a few components

* Converted a few components

* Converted a few components

* Converted a few components

* Converted a few components

* Merged weblate in

* ... -> … update

* Updated the readme

* Updateded all fonts to be woff2

* Cleaned up some strings to increase re-use

* Removed an old flow (that doesn't exist in backend any longer) from when we introduced emails on Kavita.

* Converted Series detail

* Lots more converted

* Lots more converted & hooked up the ability to flatten during prod build the language files.

* Lots more converted

* Lots more converted & fixed a bunch of broken pipes due to inject()

* Lots more converted

* Lots more converted

* Lots more converted & fixed some bad keys

* Lots more converted

* Fixed some bugs with admin dasbhoard nested tabs not rendering on first load due to not using onpush change detection

* Fixed up some localization errors and fixed forgot password error when the user doesn't have change password permission

* Fixed a stupid build issue again

* Started adding errors for interceptor and backend.

* Finished off manga-reader

* More translations

* Few fixes

* Fixed a bug where character tag badges weren't showing the name on chapter info

* All components are translated

* All toasts are translated

* All confirm/alerts are translated

* Trying something new for the backend

* Migrated the localization strings for the backend into a new file.

* Updated the localization service to be able to do backend localization with fallback to english.

* Cleaned up some external reviews code to reduce looping

* Localized AccountController.cs

* 60% done with controllers

* All controllers are done

* All KavitaExceptions are covered

* Some shakeout fixes

* Prep for initial merge

* Everything is done except options and basic shakeout proves response times are good. Unit tests are broken.

* Fixed up the unit tests

* All unit tests are now working

* Removed some quantifier

* I'm not sure I can support localization for some Volume/Chapter/Book strings within the codebase.

---------

Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
Co-authored-by: majora2007 <kavitareader@gmail.com>
Co-authored-by: expertjun <jtrobin@naver.com>
Co-authored-by: ThePromidius <thepromidiusyt@gmail.com>
This commit is contained in:
Joe Milazzo 2023-08-03 10:33:51 -05:00 committed by GitHub
parent 670bf82c38
commit 3b23d63234
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
389 changed files with 13652 additions and 7925 deletions

View file

@ -1,8 +1,5 @@
/// <reference types="@angular/localize" />
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { importProvidersFrom } from '@angular/core';
import {APP_INITIALIZER, importProvidersFrom, isDevMode} from '@angular/core';
import { AppComponent } from './app/app.component';
import { NgCircleProgressModule } from 'ng-circle-progress';
import { ToastrModule } from 'ngx-toastr';
@ -12,26 +9,97 @@ import { SAVER, getSaver } from './app/shared/_providers/saver.provider';
import { Title, BrowserModule, bootstrapApplication } from '@angular/platform-browser';
import { JwtInterceptor } from './app/_interceptors/jwt.interceptor';
import { ErrorInterceptor } from './app/_interceptors/error.interceptor';
import { HTTP_INTERCEPTORS, withInterceptorsFromDi, provideHttpClient } from '@angular/common/http';
import {HTTP_INTERCEPTORS, withInterceptorsFromDi, provideHttpClient, HttpClient} from '@angular/common/http';
import {TRANSLOCO_CONFIG, TranslocoConfig, TranslocoModule, TranslocoService} from "@ngneat/transloco";
import {environment} from "./environments/environment";
import {HttpLoader, translocoLoader} from "./httpLoader";
import {
TRANSLOCO_PERSIST_LANG_STORAGE,
TranslocoPersistLangModule,
} from '@ngneat/transloco-persist-lang';
import {PERSIST_TRANSLATIONS_STORAGE, TranslocoPersistTranslationsModule} from "@ngneat/transloco-persist-translations";
import {TranslocoLocaleModule} from "@ngneat/transloco-locale";
import {AccountService} from "./app/_services/account.service";
import {switchMap} from "rxjs";
const disableAnimations = !('animate' in document.documentElement);
export function preloadUser(userService: AccountService, transloco: TranslocoService) {
return function() {
return userService.currentUser$.pipe(switchMap((user) => {
if (user && user.preferences.locale) {
transloco.setActiveLang(user.preferences.locale);
return transloco.load(user.preferences.locale)
}
// If no user or locale is available, fallback to the default language ('en')
const localStorageLocale = localStorage.getItem(userService.localeKey) || 'en';
transloco.setActiveLang(localStorageLocale);
return transloco.load(localStorageLocale)
})).subscribe();
};
}
export const preLoad = {
provide: APP_INITIALIZER,
multi: true,
useFactory: preloadUser,
deps: [AccountService, TranslocoService]
};
bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(BrowserModule, AppRoutingModule, BrowserAnimationsModule.withConfig({ disableAnimations }), ToastrModule.forRoot({
importProvidersFrom(BrowserModule,
AppRoutingModule,
BrowserAnimationsModule.withConfig({ disableAnimations }),
ToastrModule.forRoot({
positionClass: 'toast-bottom-right',
preventDuplicates: true,
timeOut: 6000,
countDuplicates: true,
autoDismiss: true
}), NgCircleProgressModule.forRoot()),
}),
NgCircleProgressModule.forRoot(),
TranslocoModule,
TranslocoPersistLangModule.forRoot({
storage: {
provide: TRANSLOCO_PERSIST_LANG_STORAGE,
useValue: localStorage,
},
}),
TranslocoLocaleModule.forRoot(),
TranslocoPersistTranslationsModule.forRoot({
loader: HttpLoader,
storage: {
provide: PERSIST_TRANSLATIONS_STORAGE,
useValue: sessionStorage
}
})
),
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
{
provide: TRANSLOCO_CONFIG,
useValue: {
reRenderOnLangChange: true,
availableLangs: ['en', 'es'], // TODO: Derive this from the directory
prodMode: environment.production,
defaultLang: 'en',
fallbackLang: 'en',
missingHandler: {
useFallbackTranslation: true,
allowEmpty: true,
},
flatten: {
aot: !isDevMode()
}
} as TranslocoConfig
},
preLoad,
Title,
{ provide: SAVER, useFactory: getSaver },
provideHttpClient(withInterceptorsFromDi())
]
})
.catch(err => console.error(err));
.catch(err => console.error(err));