Skip to main content

Store Locator – Temporary Multi-Language Support Patch

Rose Perl Technology released a temporary JavaScript language override patch

Updated over 2 weeks ago

Category: Shopify / Store Locator
Maintained by: Rose Perl Technology
Solution Type: Temporary JavaScript Patch
Status: Active Temporary Solution - Last Updated: 4-3-26


Overview

Some Shopify Store Locator implementations do not currently support Shopify’s native localization system out of the box. To provide immediate multilingual storefront support, Rose Perl Technology released a temporary JavaScript language override patch.

This patch allows Store Locator interface text to change based on the active storefront language without requiring a full backend refactor.

It was released as a temporary workaround while native language support is being developed for a future release.


Important notice

This is a temporary frontend workaround.

Use this patch when:

  • a store needs multilingual Store Locator support now

  • native app-level language support is not yet available

  • the storefront already uses Shopify language routes, locale settings, or language-aware URL patterns

This is not the long-term localization architecture. Once official Store Locator language support is released, this patch should be deprecated and replaced with the native implementation.

What this patch does

The current implementation provides two layers of localization support:

1. SCASLSetting translation override

The script:

  • detects the active storefront locale

  • loads the matching translation dictionary

  • overrides window.SCASLSetting values with translated labels

  • retries until SCASLSetting becomes available

2. DOM label patching

The script also patches selected labels directly in the rendered DOM for cases where some visible Store Locator labels are not controlled by SCASLSetting.

This layer:

  • applies translations to known DOM-rendered labels

  • watches the Store Locator container for dynamic re-renders

  • reapplies translated labels after app redraws or content refreshes

This extra DOM layer is necessary because some labels may be rendered directly by the app and may remain untranslated even after SCASLSetting has been overridden. The original article documented the SCASLSetting-based override and retry behavior; this rewritten version extends the documentation to include the current DOM patching approach as part of the active solution.

Current limitations

This patch has the following limitations:

  • Only text exposed through SCASLSetting can be translated through the settings override layer

  • Any newly introduced Store Locator UI keys must be added manually

  • Any directly rendered labels must be maintained separately in the DOM patch layer

  • Some third-party or map-provider-generated controls may still not be translatable

  • App updates may require the script to be reviewed and updated

  • This is a frontend override, not a backend localization framework

Future state

Native language support is planned for a future version of the Store Locator tool. When that becomes available, this temporary patch should be considered deprecated and replaced with the official implementation.

Script metadata

/**
* Store Locator Multi-Language Override
* Version: 1.2.0
* Maintained by: Rose Perl Technology
*/

Supported languages

The current script supports the following locales:

Locale

Language

en-gb

English

sv-se

Swedish

nb-no

Norwegian Bokmål

de-de

German

pl-pl

Polish

es-es

Spanish

fr-ca

French

Locale handling note

The script uses full locale codes for supported storefront languages. It also accepts language-only inputs during detection and maps them to the nearest supported locale where applicable.

Examples:

  • enen-gb

  • frfr-ca

  • svsv-se

  • nb or nonb-no

  • dede-de

  • plpl-pl

  • eses-es

This allows the patch to work with Shopify locale values, URL paths, query parameters, or HTML lang values that may be supplied in either short or full locale format.

Core configuration

Setting

Value

Default fallback locale

en-gb

Supported locales

en-gb, sv-se, nb-no, de-de, pl-pl, es-es, fr-ca

Retry behavior

Up to 50 retries

Retry interval

Every 100ms

Maximum wait time

Approximately 5 seconds

DOM observation

Enabled

Script placement

Theme asset, loaded before or alongside Store Locator initialization

Language detection logic

The script detects locale in the following order of priority:

Priority 1: URL path

Examples:

  • /en-gb/pages/store-locator

  • /sv-se/pages/store-locator

  • /nb-no/pages/store-locator

  • /de-de/pages/store-locator

  • /pl-pl/pages/store-locator

  • /es-es/pages/store-locator

  • /fr-ca/pages/store-locator

Short language forms may also be resolved where appropriate.

Examples:

  • /en/pages/store-locator

  • /sv/pages/store-locator

  • /fr/pages/store-locator

Priority 2: URL hash

Examples:

  • #en-gb

  • #sv-se

  • #fr-ca

  • #fr

Priority 3: URL parameter

Examples:

  • ?lang=en-gb

  • ?lang=sv-se

  • ?lang=fr-ca

  • ?lang=fr

Priority 4: Shopify locale

If present, the script checks:

  • Shopify.locale

This supports stores where Shopify already exposes the active locale.

Priority 5: HTML lang attribute

The script also checks:

<html lang="de-de">

If no earlier method resolves to a supported locale, the script falls back to English.

The original article documented this general detection order across URL path, hash, query parameter, Shopify locale, and HTML lang.

Default fallback behavior

If no supported language is detected, the script falls back to:

en-gb

This matches the default language behavior documented in the original help article.

How the script applies translations

Once window.SCASLSetting becomes available, the script:

  • detects the active locale

  • selects the matching translation dictionary

  • merges the translated values into SCASLSetting

If SCASLSetting is not available immediately, the script retries every 100ms for up to 50 attempts.

How the DOM patch layer works

Some visible Store Locator labels may be rendered directly into the DOM instead of being sourced from SCASLSetting. To support those cases, the script includes a separate DOM_LABELS configuration and a DOM patching routine.

The DOM patch layer:

  • targets known Store Locator label selectors

  • updates the label text for the active locale

  • observes the Store Locator container with a MutationObserver

  • reapplies translations if the UI re-renders dynamically

This is particularly important for app interfaces that redraw panels, hours, or contact sections after initial page load.

DOM labels currently patched

The current DOM patch layer covers the following labels:

DOM label key

Selector

Purpose

phone_label

#scasl-phone-label

Phone field label

email_label

#scasl-email-label

Email field label

operating_hours_label

#scasl-operating-hours-label

Hours section label

These labels should be maintained for every supported locale so directly rendered labels remain consistent with the Store Locator’s translated interface.

Installation

1. Upload the script to Shopify theme assets

Create or upload:

assets/sl-i18n.js

2. Add the script to theme.liquid

Load the script before or alongside the Store Locator script:

<script src="{{ 'sl-i18n.js' | asset_url }}" defer></script>

Important loading note

This patch should load early enough that the translation override is ready before or during Store Locator initialization.

Because the script includes retry logic, it can still function if SCASLSetting is injected shortly after page load. Even so, best practice is to load the file before the Store Locator fully initializes.

The original article also required the script to be added to theme assets and loaded before the Store Locator script.

Translation maintenance guidelines

Update TRANSLATIONS when:

  • the Store Locator app exposes a label through SCASLSetting

  • an existing translated value needs revision

  • a new locale is being added

Update DOM_LABELS when:

  • a visible label does not respond to SCASLSetting

  • a Store Locator update introduces directly rendered untranslated labels

  • a supported locale is added or restored

Update DOM selectors when:

  • the Store Locator app changes element IDs or structure

  • the existing DOM patch targets no longer match rendered output

Recommended implementation notes

For any store using this patch:

  • keep sl-i18n.js in theme assets

  • load it before or alongside Store Locator initialization

  • keep translation keys aligned with current SCASLSetting keys

  • keep DOM label mappings aligned with actual rendered selectors

  • test all storefront locales after deployment

  • review the patch after every Store Locator app update

Testing checklist

After deployment, verify:

  • the correct locale is detected from storefront URLs

  • the Store Locator loads in the expected language

  • search labels are translated

  • no-result messages are translated

  • map and list controls are translated

  • operating-hours labels are translated

  • phone, email, and operating-hours DOM labels remain translated after re-render

  • English fallback works if no locale is matched

Example localized URL patterns

Locale

Example

English

/en-gb/pages/store-locator

Swedish

/sv-se/pages/store-locator

Norwegian Bokmål

/nb-no/pages/store-locator

German

/de-de/pages/store-locator

Polish

/pl-pl/pages/store-locator

Spanish

/es-es/pages/store-locator

French

/fr-ca/pages/store-locator

Shorter inputs may also resolve to supported full locale formats where alias mapping is configured.

Summary

Rose Perl Technology’s Store Locator language override patch is a temporary frontend workaround used to support multilingual Shopify storefronts before native Store Locator language support is available. The original documentation described a settings-based translation override with multi-step locale detection, retry logic, and storefront deployment requirements. The current implementation keeps that behavior and extends it with DOM label patching so directly rendered labels can also remain localized across supported storefront languages.

The current solution:

  • supports seven locales

  • detects language through multiple fallback methods

  • overrides SCASLSetting

  • patches selected DOM-rendered labels directly

  • preserves translations through dynamic re-renders

  • should remain in use only until official language support is released

This patch should remain in use only until the official language-support release is available.

Appendix: Current Script Reference

Below is the current reference implementation discussed in this article.

/**
* Store Locator Multi-Language Override
* Version: 1.2.0
* Maintained by: Rose Perl Technology
*
* PURPOSE
* -------
* Temporary frontend localization patch for Store Locator when native
* app-level translation support is not yet available.
*
* HOW IT WORKS
* ------------
* 1. Detects locale from storefront signals:
* - URL path
* - URL hash
* - ?lang= query param
* - Shopify.locale
* - <html lang="">
*
* 2. Waits for SCASLSetting to become available, then merges translated
* UI text into that object.
*
* 3. Patches selected labels directly in the DOM because some rendered
* UI text may not come from SCASLSetting.
*
* 4. Observes Store Locator DOM changes so translated labels persist
* after dynamic re-renders.
*
* USAGE NOTES
* -----------
* - Keep this file in Shopify theme assets:
* assets/sl-i18n.js
*
* - Load it in theme.liquid before or alongside Store Locator:
* <script src="{{ 'sl-i18n.js' | asset_url }}" defer></script>
*
* - Add SCASLSetting-driven labels to TRANSLATIONS.
* - Add directly rendered labels to DOM_LABELS and patchDomLabels().
*
* - Review this patch after Store Locator app updates.
*/
(function storeLocatorI18n() {
var DEFAULT_LOCALE = "en-gb";

/**
* Supported locales.
* Short language inputs are mapped to these full locale codes.
*/
var SUPPORTED_LOCALES = [
"en-gb",
"sv-se",
"nb-no",
"de-de",
"pl-pl",
"es-es",
"fr-ca"
];

/**
* Maps short language codes and locale variants to the supported locale.
*/
var LOCALE_ALIASES = {
en: "en-gb",
"en-gb": "en-gb",
"en-us": "en-gb",
"en-ca": "en-gb",

sv: "sv-se",
"sv-se": "sv-se",

nb: "nb-no",
no: "nb-no",
"nb-no": "nb-no",
"no-no": "nb-no",

de: "de-de",
"de-de": "de-de",

pl: "pl-pl",
"pl-pl": "pl-pl",

es: "es-es",
"es-es": "es-es",

fr: "fr-ca",
"fr-ca": "fr-ca",
"fr-fr": "fr-ca",
"fr-be": "fr-ca"
};

/**
* Translation strings merged into SCASLSetting.
* Add new keys here when the Store Locator app exposes them through
* the SCASLSetting configuration object.
*/
var TRANSLATIONS = {
"en-gb": {
page_title: "Store Locator",
curr_loc_text: "Current Location",
enter_a_location_text: "Enter a location",
radius_text: "Search Radius",
msr_text: "Search Radius Measurement",
find_loc_btn_text: "Find My Location",
search_btn_text: "Search",
filter_tags_text: "Filter by Tags",
no_limit_text: "No Limit",
miles_text: "Mile",
kilometers_text: "Kilometer",
kilometer_unit_text: "Kilometer",
map_text: "Map",
list_text: "List",
view_map_btn_text: "View Map",
more_text: "More",
less_text: "Less",
direction_text: "Get Directions",
no_result_title: "No results",
no_result_tags: "No stores found near this location.",
location_is_disabled_alert: "Location Services Disabled",
location_is_disabled_text:
"Please turn on device location to use Find My Location",
open_text: "Open",
open_now_text: "Open now",
opens_text: "Opens",
closed_text: "Closed",
closes_text: "Closes",
closes_soon_text: "Closes soon",
monday_text: "Monday",
tuesday_text: "Tuesday",
wednesday_text: "Wednesday",
thursday_text: "Thursday",
friday_text: "Friday",
saturday_text: "Saturday",
sunday_text: "Sunday",
monday_acronym_text: "Mon",
tuesday_acronym_text: "Tue",
wednesday_acronym_text: "Wed",
thursday_acronym_text: "Thu",
friday_acronym_text: "Fri",
saturday_acronym_text: "Sat",
sunday_acronym_text: "Sun"
},

"fr-ca": {
page_title: "Trouver une boutique",
curr_loc_text: "Emplacement actuel",
enter_a_location_text: "Entrez une adresse",
radius_text: "Rayon de recherche",
msr_text: "Unité de mesure",
find_loc_btn_text: "Me localiser",
search_btn_text: "Rechercher",
filter_tags_text: "Filtrer par tags",
no_limit_text: "Sans limite",
miles_text: "Mille",
kilometers_text: "Kilomètre",
kilometer_unit_text: "Kilomètre",
map_text: "Carte",
list_text: "Liste",
view_map_btn_text: "Voir la carte",
more_text: "Plus",
less_text: "Moins",
direction_text: "Obtenir l'itinéraire",
no_result_title: "Aucun résultat",
no_result_tags: "Aucun magasin trouvé près de cet endroit.",
location_is_disabled_alert: "Services de localisation désactivés",
location_is_disabled_text:
"Veuillez activer la localisation de votre appareil pour utiliser Me localiser",
open_text: "Ouvert",
open_now_text: "Ouvert maintenant",
opens_text: "Ouvre",
closed_text: "Fermé",
closes_text: "Ferme",
closes_soon_text: "Ferme bientôt",
monday_text: "Lundi",
tuesday_text: "Mardi",
wednesday_text: "Mercredi",
thursday_text: "Jeudi",
friday_text: "Vendredi",
saturday_text: "Samedi",
sunday_text: "Dimanche",
monday_acronym_text: "Lun",
tuesday_acronym_text: "Mar",
wednesday_acronym_text: "Mer",
thursday_acronym_text: "Jeu",
friday_acronym_text: "Ven",
saturday_acronym_text: "Sam",
sunday_acronym_text: "Dim"
},

"sv-se": {
page_title: "Butikslokalisering",
curr_loc_text: "Nuvarande plats",
enter_a_location_text: "Ange en plats",
radius_text: "Sökradie",
msr_text: "Måttenhet för sökradie",
find_loc_btn_text: "Hitta min plats",
search_btn_text: "Sök",
filter_tags_text: "Filtrera efter taggar",
no_limit_text: "Ingen gräns",
miles_text: "Mil",
kilometers_text: "Kilometer",
kilometer_unit_text: "Kilometer",
map_text: "Karta",
list_text: "Lista",
view_map_btn_text: "Visa karta",
more_text: "Mer",
less_text: "Mindre",
direction_text: "Få vägbeskrivning",
no_result_title: "Inga resultat",
no_result_tags: "Inga butiker hittades nära denna plats.",
location_is_disabled_alert: "Platstjänster är inaktiverade",
location_is_disabled_text:
"Aktivera enhetens plats för att använda Hitta min plats",
open_text: "Öppet",
open_now_text: "Öppet nu",
opens_text: "Öppnar",
closed_text: "Stängt",
closes_text: "Stänger",
closes_soon_text: "Stänger snart",
monday_text: "Måndag",
tuesday_text: "Tisdag",
wednesday_text: "Onsdag",
thursday_text: "Torsdag",
friday_text: "Fredag",
saturday_text: "Lördag",
sunday_text: "Söndag",
monday_acronym_text: "Mån",
tuesday_acronym_text: "Tis",
wednesday_acronym_text: "Ons",
thursday_acronym_text: "Tor",
friday_acronym_text: "Fre",
saturday_acronym_text: "Lör",
sunday_acronym_text: "Sön"
},

"nb-no": {
page_title: "Butikklokalisering",
curr_loc_text: "Nåværende posisjon",
enter_a_location_text: "Skriv inn et sted",
radius_text: "Søkeradius",
msr_text: "Måleenhet for søkeradius",
find_loc_btn_text: "Finn min posisjon",
search_btn_text: "Søk",
filter_tags_text: "Filtrer etter tagger",
no_limit_text: "Ingen grense",
miles_text: "Mil",
kilometers_text: "Kilometer",
kilometer_unit_text: "Kilometer",
map_text: "Kart",
list_text: "Liste",
view_map_btn_text: "Vis kart",
more_text: "Mer",
less_text: "Mindre",
direction_text: "Få veibeskrivelse",
no_result_title: "Ingen resultater",
no_result_tags: "Ingen butikker ble funnet nær dette stedet.",
location_is_disabled_alert: "Posisjonstjenester deaktivert",
location_is_disabled_text:
"Slå på enhetens posisjon for å bruke Finn min posisjon",
open_text: "Åpen",
open_now_text: "Åpen nå",
opens_text: "Åpner",
closed_text: "Stengt",
closes_text: "Stenger",
closes_soon_text: "Stenger snart",
monday_text: "Mandag",
tuesday_text: "Tirsdag",
wednesday_text: "Onsdag",
thursday_text: "Torsdag",
friday_text: "Fredag",
saturday_text: "Lørdag",
sunday_text: "Søndag",
monday_acronym_text: "Man",
tuesday_acronym_text: "Tir",
wednesday_acronym_text: "Ons",
thursday_acronym_text: "Tor",
friday_acronym_text: "Fre",
saturday_acronym_text: "Lør",
sunday_acronym_text: "Søn"
},

"de-de": {
page_title: "Filialsuche",
curr_loc_text: "Aktueller Standort",
enter_a_location_text: "Ort eingeben",
radius_text: "Suchradius",
msr_text: "Einheit für Suchradius",
find_loc_btn_text: "Meinen Standort finden",
search_btn_text: "Suchen",
filter_tags_text: "Nach Tags filtern",
no_limit_text: "Keine Begrenzung",
miles_text: "Meile",
kilometers_text: "Kilometer",
kilometer_unit_text: "Kilometer",
map_text: "Karte",
list_text: "Liste",
view_map_btn_text: "Karte anzeigen",
more_text: "Mehr",
less_text: "Weniger",
direction_text: "Route anzeigen",
no_result_title: "Keine Ergebnisse",
no_result_tags: "Keine Geschäfte in der Nähe dieses Ortes gefunden.",
location_is_disabled_alert: "Standortdienste deaktiviert",
location_is_disabled_text:
"Bitte aktivieren Sie den Standort Ihres Geräts, um Meinen Standort finden zu verwenden",
open_text: "Geöffnet",
open_now_text: "Jetzt geöffnet",
opens_text: "Öffnet",
closed_text: "Geschlossen",
closes_text: "Schließt",
closes_soon_text: "Schließt bald",
monday_text: "Montag",
tuesday_text: "Dienstag",
wednesday_text: "Mittwoch",
thursday_text: "Donnerstag",
friday_text: "Freitag",
saturday_text: "Samstag",
sunday_text: "Sonntag",
monday_acronym_text: "Mo",
tuesday_acronym_text: "Di",
wednesday_acronym_text: "Mi",
thursday_acronym_text: "Do",
friday_acronym_text: "Fr",
saturday_acronym_text: "Sa",
sunday_acronym_text: "So"
},

"pl-pl": {
page_title: "Lokalizator sklepów",
curr_loc_text: "Bieżąca lokalizacja",
enter_a_location_text: "Wpisz lokalizację",
radius_text: "Promień wyszukiwania",
msr_text: "Jednostka promienia wyszukiwania",
find_loc_btn_text: "Znajdź moją lokalizację",
search_btn_text: "Szukaj",
filter_tags_text: "Filtruj według tagów",
no_limit_text: "Bez limitu",
miles_text: "Mila",
kilometers_text: "Kilometr",
kilometer_unit_text: "Kilometr",
map_text: "Mapa",
list_text: "Lista",
view_map_btn_text: "Pokaż mapę",
more_text: "Więcej",
less_text: "Mniej",
direction_text: "Wyznacz trasę",
no_result_title: "Brak wyników",
no_result_tags: "Nie znaleziono sklepów w pobliżu tej lokalizacji.",
location_is_disabled_alert: "Usługi lokalizacji wyłączone",
location_is_disabled_text:
"Włącz lokalizację urządzenia, aby użyć opcji Znajdź moją lokalizację",
open_text: "Otwarte",
open_now_text: "Otwarte teraz",
opens_text: "Otwiera",
closed_text: "Zamknięte",
closes_text: "Zamyka",
closes_soon_text: "Wkrótce zamyka",
monday_text: "Poniedziałek",
tuesday_text: "Wtorek",
wednesday_text: "Środa",
thursday_text: "Czwartek",
friday_text: "Piątek",
saturday_text: "Sobota",
sunday_text: "Niedziela",
monday_acronym_text: "Pon",
tuesday_acronym_text: "Wt",
wednesday_acronym_text: "Śr",
thursday_acronym_text: "Czw",
friday_acronym_text: "Pt",
saturday_acronym_text: "Sob",
sunday_acronym_text: "Nd"
},

"es-es": {
page_title: "Localizador de tiendas",
curr_loc_text: "Ubicación actual",
enter_a_location_text: "Introduce una ubicación",
radius_text: "Radio de búsqueda",
msr_text: "Unidad de medida del radio",
find_loc_btn_text: "Encontrar mi ubicación",
search_btn_text: "Buscar",
filter_tags_text: "Filtrar por etiquetas",
no_limit_text: "Sin límite",
miles_text: "Milla",
kilometers_text: "Kilómetro",
kilometer_unit_text: "Kilómetro",
map_text: "Mapa",
list_text: "Lista",
view_map_btn_text: "Ver mapa",
more_text: "Más",
less_text: "Menos",
direction_text: "Obtener indicaciones",
no_result_title: "Sin resultados",
no_result_tags: "No se encontraron tiendas cerca de esta ubicación.",
location_is_disabled_alert: "Servicios de ubicación desactivados",
location_is_disabled_text:
"Activa la ubicación del dispositivo para usar Encontrar mi ubicación",
open_text: "Abierto",
open_now_text: "Abierto ahora",
opens_text: "Abre",
closed_text: "Cerrado",
closes_text: "Cierra",
closes_soon_text: "Cierra pronto",
monday_text: "Lunes",
tuesday_text: "Martes",
wednesday_text: "Miércoles",
thursday_text: "Jueves",
friday_text: "Viernes",
saturday_text: "Sábado",
sunday_text: "Domingo",
monday_acronym_text: "Lun",
tuesday_acronym_text: "Mar",
wednesday_acronym_text: "Mié",
thursday_acronym_text: "Jue",
friday_acronym_text: "Vie",
saturday_acronym_text: "Sáb",
sunday_acronym_text: "Dom"
}
};

/**
* Labels patched directly into the rendered DOM.
* Add entries here when visible labels are not controlled by SCASLSetting.
*/
var DOM_LABELS = {
"en-gb": {
phone_label: "Phone Number",
email_label: "Email",
operating_hours_label: "Operating Hours"
},
"fr-ca": {
phone_label: "Numéro de téléphone",
email_label: "Courriel",
operating_hours_label: "Heures d'ouverture"
},
"sv-se": {
phone_label: "Telefonnummer",
email_label: "E-post",
operating_hours_label: "Öppettider"
},
"nb-no": {
phone_label: "Telefonnummer",
email_label: "E-post",
operating_hours_label: "Åpningstider"
},
"de-de": {
phone_label: "Telefonnummer",
email_label: "E-Mail",
operating_hours_label: "Öffnungszeiten"
},
"pl-pl": {
phone_label: "Numer telefonu",
email_label: "E-mail",
operating_hours_label: "Godziny otwarcia"
},
"es-es": {
phone_label: "Número de teléfono",
email_label: "Correo electrónico",
operating_hours_label: "Horario de atención"
}
};

function normalizeLocale(input) {
if (!input) return null;

var normalized = String(input).toLowerCase().trim();
return LOCALE_ALIASES[normalized] || null;
}

function localeFromPath(pathname) {
var match = pathname.match(/^\/([a-z]{2}(?:-[a-z]{2})?)(\/|$)/i);
return match ? normalizeLocale(match[1]) : null;
}

function localeFromHash(hash) {
var cleaned = String(hash || "").replace(/^#/, "");
return normalizeLocale(cleaned);
}

function localeFromQuery(search) {
var params = new URLSearchParams(search);
return normalizeLocale(params.get("lang"));
}

function localeFromShopify() {
return typeof Shopify !== "undefined" && Shopify.locale
? normalizeLocale(Shopify.locale)
: null;
}

function localeFromHtmlLang() {
var htmlLang = document.documentElement.lang || "";
return normalizeLocale(htmlLang);
}

/**
* Detect the active locale using multiple storefront signals.
* Falls back to DEFAULT_LOCALE if no supported value is found.
*/
function detectLocale() {
return (
localeFromPath(window.location.pathname) ||
localeFromHash(window.location.hash) ||
localeFromQuery(window.location.search) ||
localeFromShopify() ||
localeFromHtmlLang() ||
DEFAULT_LOCALE
);
}

/**
* Merge locale strings into SCASLSetting.
*/
function applyTranslations(translations) {
if (typeof window.SCASLSetting === "undefined") {
return false;
}

Object.assign(window.SCASLSetting, translations);
return true;
}

/**
* Patch directly rendered DOM labels.
* Update selectors here if Store Locator markup changes.
*/
function patchDomLabels(labels) {
if (!labels) return;

if (labels.phone_label) {
document.querySelectorAll("#scasl-phone-label").forEach(function (el) {
if (el.textContent !== labels.phone_label) {
el.textContent = labels.phone_label;
}
});
}

if (labels.email_label) {
document.querySelectorAll("#scasl-email-label").forEach(function (el) {
if (el.textContent !== labels.email_label) {
el.textContent = labels.email_label;
}
});
}

if (labels.operating_hours_label) {
document
.querySelectorAll("#scasl-operating-hours-label")
.forEach(function (el) {
if (el.textContent !== labels.operating_hours_label) {
el.textContent = labels.operating_hours_label;
}
});
}
}

/**
* Observe Store Locator DOM changes so translated labels persist after re-renders.
*/
function observeDom(labels) {
var container =
document.querySelector("#scasl-app-container") || document.body;

var observer = new MutationObserver(function () {
patchDomLabels(labels);
});

observer.observe(container, {
childList: true,
subtree: true
});

patchDomLabels(labels);
}

/**
* Initialize localization flow.
*/
function init() {
var locale = detectLocale();
var translations = TRANSLATIONS[locale] || TRANSLATIONS[DEFAULT_LOCALE];
var domLabels = DOM_LABELS[locale] || DOM_LABELS[DEFAULT_LOCALE];

var attempts = 0;
var interval = setInterval(function () {
attempts++;

if (applyTranslations(translations)) {
clearInterval(interval);
return;
}

if (attempts >= 50) {
clearInterval(interval);
console.warn(
"[sl-i18n] SCASLSetting not found after 50 attempts. Patch not applied."
);
}
}, 100);

observeDom(domLabels);
}

if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();

Did this answer your question?