npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

inline-i18n-multi-next

v0.11.0

Published

Next.js integration for inline-i18n-multi

Downloads

510

Readme

Important: For complete documentation, examples, and best practices, please read the full documentation on GitHub.

inline-i18n-multi-next

Next.js App Router integration for inline-i18n-multi. Full SSR/SSG support with SEO utilities, rich text, locale detection, and i18n middleware.

Installation

npm install inline-i18n-multi-next

Entry Points

| Entry point | Environment | Key exports | |---|---|---| | inline-i18n-multi-next/server | Server Components | it, t, configureI18n, generateLocaleParams, createMetadata, getAlternates, createI18nMiddleware | | inline-i18n-multi-next/client | Client Components | LocaleProvider, useLocale, useT, useScopedT, it, T, RichText, useRichText, useLoadDictionaries, useDetectedLocale, registerFormatter, clearFormatters, detectLocale, clearICUCache, restoreLocale, configure, resetConfig, createScope |

Quick Start

Layout Setup

// app/[locale]/layout.tsx
import { LocaleProvider } from 'inline-i18n-multi-next/client'
import { configureI18n, generateLocaleParams } from 'inline-i18n-multi-next/server'

configureI18n({
  locales: ['en', 'ko', 'ja'],
  defaultLocale: 'en',
  baseUrl: 'https://example.com',
})

export function generateStaticParams() {
  return generateLocaleParams()
}

export default async function Layout({ children, params }) {
  const { locale } = await params
  return (
    <html lang={locale}>
      <body>
        <LocaleProvider locale={locale}>{children}</LocaleProvider>
      </body>
    </html>
  )
}

Server Components

// app/[locale]/page.tsx
import { it } from 'inline-i18n-multi-next/server'

export default async function Page() {
  return <h1>{await it('안녕하세요', 'Hello')}</h1>
}

Server Components with Key-Based Translation

import { t, setLocale, loadDictionaries } from 'inline-i18n-multi'

loadDictionaries({
  en: { greeting: 'Hello' },
  ko: { greeting: '안녕하세요' },
})

export default async function Page({ params }) {
  const { locale } = await params
  setLocale(locale)  // Required before using t()

  return <h1>{t('greeting')}</h1>
}

Client Components

'use client'
import { it, T, useT } from 'inline-i18n-multi-next/client'

export function ClientComponent() {
  const t = useT()
  return (
    <div>
      <p>{it('클라이언트', 'Client')}</p>
      <T ko="환영" en="Welcome" />
      <p>{t('nav.home')}</p>
    </div>
  )
}

Rich Text (Client Components)

Use RichText or useRichText to embed React components inside translated strings. Tags like <link>text</link> are mapped to component renderers.

RichText Component

'use client'
import { RichText } from 'inline-i18n-multi-next/client'

export function TermsNotice() {
  return (
    <RichText
      translations={{
        en: 'Read <link>terms</link> and <bold>agree</bold>',
        ko: '<link>약관</link>을 읽고 <bold>동의</bold>해주세요',
      }}
      components={{
        link: (text) => <a href="/terms">{text}</a>,
        bold: (text) => <strong>{text}</strong>,
      }}
    />
  )
}

useRichText Hook

'use client'
import { useRichText } from 'inline-i18n-multi-next/client'

export function RichContent() {
  const richT = useRichText({
    link: (text) => <a href="/terms">{text}</a>,
    bold: (text) => <strong>{text}</strong>,
  })

  return <p>{richT({ en: 'Click <link>here</link>', ko: '<link>여기</link> 클릭' })}</p>
}

Lazy Loading (Client Components)

Use useLoadDictionaries to load translations on demand in client components.

'use client'
import { useLoadDictionaries, useT } from 'inline-i18n-multi-next/client'
import { useLocale } from 'inline-i18n-multi-next/client'

export function LazySection() {
  const locale = useLocale()
  const { isLoading, error } = useLoadDictionaries(locale, 'dashboard')
  const t = useT()

  if (isLoading) return <p>Loading...</p>
  if (error) return <p>Failed to load translations</p>

  return <h2>{t('dashboard.title')}</h2>
}

Locale Detection

Client-Side: useDetectedLocale

Automatically detect and set the user's locale from browser signals (navigator, cookie, URL).

'use client'
import { useDetectedLocale } from 'inline-i18n-multi-next/client'

export function LocaleDetector() {
  useDetectedLocale({
    supportedLocales: ['en', 'ko', 'ja'],
    defaultLocale: 'en',
    sources: ['cookie', 'navigator'],
    cookieName: 'NEXT_LOCALE',
  })

  return null // detection runs on mount, updates context automatically
}

Detection sources (checked in order):

| Source | Description | |---|---| | 'navigator' | Browser navigator.languages | | 'cookie' | Read from document.cookie | | 'url' | First path segment (e.g., /ko/about) | | 'header' | Accept-Language header (SSR) |

Server-Side: createI18nMiddleware

Redirect users to locale-prefixed routes based on cookies or Accept-Language header.

// middleware.ts
import { createI18nMiddleware } from 'inline-i18n-multi-next/server'

export default createI18nMiddleware({
  locales: ['en', 'ko', 'ja'],
  defaultLocale: 'en',
  localeDetection: true,   // detect from Accept-Language (default: true)
  cookieName: 'NEXT_LOCALE', // cookie for user preference (default: 'NEXT_LOCALE')
})

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
}

The middleware checks in order: URL locale prefix, cookie preference, then Accept-Language header. If no locale prefix is found, it redirects to the detected locale path.

SEO Utilities

import { createMetadata, getAlternates } from 'inline-i18n-multi-next/server'

export async function generateMetadata({ params }) {
  const { locale } = await params
  return createMetadata(
    {
      title: { en: 'My Site', ko: '내 사이트' },
      description: { en: 'Welcome', ko: '환영합니다' },
    },
    locale,
    '/about'
  )
}

Plural Shorthand (v0.7.0)

Concise plural syntax:

// Server Component
export default async function Page() {
  return (
    <p>
      {await it({
        en: '{count, p, item|items}',
        ko: '{count}개',
      }, { count: 5 })}
    </p>
  )
}

// Client Component - also supports 3-part (zero|singular|plural)
<T en="{count, p, no items|item|items}" ko="{count, p, 없음|개|개}" count={0} />

Locale Persistence (v0.7.0)

Auto-save and restore locale:

'use client'
import { configure, restoreLocale } from 'inline-i18n-multi-next/client'

configure({
  persistLocale: { storage: 'cookie', key: 'LOCALE', expires: 365 }
})

// Restore on app init
const saved = restoreLocale() // returns locale string or undefined

Translation Scope (v0.8.0)

Scope translations to a key prefix with useScopedT. Useful for large apps where each component only needs a subset of the dictionary.

'use client'
import { useScopedT } from 'inline-i18n-multi-next/client'

export function Dashboard() {
  const t = useScopedT('dashboard')
  return (
    <div>
      <h1>{t('title')}</h1>     {/* resolves to 'dashboard.title' */}
      <p>{t('subtitle')}</p>    {/* resolves to 'dashboard.subtitle' */}
    </div>
  )
}

You can also create a reusable scope with createScope:

'use client'
import { useScopedT } from 'inline-i18n-multi-next/client'
import { createScope } from 'inline-i18n-multi-next/client'

const scope = createScope('settings.profile')

export function ProfileForm() {
  const t = useScopedT(scope)
  return <label>{t('name')}</label>  {/* resolves to 'settings.profile.name' */}
}

Context System (v0.9.0)

Select translations based on context. Pass _context to t() to choose between contextual variants defined in your dictionaries.

'use client'
import { useT } from 'inline-i18n-multi-next/client'

// Assuming dictionaries are loaded with contextual keys:
// { greeting: 'Hello', 'greeting#formal': 'Good day', 'greeting#casual': 'Hey' }

export function Greeting() {
  const t = useT()
  return (
    <div>
      <p>{t('greeting')}</p>                              {/* "Hello" */}
      <p>{t('greeting', { _context: 'formal' })}</p>      {/* "Good day" */}
      <p>{t('greeting', { _context: 'casual' })}</p>      {/* "Hey" */}
    </div>
  )
}

Server components can also use context via the core t() function:

import { t, setLocale } from 'inline-i18n-multi'

export default async function Page({ params }) {
  const { locale } = await params
  setLocale(locale)

  return <h1>{t('greeting', { _context: 'formal' })}</h1>
}

Custom Formatters

Register custom ICU formatters via the core re-exports.

'use client'
import { registerFormatter, clearFormatters } from 'inline-i18n-multi-next/client'

registerFormatter('uppercase', (value) => String(value).toUpperCase())

// Use in translations: {name, uppercase}

Documentation

Please read the full documentation on GitHub for complete API reference, SEO best practices, and advanced patterns.

License

MIT