1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00

[PS-713] Fix locale search bug (#3014)

* [PS-713] Fix locale search bug

* [PS-713] Add new locales to start at 1 char search

* [PS-713] Switch to ReplaySubject and other edits from PR comments

* PS-713: Add destroy to other sub and make locale inline a const

* PS-713: Use firstValueFrom instead of takeUntil

* PS-713: get this.locale asynchronously

Co-authored-by: Colton Hurst <churst@bitwarden.com>
This commit is contained in:
Colton Hurst
2022-07-12 09:02:19 -04:00
committed by GitHub
parent 35adf9d6e9
commit 59eac668a7
6 changed files with 42 additions and 13 deletions

View File

@@ -4,6 +4,7 @@ import { DomSanitizer } from "@angular/platform-browser";
import { NavigationEnd, Router } from "@angular/router"; import { NavigationEnd, Router } from "@angular/router";
import * as jq from "jquery"; import * as jq from "jquery";
import { IndividualConfig, ToastrService } from "ngx-toastr"; import { IndividualConfig, ToastrService } from "ngx-toastr";
import { Subject, takeUntil } from "rxjs";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { AuthService } from "@bitwarden/common/abstractions/auth.service";
@@ -48,6 +49,7 @@ export class AppComponent implements OnDestroy, OnInit {
private lastActivity: number = null; private lastActivity: number = null;
private idleTimer: number = null; private idleTimer: number = null;
private isIdle = false; private isIdle = false;
private destroy$ = new Subject<void>();
constructor( constructor(
@Inject(DOCUMENT) private document: Document, @Inject(DOCUMENT) private document: Document,
@@ -78,7 +80,9 @@ export class AppComponent implements OnDestroy, OnInit {
) {} ) {}
ngOnInit() { ngOnInit() {
this.document.documentElement.lang = this.i18nService.locale; this.i18nService.locale$.pipe(takeUntil(this.destroy$)).subscribe((locale) => {
this.document.documentElement.lang = locale;
});
this.ngZone.runOutsideAngular(() => { this.ngZone.runOutsideAngular(() => {
window.onmousemove = () => this.recordActivity(); window.onmousemove = () => this.recordActivity();
@@ -181,7 +185,7 @@ export class AppComponent implements OnDestroy, OnInit {
}); });
}); });
this.router.events.subscribe((event) => { this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event) => {
if (event instanceof NavigationEnd) { if (event instanceof NavigationEnd) {
const modals = Array.from(document.querySelectorAll(".modal")); const modals = Array.from(document.querySelectorAll(".modal"));
for (const modal of modals) { for (const modal of modals) {
@@ -211,6 +215,8 @@ export class AppComponent implements OnDestroy, OnInit {
ngOnDestroy() { ngOnDestroy() {
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
this.destroy$.next();
this.destroy$.unsubscribe();
} }
private async logOut(expired: boolean) { private async logOut(expired: boolean) {

View File

@@ -1,5 +1,6 @@
import { formatDate } from "@angular/common"; import { formatDate } from "@angular/common";
import { Component, EventEmitter, Input, Output, OnInit } from "@angular/core"; import { Component, EventEmitter, Input, Output, OnInit } from "@angular/core";
import { firstValueFrom } from "rxjs";
import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -23,6 +24,8 @@ export class SponsoringOrgRowComponent implements OnInit {
revokeSponsorshipPromise: Promise<any>; revokeSponsorshipPromise: Promise<any>;
resendEmailPromise: Promise<any>; resendEmailPromise: Promise<any>;
private locale = "";
constructor( constructor(
private apiService: ApiService, private apiService: ApiService,
private i18nService: I18nService, private i18nService: I18nService,
@@ -30,7 +33,9 @@ export class SponsoringOrgRowComponent implements OnInit {
private platformUtilsService: PlatformUtilsService private platformUtilsService: PlatformUtilsService
) {} ) {}
ngOnInit(): void { async ngOnInit() {
this.locale = await firstValueFrom(this.i18nService.locale$);
this.setStatus( this.setStatus(
this.isSelfHosted, this.isSelfHosted,
this.sponsoringOrg.familySponsorshipToDelete, this.sponsoringOrg.familySponsorshipToDelete,
@@ -98,7 +103,7 @@ export class SponsoringOrgRowComponent implements OnInit {
// They want to delete but there is a valid until date which means there is an active sponsorship // They want to delete but there is a valid until date which means there is an active sponsorship
this.statusMessage = this.i18nService.t( this.statusMessage = this.i18nService.t(
"revokeWhenExpired", "revokeWhenExpired",
formatDate(validUntil, "MM/dd/yyyy", this.i18nService.locale) formatDate(validUntil, "MM/dd/yyyy", this.locale)
); );
this.statusClass = "text-danger"; this.statusClass = "text-danger";
} else if (toDelete) { } else if (toDelete) {

View File

@@ -1,5 +1,7 @@
import { Observable } from "rxjs";
export abstract class I18nService { export abstract class I18nService {
locale: string; locale$: Observable<string>;
supportedTranslationLocales: string[]; supportedTranslationLocales: string[];
translationLocale: string; translationLocale: string;
collator: Intl.Collator; collator: Intl.Collator;

View File

@@ -1,7 +1,10 @@
import { Observable, ReplaySubject } from "rxjs";
import { I18nService as I18nServiceAbstraction } from "../abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "../abstractions/i18n.service";
export class I18nService implements I18nServiceAbstraction { export class I18nService implements I18nServiceAbstraction {
locale: string; private _locale = new ReplaySubject<string>(1);
locale$: Observable<string> = this._locale.asObservable();
// First locale is the default (English) // First locale is the default (English)
supportedTranslationLocales: string[] = ["en"]; supportedTranslationLocales: string[] = ["en"];
translationLocale: string; translationLocale: string;
@@ -85,10 +88,14 @@ export class I18nService implements I18nServiceAbstraction {
} }
this.inited = true; this.inited = true;
this.locale = this.translationLocale = locale != null ? locale : this.systemLanguage; this.translationLocale = locale != null ? locale : this.systemLanguage;
this._locale.next(this.translationLocale);
try { try {
this.collator = new Intl.Collator(this.locale, { numeric: true, sensitivity: "base" }); this.collator = new Intl.Collator(this.translationLocale, {
numeric: true,
sensitivity: "base",
});
} catch { } catch {
this.collator = null; this.collator = null;
} }

View File

@@ -14,16 +14,23 @@ export class SearchService implements SearchServiceAbstraction {
indexedEntityId?: string = null; indexedEntityId?: string = null;
private indexing = false; private indexing = false;
private index: lunr.Index = null; private index: lunr.Index = null;
private searchableMinLength = 2; private readonly immediateSearchLocales: string[] = ["zh-CN", "zh-TW", "ja", "ko", "vi"];
private readonly defaultSearchableMinLength: number = 2;
private searchableMinLength: number = this.defaultSearchableMinLength;
constructor( constructor(
private cipherService: CipherService, private cipherService: CipherService,
private logService: LogService, private logService: LogService,
private i18nService: I18nService private i18nService: I18nService
) { ) {
if (["zh-CN", "zh-TW"].indexOf(i18nService.locale) !== -1) { this.i18nService.locale$.subscribe((locale) => {
if (this.immediateSearchLocales.indexOf(locale) !== -1) {
this.searchableMinLength = 1; this.searchableMinLength = 1;
} else {
this.searchableMinLength = this.defaultSearchableMinLength;
} }
});
//register lunr pipeline function //register lunr pipeline function
lunr.Pipeline.registerFunction(this.normalizeAccentsPipelineFunction, "normalizeAccents"); lunr.Pipeline.registerFunction(this.normalizeAccentsPipelineFunction, "normalizeAccents");
} }

View File

@@ -1,7 +1,9 @@
import { Observable } from "rxjs";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
export class I18nMockService implements I18nService { export class I18nMockService implements I18nService {
locale: string; locale$: Observable<string>;
supportedTranslationLocales: string[]; supportedTranslationLocales: string[];
translationLocale: string; translationLocale: string;
collator: Intl.Collator; collator: Intl.Collator;