Skip to content
Twilight React Playground
ثيم رائدaren

buildBaseHead, localeToOgLocale

functionAdvancedserverbrowserlive demo

Builds the store-wide head defaults (title, description, canonical, Open Graph, Twitter card) from the store settings; the root route already applies them.

import { buildBaseHead, localeToOgLocale } from '@salla.sa/twilight-theme-engine/utils/baseHead';

In plain words

Every page of a store shares some head information: the store name as the title, its description, its logo as the picture when a link is shared. buildBaseHead(settings, locale) builds that HeadDescriptor from the store settings. The engine's root route already calls it for every page, so a theme rarely needs to.

localeToOgLocale('ar') turns a language code into the form Open Graph expects: 'ar_AR'.

Signature

function buildBaseHead(
  settings: StoreContext | null | undefined,
  locale?: string,   // default 'ar'
  path?: string      // without the locale, e.g. '/cart'
): HeadDescriptor

function localeToOgLocale(locale: string): string
// 'ar' → 'ar_AR', 'en' → 'en_US', any other 'xx' → 'xx_XX', '' → 'ar_AR'

Try it live

The head defaults built from this store's real settings: title, description, canonical, Open Graph and Twitter card.Try this: compare canonical with store.url: the store's username segment is gone. Pick /ar/cart to see the locale doubled in openGraph.url, and look at twitter.site.
Storefront canvas · ar · RTL
store.url
https://demostore.salla.sa/ar/dev-vgckq3fssfhjewwi/
canonical
https://demostore.salla.sa
openGraph.url
https://demostore.salla.sa
localeToOgLocale("ar")
ar_AR
buildBaseHead(settings, locale, path): {…} 5 keys
title: "ثيم رائد"
description: "<p class="ql-direction-rtl">هذا المتجر التجريبي يتيح لك استكشاف شكل وتصميم المتاجر على منصة <strong>سلة</strong>. تصفّح الأقسام، جرّب تجربة الشراء، واستعرض الم…"
canonical: "https://demostore.salla.sa"
openGraph: {…} 7 keys
type: "website"
siteName: "ثيم رائد"
title: "ثيم رائد"
description: "<p class="ql-direction-rtl">هذا المتجر التجريبي يتيح لك استكشاف شكل وتصميم المتاجر على منصة <strong>سلة</strong>. تصفّح الأقسام، جرّب تجربة الشراء، واستعرض الم…"
url: "https://demostore.salla.sa"
locale: "ar_AR"
images: "https://cdn.salla.network/salla.com/logo-wide-1.svg"
twitter: {…} 5 keys
card: "summary_large_image"
title: "ثيم رائد"
description: "<p class="ql-direction-rtl">هذا المتجر التجريبي يتيح لك استكشاف شكل وتصميم المتاجر على منصة <strong>سلة</strong>. تصفّح الأقسام، جرّب تجربة الشراء، واستعرض الم…"
site: "@https://x.com/SallaApp"
images: "https://cdn.salla.network/salla.com/logo-wide-1.svg"
Controls
What a theme writes
import { buildBaseHead } from '@salla.sa/twilight-theme-engine/utils/baseHead';
import type { HeadDescriptor } from '@salla.sa/twilight-theme-engine/utils/head';
import type { StoreContext } from '@salla.sa/twilight-theme-engine/api/store';

export function storeDefaults(settings: StoreContext, locale: string): HeadDescriptor {
  return buildBaseHead(settings, locale);
}

Example

app/components/SharePreview.tsx
import { useTwilight } from '@salla.sa/twilight-theme-engine';
import { useTranslation } from '@salla.sa/twilight-theme-engine/i18n';
import { buildBaseHead } from '@salla.sa/twilight-theme-engine/utils/baseHead';

/** How a shared link to this store looks: the store's own Open Graph defaults. */
export function SharePreview() {
  const { settings } = useTwilight();
  const { locale } = useTranslation();
  const { openGraph } = buildBaseHead(settings, locale);

  return (
    <figure className="share-preview">
      {typeof openGraph?.images === 'string' && <img src={openGraph.images} alt="" width={120} />}
      <figcaption>{openGraph?.title}</figcaption>
    </figure>
  );
}

How it behaves

  • It returns {} when settings.store is missing.

  • title is store.meta.title, else store.name. description is store.meta.description, else store.description. keywords is store.meta.keywords. Empty strings count as missing.

  • The base URL is the origin of store.url. Without path, canonical and openGraph.url are that origin. With path, canonical is origin + path and openGraph.url is origin + /<locale> + path.

  • openGraph is { type: 'website', siteName, title, description, url, locale, images: store.logo } and twitter is { card: 'summary_large_image', title, description, site, images: store.logo }, where site is store.social.twitter with an @ added when it has none.

  • alternateLanguages (from buildHreflangAlternates) is included only when path is given.

  • createTwilightRootRoute() calls buildBaseHead(settings, locale) with no path and adds its own tags on top, for every page.

  • localeToOgLocale lower-cases the code and keeps only the language part of en-GB or ar_SA, maps ar and en, and doubles anything else (frfr_FR).

Gotchas

  • For a store on a shared Salla host the username is lost. The demo store's store.url is https://demostore.salla.sa/ar/dev-vgckq3fssfhjewwi/, so its canonical is https://demostore.salla.sa, an address that is not this store.

  • Because the root route passes no path, every page gets a canonical link to the store origin. A route that sets its own canonical adds a second canonical link (TanStack Router keeps every link), and a route that does not keeps the home page as its canonical.

  • description is used as the store sends it. The demo store's description is HTML (<p class="ql-direction-rtl">…), so that markup ends up as text inside the description, og:description and twitter:description tags.

  • twitter.site only prepends @. The demo store sends store.social.twitter as a profile URL, https://x.com/SallaApp, which becomes @https://x.com/SallaApp.

  • Pass path without the locale: with /ar/cart, openGraph.url becomes …/ar/ar/cart.

  • localeToOgLocale guesses the region by doubling the code, which is not always a real locale: urur_UR, zh-Hantzh_ZH, and en-GBen_US.

Related

Source and docs