summaryrefslogtreecommitdiff
path: root/src/utils/locale.ts
diff options
context:
space:
mode:
authorrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
committerrxliuli <rxliuli@gmail.com>2025-11-04 05:03:50 +0800
commitbce557cc2dc767628bed6aac87301a1be7c5431b (patch)
treeb51a051228d01fe3306cd7626d4a96768aadb944 /src/utils/locale.ts
init commit
Diffstat (limited to 'src/utils/locale.ts')
-rw-r--r--src/utils/locale.ts142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/utils/locale.ts b/src/utils/locale.ts
new file mode 100644
index 0000000..cd1151a
--- /dev/null
+++ b/src/utils/locale.ts
@@ -0,0 +1,142 @@
+import type { Opt } from '@jet/environment';
+import { DEFAULT_STOREFRONT_CODE } from '~/constants/storefront';
+
+import type {
+ NormalizedLocale,
+ NormalizedStorefront,
+ NormalizedLanguage,
+} from '@jet-app/app-store/api/locale';
+import type { Locale } from '@jet-app/app-store/foundation/dependencies/locale/locale';
+
+import { TEXT_DIRECTION } from '@amp/web-app-components/src/constants';
+import { getLocAttributes } from '@amp/web-apps-localization';
+
+import { regions } from '~/utils/storefront-data';
+import { getJet } from '~/jet/svelte';
+
+export type NormalizedLocaleWithDefault = NormalizedLocale & {
+ isDefaultLanguage: boolean;
+};
+
+type LanguageDetails = {
+ languages: NormalizedLanguage[];
+ defaultLanguage: NormalizedLanguage;
+};
+
+export function normalizeStorefront(storefront: Opt<string>): {
+ storefront: NormalizedStorefront;
+ languages: NormalizedLanguage[];
+ defaultLanguage: NormalizedLanguage;
+} {
+ const storefronts: Record<NormalizedStorefront, LanguageDetails> = {};
+
+ for (const { locales } of regions) {
+ for (const { id, language, isDefault } of locales) {
+ if (isDefault) {
+ storefronts[id as NormalizedStorefront] = {
+ languages: [],
+ defaultLanguage: language as NormalizedLanguage,
+ };
+ }
+
+ if (id in storefronts) {
+ storefronts[id as NormalizedStorefront].languages.push(
+ language as NormalizedLanguage,
+ );
+ }
+ }
+ }
+
+ const normalizedStorefront = (storefront || '').toLowerCase();
+ const chosenStorefront =
+ normalizedStorefront in storefronts
+ ? (normalizedStorefront as NormalizedStorefront)
+ : DEFAULT_STOREFRONT_CODE;
+
+ return {
+ storefront: chosenStorefront,
+ ...storefronts[chosenStorefront],
+ };
+}
+
+export function normalizeLanguage(
+ language: string,
+ languages: NormalizedLanguage[],
+ defaultLanguage: NormalizedLanguage,
+): { language: NormalizedLanguage; isDefaultLanguage: boolean } {
+ function annotateReturn(language: NormalizedLanguage): {
+ language: NormalizedLanguage;
+ isDefaultLanguage: boolean;
+ } {
+ return {
+ language,
+ isDefaultLanguage: language === defaultLanguage,
+ };
+ }
+
+ // Prefer an exact match (ex. en-US matches en-US)
+ const exactMatch = findMatch(language, languages, (a, b) => a === b);
+ if (exactMatch) {
+ return annotateReturn(exactMatch);
+ }
+
+ // Try partial match (ex. fr-CA or fr matches fr-FR)
+ const partialMatch = findMatch(
+ language,
+ languages,
+ (a, b) => a.split('-')[0] === b.split('-')[0],
+ );
+ if (partialMatch) {
+ return annotateReturn(partialMatch);
+ }
+
+ // The only remaining choice is the storefront default
+ return annotateReturn(defaultLanguage);
+}
+
+function findMatch<T extends string>(
+ needle: string,
+ haystack: T[],
+ matches: (a: string, b: string) => boolean,
+): Opt<T> {
+ return haystack.find((possibility) =>
+ matches(possibility.toLowerCase(), needle.toLowerCase()),
+ );
+}
+
+/**
+ * Gets the current Locale instance from the Svelte context.
+ *
+ * @return the active {@linkcode NormalizedLocale}
+ */
+export function getLocale(): NormalizedLocale {
+ let locale: Locale | undefined;
+
+ try {
+ const { objectGraph } = getJet();
+
+ locale = objectGraph.locale;
+ } catch {
+ throw new Error('`getLocale` called before `Jet.load`');
+ }
+
+ return {
+ storefront: locale.activeStorefront,
+ language: locale.activeLanguage,
+ };
+}
+
+/**
+ * Returns whether or not the document is in RTL mode, first based on the document's direction,
+ * with a fallback to the storefronts default writing direction.
+ */
+export function isRtl() {
+ const { storefront } = getLocale();
+ const { dir } = getLocAttributes(storefront);
+
+ return (
+ (typeof document !== 'undefined' &&
+ document.dir === TEXT_DIRECTION.RTL) ||
+ dir === TEXT_DIRECTION.RTL
+ );
+}