Better I18NBetter I18N
Remix & Hydrogen

Getting Started

CDN-powered i18n for Remix & Shopify Hydrogen

Overview

@better-i18n/remix brings CDN-powered translations to Remix and Shopify Hydrogen apps. Unlike client-side solutions, translations are loaded on the server before rendering — no loading spinners, no layout shift.

The SDK is built on top of @better-i18n/core and adds Remix-specific utilities:

  • Server-side data loading — Translations are fetched in server.ts or loaders, not on the client
  • Provider-optional — Raw messages accessible as loader data; add I18nextProvider or RemixI18nProvider for hook-based translations
  • TtlCache singleton — A single module-scoped instance shares cache across all requests
  • Accept-Language detection — Built-in locale detection from request headers

Prerequisite: Before starting, create a project at dash.better-i18n.com and publish your translations. Your project identifier will be in the format org/project (e.g., acme/web-app).

Integrating with AI? Run npx skills add better-i18n/skills first — your agent (Cursor, Claude Code, or Windsurf) will already know the SDK patterns, CDN behavior, and key conventions. Then just ask it to set up the integration for you. Learn more →

Features

CDN Delivery

Translations served from the edge via Better i18n CDN. Sub-50ms response times globally.

Server-Side Loading

Fetch translations before render. No client-side loading states or hydration mismatches.

Locale Detection

Built-in Accept-Language header parsing with quality-factor sorting and smart fallbacks.

Hydrogen Support

First-class Shopify Hydrogen integration with Storefront API locale bridging.

Quick Start

app/i18n.server.ts
import { createRemixI18n } from "@better-i18n/remix"; 

export const i18n = createRemixI18n({ 
  project: "my-company/web-app", 
  defaultLocale: "en", 
}); 
app/root.tsx
import { i18n } from "~/i18n.server"; 

export async function loader({ request }: LoaderFunctionArgs) {
  const locale = await i18n.detectLocale(request); 
  const messages = await i18n.getMessages(locale); 
  return { locale, messages };
}

export default function App() {
  const { locale, messages } = useLoaderData<typeof loader>();

  return (
    <html lang={locale} translate="no">
      <head><Meta /><Links /></head>
      <body>
        <Outlet />
        <Scripts />
      </body>
    </html>
  );
}

This Quick Start loads translations in the root loader. For production apps, load translations in server.ts via getLoadContext() instead — see the full setup guide. For hook-based translations with ICU support, wrap <Outlet /> with a provider — see the Setup guide.

Guide

Comparison

FeatureRemixNext.jsTanStack StartVite
RenderingSSRSSR + ISRSSRCSR only
Data loadingLoadersServer ComponentsServer FunctionsClient fetch
Provider neededOptionalOptionalYesYes
Hydrogen supportYesNoNoNo
MiddlewareManualBuilt-inBuilt-inN/A

Choose @better-i18n/remix for Remix or Shopify Hydrogen apps. For Next.js, see @better-i18n/next. For Vite SPAs, see Vite.

AI Tooling

Now that you've integrated the SDK, your AI agent can check coverage, translate keys, and publish — all without leaving your editor.

On this page