{"version":3,"file":"server.cjs","names":[],"sources":["../../src/appRouter/config.ts","../../src/appRouter/server.ts"],"sourcesContent":["import type { I18nConfig, NormalizedConfig } from './types'\n\nexport function defineConfig(config: I18nConfig): I18nConfig {\n  return config\n}\n\nexport function normalizeConfig(userConfig: I18nConfig): NormalizedConfig {\n  // Support legacy format: { i18n: { defaultLocale, locales } }\n  const supportedLngs = userConfig.supportedLngs ??\n    userConfig.i18n?.locales?.filter((l: string) => l !== 'default') ??\n    ['en']\n  const fallbackLng = userConfig.fallbackLng ??\n    userConfig.i18n?.defaultLocale ??\n    supportedLngs[0]\n\n  if (!fallbackLng) {\n    throw new Error('next-i18next: fallbackLng (or i18n.defaultLocale) is required')\n  }\n  if (supportedLngs.length === 0) {\n    throw new Error('next-i18next: supportedLngs (or i18n.locales) must contain at least one language')\n  }\n\n  const defaultNS = userConfig.defaultNS ?? 'common'\n\n  return {\n    supportedLngs,\n    fallbackLng,\n    defaultNS,\n    ns: userConfig.ns ?? [defaultNS],\n    localeInPath: userConfig.localeInPath ?? true,\n    hideDefaultLocale: userConfig.hideDefaultLocale ?? false,\n    localePath: userConfig.localePath ?? '/locales',\n    localeStructure: userConfig.localeStructure ?? '{{lng}}/{{ns}}',\n    localeExtension: userConfig.localeExtension ?? 'json',\n    cookieName: userConfig.cookieName ?? 'i18next',\n    headerName: userConfig.headerName ?? 'x-i18next-current-language',\n    cookieMaxAge: userConfig.cookieMaxAge ?? 365 * 24 * 60 * 60,\n    ignoredPaths: userConfig.ignoredPaths ?? ['/api', '/_next', '/static'],\n    basePath: userConfig.basePath,\n    resources: userConfig.resources,\n    resourceLoader: userConfig.resourceLoader,\n    use: userConfig.use ?? [],\n    i18nextOptions: (userConfig.i18nextOptions ?? {}) as Record<string, any>,\n    nonExplicitSupportedLngs: userConfig.nonExplicitSupportedLngs ?? false,\n    // Preserve legacy fields\n    i18n: userConfig.i18n,\n    serializeConfig: userConfig.serializeConfig,\n    reloadOnPrerender: userConfig.reloadOnPrerender,\n  }\n}\n","import { createInstance } from 'i18next'\nimport type { i18n as I18NextClient, Resource, Module, FlatNamespace, KeyPrefix } from 'i18next'\nimport resourcesToBackend from 'i18next-resources-to-backend'\nimport { cache } from 'react'\nimport { headers, cookies } from 'next/headers'\n\nimport type { I18nConfig, NormalizedConfig, GetTResult } from './types'\nimport { normalizeConfig } from './config'\n\nlet _config: NormalizedConfig | null = null\n\n// Module-level singleton: persists across requests within the same server process.\n// This is critical for custom backends (i18next-http-backend, i18next-locize-backend)\n// to avoid re-fetching translations on every request.\n// In serverless environments (Lambda, Cloud Functions, etc.), this lives as long as\n// the warm function instance — backends with reloadInterval will refresh automatically.\nlet _sharedInstance: I18NextClient | null = null\nlet _sharedInstancePromise: Promise<I18NextClient> | null = null\n\nfunction getConfig(): NormalizedConfig {\n  if (!_config) {\n    throw new Error(\n      'next-i18next: Server module not initialized. Call initServerI18next(config) in your root layout.'\n    )\n  }\n  return _config\n}\n\n/**\n * Initialize the server-side i18next configuration.\n * Call this once in your root layout or a shared setup file.\n */\nexport function initServerI18next(userConfig: I18nConfig): void {\n  _config = normalizeConfig(userConfig)\n}\n\nfunction hasCustomBackend(plugins: any[]): boolean {\n  return plugins.some((b: Module) => b.type === 'backend')\n}\n\nfunction createResourceBackend(config: NormalizedConfig) {\n  if (config.resourceLoader) {\n    return resourcesToBackend(config.resourceLoader)\n  }\n  return resourcesToBackend(async (language: string, namespace: string) => {\n    const filePath = `${config.localePath}/${config.localeStructure\n      .replace('{{lng}}', language)\n      .replace('{{ns}}', namespace)}.${config.localeExtension}`\n\n    // Node.js runtime: read from filesystem\n    if (typeof process !== 'undefined' && process.versions?.node) {\n      try {\n        const fs = await import('fs/promises')\n        const pathMod = await import('path')\n        const resolved = pathMod.resolve(process.cwd(), `public${filePath}`)\n        const content = await fs.readFile(resolved, 'utf-8')\n        return JSON.parse(content)\n      } catch {\n        throw new Error(\n          `next-i18next: Could not read locale file \"public${filePath}\". ` +\n          'On serverless platforms (Vercel, AWS Lambda, etc.), files in public/ are served via CDN ' +\n          'but are NOT available on the filesystem at runtime. Use the `resourceLoader` option with ' +\n          'dynamic imports instead:\\n\\n' +\n          '  resourceLoader: (language, namespace) =>\\n' +\n          // eslint-disable-next-line no-template-curly-in-string\n          '    import(`./public/locales/${language}/${namespace}.json`)\\n'\n        )\n      }\n    }\n\n    // Edge runtime: filesystem not available\n    throw new Error(\n      `next-i18next: Cannot load locale file \"${filePath}\" in Edge Runtime. ` +\n      'Provide pre-bundled `resources`, a custom `resourceLoader`, or use a custom backend (e.g. i18next-http-backend) via the `use` option.'\n    )\n  })\n}\n\n/**\n * Get or create the shared i18next instance.\n * The instance is created once and reused across all requests.\n * All languages are preloaded so that getFixedT(lng) works for any supported language.\n * Additional namespaces are loaded on demand and cached in the instance store.\n */\nasync function getSharedInstance(config: NormalizedConfig): Promise<I18NextClient> {\n  if (_sharedInstance?.isInitialized) return _sharedInstance\n\n  // Deduplicate concurrent init calls (multiple requests arriving while first init is in flight)\n  if (_sharedInstancePromise) return _sharedInstancePromise\n\n  _sharedInstancePromise = (async () => {\n    const i18nInstance = createInstance()\n\n    // Add a backend when needed:\n    // - No resources provided → backend loads everything\n    // - Resources provided with partialBundledLanguages → backend loads the rest\n    // - Custom backend in config.use → user handles it, skip default backend\n    const partialBundled = config.i18nextOptions?.partialBundledLanguages\n    if ((!config.resources || partialBundled) && !hasCustomBackend(config.use)) {\n      i18nInstance.use(createResourceBackend(config))\n    }\n\n    config.use.forEach((plugin: any) => i18nInstance.use(plugin))\n\n    await i18nInstance.init({\n      // No `lng` — the shared instance is language-neutral.\n      // We use getFixedT(lng, ns) to get language-specific translators.\n      lng: config.fallbackLng,\n      ns: config.ns,\n      defaultNS: config.defaultNS,\n      fallbackLng: config.fallbackLng,\n      supportedLngs: config.supportedLngs,\n      nonExplicitSupportedLngs: config.nonExplicitSupportedLngs,\n      fallbackNS: config.defaultNS,\n      preload: config.supportedLngs, // preload ALL languages upfront\n      interpolation: { escapeValue: false },\n      ...(config.resources ? { resources: config.resources } : {}),\n      ...config.i18nextOptions,\n    })\n\n    _sharedInstance = i18nInstance\n    return i18nInstance\n  })()\n\n  return _sharedInstancePromise\n}\n\n// Dev-only hot-reload: refetch resources for the requested language so edits\n// to locale files appear without restarting `next dev`. Wrapped in `cache()`\n// so multiple `getT` calls within the same render dedupe to a single reload.\n// Gated on `NODE_ENV !== 'production'` at the call site so HTTP/locize/chained\n// backends are never refetched per-request in prod.\nconst reloadResourcesForRender = cache(\n  async (i18n: I18NextClient, lng: string): Promise<void> => {\n    const ns = (i18n.options.ns as string[] | undefined) ?? []\n    await i18n.reloadResources([lng], ns)\n  }\n)\n\n// Per-request language detection, deduplicated within a single React render\nconst detectLanguage = cache(async (config: NormalizedConfig): Promise<string> => {\n  const headerList = await headers()\n  const fromHeader = headerList.get(config.headerName)\n  if (fromHeader) return fromHeader\n\n  const cookieStore = await cookies()\n  const cookieValue = cookieStore.get(config.cookieName)?.value\n  if (cookieValue) {\n    if (config.supportedLngs.includes(cookieValue)) {\n      return cookieValue\n    }\n    // nonExplicitSupportedLngs: e.g. cookie 'en' matches supported 'en-US'\n    if (config.nonExplicitSupportedLngs) {\n      const prefix = cookieValue.toLowerCase().split('-')[0]\n      const match = config.supportedLngs.find(\n        l => l.toLowerCase() === prefix || l.toLowerCase().split('-')[0] === prefix\n      )\n      if (match) return match\n    }\n  }\n\n  return config.fallbackLng\n})\n\n/**\n * Get a translation function for use in Server Components, layouts, and generateMetadata.\n *\n * The underlying i18next instance is a **module-level singleton** that persists across\n * requests. This means custom backends (i18next-http-backend, i18next-locize-backend, etc.)\n * only fetch translations once (or according to their own reloadInterval), not on every request.\n *\n * @example\n * ```tsx\n * import { getT } from 'next-i18next/server'\n *\n * export default async function Page() {\n *   const { t, i18n } = await getT('home')\n *   return <h1>{t('heading')}</h1>\n * }\n * ```\n */\nexport async function getT<\n  Ns extends FlatNamespace = FlatNamespace,\n  KPrefix extends KeyPrefix<Ns> = undefined,\n>(\n  ns?: Ns | Ns[],\n  options: { keyPrefix?: KPrefix; lng?: string } = {},\n): Promise<GetTResult<Ns, KPrefix>> {\n  const config = getConfig()\n\n  const lng = options.lng || await detectLanguage(config)\n  const i18nInstance = await getSharedInstance(config)\n\n  if (config.reloadOnPrerender && process.env.NODE_ENV !== 'production') {\n    await reloadResourcesForRender(i18nInstance, lng)\n  }\n\n  // Load additional namespaces on demand if not already loaded\n  const nsArray: string[] = ns\n    ? (Array.isArray(ns) ? ns as string[] : [ns as string])\n    : config.ns\n  const missingNs = nsArray.filter(n => !i18nInstance.hasLoadedNamespace(n))\n  if (missingNs.length > 0) {\n    await i18nInstance.loadNamespaces(missingNs)\n  }\n\n  const resolvedNs = ns\n    ? (Array.isArray(ns) ? ns[0] : ns) as string\n    : config.defaultNS\n\n  return {\n    t: i18nInstance.getFixedT(lng, resolvedNs, options.keyPrefix as string | undefined),\n    i18n: i18nInstance,\n    lng,\n  } as any\n}\n\n/**\n * Extract loaded resources from the server i18next instance for passing to I18nProvider.\n *\n * @example\n * ```tsx\n * const { i18n } = await getT()\n * const resources = getResources(i18n, ['common', 'footer'])\n * return <I18nProvider language={i18n.language} resources={resources}>{children}</I18nProvider>\n * ```\n */\nexport function getResources(\n  i18n: I18NextClient,\n  namespaces?: string[],\n): Resource {\n  const resources: Resource = {}\n  const store = i18n.store?.data || {}\n  const nsFilter = namespaces ? new Set(namespaces) : null\n\n  for (const lng of Object.keys(store)) {\n    resources[lng] = {}\n    for (const ns of Object.keys(store[lng])) {\n      if (!nsFilter || nsFilter.has(ns)) {\n        resources[lng][ns] = store[lng][ns]\n      }\n    }\n  }\n\n  return resources\n}\n\n/**\n * Helper for generateStaticParams — returns params for all supported languages.\n *\n * @example\n * ```tsx\n * import { generateI18nStaticParams } from 'next-i18next/server'\n *\n * export async function generateStaticParams() {\n *   return generateI18nStaticParams()\n * }\n * ```\n */\nexport function generateI18nStaticParams(): { lng: string }[] {\n  const config = getConfig()\n  return config.supportedLngs.map(lng => ({ lng }))\n}\n"],"mappings":"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"}