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,51 +1,53 @@
<div class="card mt-2">
<div class="card-body">
<div class="card-title">
<div class="container-fluid row mb-2">
<div class="col-10 col-sm-11"><h4 id="anilist-token-header">Scrobbling Providers</h4></div>
<div class="col-1 text-end">
<button class="btn btn-primary btn-sm" [disabled]="!hasValidLicense" (click)="toggleViewMode()">{{isViewMode ? 'Edit' : 'Cancel'}}</button>
<ng-container *transloco="let t; read:'scrobbling-providers'">
<div class="card mt-2">
<div class="card-body">
<div class="card-title">
<div class="container-fluid row mb-2">
<div class="col-10 col-sm-11"><h4 id="anilist-token-header">{{t('title')}}</h4></div>
<div class="col-1 text-end">
<button class="btn btn-primary btn-sm" [disabled]="!hasValidLicense" (click)="toggleViewMode()">{{isViewMode ? t('edit') : t('cancel')}}</button>
</div>
</div>
</div>
</div>
<ng-container *ngIf="isViewMode">
<div class="container-fluid row">
<ng-container *ngIf="isViewMode">
<div class="container-fluid row">
<span class="col-12">
<ng-container *ngIf="!hasValidLicense; else showToken">
This feature requires an active <a href="" target="_blank" rel="noreferrer nofollow">Kavita+</a> license
{{t('requires', {product: 'Kavita+'})}}
</ng-container>
<ng-template #showToken>
<ng-container *ngIf="token && token.length > 0; else noToken">
<img class="me-2" width="32" height="32" ngSrc="assets/images/ExternalServices/AniList.png" alt="AniList" ngbTooltip="AniList"> Token Set
<i class="error fa-solid fa-exclamation-circle" ngbTooltip="Token Expired" *ngIf="tokenExpired">
<span class="visually-hidden">Token Expired</span>
<img class="me-2" width="32" height="32" ngSrc="assets/images/ExternalServices/AniList.png" alt="AniList" ngbTooltip="AniList"> {{t('token-set')}}
<i class="error fa-solid fa-exclamation-circle" [ngbTooltip]="t('token-expired')" *ngIf="tokenExpired">
<span class="visually-hidden">{{t('token-expired')}}</span>
</i>
</ng-container>
<ng-template #noToken>No Token Set</ng-template>
<ng-template #noToken>{{t('no-token-set')}}</ng-template>
</ng-template>
</span>
</div>
</ng-container>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isViewMode">
<p>First time users should click on "Generate" below to allow KavitaPlus to talk with Anilist.
Once you authorize the program, copy and paste the token in the input below. You can regenerate your token at any time.</p>
<form [formGroup]="formGroup">
<div class="form-group mb-3">
<label for="anilist-token">AniList Token Goes Here</label>
<textarea id="anilist-token" rows="2" cols="3" class="form-control" formControlName="aniListToken"></textarea>
</div>
</form>
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
<a class="flex-fill btn btn-secondary me-2"
href="https://anilist.co/api/v2/oauth/authorize?client_id=12809&redirect_url=https://anilist.co/api/v2/oauth/pin&response_type=token"
target="_blank" rel="noopener noreferrer">Generate</a>
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="anilist-token-header" (click)="saveForm()">Save</button>
</ng-container>
<div #collapse="ngbCollapse" [(ngbCollapse)]="isViewMode">
<p>{{t('instructions', {service: 'AniList'})}}</p>
<form [formGroup]="formGroup">
<div class="form-group mb-3">
<label for="anilist-token">{{t('token-input-label', {service: 'AniList'})}}</label>
<textarea id="anilist-token" rows="2" cols="3" class="form-control" formControlName="aniListToken"></textarea>
</div>
</form>
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
<a class="flex-fill btn btn-secondary me-2"
href="https://anilist.co/api/v2/oauth/authorize?client_id=12809&redirect_url=https://anilist.co/api/v2/oauth/pin&response_type=token"
target="_blank" rel="noopener noreferrer">{{t('generate')}}</a>
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="anilist-token-header" (click)="saveForm()">{{t('save')}}</button>
</div>
</div>
</div>
</div>
</div>
</ng-container>

View file

@ -14,6 +14,7 @@ import {ScrobbleProvider, ScrobblingService} from "../../_services/scrobbling.se
import {AccountService} from "../../_services/account.service";
import { NgbTooltip, NgbCollapse } from '@ng-bootstrap/ng-bootstrap';
import { NgIf, NgOptimizedImage } from '@angular/common';
import {translate, TranslocoModule} from "@ngneat/transloco";
@Component({
selector: 'app-anilist-key',
@ -21,7 +22,7 @@ import { NgIf, NgOptimizedImage } from '@angular/common';
styleUrls: ['./anilist-key.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [NgIf, NgOptimizedImage, NgbTooltip, NgbCollapse, ReactiveFormsModule]
imports: [NgIf, NgOptimizedImage, NgbTooltip, NgbCollapse, ReactiveFormsModule, TranslocoModule]
})
export class AnilistKeyComponent implements OnInit {
@ -65,7 +66,7 @@ export class AnilistKeyComponent implements OnInit {
saveForm() {
this.scrobblingService.updateAniListToken(this.formGroup.get('aniListToken')!.value).subscribe(() => {
this.toastr.success('AniList Token has been updated');
this.toastr.success(translate('toasts.anilist-token-updated'));
this.token = this.formGroup.get('aniListToken')!.value;
this.resetForm();
this.isViewMode = true;