All files / translate si-translate.service.ts

90% Statements 9/10
100% Branches 2/2
75% Functions 3/4
88.88% Lines 8/9

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                        1x 2x         1x 2x                     1x 28x 28x                                                                                                                                                                                                 19x      
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import { inject, Injectable, DOCUMENT } from '@angular/core';
import { NEVER, Observable } from 'rxjs';
 
export type TranslationResult<T> = T extends string ? string : Record<string, string>;
 
/**
 * @returns The culture language code of the browser, e.g. "en-US".
 */
export const getBrowserCultureLanguage = (): string | undefined =>
  window?.navigator?.languages?.[0] ?? window?.navigator?.language;
 
/**
 * @returns The language code of the browser, e.g. "en".
 */
export const getBrowserLanguage = (): string | undefined =>
  getBrowserCultureLanguage()?.split(/-|_/)[0];
 
/**
 * Wrapper around an actual translation framework which is meant to be used internally by Element.
 * Applications must not use this service.
 *
 * Use {@link injectSiTranslateService} to get an instance of the translation service.
 *
 * @internal
 */
@Injectable()
export abstract class SiTranslateService {
  protected translationChange$: Observable<void> = NEVER;
  private documentRef: Document = inject(DOCUMENT);
 
  prevent$LocalizeInit?: boolean;
 
  /**
   * The currently used language.
   */
  abstract get currentLanguage(): string;
 
  /**
   * Sets a new language to be used. If needed, loads the language file.
   * @param lang - The language to be used.
   * @returns An observable that emits when the new language is loaded and activated.
   */
  abstract setCurrentLanguage(lang: string): Observable<void>;
 
  /**
   * The language to be used as default.
   * @param lang - The language code.
   */
  abstract setDefaultLanguage(lang: string): void;
 
  /**
   * The language to be used as default.
   * @returns The code of the default language.
   */
  abstract getDefaultLanguage(): string;
 
  /**
   * The available languages.
   */
  abstract get availableLanguages(): string[];
  abstract set availableLanguages(languages: string[]);
 
  /**
   * If the underlying translation library supports switching the language
   * and/or updating the translation texts, this observable will emit.
   * There is no initial emit.
   */
  get translationChange(): Observable<void> {
    return this.translationChange$;
  }
 
  /**
   * Translates the key(s) by using the underlying translation library.
   *
   * @param keys - A single translation key or an array of keys.
   * @param params - Parameters to be replaced within the translation text.
   *
   * @returns Returns the translated key or an object with the translated keys.
   * Depending on the underlying translation library (sync/async) the result will
   * be wrapped in an Observable.
   */
  abstract translate<T extends string | string[]>(
    keys: T,
    params?: Record<string, unknown>
  ): Observable<TranslationResult<T>> | TranslationResult<T>;
 
  /**
   * Translates the key(s) by using the underlying translation library in an asynchronous manner.
   * It will emit each time the active language is changed.
   *
   * @param keys - A single translation key or an array of keys.
   * @param params - Parameters to be replaced within the translation text.
   *
   * @returns Returns the translated key or an object with the translated keys wrapped in an Observable.
   */
  abstract translateAsync<T extends string | string[]>(
    keys: T,
    params?: Record<string, unknown>
  ): Observable<TranslationResult<T>>;
 
  /**
   * Translates the key(s) by using the underlying translation library in a synchronous manner.
   *
   * Warning: The caller of this function needs to make sure the translation file(s) are already loaded.
   * It is generally not recommended to use this function unless you know exactly what you are doing.
   *
   * @param keys - A single translation key or an array of keys.
   * @param params - Parameters to be replaced within the translation text.
   *
   * @returns Returns the translated key or an object with the translated keys.
   */
  abstract translateSync<T extends string | string[]>(
    keys: T,
    params?: Record<string, unknown>
  ): TranslationResult<T>;
 
  /**
   * If supported by the underlying translation library, this method can be used to add a translation for a specific key.
   * It is intended to be used for adding the english default value.
   * It will be called whenever a key within element is resolved.
   * An implementation of this method must check that it does not override an existing translation.
   */
  setTranslation?(key: string, value: string): void;
 
  setDocumentLanguage(lang: string): void {
    this.documentRef?.documentElement?.setAttribute('lang', lang);
  }
}