/ src / jet / dependencies / locale.ts
locale.ts
 1  import type { Locale as JetLocaleDependency } from '@jet-app/app-store/foundation/dependencies/locale/locale';
 2  import type {
 3      NormalizedLanguage,
 4      NormalizedStorefront,
 5      NormalizedLocale,
 6      UnnormalizedLocale,
 7  } from '@jet-app/app-store/api/locale';
 8  import type I18N from '@amp/web-apps-localization';
 9  import type { Logger, LoggerFactory } from '@amp/web-apps-logger';
10  
11  import type { Jet } from '~/jet/jet';
12  import {
13      DEFAULT_STOREFRONT_CODE,
14      DEFAULT_LANGUAGE_BCP47,
15  } from '~/constants/storefront';
16  import {
17      type NormalizedLocaleWithDefault,
18      normalizeStorefront,
19      normalizeLanguage,
20  } from '~/utils/locale';
21  import type { Optional } from '@jet/environment';
22  
23  /**
24   * Contains information related to the locale of the request currently being
25   * made to the application.
26   *
27   * Typically, localization information is expected to be known when the Jet
28   * instance is initialized. The Web, however, will not know the current
29   * locale and langauge until after routing has already taken place.
30   *
31   * This object exists to contain that lazily-determined locale information,
32   * so that other dependencies can retreive it from here. It is to be created
33   * with the rest of the dependencies and passed to them when they are created.
34   *
35   * Localization information is set in the {@linkcode Jet#setLocale} method
36   */
37  export class Locale implements JetLocaleDependency {
38      private readonly logger: Logger;
39  
40      private _storefront: NormalizedStorefront | undefined;
41      private _language: NormalizedLanguage | undefined;
42  
43      i18n: I18N | undefined;
44  
45      constructor(loggerFactory: LoggerFactory) {
46          this.logger = loggerFactory.loggerFor('locale');
47      }
48  
49      get activeStorefront(): NormalizedStorefront {
50          if (!this._storefront) {
51              this.logger.warn('`storefront` was accessed before being set');
52              return DEFAULT_STOREFRONT_CODE;
53          }
54  
55          return this._storefront;
56      }
57  
58      get activeLanguage(): NormalizedLanguage {
59          if (!this._language) {
60              this.logger.warn('`language` was accessed before being set');
61              return DEFAULT_LANGUAGE_BCP47;
62          }
63  
64          return this._language;
65      }
66  
67      setActiveLocale(locale: NormalizedLocale): void {
68          this._storefront = locale.storefront;
69          this._language = locale.language;
70      }
71  
72      normalize({
73          storefront,
74          language,
75      }: UnnormalizedLocale): NormalizedLocaleWithDefault {
76          const {
77              storefront: normalizedStorefront,
78              languages,
79              defaultLanguage,
80          } = normalizeStorefront(storefront);
81  
82          return {
83              storefront: normalizedStorefront,
84              ...normalizeLanguage(language || '', languages, defaultLanguage),
85          };
86      }
87  
88      deriveLocaleForUrl(locale: NormalizedLocale): {
89          storefront: string;
90          language: Optional<string>;
91      } {
92          const { isDefaultLanguage } = this.normalize(locale);
93  
94          return {
95              storefront: locale.storefront,
96              language: isDefaultLanguage ? undefined : locale.language,
97          };
98      }
99  }