Better OG

Fonts & i18n

Script-aware font loading with automatic fallbacks for multilingual OG images.

Font Loading

Better OG provides two approaches to loading fonts for OG image rendering:

Google Fonts (for next/og)

Use loadGoogleFontForImageResponse to load fonts compatible with next/og:

import { loadGoogleFontForImageResponse } from "@better-og/next";

const fonts = await loadGoogleFontForImageResponse({
  family: "Geist",
  weights: [400, 700],
});

Raw Google Fonts

Use loadGoogleFonts from the core package for any runtime:

import { loadGoogleFonts } from "@better-og/core";

const fonts = await loadGoogleFonts({
  family: "Inter",
  weights: [400, 600],
});

Font Setup

The resolveFontSetup function combines your base fonts with script-aware fallbacks and returns both the font data and resolved family names:

import { resolveFontSetup } from "@better-og/core";

const fontSetup = await resolveFontSetup({
  baseFonts: myBaseFonts,
  fallbackLocales: ["ja", "ar"],
});

// fontSetup.families.base     → "Geist"
// fontSetup.families.locales  → { ja: "Noto Sans JP", ar: "Noto Sans Arabic" }
// fontSetup.fonts             → [...all font data]

Built-in Locale Fallbacks

Better OG ships with Google Fonts mappings for these locales:

LocaleFont Family
enNoto Sans
ruNoto Sans
ukNoto Sans
zhNoto Sans SC
jaNoto Sans JP
koNoto Sans KR
arNoto Sans Arabic
hiNoto Sans Devanagari

When you specify fallbackLocales, Better OG automatically loads the appropriate Noto Sans variant and appends it to the font stack. Mixed-script strings also trigger the corresponding fallback locales automatically.

Using Locale Fonts in Components

Use the resolved family names from fontSetup.families.locales to apply the correct font per locale:

<div
  style={{
    fontFamily:
      lang === "ja" ? fontSetup.families.locales.ja : fontSetup.families.base,
  }}
>
  {localizedText}
</div>

Locale Resolution

In route handlers, Better OG resolves the locale from:

  1. localeFromRequest callback (custom per-request locale detection)
  2. Route params (params.lang or params.locale)
  3. First truthy param value as fallback

This integrates naturally with Next.js [lang] dynamic segments and i18n middleware.

Edit on GitHub

Last updated on

On this page