All files / lib/services app-translation-utils.service.ts

100% Statements 29/29
100% Branches 6/6
100% Functions 11/11
100% Lines 29/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142                                  1x 9x   9x   9x   9x   9x         9x   9x         9x                                     9x             10x 10x 10x 10x 10x                 2x 2x 2x             1x             1x             1x               3x 2x                 2x             9x 12x 12x 12x                   22x      
import { inject, Injectable } from '@angular/core';
import { DateAdapter } from '@angular/material/core';
import { WINDOW } from '@app/client-util';
import { LangChangeEvent, TranslateService } from '@ngx-translate/core';
import { Subject } from 'rxjs';
 
import { EN_DICTIONARY } from '../dictionaries/en';
import { RU_DICTIONARY } from '../dictionaries/ru';
import { ISupportedLanguage, IUiLanguagesInterface, TLangCode, uiLanguages } from '../interfaces/ui-languages.interface';
import { IUiTranslations } from '../interfaces/ui-translations.interface';
 
/**
 * Application translation utils service.
 */
@Injectable({
  providedIn: 'root',
})
export class AppTranslationUtilsService {
  private readonly translate = inject(TranslateService);
 
  private readonly dateAdapter = inject(DateAdapter<unknown>);
 
  private readonly win = inject(WINDOW);
 
  private readonly ruDictionary = inject(RU_DICTIONARY);
 
  private readonly enDictionary = inject(EN_DICTIONARY);
 
  /**
   * Language changes notifier.
   */
  private readonly languageChangesSubject = new Subject<LangChangeEvent>();
 
  public readonly languageChanges$ = this.languageChangesSubject.asObservable();
 
  /**
   * Available UI language codes.
   */
  private readonly langs = { ...uiLanguages };
 
  /**
   * Supported UI languages.
   */
  private readonly supportedLangs: ISupportedLanguage[] = [
    { key: 'en', name: 'English' },
    { key: 'ru', name: 'Russian' },
  ];
 
  /**
   * UI dictionaries.
   */
  private readonly translations: IUiTranslations = {
    ru: { ...this.ruDictionary },
    en: { ...this.enDictionary },
  };
 
  constructor() {
    this.languageChangeSubscription();
  }
 
  /**
   * Initializes Translate service.
   */
  public initialize(): void {
    this.setDatepickersLocale('ru');
    void this.translate.setFallbackLang(this.langs.ru).subscribe();
    this.translate.setTranslation(this.langs.ru, this.translations.ru);
    this.translate.setTranslation(this.langs.en, this.translations.en);
    void this.translate.use(this.langs.ru);
  }
 
  /**
   * Sets UI language, depending on preferences in user browser.
   * For now there are only dictionaries only: English, Russian
   * Russian language is set is user preference does not include one of the supported languages.
   */
  public getUserLanguagePreference(): TLangCode {
    const navLang: string = this.win.navigator.language;
    const userPreference: TLangCode = Boolean(navLang.match(/(ru-RU|ru)/gi)) || Boolean(navLang[0].match(/(ru)/gi)) ? 'ru' : 'en';
    return userPreference;
  }
 
  /**
   * Available UI language codes.
   */
  public languages(): IUiLanguagesInterface {
    return this.langs;
  }
 
  /**
   * Supported UI languages.
   */
  public supportedLanguages(): ISupportedLanguage[] {
    return this.supportedLangs;
  }
 
  /**
   * UI dictionaries.
   */
  public dictionaries(): IUiTranslations {
    return this.translations;
  }
 
  /**
   * Uses specific language for UI.
   * @param langCode language code
   */
  public useLanguage(langCode: TLangCode): void {
    if (langCode in this.langs) {
      void this.translate.use(this.langs[langCode]);
    }
  }
 
  /**
   * Resolves if language is current based on provided language code
   * @param langCode language code
   */
  public isCurrentLanguage(langCode: TLangCode): boolean {
    return this.translate.getCurrentLang() === langCode;
  }
 
  /**
   * Translate service language change subscription.
   */
  private languageChangeSubscription(): void {
    void this.translate.onLangChange.subscribe((langChangeEvent: LangChangeEvent) => {
      this.languageChangesSubject.next(langChangeEvent);
      const langCode: TLangCode = langChangeEvent.lang as TLangCode;
      this.setDatepickersLocale(langCode);
    });
  }
 
  /**
   * Sets datapickers locale:
   * 'ru' if key corresponds Russian language, 'en' in all other cases.
   * @param key language key to be seleted, supported languages: en, ru
   */
  private setDatepickersLocale(key: TLangCode): void {
    this.dateAdapter.setLocale(key);
  }
}