Skip to content

Instantly share code, notes, and snippets.

@panoply
Last active November 27, 2023 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save panoply/7441295808695e37674ae2d59e13e0ea to your computer and use it in GitHub Desktop.
Save panoply/7441295808695e37674ae2d59e13e0ea to your computer and use it in GitHub Desktop.
Shopify Markets Domain Parse

What is this?

Shopify offers a rather fustrating solution for localization on the front-end and developers are likely at the behest of their slop served up as the "Geo" app... We are not animals. Anyway, this is a tiny little url parser to extract subfolder prefixes and provides determination for cases where you are employing your own solution and have a webshop operating multiple domains and/or targeting different markets using subfolders.

The typings will explain in rich detail each value in the closure. If you don't use TypeScript then maybe try acting like an adult.

Usage

Usage is simple, and only configuration required is setting you main domain, by default the function assumed your main domain is using a .com extension, change this if it differs.

const url = root();

url.domain: string                  // your-store.com
url.root: string                    // The root subfolder prefix, e.g: /en-us  
url.path: string                    // pathname excluding subfolders or '' if at root
url.localizedDomain: boolean        // Whether or not domain differs from main one
url.localizedSubfolder: boolean     // Whether url contains both language and country, e.g: en-us
url.languageCode: string            // The extracted language code in uppercase, e.g: EN    
url.countryCode: string             // The extracted country code in uppercase, e.g: US
url.subfolderCountry: boolean       // Whether or not url contains a subfolder country code
url.subfolderLanguage: boolean      // Whether or not url contains a subfolder language code
/* -------------------------------------------- */
/* SUBFOLDER ROOT */
/* -------------------------------------------- */
export interface Root {
/**
* The root subfolder prefix without trailing slash
*
* Examples:
*
* - `/`
* - `/en`
* - `/en-nl`
*/
root:string;
/**
* The url path name following the root subfolder prefix.
* This will be an empty string (eg: `''`) if path is index.
*
* Examples:
*
* ```js
* // Pathnames following subfolders
* 'domain.co.uk/en-nl/foo' => '/foo'
* 'domain.com/product/xxx' => '/product/xxx'
* 'domain.de/de/colletion' => '/collection'
* ```
*
* As aforementioned, in cases where we on root page (i.e: `/`)
* then this value is an empty string, e.g:
*
* ```js
* // Empty Strings
* 'domain.com/en-nl' => ''
* 'domain.nl/nl' => ''
* ```
*/
path: string;
/**
* The 2 letter language ISO code contained in the root subfolder
* prefix, if a root exists. This defaults to using the reference
* of `window.Shopify.locale.language`.
*/
languageCode: string;
/**
* The 2 letter country ISO code contained in the root subfolder
* prefix, if a root exists. This defaults to using the reference
* of `window.Shopify.locale.country`.
*/
countryCode: string;
/**
* Whether or not the pathname URL contains a 2 letter country ISO code.
* When true, the root prefix contains a country reference, eg: `/en-de`
*/
subfolderCountry: boolean;
/**
* Whether or not the pathname URL contains a 2 letter language ISO code
* When `true` the root prefix contains a **language** reference, for example:
*
* - `/en-nl`
* - `/nl`
* - `/de-de`
*
* In some cases the URL subfolder prefix may only contain language suffix
* and not country suffix (eg: `/de/`) - This will apply when `localizedDomain`
* is `true` and users language is not `EN` or depending on defaults.
*/
subfolderLanguage: boolean;
/**
* The hostname domain reference of the URL. This will default to
* using the `window.location.hostname` reference, for example:
*
* ```js
* 'domain.com'
* 'domain.nl'
* // etc etc
* ```
*
*/
domain: string;
/**
* A boolean indicating whether or not the url pathname is within a localized
* state. When `true` it infers that a **root** subfolder prefix exists in the path.
*
* The value will be `false` if root prefix is only a language ISO. This will _typically_
* only apply on localized domains.
*
* For example:
*
* ```js
* // subfolders using both language + country code will result in true
* '/en-nl/product/foo' => true
* '/de-fr/product/foo' => true
*
* // subfolders using language code only will result in false
* '/de/collection/xxx' => false
* '/nl/product/foo-xx' => false
* ```
*/
localizedSubfolder: boolean;
/**
* A boolean indicating whether or not the url (hostname) domain is in
* a localized state. When `true` it infers we are on a domain that is not
* your main domain, for example
*
* ```js
* // When on main domain, this value is false
* 'domain.com' => false
*
* // These such domains will be true
* 'domain.de' => true
* 'domain.co.uk' => true
* 'domain.dk' => true
* 'domain.nl' => true
* ```
*/
localizedDomain: boolean;
}
/**
* Root Paths
*
* Obtains the current localized pathname context. Returns
* an object which describes the current path location.
*/
export function root (): Root {
const { pathname, hostname } = location;
const locale: Root = Object.create(null);
locale.root = '/';
locale.path = '';
locale.subfolderCountry = false;
locale.subfolderLanguage = false;
locale.localizedSubfolder = false;
locale.localizedDomain = /\.com$/.test(hostname) === false;
locale.domain = hostname;
locale.languageCode = Shopify.locale.toUpperCase();
locale.countryCode = Shopify.country;
const path = pathname.split('/').filter(Boolean).shift();
if (path && path.length === 2 && /[a-z]{2}$/.test(path)) {
const p = pathname.slice(3);
locale.path = p[p.length - 1] === '/' ? p.slice(0, -1) : p;
locale.root = `/${path}`;
locale.languageCode = path.toUpperCase();
locale.countryCode = path.toUpperCase();
locale.subfolderLanguage = true;
} else if (/[a-z]{2}-[a-z]{2}$/.test(path)) {
const [ language, iso ] = path.split('-');
const p = pathname.slice(6);
locale.path = p[p.length - 1] === '/' ? p.slice(0, -1) : p;
locale.root = `/${path}`;
locale.languageCode = language.toUpperCase();
locale.localizedSubfolder = true;
locale.countryCode = iso.toUpperCase();
locale.subfolderCountry = true;
locale.subfolderLanguage = true;
} else {
locale.path = pathname[pathname.length - 1] === '/' ? pathname.slice(0, -1) : pathname;
}
return locale;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment