@fluenti/nuxt 0.3.3 → 0.4.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{detectors-CAqp_VCN.js → detectors-CBe19LCy.js} +3 -3
- package/dist/detectors-CBe19LCy.js.map +1 -0
- package/dist/detectors-CxhqsYjl.cjs +2 -0
- package/dist/detectors-CxhqsYjl.cjs.map +1 -0
- package/dist/locale-head-CV660rxz.js +97 -0
- package/dist/locale-head-CV660rxz.js.map +1 -0
- package/dist/locale-head-CwFSeJqY.cjs +2 -0
- package/dist/locale-head-CwFSeJqY.cjs.map +1 -0
- package/dist/module.cjs +1 -1
- package/dist/module.cjs.map +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +10 -23
- package/dist/module.js.map +1 -1
- package/dist/page-meta-transform.d.ts.map +1 -1
- package/dist/runtime/client.cjs +1 -1
- package/dist/runtime/client.js +1 -1
- package/dist/runtime/composables.cjs +1 -1
- package/dist/runtime/composables.js +1 -1
- package/dist/runtime/index.cjs +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/locale-head.d.ts.map +1 -1
- package/dist/runtime/middleware/locale-redirect.cjs +1 -1
- package/dist/runtime/middleware/locale-redirect.js +1 -1
- package/dist/runtime/plugin.cjs +1 -1
- package/dist/runtime/plugin.cjs.map +1 -1
- package/dist/runtime/plugin.d.ts.map +1 -1
- package/dist/runtime/plugin.js +1 -7
- package/dist/runtime/plugin.js.map +1 -1
- package/dist/runtime/server/locale-redirect.cjs +1 -1
- package/dist/runtime/server/locale-redirect.cjs.map +1 -1
- package/dist/runtime/server/locale-redirect.d.ts.map +1 -1
- package/dist/runtime/server/locale-redirect.js +5 -5
- package/dist/runtime/server/locale-redirect.js.map +1 -1
- package/dist/runtime/standalone-composables.cjs +1 -1
- package/dist/runtime/standalone-composables.js +1 -1
- package/package.json +3 -3
- package/dist/detectors-BnmzZTww.cjs +0 -2
- package/dist/detectors-BnmzZTww.cjs.map +0 -1
- package/dist/detectors-CAqp_VCN.js.map +0 -1
- package/dist/locale-head-BuSO-fCZ.js +0 -88
- package/dist/locale-head-BuSO-fCZ.js.map +0 -1
- package/dist/locale-head-D1NAUQc8.cjs +0 -2
- package/dist/locale-head-D1NAUQc8.cjs.map +0 -1
package/dist/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","names":[],"sources":["../src/types.ts","../src/isr-validation.ts","../src/devtools.ts","../src/page-meta-transform.ts","../src/sitemap.ts","../src/module.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\n// Re-export core types for backwards compatibility\nexport type { LocaleObject, LocaleDefinition } from '@fluenti/core'\nexport { resolveLocaleCodes }\n\n// Import core types needed locally\nimport type { LocaleDefinition, LocaleObject } from '@fluenti/core'\n\n/** Routing strategy for locale-prefixed URLs */\nexport type Strategy = 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix' | 'domains'\n\n/** Browser language detection options */\nexport interface DetectBrowserLanguageOptions {\n /** Use a cookie to persist the detected locale */\n useCookie?: boolean\n /** Cookie key name (default: 'fluenti_locale') */\n cookieKey?: string\n /** Fallback locale when detection fails */\n fallbackLocale?: string\n}\n\n/** Built-in detector names */\nexport type BuiltinDetector = 'path' | 'cookie' | 'header' | 'query' | 'domain'\n\n/**\n * Context passed to locale detectors and the `fluenti:detect-locale` hook.\n *\n * Detectors inspect the context and call `setLocale()` to claim a locale.\n * Once a locale is set, subsequent detectors are skipped.\n */\nexport interface LocaleDetectContext {\n /** The request path (e.g. '/ja/about') */\n path: string\n /** Available locale codes */\n locales: string[]\n /** Default locale */\n defaultLocale: string\n /** Routing strategy */\n strategy: Strategy\n /** detectBrowserLanguage config */\n detectBrowserLanguage?: DetectBrowserLanguageOptions\n /** The detected locale so far (null if not yet detected) */\n detectedLocale: string | null\n /** Set the locale and stop the detection chain */\n setLocale: (locale: string) => void\n /** Whether we are running on the server */\n isServer: boolean\n /** The request hostname (available when `strategy: 'domains'`) */\n host?: string\n /** Pre-read cookie value (hoisted before await in plugin) */\n cookieValue?: string | null\n /** Pre-read Accept-Language header (hoisted before await in plugin) */\n acceptLanguage?: string\n}\n\n/**\n * A locale detector function.\n *\n * Can be sync or async. Call `ctx.setLocale(locale)` to claim a locale.\n */\nexport type LocaleDetectorFn = (ctx: LocaleDetectContext) => void | Promise<void>\n\n/**\n * Per-page locale configuration.\n *\n * Restricts which locales a page supports. Routes will only be generated\n * for the specified locales.\n *\n * @example\n * ```ts\n * // In a page component's <script setup>\n * defineI18nRoute({ locales: ['en', 'ja'] }) // only en and ja for this page\n * defineI18nRoute(false) // disable i18n for this page\n * ```\n */\nexport type I18nRouteConfig = { locales: string[] } | false\n\n/** Domain-to-locale mapping for the `'domains'` strategy */\nexport interface DomainConfig {\n /** Domain hostname (e.g. 'example.jp', 'ja.example.com') */\n domain: string\n /** Locale code for this domain */\n locale: string\n /** Whether this is the default domain (used for x-default hreflang) */\n defaultForLocale?: boolean\n}\n\n/** @fluenti/nuxt module options (set in nuxt.config.ts under `fluenti` key) */\nexport interface FluentNuxtOptions {\n /** fluenti.config.ts path or inline config */\n config?: string | FluentiBuildConfig\n\n // ---- Core overrides (take precedence over fluenti.config.ts) ----\n\n /** Override locales from fluenti.config.ts */\n locales?: FluentiBuildConfig['locales']\n /** Override defaultLocale from fluenti.config.ts */\n defaultLocale?: string\n /** Override sourceLocale from fluenti.config.ts */\n sourceLocale?: string\n /** Override catalogDir from fluenti.config.ts */\n catalogDir?: string\n\n // ---- Nuxt-specific: routing, detection, components ----\n\n /** URL routing strategy */\n strategy?: Strategy\n /** Browser language detection settings */\n detectBrowserLanguage?: DetectBrowserLanguageOptions\n /**\n * Ordered list of locale detectors.\n *\n * Each entry is either a built-in detector name ('path', 'cookie', 'header', 'query', 'domain')\n * or a file path to a custom detector module (e.g. '~/detectors/jwt-detector').\n *\n * Detectors run in order; the first one to call `ctx.setLocale()` wins.\n *\n * @default ['path', 'cookie', 'header']\n */\n detectOrder?: Array<BuiltinDetector | string>\n /**\n * Query parameter name for locale detection (e.g. `?lang=ja`).\n *\n * @default 'locale'\n */\n queryParamKey?: string\n /**\n * Prefix for globally registered i18n components (Trans, Plural, Select, DateTime, NumberFormat).\n *\n * Use this to avoid naming conflicts with other libraries.\n *\n * @example 'I18n' // → I18nTrans, I18nPlural, I18nSelect, I18nDateTime, I18nNumberFormat\n * @default '' (no prefix)\n */\n componentPrefix?: string\n /**\n * Automatically register `@fluenti/vite-plugin` in the Vite config.\n *\n * Set to `false` to disable if you configure the Vite plugin manually.\n *\n * @default true\n */\n autoVitePlugin?: boolean\n /**\n * Whether to auto-import composables (useLocalePath, useSwitchLocalePath, useLocaleHead, useI18n).\n *\n * Set to `false` to disable all auto-imports. Useful when migrating from `@nuxtjs/i18n`\n * or when you want explicit imports to avoid naming collisions.\n *\n * @default true\n */\n autoImports?: boolean\n /**\n * Whether to extend routes with locale-prefixed variants.\n *\n * Set to `false` to handle locale routing yourself (e.g., via a custom\n * `pages:extend` hook or Nuxt Layers). When `false`, the module will NOT\n * create locale-suffixed route clones and will NOT remove unprefixed routes.\n *\n * @default true\n */\n extendRoutes?: boolean\n /**\n * Route generation mode for locale variants.\n *\n * - `'all'` (default): All pages get locale route variants unless explicitly\n * opted out via `definePageMeta({ i18n: false })`.\n * - `'opt-in'`: Only pages that explicitly declare `definePageMeta({ i18n: { locales: [...] } })`\n * get locale route variants. Pages without an `i18n` meta field are left untouched.\n *\n * Use `'opt-in'` for large projects where only a subset of pages need i18n routing.\n *\n * @default 'all'\n */\n routeMode?: 'all' | 'opt-in'\n /**\n * Template for generating locale-specific route names.\n *\n * Receives the original route name and locale code, returns the desired name.\n * Only used when `extendRoutes` is not `false`.\n *\n * @default (name, locale) => `${name}___${locale}`\n * @example (name, locale) => `${locale}:${name}`\n */\n routeNameTemplate?: (name: string, locale: string) => string\n /**\n * Custom route paths per locale.\n *\n * Allows different URL slugs for different locales (e.g. `/about` in English\n * becomes `/について` in Japanese).\n *\n * Keys are the original route paths; values are locale-to-path mappings.\n *\n * @example\n * ```ts\n * routeOverrides: {\n * '/about': { ja: '/について', 'zh-CN': '/关于' },\n * '/contact': { ja: '/お問い合わせ' },\n * }\n * ```\n */\n routeOverrides?: Record<string, Record<string, string>>\n /**\n * Whether the locale redirect middleware should be registered globally.\n *\n * Set to `false` to register it as a named middleware instead, so you can\n * apply it only to specific pages via `definePageMeta({ middleware: ['fluenti-locale-redirect'] })`.\n *\n * Only relevant when `strategy` is `'prefix'`.\n *\n * @default true\n */\n globalMiddleware?: boolean\n /**\n * Whether to register the `NuxtLinkLocale` component globally.\n *\n * Set to `false` to disable registration. You can still import it manually\n * from `@fluenti/nuxt/runtime/components/NuxtLinkLocale`.\n *\n * @default true\n */\n registerNuxtLinkLocale?: boolean\n /**\n * Domain-to-locale mappings for the `'domains'` strategy.\n *\n * Each entry maps a domain hostname to a locale. Required when `strategy` is `'domains'`.\n *\n * Can also be specified inline in locale objects via `{ code: 'ja', domain: 'example.jp' }`.\n *\n * @example\n * ```ts\n * domains: [\n * { domain: 'example.com', locale: 'en', defaultForLocale: true },\n * { domain: 'example.jp', locale: 'ja' },\n * ]\n * ```\n */\n domains?: DomainConfig[]\n /**\n * Incremental Static Regeneration (ISR) settings.\n *\n * When enabled, the module automatically generates `routeRules` with\n * ISR caching for all locale route patterns.\n */\n isr?: ISROptions\n /** Enable @fluenti/vue-i18n-compat bridge mode */\n compat?: boolean\n /**\n * Whether to inject `$localePath` onto `app.config.globalProperties`.\n *\n * Set to `false` if another plugin (e.g. `@nuxtjs/i18n`) already provides `$localePath`,\n * or when using composition API exclusively.\n *\n * @default true\n */\n injectGlobalProperties?: boolean\n /**\n * Callback fired when a translation key is missing from the catalog.\n *\n * Useful for logging, error tracking, or providing dynamic fallbacks.\n */\n onMissingTranslation?: (locale: string, id: string) => string | undefined\n /**\n * Structured error handler for i18n errors.\n */\n onError?: I18nErrorHandler\n /**\n * Generate fallback text when a translation is missing or errors.\n */\n getMessageFallback?: MessageFallbackHandler\n}\n\n/** Structured i18n error types */\nexport type I18nErrorCode = 'MISSING_MESSAGE' | 'MISSING_LOCALE' | 'FORMAT_ERROR' | 'LOAD_ERROR'\n\n/** Structured error passed to the onError callback */\nexport interface I18nError {\n /** Error classification */\n code: I18nErrorCode\n /** Human-readable error message */\n message: string\n /** The message key that caused the error */\n key?: string\n /** The locale that caused the error */\n locale?: string\n /** The original error (if wrapping a lower-level error) */\n cause?: unknown\n}\n\n/** Callback for structured i18n error handling */\nexport type I18nErrorHandler = (error: I18nError) => void\n\n/**\n * Callback to generate fallback text when a translation is missing or errors.\n *\n * Return a string to use as the fallback, or `undefined` for default behavior\n * (which shows the message key).\n */\nexport type MessageFallbackHandler = (error: I18nError) => string | undefined\n\n/** ISR configuration */\nexport interface ISROptions {\n /** Enable ISR route rules generation */\n enabled: boolean\n /** Cache TTL in seconds (default: 3600 — 1 hour) */\n ttl?: number\n}\n\n/** Runtime config injected into Nuxt's public runtimeConfig */\nexport interface FluentNuxtRuntimeConfig {\n locales: string[]\n defaultLocale: string\n strategy: Strategy\n detectBrowserLanguage?: DetectBrowserLanguageOptions\n /** Ordered list of detector names/paths */\n detectOrder: Array<string>\n /** Query parameter name for locale detection */\n queryParamKey: string\n /** Whether to inject $localePath onto globalProperties */\n injectGlobalProperties: boolean\n /** Domain-to-locale mappings (when strategy is 'domains') */\n domains?: DomainConfig[]\n /** Locale metadata (iso tags, dir, names) — keyed by locale code */\n localeProperties?: Record<string, LocaleObject>\n}\n\n// ---- Utility helpers ----\n\n/** Build a locale properties map from LocaleDefinition[] */\nexport function resolveLocaleProperties(locales: LocaleDefinition[]): Record<string, LocaleObject> {\n const map: Record<string, LocaleObject> = {}\n for (const l of locales) {\n if (typeof l === 'string') {\n map[l] = { code: l }\n } else {\n map[l.code] = l\n }\n }\n return map\n}\n\n/** Build domain configs from locale objects that have a `domain` field */\nexport function resolveDomainConfigs(\n locales: LocaleDefinition[],\n explicit?: DomainConfig[],\n): DomainConfig[] {\n if (explicit?.length) return explicit\n const configs: DomainConfig[] = []\n for (const l of locales) {\n if (typeof l !== 'string' && l.domain) {\n configs.push({ domain: l.domain, locale: l.code })\n }\n }\n return configs\n}\n","import type { FluentNuxtOptions, Strategy } from './types'\n\nexport interface ISRWarning {\n level: 'warn' | 'error'\n message: string\n}\n\n/**\n * Validate ISR configuration against locale detection settings.\n *\n * ISR caches responses by URL path. If locale detection relies on\n * non-path signals (cookies, headers), the cached response may serve\n * the wrong locale to subsequent visitors.\n */\nexport function validateISRConfig(\n isr: FluentNuxtOptions['isr'],\n strategy: Strategy,\n detectOrder: string[],\n): ISRWarning[] {\n const warnings: ISRWarning[] = []\n if (!isr?.enabled) return warnings\n\n const nonPathDetectors = detectOrder.filter(\n (d) => d === 'cookie' || d === 'header',\n )\n if (nonPathDetectors.length > 0) {\n warnings.push({\n level: 'warn',\n message:\n `[@fluenti/nuxt] ISR is enabled but detectOrder includes non-path ` +\n `detectors (${nonPathDetectors.join(', ')}). ISR caches by URL path, ` +\n `so cookie/header-based detection may serve the wrong locale from ` +\n `cache. Consider using detectOrder: ['path'] with ISR.`,\n })\n }\n\n if (strategy === 'no_prefix') {\n warnings.push({\n level: 'warn',\n message:\n `[@fluenti/nuxt] ISR is enabled with strategy: 'no_prefix'. All ` +\n `locales share the same URL path, so ISR will cache only one locale ` +\n `per URL. Use 'prefix' or 'prefix_except_default' strategy with ISR.`,\n })\n }\n\n return warnings\n}\n","import type { Nuxt } from '@nuxt/schema'\n\n/**\n * DevTools state exposed to the custom tab.\n * Serialized to JSON and sent to the DevTools panel.\n */\nexport interface DevToolsI18nState {\n currentLocale: string\n availableLocales: string[]\n defaultLocale: string\n strategy: string\n detectedBy: string\n messageCount: number\n loadedLocales: string[]\n missingKeys: string[]\n}\n\n/**\n * Register a Nuxt DevTools custom tab for Fluenti.\n *\n * Shows: current locale, available locales, detection chain result,\n * loaded message count, and missing translation keys.\n */\nexport function setupDevTools(nuxt: Nuxt, localeCodes: string[], defaultLocale: string, strategy: string): void {\n try {\n // Attempt to use @nuxt/devtools-kit if available\n // @ts-expect-error — devtools:customTabs hook is provided by @nuxt/devtools\n nuxt.hook('devtools:customTabs', (tabs: unknown[]) => {\n tabs.push({\n name: 'fluenti',\n title: 'Fluenti i18n',\n icon: 'i-carbon-translate',\n view: {\n type: 'client-component',\n componentName: 'FluentiDevToolsPanel',\n },\n })\n })\n } catch {\n // DevTools not available — silently skip\n }\n\n // Inject DevTools client component via virtual module\n // @ts-expect-error — nitro:config hook is provided by Nitro\n nuxt.hook('nitro:config', (nitroConfig: Record<string, unknown>) => {\n const publicConfig = nitroConfig['runtimeConfig'] as Record<string, unknown> | undefined\n if (publicConfig) {\n const pub = (publicConfig['public'] ?? (publicConfig['public'] = {})) as Record<string, unknown>\n const fluentiConfig = (pub['fluenti'] ?? {}) as Record<string, unknown>\n fluentiConfig['devtools'] = {\n enabled: true,\n locales: localeCodes,\n defaultLocale,\n strategy,\n }\n }\n })\n}\n\n/**\n * Client-side DevTools panel component source.\n *\n * This is injected as a virtual module and rendered inside the\n * Nuxt DevTools panel. It reads the Fluenti runtime state and\n * displays it in a simple, readable format.\n */\nexport const DEVTOOLS_PANEL_COMPONENT = `\n<template>\n <div style=\"padding: 16px; font-family: system-ui, sans-serif;\">\n <h2 style=\"margin: 0 0 16px; font-size: 18px;\">🌐 Fluenti i18n</h2>\n\n <div style=\"display: grid; grid-template-columns: 140px 1fr; gap: 8px 16px; font-size: 14px;\">\n <span style=\"color: #888;\">Current locale:</span>\n <strong>{{ state.currentLocale }}</strong>\n\n <span style=\"color: #888;\">Default locale:</span>\n <span>{{ state.defaultLocale }}</span>\n\n <span style=\"color: #888;\">Strategy:</span>\n <span>{{ state.strategy }}</span>\n\n <span style=\"color: #888;\">Available:</span>\n <span>{{ state.availableLocales.join(', ') }}</span>\n\n <span style=\"color: #888;\">Loaded:</span>\n <span>{{ state.loadedLocales.join(', ') || 'none' }}</span>\n\n <span style=\"color: #888;\">Messages:</span>\n <span>{{ state.messageCount }}</span>\n\n <span style=\"color: #888;\">Missing keys:</span>\n <span :style=\"{ color: state.missingKeys.length > 0 ? '#e53e3e' : '#38a169' }\">\n {{ state.missingKeys.length > 0 ? state.missingKeys.length + ' missing' : 'All translated ✓' }}\n </span>\n </div>\n\n <div v-if=\"state.missingKeys.length > 0\" style=\"margin-top: 16px;\">\n <h3 style=\"margin: 0 0 8px; font-size: 14px; color: #e53e3e;\">Missing translations:</h3>\n <ul style=\"margin: 0; padding: 0 0 0 20px; font-size: 13px; font-family: monospace;\">\n <li v-for=\"key in state.missingKeys\" :key=\"key\" style=\"margin: 2px 0;\">{{ key }}</li>\n </ul>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, onMounted } from 'vue'\n\nconst state = ref({\n currentLocale: '',\n defaultLocale: '',\n strategy: '',\n availableLocales: [],\n loadedLocales: [],\n messageCount: 0,\n missingKeys: [],\n})\n\nonMounted(() => {\n try {\n const nuxtApp = window.__NUXT_DEVTOOLS_VIEW__?.nuxtApp ?? useNuxtApp()\n const config = nuxtApp.$config?.public?.fluenti ?? {}\n const fluentiLocale = nuxtApp.$fluentiLocale ?? ref('')\n\n state.value = {\n currentLocale: fluentiLocale.value || config.defaultLocale || '',\n defaultLocale: config.defaultLocale || '',\n strategy: config.strategy || '',\n availableLocales: config.locales || [],\n loadedLocales: [],\n messageCount: 0,\n missingKeys: [],\n }\n } catch (e) {\n // DevTools context not available\n }\n})\n</script>\n`\n","import type { Plugin } from 'vite'\n\n/**\n * Vite plugin that transforms `definePageMeta({ i18n: ... })` into\n * the internal `i18nRoute` format used by the page extension system.\n *\n * This allows users to use native Nuxt `definePageMeta` with an `i18n` key\n * instead of the separate `defineI18nRoute()` macro.\n *\n * Supports:\n * - `definePageMeta({ i18n: { locales: ['en', 'ja'] } })`\n * - `definePageMeta({ i18n: false })`\n *\n * The transform also rewrites `defineI18nRoute(...)` to\n * `definePageMeta({ i18nRoute: ... })` for backwards compatibility.\n */\nexport function createPageMetaTransform(): Plugin {\n return {\n name: 'fluenti:page-meta-transform',\n enforce: 'pre',\n\n transform(code, id) {\n // Only transform Vue SFC script blocks and TS/JS files in pages/\n if (!id.includes('/pages/') && !id.includes('\\\\pages\\\\')) return null\n if (!code.includes('defineI18nRoute') && !code.includes('i18n')) return null\n\n let transformed = code\n\n // Transform: defineI18nRoute({ locales: [...] })\n // → definePageMeta({ i18nRoute: { locales: [...] } })\n // Transform: defineI18nRoute(false)\n // → definePageMeta({ i18nRoute: false })\n const defineI18nRouteRegex = /defineI18nRoute\\s*\\(([^)]+)\\)/g\n if (defineI18nRouteRegex.test(transformed)) {\n transformed = transformed.replace(\n /defineI18nRoute\\s*\\(([^)]+)\\)/g,\n (_match, arg: string) => `definePageMeta({ i18nRoute: ${arg.trim()} })`,\n )\n }\n\n // Support native: definePageMeta({ i18n: { locales: [...] } })\n // Rewrite `i18n:` key to `i18nRoute:` so page-extend can read it\n if (transformed.includes('definePageMeta') && transformed.includes('i18n:')) {\n // Simple regex for { i18n: ... } within definePageMeta\n // This handles the common case; complex nested objects may need\n // AST-based transformation in the future.\n transformed = transformed.replace(\n /(definePageMeta\\s*\\(\\s*\\{[^}]*)\\bi18n\\s*:/g,\n '$1i18nRoute:',\n )\n }\n\n if (transformed === code) return null\n\n return {\n code: transformed,\n map: null,\n }\n },\n }\n}\n","import type { Strategy } from './types'\n\nexport interface SitemapUrl {\n loc: string\n alternatives?: Array<{ hreflang: string; href: string }>\n}\n\n/**\n * Generate multi-locale sitemap URLs from a list of base paths.\n *\n * For each base path, produces a URL entry with hreflang alternatives\n * pointing to every locale variant. Compatible with `@nuxtjs/sitemap`'s\n * `sources` hook format.\n */\nexport function generateSitemapUrls(\n paths: string[],\n locales: string[],\n defaultLocale: string,\n strategy: Strategy,\n baseUrl?: string,\n): SitemapUrl[] {\n const urls: SitemapUrl[] = []\n const base = baseUrl ?? ''\n\n for (const rawPath of paths) {\n const path = rawPath.startsWith('/') ? rawPath : `/${rawPath}`\n\n for (const locale of locales) {\n const localizedPath = buildLocalePath(path, locale, defaultLocale, strategy)\n\n const alternatives = locales.map((altLocale) => ({\n hreflang: altLocale,\n href: `${base}${buildLocalePath(path, altLocale, defaultLocale, strategy)}`,\n }))\n\n // Add x-default pointing to default locale\n alternatives.push({\n hreflang: 'x-default',\n href: `${base}${buildLocalePath(path, defaultLocale, defaultLocale, strategy)}`,\n })\n\n urls.push({\n loc: `${base}${localizedPath}`,\n alternatives,\n })\n }\n }\n\n return urls\n}\n\nfunction buildLocalePath(\n path: string,\n locale: string,\n defaultLocale: string,\n strategy: Strategy,\n): string {\n if (strategy === 'no_prefix') return path\n\n if (strategy === 'prefix_except_default' && locale === defaultLocale) {\n return path\n }\n\n const cleanPath = path === '/' ? '' : path\n return `/${locale}${cleanPath}`\n}\n\n/**\n * Hook handler for `@nuxtjs/sitemap`'s `sitemap:generate` hook.\n *\n * Transforms single-locale URLs into multi-locale entries with hreflang.\n * Register this in your nuxt.config.ts or let the module auto-register it.\n */\nexport function createSitemapHook(\n locales: string[],\n defaultLocale: string,\n strategy: Strategy,\n baseUrl?: string,\n) {\n return (urls: SitemapUrl[]) => {\n if (strategy === 'no_prefix') return urls\n\n const expanded: SitemapUrl[] = []\n\n for (const url of urls) {\n const loc = url.loc.replace(/^https?:\\/\\/[^/]+/, '')\n\n for (const locale of locales) {\n const localizedPath = buildLocalePath(loc, locale, defaultLocale, strategy)\n const alternatives = locales.map((altLocale) => ({\n hreflang: altLocale,\n href: `${baseUrl ?? ''}${buildLocalePath(loc, altLocale, defaultLocale, strategy)}`,\n }))\n alternatives.push({\n hreflang: 'x-default',\n href: `${baseUrl ?? ''}${buildLocalePath(loc, defaultLocale, defaultLocale, strategy)}`,\n })\n\n expanded.push({\n loc: `${baseUrl ?? ''}${localizedPath}`,\n alternatives,\n })\n }\n }\n\n return expanded\n }\n}\n","import { defineNuxtModule, addPlugin, addImports, addComponent, addRouteMiddleware, addServerHandler, createResolver } from '@nuxt/kit'\nimport { createRequire } from 'node:module'\nimport type { FluentNuxtOptions } from './types'\nimport { resolveLocaleProperties, resolveDomainConfigs } from './types'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\nimport type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport fluentiVue from '@fluenti/vue/vite-plugin'\nimport { extendPages } from './runtime/page-extend'\nimport { validateISRConfig } from './isr-validation'\nimport { setupDevTools } from './devtools'\nimport { createPageMetaTransform } from './page-meta-transform'\n\nexport type { FluentNuxtOptions, Strategy, FluentNuxtRuntimeConfig, DetectBrowserLanguageOptions, LocaleDetectContext, LocaleDetectorFn, BuiltinDetector, ISROptions, LocaleObject, LocaleDefinition, DomainConfig, I18nRouteConfig, I18nError, I18nErrorCode, I18nErrorHandler, MessageFallbackHandler } from './types'\nexport { generateSitemapUrls, createSitemapHook } from './sitemap'\nexport type { SitemapUrl } from './sitemap'\nexport { resolveLocaleProperties, resolveDomainConfigs } from './types'\nexport { resolveLocaleCodes } from '@fluenti/core/internal'\nexport { localePath, extractLocaleFromPath, switchLocalePath } from './runtime/path-utils'\nexport { extendPages } from './runtime/page-extend'\nexport type { PageRoute, RouteNameTemplate, ExtendPagesOptions } from './runtime/page-extend'\nexport { buildLocaleHead } from './runtime/locale-head'\nexport type { LocaleHeadMeta, LocaleHeadOptions } from './runtime/locale-head'\nexport { useLocalePath, useSwitchLocalePath, useLocaleRoute, useLocaleHead } from './runtime/standalone-composables'\nexport { defineI18nRoute } from './runtime/define-i18n-route'\n\nexport const MODULE_NAME = '@fluenti/nuxt'\nexport const CONFIG_KEY = 'fluenti'\n\n// Module-level require that works in both CJS and ESM after bundling.\n// See packages/core/src/config-loader.ts for explanation of the pattern.\nconst _require = createRequire(\n typeof __filename !== 'undefined' ? __filename : import.meta.url,\n)\n\n/**\n * Resolve the FluentiBuildConfig from the module options.\n */\nfunction resolveFluentiBuildConfig(configOption: string | FluentiBuildConfig | undefined, rootDir: string): FluentiBuildConfig {\n\n if (typeof configOption === 'object') {\n // Inline config — merge with defaults\n try {\n const { DEFAULT_FLUENTI_CONFIG } = _require('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: FluentiBuildConfig\n }\n return { ...DEFAULT_FLUENTI_CONFIG, ...configOption }\n } catch {\n return configOption as FluentiBuildConfig\n }\n }\n\n // string → specified path; undefined → auto-discover\n try {\n const { loadConfigSync } = _require('@fluenti/core/config') as {\n loadConfigSync: (configPath?: string, cwd?: string) => FluentiBuildConfig\n }\n return loadConfigSync(\n typeof configOption === 'string' ? configOption : undefined,\n rootDir,\n )\n } catch {\n // @fluenti/core not available — return minimal defaults\n return {\n sourceLocale: 'en',\n locales: ['en'],\n catalogDir: './locales',\n format: 'po',\n include: ['./src/**/*.{vue,tsx,jsx,ts,js}'],\n compileOutDir: './src/locales/compiled',\n }\n }\n}\n\nexport default defineNuxtModule<FluentNuxtOptions>({\n meta: {\n name: MODULE_NAME,\n configKey: CONFIG_KEY,\n compatibility: { nuxt: '>=3.0.0' },\n },\n defaults: {\n strategy: 'prefix_except_default',\n },\n setup(options, nuxt) {\n const { resolve } = createResolver(import.meta.url)\n\n // --- Resolve FluentiBuildConfig from options.config, then overlay module-level options ---\n const rootDir = nuxt.options.rootDir ?? process.cwd()\n const fluentiConfig = resolveFluentiBuildConfig(options.config, rootDir)\n\n // Module-level options (e.g. nuxt.config.ts `fluenti.locales`) override the\n // resolved fluenti.config.ts values — this ensures Nuxt-specific config takes\n // precedence even when config file loading fails (e.g. CJS/jiti issues).\n if (options.locales) fluentiConfig.locales = options.locales\n if (options.defaultLocale) fluentiConfig.defaultLocale = options.defaultLocale\n if (options.sourceLocale) fluentiConfig.sourceLocale = options.sourceLocale\n if (options.catalogDir) fluentiConfig.catalogDir = options.catalogDir\n\n // --- Resolve locale codes and metadata ---\n const localeCodes = resolveLocaleCodes(fluentiConfig.locales)\n const localeProperties = resolveLocaleProperties(fluentiConfig.locales)\n const defaultLocale = fluentiConfig.defaultLocale ?? fluentiConfig.sourceLocale\n const domainConfigs = options.strategy === 'domains'\n ? resolveDomainConfigs(fluentiConfig.locales, options.domains)\n : undefined\n\n // --- Inject runtime config ---\n const detectOrder = options.detectOrder ?? (\n options.strategy === 'domains'\n ? ['domain', 'cookie', 'header']\n : ['path', 'cookie', 'header']\n )\n nuxt.options.runtimeConfig.public['fluenti'] = {\n locales: localeCodes,\n defaultLocale,\n strategy: options.strategy ?? 'prefix_except_default',\n detectBrowserLanguage: options.detectBrowserLanguage,\n detectOrder,\n queryParamKey: options.queryParamKey ?? 'locale',\n injectGlobalProperties: options.injectGlobalProperties !== false,\n ...(domainConfigs ? { domains: domainConfigs } : {}),\n localeProperties,\n }\n\n // --- Auto-register @fluenti/vue vite plugin (includes v-t transform + scope transform) ---\n if (options.autoVitePlugin !== false) {\n nuxt.options.vite = nuxt.options.vite || {}\n nuxt.options.vite.plugins = nuxt.options.vite.plugins || []\n ;(nuxt.options.vite.plugins as unknown[]).push(\n ...fluentiVue({ config: fluentiConfig }),\n )\n }\n\n // --- Register definePageMeta({ i18n }) transform ---\n nuxt.options.vite = nuxt.options.vite || {}\n nuxt.options.vite.plugins = nuxt.options.vite.plugins || []\n ;(nuxt.options.vite.plugins as unknown[]).push(createPageMetaTransform())\n\n // --- Register runtime plugin ---\n addPlugin({\n src: resolve('./runtime/plugin'),\n mode: 'all',\n })\n\n // --- Extend routes with locale prefixes ---\n const strategy = options.strategy ?? 'prefix_except_default'\n if (strategy !== 'no_prefix' && strategy !== 'domains' && options.extendRoutes !== false) {\n nuxt.hook('pages:extend', (pages) => {\n extendPages(pages, {\n locales: localeCodes,\n defaultLocale,\n strategy,\n ...(options.routeNameTemplate ? { routeNameTemplate: options.routeNameTemplate } : {}),\n ...(options.routeOverrides ? { routeOverrides: options.routeOverrides } : {}),\n ...(options.routeMode ? { routeMode: options.routeMode } : {}),\n })\n })\n }\n\n // --- Register locale redirect middleware ---\n if (strategy === 'prefix') {\n addRouteMiddleware({\n name: 'fluenti-locale-redirect',\n path: resolve('./runtime/middleware/locale-redirect'),\n global: options.globalMiddleware !== false,\n })\n }\n\n // --- Auto-import composables ---\n if (options.autoImports !== false) {\n addImports([\n { name: 'useLocalePath', from: resolve('./runtime/composables') },\n { name: 'useSwitchLocalePath', from: resolve('./runtime/composables') },\n { name: 'useLocaleRoute', from: resolve('./runtime/composables') },\n { name: 'useLocaleHead', from: resolve('./runtime/composables') },\n { name: 'useI18nScoped', from: resolve('./runtime/composables') },\n { name: 'useI18n', from: '@fluenti/vue' },\n { name: 'defineI18nRoute', from: resolve('./runtime/define-i18n-route') },\n ])\n }\n\n // --- Register components (including DateTime + NumberFormat) ---\n const prefix = options.componentPrefix ?? ''\n if (options.registerNuxtLinkLocale !== false) {\n addComponent({\n name: `${prefix}NuxtLinkLocale`,\n filePath: resolve('./runtime/components/NuxtLinkLocale'),\n })\n }\n\n // Auto-import DateTime and NumberFormat from @fluenti/vue\n addComponent({ name: `${prefix}Trans`, filePath: '@fluenti/vue', export: 'Trans' })\n addComponent({ name: `${prefix}Plural`, filePath: '@fluenti/vue', export: 'Plural' })\n addComponent({ name: `${prefix}Select`, filePath: '@fluenti/vue', export: 'Select' })\n addComponent({ name: `${prefix}DateTime`, filePath: '@fluenti/vue', export: 'DateTime' })\n addComponent({ name: `${prefix}NumberFormat`, filePath: '@fluenti/vue', export: 'NumberFormat' })\n\n // --- SSG / ISR: configure nitro prerender and route rules ---\n if (strategy !== 'no_prefix' && strategy !== 'domains') {\n const nuxtOpts = nuxt.options as unknown as Record<string, unknown>\n\n // Enable link crawling so locale-prefixed routes are discovered during prerender\n const nitroOpts = (nuxtOpts['nitro'] ?? (nuxtOpts['nitro'] = {})) as Record<string, unknown>\n const prerender = (nitroOpts['prerender'] ?? (nitroOpts['prerender'] = {})) as Record<string, unknown>\n prerender['crawlLinks'] = prerender['crawlLinks'] ?? true\n\n // For 'prefix' strategy, / has no matching route (all routes are\n // locale-prefixed). Replace the default / initial route with\n // /<defaultLocale> so the prerenderer starts from a valid route.\n if (strategy === 'prefix') {\n const routes = (prerender['routes'] ?? ['/']) as string[]\n prerender['routes'] = routes.map((r) =>\n r === '/' ? `/${defaultLocale}` : r,\n )\n }\n\n // ISR: validate configuration and generate routeRules\n for (const w of validateISRConfig(options.isr, strategy, detectOrder)) {\n console.warn(w.message)\n }\n if (options.isr?.enabled) {\n const routeRules = (nuxtOpts['routeRules'] ?? (nuxtOpts['routeRules'] = {})) as Record<string, Record<string, unknown>>\n const ttl = options.isr.ttl ?? 3600\n for (const locale of localeCodes) {\n if (locale === defaultLocale && strategy === 'prefix_except_default') {\n routeRules['/**'] = { ...routeRules['/**'], isr: ttl }\n } else {\n routeRules[`/${locale}/**`] = { ...routeRules[`/${locale}/**`], isr: ttl }\n }\n }\n }\n }\n\n // --- Nuxt DevTools integration ---\n if (nuxt.options.dev) {\n setupDevTools(nuxt, localeCodes, defaultLocale, strategy)\n }\n\n // --- Nitro server handler for locale redirect (T2-10) ---\n if (strategy === 'prefix' || strategy === 'prefix_and_default') {\n addServerHandler({\n handler: resolve('./runtime/server/locale-redirect'),\n middleware: true,\n })\n }\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.js","names":[],"sources":["../src/types.ts","../src/isr-validation.ts","../src/devtools.ts","../src/page-meta-transform.ts","../src/sitemap.ts","../src/module.ts"],"sourcesContent":["import type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\n// Re-export core types for backwards compatibility\nexport type { LocaleObject, LocaleDefinition } from '@fluenti/core'\nexport { resolveLocaleCodes }\n\n// Import core types needed locally\nimport type { LocaleDefinition, LocaleObject } from '@fluenti/core'\n\n/** Routing strategy for locale-prefixed URLs */\nexport type Strategy = 'prefix' | 'prefix_except_default' | 'prefix_and_default' | 'no_prefix' | 'domains'\n\n/** Browser language detection options */\nexport interface DetectBrowserLanguageOptions {\n /** Use a cookie to persist the detected locale */\n useCookie?: boolean\n /** Cookie key name (default: 'fluenti_locale') */\n cookieKey?: string\n /** Fallback locale when detection fails */\n fallbackLocale?: string\n}\n\n/** Built-in detector names */\nexport type BuiltinDetector = 'path' | 'cookie' | 'header' | 'query' | 'domain'\n\n/**\n * Context passed to locale detectors and the `fluenti:detect-locale` hook.\n *\n * Detectors inspect the context and call `setLocale()` to claim a locale.\n * Once a locale is set, subsequent detectors are skipped.\n */\nexport interface LocaleDetectContext {\n /** The request path (e.g. '/ja/about') */\n path: string\n /** Available locale codes */\n locales: string[]\n /** Default locale */\n defaultLocale: string\n /** Routing strategy */\n strategy: Strategy\n /** detectBrowserLanguage config */\n detectBrowserLanguage?: DetectBrowserLanguageOptions\n /** The detected locale so far (null if not yet detected) */\n detectedLocale: string | null\n /** Set the locale and stop the detection chain */\n setLocale: (locale: string) => void\n /** Whether we are running on the server */\n isServer: boolean\n /** The request hostname (available when `strategy: 'domains'`) */\n host?: string\n /** Pre-read cookie value (hoisted before await in plugin) */\n cookieValue?: string | null\n /** Pre-read Accept-Language header (hoisted before await in plugin) */\n acceptLanguage?: string\n}\n\n/**\n * A locale detector function.\n *\n * Can be sync or async. Call `ctx.setLocale(locale)` to claim a locale.\n */\nexport type LocaleDetectorFn = (ctx: LocaleDetectContext) => void | Promise<void>\n\n/**\n * Per-page locale configuration.\n *\n * Restricts which locales a page supports. Routes will only be generated\n * for the specified locales.\n *\n * @example\n * ```ts\n * // In a page component's <script setup>\n * defineI18nRoute({ locales: ['en', 'ja'] }) // only en and ja for this page\n * defineI18nRoute(false) // disable i18n for this page\n * ```\n */\nexport type I18nRouteConfig = { locales: string[] } | false\n\n/** Domain-to-locale mapping for the `'domains'` strategy */\nexport interface DomainConfig {\n /** Domain hostname (e.g. 'example.jp', 'ja.example.com') */\n domain: string\n /** Locale code for this domain */\n locale: string\n /** Whether this is the default domain (used for x-default hreflang) */\n defaultForLocale?: boolean\n}\n\n/** @fluenti/nuxt module options (set in nuxt.config.ts under `fluenti` key) */\nexport interface FluentNuxtOptions {\n /** fluenti.config.ts path or inline config */\n config?: string | FluentiBuildConfig\n\n // ---- Core overrides (take precedence over fluenti.config.ts) ----\n\n /** Override locales from fluenti.config.ts */\n locales?: FluentiBuildConfig['locales']\n /** Override defaultLocale from fluenti.config.ts */\n defaultLocale?: string\n /** Override sourceLocale from fluenti.config.ts */\n sourceLocale?: string\n /** Override catalogDir from fluenti.config.ts */\n catalogDir?: string\n\n // ---- Nuxt-specific: routing, detection, components ----\n\n /** URL routing strategy */\n strategy?: Strategy\n /** Browser language detection settings */\n detectBrowserLanguage?: DetectBrowserLanguageOptions\n /**\n * Ordered list of locale detectors.\n *\n * Each entry is either a built-in detector name ('path', 'cookie', 'header', 'query', 'domain')\n * or a file path to a custom detector module (e.g. '~/detectors/jwt-detector').\n *\n * Detectors run in order; the first one to call `ctx.setLocale()` wins.\n *\n * @default ['path', 'cookie', 'header']\n */\n detectOrder?: Array<BuiltinDetector | string>\n /**\n * Query parameter name for locale detection (e.g. `?lang=ja`).\n *\n * @default 'locale'\n */\n queryParamKey?: string\n /**\n * Prefix for globally registered i18n components (Trans, Plural, Select, DateTime, NumberFormat).\n *\n * Use this to avoid naming conflicts with other libraries.\n *\n * @example 'I18n' // → I18nTrans, I18nPlural, I18nSelect, I18nDateTime, I18nNumberFormat\n * @default '' (no prefix)\n */\n componentPrefix?: string\n /**\n * Automatically register `@fluenti/vite-plugin` in the Vite config.\n *\n * Set to `false` to disable if you configure the Vite plugin manually.\n *\n * @default true\n */\n autoVitePlugin?: boolean\n /**\n * Whether to auto-import composables (useLocalePath, useSwitchLocalePath, useLocaleHead, useI18n).\n *\n * Set to `false` to disable all auto-imports. Useful when migrating from `@nuxtjs/i18n`\n * or when you want explicit imports to avoid naming collisions.\n *\n * @default true\n */\n autoImports?: boolean\n /**\n * Whether to extend routes with locale-prefixed variants.\n *\n * Set to `false` to handle locale routing yourself (e.g., via a custom\n * `pages:extend` hook or Nuxt Layers). When `false`, the module will NOT\n * create locale-suffixed route clones and will NOT remove unprefixed routes.\n *\n * @default true\n */\n extendRoutes?: boolean\n /**\n * Route generation mode for locale variants.\n *\n * - `'all'` (default): All pages get locale route variants unless explicitly\n * opted out via `definePageMeta({ i18n: false })`.\n * - `'opt-in'`: Only pages that explicitly declare `definePageMeta({ i18n: { locales: [...] } })`\n * get locale route variants. Pages without an `i18n` meta field are left untouched.\n *\n * Use `'opt-in'` for large projects where only a subset of pages need i18n routing.\n *\n * @default 'all'\n */\n routeMode?: 'all' | 'opt-in'\n /**\n * Template for generating locale-specific route names.\n *\n * Receives the original route name and locale code, returns the desired name.\n * Only used when `extendRoutes` is not `false`.\n *\n * @default (name, locale) => `${name}___${locale}`\n * @example (name, locale) => `${locale}:${name}`\n */\n routeNameTemplate?: (name: string, locale: string) => string\n /**\n * Custom route paths per locale.\n *\n * Allows different URL slugs for different locales (e.g. `/about` in English\n * becomes `/について` in Japanese).\n *\n * Keys are the original route paths; values are locale-to-path mappings.\n *\n * @example\n * ```ts\n * routeOverrides: {\n * '/about': { ja: '/について', 'zh-CN': '/关于' },\n * '/contact': { ja: '/お問い合わせ' },\n * }\n * ```\n */\n routeOverrides?: Record<string, Record<string, string>>\n /**\n * Whether the locale redirect middleware should be registered globally.\n *\n * Set to `false` to register it as a named middleware instead, so you can\n * apply it only to specific pages via `definePageMeta({ middleware: ['fluenti-locale-redirect'] })`.\n *\n * Only relevant when `strategy` is `'prefix'`.\n *\n * @default true\n */\n globalMiddleware?: boolean\n /**\n * Whether to register the `NuxtLinkLocale` component globally.\n *\n * Set to `false` to disable registration. You can still import it manually\n * from `@fluenti/nuxt/runtime/components/NuxtLinkLocale`.\n *\n * @default true\n */\n registerNuxtLinkLocale?: boolean\n /**\n * Domain-to-locale mappings for the `'domains'` strategy.\n *\n * Each entry maps a domain hostname to a locale. Required when `strategy` is `'domains'`.\n *\n * Can also be specified inline in locale objects via `{ code: 'ja', domain: 'example.jp' }`.\n *\n * @example\n * ```ts\n * domains: [\n * { domain: 'example.com', locale: 'en', defaultForLocale: true },\n * { domain: 'example.jp', locale: 'ja' },\n * ]\n * ```\n */\n domains?: DomainConfig[]\n /**\n * Incremental Static Regeneration (ISR) settings.\n *\n * When enabled, the module automatically generates `routeRules` with\n * ISR caching for all locale route patterns.\n */\n isr?: ISROptions\n /** Enable @fluenti/vue-i18n-compat bridge mode */\n compat?: boolean\n /**\n * Whether to inject `$localePath` onto `app.config.globalProperties`.\n *\n * Set to `false` if another plugin (e.g. `@nuxtjs/i18n`) already provides `$localePath`,\n * or when using composition API exclusively.\n *\n * @default true\n */\n injectGlobalProperties?: boolean\n /**\n * Callback fired when a translation key is missing from the catalog.\n *\n * Useful for logging, error tracking, or providing dynamic fallbacks.\n */\n onMissingTranslation?: (locale: string, id: string) => string | undefined\n /**\n * Structured error handler for i18n errors.\n */\n onError?: I18nErrorHandler\n /**\n * Generate fallback text when a translation is missing or errors.\n */\n getMessageFallback?: MessageFallbackHandler\n}\n\n/** Structured i18n error types */\nexport type I18nErrorCode = 'MISSING_MESSAGE' | 'MISSING_LOCALE' | 'FORMAT_ERROR' | 'LOAD_ERROR'\n\n/** Structured error passed to the onError callback */\nexport interface I18nError {\n /** Error classification */\n code: I18nErrorCode\n /** Human-readable error message */\n message: string\n /** The message key that caused the error */\n key?: string\n /** The locale that caused the error */\n locale?: string\n /** The original error (if wrapping a lower-level error) */\n cause?: unknown\n}\n\n/** Callback for structured i18n error handling */\nexport type I18nErrorHandler = (error: I18nError) => void\n\n/**\n * Callback to generate fallback text when a translation is missing or errors.\n *\n * Return a string to use as the fallback, or `undefined` for default behavior\n * (which shows the message key).\n */\nexport type MessageFallbackHandler = (error: I18nError) => string | undefined\n\n/** ISR configuration */\nexport interface ISROptions {\n /** Enable ISR route rules generation */\n enabled: boolean\n /** Cache TTL in seconds (default: 3600 — 1 hour) */\n ttl?: number\n}\n\n/** Runtime config injected into Nuxt's public runtimeConfig */\nexport interface FluentNuxtRuntimeConfig {\n locales: string[]\n defaultLocale: string\n strategy: Strategy\n detectBrowserLanguage?: DetectBrowserLanguageOptions\n /** Ordered list of detector names/paths */\n detectOrder: Array<string>\n /** Query parameter name for locale detection */\n queryParamKey: string\n /** Whether to inject $localePath onto globalProperties */\n injectGlobalProperties: boolean\n /** Domain-to-locale mappings (when strategy is 'domains') */\n domains?: DomainConfig[]\n /** Locale metadata (iso tags, dir, names) — keyed by locale code */\n localeProperties?: Record<string, LocaleObject>\n}\n\n// ---- Utility helpers ----\n\n/** Build a locale properties map from LocaleDefinition[] */\nexport function resolveLocaleProperties(locales: LocaleDefinition[]): Record<string, LocaleObject> {\n const map: Record<string, LocaleObject> = {}\n for (const l of locales) {\n if (typeof l === 'string') {\n map[l] = { code: l }\n } else {\n map[l.code] = l\n }\n }\n return map\n}\n\n/** Build domain configs from locale objects that have a `domain` field */\nexport function resolveDomainConfigs(\n locales: LocaleDefinition[],\n explicit?: DomainConfig[],\n): DomainConfig[] {\n if (explicit?.length) return explicit\n const configs: DomainConfig[] = []\n for (const l of locales) {\n if (typeof l !== 'string' && l.domain) {\n configs.push({ domain: l.domain, locale: l.code })\n }\n }\n return configs\n}\n","import type { FluentNuxtOptions, Strategy } from './types'\n\nexport interface ISRWarning {\n level: 'warn' | 'error'\n message: string\n}\n\n/**\n * Validate ISR configuration against locale detection settings.\n *\n * ISR caches responses by URL path. If locale detection relies on\n * non-path signals (cookies, headers), the cached response may serve\n * the wrong locale to subsequent visitors.\n */\nexport function validateISRConfig(\n isr: FluentNuxtOptions['isr'],\n strategy: Strategy,\n detectOrder: string[],\n): ISRWarning[] {\n const warnings: ISRWarning[] = []\n if (!isr?.enabled) return warnings\n\n const nonPathDetectors = detectOrder.filter(\n (d) => d === 'cookie' || d === 'header',\n )\n if (nonPathDetectors.length > 0) {\n warnings.push({\n level: 'warn',\n message:\n `[@fluenti/nuxt] ISR is enabled but detectOrder includes non-path ` +\n `detectors (${nonPathDetectors.join(', ')}). ISR caches by URL path, ` +\n `so cookie/header-based detection may serve the wrong locale from ` +\n `cache. Consider using detectOrder: ['path'] with ISR.`,\n })\n }\n\n if (strategy === 'no_prefix') {\n warnings.push({\n level: 'warn',\n message:\n `[@fluenti/nuxt] ISR is enabled with strategy: 'no_prefix'. All ` +\n `locales share the same URL path, so ISR will cache only one locale ` +\n `per URL. Use 'prefix' or 'prefix_except_default' strategy with ISR.`,\n })\n }\n\n return warnings\n}\n","import type { Nuxt } from '@nuxt/schema'\n\n/**\n * DevTools state exposed to the custom tab.\n * Serialized to JSON and sent to the DevTools panel.\n */\nexport interface DevToolsI18nState {\n currentLocale: string\n availableLocales: string[]\n defaultLocale: string\n strategy: string\n detectedBy: string\n messageCount: number\n loadedLocales: string[]\n missingKeys: string[]\n}\n\n/**\n * Register a Nuxt DevTools custom tab for Fluenti.\n *\n * Shows: current locale, available locales, detection chain result,\n * loaded message count, and missing translation keys.\n */\nexport function setupDevTools(nuxt: Nuxt, localeCodes: string[], defaultLocale: string, strategy: string): void {\n try {\n // Attempt to use @nuxt/devtools-kit if available\n // @ts-expect-error — devtools:customTabs hook is provided by @nuxt/devtools\n nuxt.hook('devtools:customTabs', (tabs: unknown[]) => {\n tabs.push({\n name: 'fluenti',\n title: 'Fluenti i18n',\n icon: 'i-carbon-translate',\n view: {\n type: 'client-component',\n componentName: 'FluentiDevToolsPanel',\n },\n })\n })\n } catch {\n // DevTools not available — silently skip\n }\n\n // Inject DevTools client component via virtual module\n // @ts-expect-error — nitro:config hook is provided by Nitro\n nuxt.hook('nitro:config', (nitroConfig: Record<string, unknown>) => {\n const publicConfig = nitroConfig['runtimeConfig'] as Record<string, unknown> | undefined\n if (publicConfig) {\n const pub = (publicConfig['public'] ?? (publicConfig['public'] = {})) as Record<string, unknown>\n const fluentiConfig = (pub['fluenti'] ?? {}) as Record<string, unknown>\n fluentiConfig['devtools'] = {\n enabled: true,\n locales: localeCodes,\n defaultLocale,\n strategy,\n }\n }\n })\n}\n\n/**\n * Client-side DevTools panel component source.\n *\n * This is injected as a virtual module and rendered inside the\n * Nuxt DevTools panel. It reads the Fluenti runtime state and\n * displays it in a simple, readable format.\n */\nexport const DEVTOOLS_PANEL_COMPONENT = `\n<template>\n <div style=\"padding: 16px; font-family: system-ui, sans-serif;\">\n <h2 style=\"margin: 0 0 16px; font-size: 18px;\">🌐 Fluenti i18n</h2>\n\n <div style=\"display: grid; grid-template-columns: 140px 1fr; gap: 8px 16px; font-size: 14px;\">\n <span style=\"color: #888;\">Current locale:</span>\n <strong>{{ state.currentLocale }}</strong>\n\n <span style=\"color: #888;\">Default locale:</span>\n <span>{{ state.defaultLocale }}</span>\n\n <span style=\"color: #888;\">Strategy:</span>\n <span>{{ state.strategy }}</span>\n\n <span style=\"color: #888;\">Available:</span>\n <span>{{ state.availableLocales.join(', ') }}</span>\n\n <span style=\"color: #888;\">Loaded:</span>\n <span>{{ state.loadedLocales.join(', ') || 'none' }}</span>\n\n <span style=\"color: #888;\">Messages:</span>\n <span>{{ state.messageCount }}</span>\n\n <span style=\"color: #888;\">Missing keys:</span>\n <span :style=\"{ color: state.missingKeys.length > 0 ? '#e53e3e' : '#38a169' }\">\n {{ state.missingKeys.length > 0 ? state.missingKeys.length + ' missing' : 'All translated ✓' }}\n </span>\n </div>\n\n <div v-if=\"state.missingKeys.length > 0\" style=\"margin-top: 16px;\">\n <h3 style=\"margin: 0 0 8px; font-size: 14px; color: #e53e3e;\">Missing translations:</h3>\n <ul style=\"margin: 0; padding: 0 0 0 20px; font-size: 13px; font-family: monospace;\">\n <li v-for=\"key in state.missingKeys\" :key=\"key\" style=\"margin: 2px 0;\">{{ key }}</li>\n </ul>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, onMounted } from 'vue'\n\nconst state = ref({\n currentLocale: '',\n defaultLocale: '',\n strategy: '',\n availableLocales: [],\n loadedLocales: [],\n messageCount: 0,\n missingKeys: [],\n})\n\nonMounted(() => {\n try {\n const nuxtApp = window.__NUXT_DEVTOOLS_VIEW__?.nuxtApp ?? useNuxtApp()\n const config = nuxtApp.$config?.public?.fluenti ?? {}\n const fluentiLocale = nuxtApp.$fluentiLocale ?? ref('')\n\n state.value = {\n currentLocale: fluentiLocale.value || config.defaultLocale || '',\n defaultLocale: config.defaultLocale || '',\n strategy: config.strategy || '',\n availableLocales: config.locales || [],\n loadedLocales: [],\n messageCount: 0,\n missingKeys: [],\n }\n } catch (e) {\n // DevTools context not available\n }\n})\n</script>\n`\n","import type { Plugin } from 'vite'\n\n/**\n * Vite plugin that transforms `definePageMeta({ i18n: ... })` into\n * the internal `i18nRoute` format used by the page extension system.\n *\n * This allows users to use native Nuxt `definePageMeta` with an `i18n` key\n * instead of the separate `defineI18nRoute()` macro.\n *\n * Supports:\n * - `definePageMeta({ i18n: { locales: ['en', 'ja'] } })`\n * - `definePageMeta({ i18n: false })`\n *\n * The transform also rewrites `defineI18nRoute(...)` to\n * `definePageMeta({ i18nRoute: ... })` for backwards compatibility.\n */\nexport function createPageMetaTransform(): Plugin {\n return {\n name: 'fluenti:page-meta-transform',\n enforce: 'pre',\n\n transform(code, id) {\n // Only transform Vue SFC script blocks and TS/JS files in pages/\n if (!id.includes('/pages/') && !id.includes('\\\\pages\\\\')) return null\n if (!code.includes('defineI18nRoute') && !code.includes('i18n')) return null\n\n let transformed = code\n\n // Transform: defineI18nRoute({ locales: [...] })\n // → definePageMeta({ i18nRoute: { locales: [...] } })\n // Transform: defineI18nRoute(false)\n // → definePageMeta({ i18nRoute: false })\n const defineI18nRouteRegex = /defineI18nRoute\\s*\\(([^)]{1,5000})\\)/g\n if (defineI18nRouteRegex.test(transformed)) {\n transformed = transformed.replace(\n /defineI18nRoute\\s*\\(([^)]{1,5000})\\)/g,\n (_match, arg: string) => `definePageMeta({ i18nRoute: ${arg.trim()} })`,\n )\n }\n\n // Support native: definePageMeta({ i18n: { locales: [...] } })\n // Rewrite `i18n:` key to `i18nRoute:` so page-extend can read it\n if (transformed.includes('definePageMeta') && transformed.includes('i18n:')) {\n // Simple regex for { i18n: ... } within definePageMeta\n // This handles the common case; complex nested objects may need\n // AST-based transformation in the future.\n // Length limit on [^}] prevents catastrophic backtracking (ReDoS)\n transformed = transformed.replace(\n /(definePageMeta\\s*\\(\\s*\\{[^}]{0,5000})\\bi18n\\s*:/g,\n '$1i18nRoute:',\n )\n }\n\n if (transformed === code) return null\n\n return {\n code: transformed,\n map: null,\n }\n },\n }\n}\n","import type { Strategy } from './types'\n\nexport interface SitemapUrl {\n loc: string\n alternatives?: Array<{ hreflang: string; href: string }>\n}\n\n/**\n * Generate multi-locale sitemap URLs from a list of base paths.\n *\n * For each base path, produces a URL entry with hreflang alternatives\n * pointing to every locale variant. Compatible with `@nuxtjs/sitemap`'s\n * `sources` hook format.\n */\nexport function generateSitemapUrls(\n paths: string[],\n locales: string[],\n defaultLocale: string,\n strategy: Strategy,\n baseUrl?: string,\n): SitemapUrl[] {\n const urls: SitemapUrl[] = []\n const base = baseUrl ?? ''\n\n for (const rawPath of paths) {\n const path = rawPath.startsWith('/') ? rawPath : `/${rawPath}`\n\n for (const locale of locales) {\n const localizedPath = buildLocalePath(path, locale, defaultLocale, strategy)\n\n const alternatives = locales.map((altLocale) => ({\n hreflang: altLocale,\n href: `${base}${buildLocalePath(path, altLocale, defaultLocale, strategy)}`,\n }))\n\n // Add x-default pointing to default locale\n alternatives.push({\n hreflang: 'x-default',\n href: `${base}${buildLocalePath(path, defaultLocale, defaultLocale, strategy)}`,\n })\n\n urls.push({\n loc: `${base}${localizedPath}`,\n alternatives,\n })\n }\n }\n\n return urls\n}\n\nfunction buildLocalePath(\n path: string,\n locale: string,\n defaultLocale: string,\n strategy: Strategy,\n): string {\n if (strategy === 'no_prefix') return path\n\n if (strategy === 'prefix_except_default' && locale === defaultLocale) {\n return path\n }\n\n const cleanPath = path === '/' ? '' : path\n return `/${locale}${cleanPath}`\n}\n\n/**\n * Hook handler for `@nuxtjs/sitemap`'s `sitemap:generate` hook.\n *\n * Transforms single-locale URLs into multi-locale entries with hreflang.\n * Register this in your nuxt.config.ts or let the module auto-register it.\n */\nexport function createSitemapHook(\n locales: string[],\n defaultLocale: string,\n strategy: Strategy,\n baseUrl?: string,\n) {\n return (urls: SitemapUrl[]) => {\n if (strategy === 'no_prefix') return urls\n\n const expanded: SitemapUrl[] = []\n\n for (const url of urls) {\n const loc = url.loc.replace(/^https?:\\/\\/[^/]+/, '')\n\n for (const locale of locales) {\n const localizedPath = buildLocalePath(loc, locale, defaultLocale, strategy)\n const alternatives = locales.map((altLocale) => ({\n hreflang: altLocale,\n href: `${baseUrl ?? ''}${buildLocalePath(loc, altLocale, defaultLocale, strategy)}`,\n }))\n alternatives.push({\n hreflang: 'x-default',\n href: `${baseUrl ?? ''}${buildLocalePath(loc, defaultLocale, defaultLocale, strategy)}`,\n })\n\n expanded.push({\n loc: `${baseUrl ?? ''}${localizedPath}`,\n alternatives,\n })\n }\n }\n\n return expanded\n }\n}\n","import { defineNuxtModule, addPlugin, addImports, addComponent, addRouteMiddleware, addServerHandler, createResolver } from '@nuxt/kit'\nimport { createRequire } from 'node:module'\nimport type { FluentNuxtOptions } from './types'\nimport { resolveLocaleProperties, resolveDomainConfigs } from './types'\nimport { resolveLocaleCodes } from '@fluenti/core/internal'\nimport type { FluentiBuildConfig } from '@fluenti/core/internal'\nimport fluentiVue from '@fluenti/vue/vite-plugin'\nimport { extendPages } from './runtime/page-extend'\nimport { validateISRConfig } from './isr-validation'\nimport { setupDevTools } from './devtools'\nimport { createPageMetaTransform } from './page-meta-transform'\n\nexport type { FluentNuxtOptions, Strategy, FluentNuxtRuntimeConfig, DetectBrowserLanguageOptions, LocaleDetectContext, LocaleDetectorFn, BuiltinDetector, ISROptions, LocaleObject, LocaleDefinition, DomainConfig, I18nRouteConfig, I18nError, I18nErrorCode, I18nErrorHandler, MessageFallbackHandler } from './types'\nexport { generateSitemapUrls, createSitemapHook } from './sitemap'\nexport type { SitemapUrl } from './sitemap'\nexport { resolveLocaleProperties, resolveDomainConfigs } from './types'\nexport { resolveLocaleCodes } from '@fluenti/core/internal'\nexport { localePath, extractLocaleFromPath, switchLocalePath } from './runtime/path-utils'\nexport { extendPages } from './runtime/page-extend'\nexport type { PageRoute, RouteNameTemplate, ExtendPagesOptions } from './runtime/page-extend'\nexport { buildLocaleHead } from './runtime/locale-head'\nexport type { LocaleHeadMeta, LocaleHeadOptions } from './runtime/locale-head'\nexport { useLocalePath, useSwitchLocalePath, useLocaleRoute, useLocaleHead } from './runtime/standalone-composables'\nexport { defineI18nRoute } from './runtime/define-i18n-route'\n\nexport const MODULE_NAME = '@fluenti/nuxt'\nexport const CONFIG_KEY = 'fluenti'\n\n// Module-level require that works in both CJS and ESM after bundling.\n// See packages/core/src/config-loader.ts for explanation of the pattern.\nconst _require = createRequire(\n typeof __filename !== 'undefined' ? __filename : import.meta.url,\n)\n\n/**\n * Resolve the FluentiBuildConfig from the module options.\n */\nfunction resolveFluentiBuildConfig(configOption: string | FluentiBuildConfig | undefined, rootDir: string): FluentiBuildConfig {\n\n if (typeof configOption === 'object') {\n const { DEFAULT_FLUENTI_CONFIG } = _require('@fluenti/core/config') as {\n DEFAULT_FLUENTI_CONFIG: FluentiBuildConfig\n }\n return { ...DEFAULT_FLUENTI_CONFIG, ...configOption }\n }\n\n const { loadConfigSync } = _require('@fluenti/core/config') as {\n loadConfigSync: (configPath?: string, cwd?: string) => FluentiBuildConfig\n }\n return loadConfigSync(\n typeof configOption === 'string' ? configOption : undefined,\n rootDir,\n )\n}\n\nexport default defineNuxtModule<FluentNuxtOptions>({\n meta: {\n name: MODULE_NAME,\n configKey: CONFIG_KEY,\n compatibility: { nuxt: '>=3.0.0' },\n },\n defaults: {\n strategy: 'prefix_except_default',\n },\n setup(options, nuxt) {\n const { resolve } = createResolver(import.meta.url)\n\n // --- Resolve FluentiBuildConfig from options.config, then overlay module-level options ---\n const rootDir = nuxt.options.rootDir ?? process.cwd()\n const fluentiConfig = resolveFluentiBuildConfig(options.config, rootDir)\n\n // Module-level options (e.g. nuxt.config.ts `fluenti.locales`) override the\n // resolved fluenti.config.ts values — this ensures Nuxt-specific config takes\n // precedence even when config file loading fails (e.g. CJS/jiti issues).\n if (options.locales) fluentiConfig.locales = options.locales\n if (options.defaultLocale) fluentiConfig.defaultLocale = options.defaultLocale\n if (options.sourceLocale) fluentiConfig.sourceLocale = options.sourceLocale\n if (options.catalogDir) fluentiConfig.catalogDir = options.catalogDir\n\n // --- Resolve locale codes and metadata ---\n const localeCodes = resolveLocaleCodes(fluentiConfig.locales)\n const localeProperties = resolveLocaleProperties(fluentiConfig.locales)\n const defaultLocale = fluentiConfig.defaultLocale ?? fluentiConfig.sourceLocale\n const domainConfigs = options.strategy === 'domains'\n ? resolveDomainConfigs(fluentiConfig.locales, options.domains)\n : undefined\n\n // --- Inject runtime config ---\n const detectOrder = options.detectOrder ?? (\n options.strategy === 'domains'\n ? ['domain', 'cookie', 'header']\n : ['path', 'cookie', 'header']\n )\n nuxt.options.runtimeConfig.public['fluenti'] = {\n locales: localeCodes,\n defaultLocale,\n strategy: options.strategy ?? 'prefix_except_default',\n detectBrowserLanguage: options.detectBrowserLanguage,\n detectOrder,\n queryParamKey: options.queryParamKey ?? 'locale',\n injectGlobalProperties: options.injectGlobalProperties !== false,\n ...(domainConfigs ? { domains: domainConfigs } : {}),\n localeProperties,\n }\n\n // --- Auto-register @fluenti/vue vite plugin (includes v-t transform + scope transform) ---\n if (options.autoVitePlugin !== false) {\n nuxt.options.vite = nuxt.options.vite || {}\n nuxt.options.vite.plugins = nuxt.options.vite.plugins || []\n ;(nuxt.options.vite.plugins as unknown[]).push(\n ...fluentiVue({ config: fluentiConfig }),\n )\n }\n\n // --- Register definePageMeta({ i18n }) transform ---\n nuxt.options.vite = nuxt.options.vite || {}\n nuxt.options.vite.plugins = nuxt.options.vite.plugins || []\n ;(nuxt.options.vite.plugins as unknown[]).push(createPageMetaTransform())\n\n // --- Register runtime plugin ---\n addPlugin({\n src: resolve('./runtime/plugin'),\n mode: 'all',\n })\n\n // --- Extend routes with locale prefixes ---\n const strategy = options.strategy ?? 'prefix_except_default'\n if (strategy !== 'no_prefix' && strategy !== 'domains' && options.extendRoutes !== false) {\n nuxt.hook('pages:extend', (pages) => {\n extendPages(pages, {\n locales: localeCodes,\n defaultLocale,\n strategy,\n ...(options.routeNameTemplate ? { routeNameTemplate: options.routeNameTemplate } : {}),\n ...(options.routeOverrides ? { routeOverrides: options.routeOverrides } : {}),\n ...(options.routeMode ? { routeMode: options.routeMode } : {}),\n })\n })\n }\n\n // --- Register locale redirect middleware ---\n if (strategy === 'prefix') {\n addRouteMiddleware({\n name: 'fluenti-locale-redirect',\n path: resolve('./runtime/middleware/locale-redirect'),\n global: options.globalMiddleware !== false,\n })\n }\n\n // --- Auto-import composables ---\n if (options.autoImports !== false) {\n addImports([\n { name: 'useLocalePath', from: resolve('./runtime/composables') },\n { name: 'useSwitchLocalePath', from: resolve('./runtime/composables') },\n { name: 'useLocaleRoute', from: resolve('./runtime/composables') },\n { name: 'useLocaleHead', from: resolve('./runtime/composables') },\n { name: 'useI18nScoped', from: resolve('./runtime/composables') },\n { name: 'useI18n', from: '@fluenti/vue' },\n { name: 'defineI18nRoute', from: resolve('./runtime/define-i18n-route') },\n ])\n }\n\n // --- Register components (including DateTime + NumberFormat) ---\n const prefix = options.componentPrefix ?? ''\n if (options.registerNuxtLinkLocale !== false) {\n addComponent({\n name: `${prefix}NuxtLinkLocale`,\n filePath: resolve('./runtime/components/NuxtLinkLocale'),\n })\n }\n\n // Auto-import DateTime and NumberFormat from @fluenti/vue\n addComponent({ name: `${prefix}Trans`, filePath: '@fluenti/vue/components', export: 'Trans' })\n addComponent({ name: `${prefix}Plural`, filePath: '@fluenti/vue/components', export: 'Plural' })\n addComponent({ name: `${prefix}Select`, filePath: '@fluenti/vue/components', export: 'Select' })\n addComponent({ name: `${prefix}DateTime`, filePath: '@fluenti/vue/components', export: 'DateTime' })\n addComponent({ name: `${prefix}NumberFormat`, filePath: '@fluenti/vue/components', export: 'NumberFormat' })\n\n // --- SSG / ISR: configure nitro prerender and route rules ---\n if (strategy !== 'no_prefix' && strategy !== 'domains') {\n const nuxtOpts = nuxt.options as unknown as Record<string, unknown>\n\n // Enable link crawling so locale-prefixed routes are discovered during prerender\n const nitroOpts = (nuxtOpts['nitro'] ?? (nuxtOpts['nitro'] = {})) as Record<string, unknown>\n const prerender = (nitroOpts['prerender'] ?? (nitroOpts['prerender'] = {})) as Record<string, unknown>\n prerender['crawlLinks'] = prerender['crawlLinks'] ?? true\n\n // For 'prefix' strategy, / has no matching route (all routes are\n // locale-prefixed). Replace the default / initial route with\n // /<defaultLocale> so the prerenderer starts from a valid route.\n if (strategy === 'prefix') {\n const routes = (prerender['routes'] ?? ['/']) as string[]\n prerender['routes'] = routes.map((r) =>\n r === '/' ? `/${defaultLocale}` : r,\n )\n }\n\n // ISR: validate configuration and generate routeRules\n for (const w of validateISRConfig(options.isr, strategy, detectOrder)) {\n console.warn(w.message)\n }\n if (options.isr?.enabled) {\n const routeRules = (nuxtOpts['routeRules'] ?? (nuxtOpts['routeRules'] = {})) as Record<string, Record<string, unknown>>\n const ttl = options.isr.ttl ?? 3600\n for (const locale of localeCodes) {\n if (locale === defaultLocale && strategy === 'prefix_except_default') {\n routeRules['/**'] = { ...routeRules['/**'], isr: ttl }\n } else {\n routeRules[`/${locale}/**`] = { ...routeRules[`/${locale}/**`], isr: ttl }\n }\n }\n }\n }\n\n // --- Nuxt DevTools integration ---\n if (nuxt.options.dev) {\n setupDevTools(nuxt as any, localeCodes, defaultLocale, strategy)\n }\n\n // --- Nitro server handler for locale redirect (T2-10) ---\n if (strategy === 'prefix' || strategy === 'prefix_and_default') {\n addServerHandler({\n handler: resolve('./runtime/server/locale-redirect'),\n middleware: true,\n })\n }\n },\n})\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-meta-transform.d.ts","sourceRoot":"","sources":["../src/page-meta-transform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"page-meta-transform.d.ts","sourceRoot":"","sources":["../src/page-meta-transform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CA6ChD"}
|
package/dist/runtime/client.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../page-extend-tRXsujtK.cjs`),t=require(`../path-utils-BQIsp_or.cjs`),n=require(`../locale-head-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../page-extend-tRXsujtK.cjs`),t=require(`../path-utils-BQIsp_or.cjs`),n=require(`../locale-head-CwFSeJqY.cjs`);require(`../module.cjs`);let r=require(`vue`);function i(e,n){return(r,i)=>t.n(r,i??e.value,n.defaultLocale,n.strategy)}function a(e,n){return r=>t.r(e.value,r,n.locales,n.defaultLocale,n.strategy)}function o(e,t,i,a){return(0,r.computed)(()=>n.t(e.value,t.value,i,a))}exports.buildLocaleHead=n.t,exports.extendPages=e.t,exports.extractLocaleFromPath=t.t,exports.localePath=t.n,exports.switchLocalePath=t.r,exports.useLocaleHead=o,exports.useLocalePath=i,exports.useSwitchLocalePath=a;
|
|
2
2
|
//# sourceMappingURL=client.cjs.map
|
package/dist/runtime/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as e } from "../page-extend-BrPO2RhM.js";
|
|
2
2
|
import { n as t, r as n, t as r } from "../path-utils-BcvXLCGi.js";
|
|
3
|
-
import { t as i } from "../locale-head-
|
|
3
|
+
import { t as i } from "../locale-head-CV660rxz.js";
|
|
4
4
|
import { computed as a } from "vue";
|
|
5
5
|
//#region src/runtime/client.ts
|
|
6
6
|
function o(e, n) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../path-utils-BQIsp_or.cjs`),t=require(`../locale-head-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../path-utils-BQIsp_or.cjs`),t=require(`../locale-head-CwFSeJqY.cjs`);require(`../module.cjs`);let n=require(`vue`),r=require(`#imports`),i=require(`@fluenti/vue`);function a(){return(0,r.useRuntimeConfig)().public.fluenti}function o(){let{locale:t}=(0,i.useI18n)(),n=a();return(r,i)=>e.n(r,i??t.value,n.defaultLocale,n.strategy)}function s(){let t=(0,r.useRoute)(),n=a();return r=>e.r(t.path,r,n.locales,n.defaultLocale,n.strategy)}function c(){let{locale:t}=(0,i.useI18n)(),n=(0,r.useRouter)(),o=a();return(r,i)=>{let a=i??t.value;if(typeof r==`string`){let t=e.n(r,a,o.defaultLocale,o.strategy);return n.resolve(t)}if(`path`in r&&r.path){let t=e.n(r.path,a,o.defaultLocale,o.strategy);return n.resolve({...r,path:t})}return n.resolve(r)}}function l(e){let t=(0,i.useI18n)();return{...t,t(n,r){if(typeof n==`string`)return t.t(`${e}.${n}`,r);if(n&&typeof n==`object`&&`id`in n){let i=n;return t.t({...i,id:`${e}.${i.id}`},r)}return t.t(n,r)},te(n,r){return t.te(`${e}.${n}`,r)},tm(n,r){return t.tm(`${e}.${n}`,r)},namespace:e}}function u(e){let{locale:o}=(0,i.useI18n)(),s=(0,r.useRoute)(),c=a();return(0,n.computed)(()=>t.t(o.value,s.path,c,e))}exports.useI18nScoped=l,exports.useLocaleHead=u,exports.useLocalePath=o,exports.useLocaleRoute=c,exports.useSwitchLocalePath=s;
|
|
2
2
|
//# sourceMappingURL=composables.cjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e, r as t } from "../path-utils-BcvXLCGi.js";
|
|
2
|
-
import { t as n } from "../locale-head-
|
|
2
|
+
import { t as n } from "../locale-head-CV660rxz.js";
|
|
3
3
|
import { computed as r } from "vue";
|
|
4
4
|
import { useRoute as i, useRouter as a, useRuntimeConfig as o } from "#imports";
|
|
5
5
|
import { useI18n as s } from "@fluenti/vue";
|
package/dist/runtime/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../page-extend-tRXsujtK.cjs`),t=require(`../path-utils-BQIsp_or.cjs`),n=require(`../locale-head-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../page-extend-tRXsujtK.cjs`),t=require(`../path-utils-BQIsp_or.cjs`),n=require(`../locale-head-CwFSeJqY.cjs`),r=require(`./composables.cjs`),i=require(`./components/NuxtLinkLocale.cjs`);exports.NuxtLinkLocale=i.NuxtLinkLocale,exports.buildLocaleHead=n.t,exports.extendPages=e.t,exports.extractLocaleFromPath=t.t,exports.localePath=t.n,exports.switchLocalePath=t.r,exports.useI18nScoped=r.useI18nScoped,exports.useLocaleHead=r.useLocaleHead,exports.useLocalePath=r.useLocalePath,exports.useLocaleRoute=r.useLocaleRoute,exports.useSwitchLocalePath=r.useSwitchLocalePath;
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as e } from "../page-extend-BrPO2RhM.js";
|
|
2
2
|
import { n as t, r as n, t as r } from "../path-utils-BcvXLCGi.js";
|
|
3
|
-
import { t as i } from "../locale-head-
|
|
3
|
+
import { t as i } from "../locale-head-CV660rxz.js";
|
|
4
4
|
import { useI18nScoped as a, useLocaleHead as o, useLocalePath as s, useLocaleRoute as c, useSwitchLocalePath as l } from "./composables.js";
|
|
5
5
|
import { NuxtLinkLocale as u } from "./components/NuxtLinkLocale.js";
|
|
6
6
|
export { u as NuxtLinkLocale, i as buildLocaleHead, e as extendPages, r as extractLocaleFromPath, t as localePath, n as switchLocalePath, a as useI18nScoped, o as useLocaleHead, s as useLocalePath, c as useLocaleRoute, l as useSwitchLocalePath };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-head.d.ts","sourceRoot":"","sources":["../../src/runtime/locale-head.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"locale-head.d.ts","sourceRoot":"","sources":["../../src/runtime/locale-head.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAmBvD,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzC,IAAI,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5D,IAAI,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kGAAkG;IAClG,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,uBAAuB,EAC/B,OAAO,CAAC,EAAE,iBAAiB,GAC1B,cAAc,CAsHhB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../path-utils-BQIsp_or.cjs`);require(`../../module.cjs`);const t=require(`../../detectors-
|
|
1
|
+
const e=require(`../../path-utils-BQIsp_or.cjs`);require(`../../module.cjs`);const t=require(`../../detectors-CxhqsYjl.cjs`);let n=require(`#imports`);var r=(0,n.defineNuxtRouteMiddleware)(async r=>{let i=(0,n.useRuntimeConfig)().public.fluenti;if(i.strategy===`no_prefix`)return;let{locale:a}=e.t(r.path,i.locales);if(a||i.strategy===`prefix_except_default`)return;let o=(0,n.useNuxtApp)(),s={...i,detectOrder:i.detectOrder.filter(e=>e!==`path`)},c=await t.t(r.path,s),l=e.n(r.path,c,i.defaultLocale,i.strategy);if(l!==r.path)return o.runWithContext(()=>(0,n.navigateTo)(l,{redirectCode:302}))});module.exports=r;
|
|
2
2
|
//# sourceMappingURL=locale-redirect.cjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e, t } from "../../path-utils-BcvXLCGi.js";
|
|
2
|
-
import { t as n } from "../../detectors-
|
|
2
|
+
import { t as n } from "../../detectors-CBe19LCy.js";
|
|
3
3
|
import { defineNuxtRouteMiddleware as r, navigateTo as i, useNuxtApp as a, useRuntimeConfig as o } from "#imports";
|
|
4
4
|
//#region src/runtime/middleware/locale-redirect.ts
|
|
5
5
|
var s = r(async (r) => {
|
package/dist/runtime/plugin.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../path-utils-BQIsp_or.cjs`);require(`../module.cjs`);const t=require(`../detectors-
|
|
1
|
+
const e=require(`../path-utils-BQIsp_or.cjs`);require(`../module.cjs`);const t=require(`../detectors-CxhqsYjl.cjs`);let n=require(`vue`),r=require(`#imports`);var i=(0,r.defineNuxtPlugin)(async i=>{let a=(0,r.useRuntimeConfig)().public.fluenti,o=(0,r.useRoute)(),s=a.detectBrowserLanguage?.useCookie?a.detectBrowserLanguage:null,c=s?.cookieKey??`fluenti_locale`,l=s?(0,r.useCookie)(c):null,u,d;if({}.server)try{let e=(0,r.useRequestHeaders)([`host`,`accept-language`]);d=e[`accept-language`],a.strategy===`domains`&&(u=e.host)}catch(e){({}).dev&&console.debug(`[fluenti] Header read failed:`,e)}else if(a.strategy===`domains`)try{u=window.location.host}catch(e){({}).dev&&console.debug(`[fluenti] Domain detection failed:`,e)}let f;if({}.server){f=await t.t(o.path,a,void 0,async e=>{await i.callHook(`fluenti:detect-locale`,e)},u,l?.value??void 0,d),i.payload.fluentiLocale=f;try{let e=i.ssrContext?.event;e&&(e.context.locale=f)}catch(e){({}).dev&&console.debug(`[fluenti] Event context not available:`,e)}}else if(i.payload.fluentiLocale)f=i.payload.fluentiLocale;else if(a.strategy===`domains`&&u&&a.domains?.length){let e=u.toLowerCase().replace(/:\d+$/,``),t=a.domains.find(t=>t.domain.toLowerCase()===e);f=t?t.locale:a.defaultLocale}else{let{locale:t}=e.t(o.path,a.locales);f=t||(l&&l.value&&a.locales.includes(l.value)?l.value:a.defaultLocale)}let p=(0,n.ref)(f);if(a.strategy!==`no_prefix`&&a.strategy!==`domains`&&(0,n.watch)(()=>o.path,t=>{let{locale:n}=e.t(t,a.locales);n?p.value=n:a.strategy===`prefix_except_default`&&(p.value=a.defaultLocale)}),l&&(0,n.watch)(p,e=>{l.value=e}),a.injectGlobalProperties){let t=i.vueApp.config.globalProperties;t.$localePath=(t,n)=>e.n(t,n??p.value,a.defaultLocale,a.strategy),t.$switchLocalePath=t=>e.r(o.path,t,a.locales,a.defaultLocale,a.strategy)}return{provide:{fluentiLocale:p,fluentiConfig:a}}});module.exports=i;
|
|
2
2
|
//# sourceMappingURL=plugin.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs","names":[],"sources":["../../src/runtime/plugin.ts"],"sourcesContent":["import { defineNuxtPlugin, useRuntimeConfig, useRoute, useCookie, useRequestHeaders } from '#imports'\nimport { ref, watch } from 'vue'\nimport { localePath, extractLocaleFromPath, switchLocalePath } from './path-utils'\nimport { runDetectors } from './detectors'\nimport type { FluentNuxtRuntimeConfig, LocaleDetectContext } from '../types'\n\n/**\n * Nuxt runtime plugin that:\n * 1. Server: runs the locale detection chain, stores locale in payload for hydration\n * 2. Client: reads locale from payload to avoid hydration mismatch\n * 3. Provides reactive locale state and global helpers\n */\nexport default defineNuxtPlugin(async (nuxtApp) => {\n const config = useRuntimeConfig().public['fluenti'] as FluentNuxtRuntimeConfig\n const route = useRoute()\n\n // Hoist useCookie calls BEFORE any await to avoid losing the Nuxt\n // composable context (async local storage is dropped after await).\n const cookieCfg = config.detectBrowserLanguage?.useCookie\n ? config.detectBrowserLanguage\n : null\n const cookieKey = cookieCfg?.cookieKey ?? 'fluenti_locale'\n const localeCookie = cookieCfg ? useCookie(cookieKey) : null\n\n // Hoist all server-side header/cookie reads BEFORE any await.\n // Nuxt composables rely on async local storage that is dropped after await.\n let host: string | undefined\n let acceptLanguage: string | undefined\n if (import.meta.server) {\n try {\n const reqHeaders = useRequestHeaders(['host', 'accept-language'])\n acceptLanguage = reqHeaders['accept-language']\n if (config.strategy === 'domains') {\n host = reqHeaders['host']\n }\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Header read failed:', err)\n }\n } else if (config.strategy === 'domains') {\n try {\n host = window.location.host\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Domain detection failed:', err)\n }\n }\n\n let detectedLocale: string\n\n if (import.meta.server) {\n // --- Server (SSR / SSG / ISR): run full detection chain ---\n detectedLocale = await runDetectors(\n route.path,\n config,\n undefined,\n async (ctx: LocaleDetectContext) => {\n await (nuxtApp.callHook as Function)('fluenti:detect-locale', ctx)\n },\n host,\n localeCookie?.value ?? undefined,\n acceptLanguage,\n )\n // Store in payload — Nuxt serializes this to HTML automatically.\n // The client reads it back to ensure hydration uses the same locale.\n nuxtApp.payload['fluentiLocale'] = detectedLocale\n // Also set on event context so other plugins (e.g. i18n.ts) can read it\n try {\n const event = (nuxtApp as unknown as { ssrContext?: { event?: { context: Record<string, unknown> } } }).ssrContext?.event\n if (event) event.context['locale'] = detectedLocale\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Event context not available:', err)\n }\n } else if (nuxtApp.payload['fluentiLocale']) {\n // --- Client (SSR hydration): read from payload to avoid mismatch ---\n detectedLocale = nuxtApp.payload['fluentiLocale'] as string\n } else {\n // --- Client (SPA mode / no payload): detect from path and cookie ---\n if (config.strategy === 'domains' && host && config.domains?.length) {\n const cleanHost = host.toLowerCase().replace(/:\\d+$/, '')\n const domainMatch = config.domains.find((d) => d.domain.toLowerCase() === cleanHost)\n if (domainMatch) {\n detectedLocale = domainMatch.locale\n } else {\n detectedLocale = config.defaultLocale\n }\n } else {\n const { locale: pathLocale } = extractLocaleFromPath(route.path, config.locales)\n if (pathLocale) {\n detectedLocale = pathLocale\n } else if (localeCookie) {\n detectedLocale = (localeCookie.value && config.locales.includes(localeCookie.value))\n ? localeCookie.value\n : config.defaultLocale\n } else {\n detectedLocale = config.defaultLocale\n }\n }\n }\n\n const currentLocale = ref(detectedLocale)\n\n // Sync locale when route changes (path-based detection)\n if (config.strategy !== 'no_prefix' && config.strategy !== 'domains') {\n watch(() => route.path, (newPath) => {\n const { locale } = extractLocaleFromPath(newPath, config.locales)\n if (locale) {\n currentLocale.value = locale\n } else if (config.strategy === 'prefix_except_default') {\n // No locale prefix found — this means we're on a default locale route\n currentLocale.value = config.defaultLocale\n }\n })\n }\n\n // Persist locale in cookie if detectBrowserLanguage is configured\n if (localeCookie) {\n watch(currentLocale, (newLocale) => {\n localeCookie.value = newLocale\n })\n }\n\n // --- Inject global helpers ---\n if (config.injectGlobalProperties) {\n const gp = nuxtApp.vueApp.config.globalProperties\n gp.$localePath = (path: string, locale?: string) => {\n return localePath(\n path,\n locale ?? currentLocale.value,\n config.defaultLocale,\n config.strategy,\n )\n }\n gp.$switchLocalePath = (newLocale: string) => {\n return switchLocalePath(\n route.path,\n newLocale,\n config.locales,\n config.defaultLocale,\n config.strategy,\n )\n }\n\n //
|
|
1
|
+
{"version":3,"file":"plugin.cjs","names":[],"sources":["../../src/runtime/plugin.ts"],"sourcesContent":["import { defineNuxtPlugin, useRuntimeConfig, useRoute, useCookie, useRequestHeaders } from '#imports'\nimport { ref, watch } from 'vue'\nimport { localePath, extractLocaleFromPath, switchLocalePath } from './path-utils'\nimport { runDetectors } from './detectors'\nimport type { FluentNuxtRuntimeConfig, LocaleDetectContext } from '../types'\n\n/**\n * Nuxt runtime plugin that:\n * 1. Server: runs the locale detection chain, stores locale in payload for hydration\n * 2. Client: reads locale from payload to avoid hydration mismatch\n * 3. Provides reactive locale state and global helpers\n */\nexport default defineNuxtPlugin(async (nuxtApp) => {\n const config = useRuntimeConfig().public['fluenti'] as FluentNuxtRuntimeConfig\n const route = useRoute()\n\n // Hoist useCookie calls BEFORE any await to avoid losing the Nuxt\n // composable context (async local storage is dropped after await).\n const cookieCfg = config.detectBrowserLanguage?.useCookie\n ? config.detectBrowserLanguage\n : null\n const cookieKey = cookieCfg?.cookieKey ?? 'fluenti_locale'\n const localeCookie = cookieCfg ? useCookie(cookieKey) : null\n\n // Hoist all server-side header/cookie reads BEFORE any await.\n // Nuxt composables rely on async local storage that is dropped after await.\n let host: string | undefined\n let acceptLanguage: string | undefined\n if (import.meta.server) {\n try {\n const reqHeaders = useRequestHeaders(['host', 'accept-language'])\n acceptLanguage = reqHeaders['accept-language']\n if (config.strategy === 'domains') {\n host = reqHeaders['host']\n }\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Header read failed:', err)\n }\n } else if (config.strategy === 'domains') {\n try {\n host = window.location.host\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Domain detection failed:', err)\n }\n }\n\n let detectedLocale: string\n\n if (import.meta.server) {\n // --- Server (SSR / SSG / ISR): run full detection chain ---\n detectedLocale = await runDetectors(\n route.path,\n config,\n undefined,\n async (ctx: LocaleDetectContext) => {\n await (nuxtApp.callHook as Function)('fluenti:detect-locale', ctx)\n },\n host,\n localeCookie?.value ?? undefined,\n acceptLanguage,\n )\n // Store in payload — Nuxt serializes this to HTML automatically.\n // The client reads it back to ensure hydration uses the same locale.\n nuxtApp.payload['fluentiLocale'] = detectedLocale\n // Also set on event context so other plugins (e.g. i18n.ts) can read it\n try {\n const event = (nuxtApp as unknown as { ssrContext?: { event?: { context: Record<string, unknown> } } }).ssrContext?.event\n if (event) event.context['locale'] = detectedLocale\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Event context not available:', err)\n }\n } else if (nuxtApp.payload['fluentiLocale']) {\n // --- Client (SSR hydration): read from payload to avoid mismatch ---\n detectedLocale = nuxtApp.payload['fluentiLocale'] as string\n } else {\n // --- Client (SPA mode / no payload): detect from path and cookie ---\n if (config.strategy === 'domains' && host && config.domains?.length) {\n const cleanHost = host.toLowerCase().replace(/:\\d+$/, '')\n const domainMatch = config.domains.find((d) => d.domain.toLowerCase() === cleanHost)\n if (domainMatch) {\n detectedLocale = domainMatch.locale\n } else {\n detectedLocale = config.defaultLocale\n }\n } else {\n const { locale: pathLocale } = extractLocaleFromPath(route.path, config.locales)\n if (pathLocale) {\n detectedLocale = pathLocale\n } else if (localeCookie) {\n detectedLocale = (localeCookie.value && config.locales.includes(localeCookie.value))\n ? localeCookie.value\n : config.defaultLocale\n } else {\n detectedLocale = config.defaultLocale\n }\n }\n }\n\n const currentLocale = ref(detectedLocale)\n\n // Sync locale when route changes (path-based detection)\n if (config.strategy !== 'no_prefix' && config.strategy !== 'domains') {\n watch(() => route.path, (newPath) => {\n const { locale } = extractLocaleFromPath(newPath, config.locales)\n if (locale) {\n currentLocale.value = locale\n } else if (config.strategy === 'prefix_except_default') {\n // No locale prefix found — this means we're on a default locale route\n currentLocale.value = config.defaultLocale\n }\n })\n }\n\n // Persist locale in cookie if detectBrowserLanguage is configured\n if (localeCookie) {\n watch(currentLocale, (newLocale) => {\n localeCookie.value = newLocale\n })\n }\n\n // --- Inject global helpers ---\n if (config.injectGlobalProperties) {\n const gp = nuxtApp.vueApp.config.globalProperties\n gp.$localePath = (path: string, locale?: string) => {\n return localePath(\n path,\n locale ?? currentLocale.value,\n config.defaultLocale,\n config.strategy,\n )\n }\n gp.$switchLocalePath = (newLocale: string) => {\n return switchLocalePath(\n route.path,\n newLocale,\n config.locales,\n config.defaultLocale,\n config.strategy,\n )\n }\n\n // $t/$d/$n are injected by the @fluenti/vue plugin via globalProperties.\n // No additional injection needed here — useI18n() cannot be called outside\n // a component setup() context.\n }\n\n return {\n provide: {\n fluentiLocale: currentLocale,\n fluentiConfig: config,\n },\n }\n})\n"],"mappings":"+JAYA,IAAA,GAAA,EAAA,EAAA,kBAAgC,KAAO,IAAY,CACjD,IAAM,GAAA,EAAA,EAAA,mBAA2B,CAAC,OAAO,QACnC,GAAA,EAAA,EAAA,WAAkB,CAIlB,EAAY,EAAO,uBAAuB,UAC5C,EAAO,sBACP,KACE,EAAY,GAAW,WAAa,iBACpC,EAAe,GAAA,EAAA,EAAA,WAAsB,EAAU,CAAG,KAIpD,EACA,EACJ,GAAA,EAAA,CAAgB,OACd,GAAI,CACF,IAAM,GAAA,EAAA,EAAA,mBAA+B,CAAC,OAAQ,kBAAkB,CAAC,CACjE,EAAiB,EAAW,mBACxB,EAAO,WAAa,YACtB,EAAO,EAAW,YAEb,EAAK,EACZ,EAAA,EAAgB,KAAK,QAAQ,MAAM,gCAAiC,EAAI,SAEjE,EAAO,WAAa,UAC7B,GAAI,CACF,EAAO,OAAO,SAAS,WAChB,EAAK,EACZ,EAAA,EAAgB,KAAK,QAAQ,MAAM,qCAAsC,EAAI,CAIjF,IAAI,EAEJ,GAAA,EAAA,CAAgB,OAAQ,CAEtB,EAAiB,MAAM,EAAA,EACrB,EAAM,KACN,EACA,IAAA,GACA,KAAO,IAA6B,CAClC,MAAO,EAAQ,SAAsB,wBAAyB,EAAI,EAEpE,EACA,GAAc,OAAS,IAAA,GACvB,EACD,CAGD,EAAQ,QAAQ,cAAmB,EAEnC,GAAI,CACF,IAAM,EAAS,EAAyF,YAAY,MAChH,IAAO,EAAM,QAAQ,OAAY,SAC9B,EAAK,EACZ,EAAA,EAAgB,KAAK,QAAQ,MAAM,yCAA0C,EAAI,UAE1E,EAAQ,QAAQ,cAEzB,EAAiB,EAAQ,QAAQ,sBAG7B,EAAO,WAAa,WAAa,GAAQ,EAAO,SAAS,OAAQ,CACnE,IAAM,EAAY,EAAK,aAAa,CAAC,QAAQ,QAAS,GAAG,CACnD,EAAc,EAAO,QAAQ,KAAM,GAAM,EAAE,OAAO,aAAa,GAAK,EAAU,CACpF,AAGE,EAHE,EACe,EAAY,OAEZ,EAAO,kBAErB,CACL,GAAM,CAAE,OAAQ,GAAe,EAAA,EAAsB,EAAM,KAAM,EAAO,QAAQ,CAChF,AAOE,EAPE,IAEO,GACS,EAAa,OAAS,EAAO,QAAQ,SAAS,EAAa,MAAM,CAC/E,EAAa,MACb,EAAO,eAOjB,IAAM,GAAA,EAAA,EAAA,KAAoB,EAAe,CAuBzC,GApBI,EAAO,WAAa,aAAe,EAAO,WAAa,YACzD,EAAA,EAAA,WAAY,EAAM,KAAO,GAAY,CACnC,GAAM,CAAE,UAAW,EAAA,EAAsB,EAAS,EAAO,QAAQ,CAC7D,EACF,EAAc,MAAQ,EACb,EAAO,WAAa,0BAE7B,EAAc,MAAQ,EAAO,gBAE/B,CAIA,IACF,EAAA,EAAA,OAAM,EAAgB,GAAc,CAClC,EAAa,MAAQ,GACrB,CAIA,EAAO,uBAAwB,CACjC,IAAM,EAAK,EAAQ,OAAO,OAAO,iBACjC,EAAG,aAAe,EAAc,IACvB,EAAA,EACL,EACA,GAAU,EAAc,MACxB,EAAO,cACP,EAAO,SACR,CAEH,EAAG,kBAAqB,GACf,EAAA,EACL,EAAM,KACN,EACA,EAAO,QACP,EAAO,cACP,EAAO,SACR,CAQL,MAAO,CACL,QAAS,CACP,cAAe,EACf,cAAe,EAChB,CACF,EACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/runtime/plugin.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;;AACH,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/runtime/plugin.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;;AACH,wBA4IE"}
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e, r as t, t as n } from "../path-utils-BcvXLCGi.js";
|
|
2
|
-
import { t as r } from "../detectors-
|
|
2
|
+
import { t as r } from "../detectors-CBe19LCy.js";
|
|
3
3
|
import { ref as i, watch as a } from "vue";
|
|
4
4
|
import { defineNuxtPlugin as o, useCookie as s, useRequestHeaders as c, useRoute as l, useRuntimeConfig as u } from "#imports";
|
|
5
5
|
//#region src/runtime/plugin.ts
|
|
@@ -44,12 +44,6 @@ var d = o(async (o) => {
|
|
|
44
44
|
}), d.injectGlobalProperties) {
|
|
45
45
|
let n = o.vueApp.config.globalProperties;
|
|
46
46
|
n.$localePath = (t, n) => e(t, n ?? y.value, d.defaultLocale, d.strategy), n.$switchLocalePath = (e) => t(f.path, e, d.locales, d.defaultLocale, d.strategy);
|
|
47
|
-
try {
|
|
48
|
-
let { useI18n: e } = await import("@fluenti/vue"), t = e();
|
|
49
|
-
n.$t ||= t.t, n.$d ||= t.d, n.$n ||= t.n;
|
|
50
|
-
} catch (e) {
|
|
51
|
-
import.meta.dev && console.debug("[fluenti] Vue plugin not yet installed, skipping $t/$d/$n injection:", e);
|
|
52
|
-
}
|
|
53
47
|
}
|
|
54
48
|
return { provide: {
|
|
55
49
|
fluentiLocale: y,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","names":[],"sources":["../../src/runtime/plugin.ts"],"sourcesContent":["import { defineNuxtPlugin, useRuntimeConfig, useRoute, useCookie, useRequestHeaders } from '#imports'\nimport { ref, watch } from 'vue'\nimport { localePath, extractLocaleFromPath, switchLocalePath } from './path-utils'\nimport { runDetectors } from './detectors'\nimport type { FluentNuxtRuntimeConfig, LocaleDetectContext } from '../types'\n\n/**\n * Nuxt runtime plugin that:\n * 1. Server: runs the locale detection chain, stores locale in payload for hydration\n * 2. Client: reads locale from payload to avoid hydration mismatch\n * 3. Provides reactive locale state and global helpers\n */\nexport default defineNuxtPlugin(async (nuxtApp) => {\n const config = useRuntimeConfig().public['fluenti'] as FluentNuxtRuntimeConfig\n const route = useRoute()\n\n // Hoist useCookie calls BEFORE any await to avoid losing the Nuxt\n // composable context (async local storage is dropped after await).\n const cookieCfg = config.detectBrowserLanguage?.useCookie\n ? config.detectBrowserLanguage\n : null\n const cookieKey = cookieCfg?.cookieKey ?? 'fluenti_locale'\n const localeCookie = cookieCfg ? useCookie(cookieKey) : null\n\n // Hoist all server-side header/cookie reads BEFORE any await.\n // Nuxt composables rely on async local storage that is dropped after await.\n let host: string | undefined\n let acceptLanguage: string | undefined\n if (import.meta.server) {\n try {\n const reqHeaders = useRequestHeaders(['host', 'accept-language'])\n acceptLanguage = reqHeaders['accept-language']\n if (config.strategy === 'domains') {\n host = reqHeaders['host']\n }\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Header read failed:', err)\n }\n } else if (config.strategy === 'domains') {\n try {\n host = window.location.host\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Domain detection failed:', err)\n }\n }\n\n let detectedLocale: string\n\n if (import.meta.server) {\n // --- Server (SSR / SSG / ISR): run full detection chain ---\n detectedLocale = await runDetectors(\n route.path,\n config,\n undefined,\n async (ctx: LocaleDetectContext) => {\n await (nuxtApp.callHook as Function)('fluenti:detect-locale', ctx)\n },\n host,\n localeCookie?.value ?? undefined,\n acceptLanguage,\n )\n // Store in payload — Nuxt serializes this to HTML automatically.\n // The client reads it back to ensure hydration uses the same locale.\n nuxtApp.payload['fluentiLocale'] = detectedLocale\n // Also set on event context so other plugins (e.g. i18n.ts) can read it\n try {\n const event = (nuxtApp as unknown as { ssrContext?: { event?: { context: Record<string, unknown> } } }).ssrContext?.event\n if (event) event.context['locale'] = detectedLocale\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Event context not available:', err)\n }\n } else if (nuxtApp.payload['fluentiLocale']) {\n // --- Client (SSR hydration): read from payload to avoid mismatch ---\n detectedLocale = nuxtApp.payload['fluentiLocale'] as string\n } else {\n // --- Client (SPA mode / no payload): detect from path and cookie ---\n if (config.strategy === 'domains' && host && config.domains?.length) {\n const cleanHost = host.toLowerCase().replace(/:\\d+$/, '')\n const domainMatch = config.domains.find((d) => d.domain.toLowerCase() === cleanHost)\n if (domainMatch) {\n detectedLocale = domainMatch.locale\n } else {\n detectedLocale = config.defaultLocale\n }\n } else {\n const { locale: pathLocale } = extractLocaleFromPath(route.path, config.locales)\n if (pathLocale) {\n detectedLocale = pathLocale\n } else if (localeCookie) {\n detectedLocale = (localeCookie.value && config.locales.includes(localeCookie.value))\n ? localeCookie.value\n : config.defaultLocale\n } else {\n detectedLocale = config.defaultLocale\n }\n }\n }\n\n const currentLocale = ref(detectedLocale)\n\n // Sync locale when route changes (path-based detection)\n if (config.strategy !== 'no_prefix' && config.strategy !== 'domains') {\n watch(() => route.path, (newPath) => {\n const { locale } = extractLocaleFromPath(newPath, config.locales)\n if (locale) {\n currentLocale.value = locale\n } else if (config.strategy === 'prefix_except_default') {\n // No locale prefix found — this means we're on a default locale route\n currentLocale.value = config.defaultLocale\n }\n })\n }\n\n // Persist locale in cookie if detectBrowserLanguage is configured\n if (localeCookie) {\n watch(currentLocale, (newLocale) => {\n localeCookie.value = newLocale\n })\n }\n\n // --- Inject global helpers ---\n if (config.injectGlobalProperties) {\n const gp = nuxtApp.vueApp.config.globalProperties\n gp.$localePath = (path: string, locale?: string) => {\n return localePath(\n path,\n locale ?? currentLocale.value,\n config.defaultLocale,\n config.strategy,\n )\n }\n gp.$switchLocalePath = (newLocale: string) => {\n return switchLocalePath(\n route.path,\n newLocale,\n config.locales,\n config.defaultLocale,\n config.strategy,\n )\n }\n\n //
|
|
1
|
+
{"version":3,"file":"plugin.js","names":[],"sources":["../../src/runtime/plugin.ts"],"sourcesContent":["import { defineNuxtPlugin, useRuntimeConfig, useRoute, useCookie, useRequestHeaders } from '#imports'\nimport { ref, watch } from 'vue'\nimport { localePath, extractLocaleFromPath, switchLocalePath } from './path-utils'\nimport { runDetectors } from './detectors'\nimport type { FluentNuxtRuntimeConfig, LocaleDetectContext } from '../types'\n\n/**\n * Nuxt runtime plugin that:\n * 1. Server: runs the locale detection chain, stores locale in payload for hydration\n * 2. Client: reads locale from payload to avoid hydration mismatch\n * 3. Provides reactive locale state and global helpers\n */\nexport default defineNuxtPlugin(async (nuxtApp) => {\n const config = useRuntimeConfig().public['fluenti'] as FluentNuxtRuntimeConfig\n const route = useRoute()\n\n // Hoist useCookie calls BEFORE any await to avoid losing the Nuxt\n // composable context (async local storage is dropped after await).\n const cookieCfg = config.detectBrowserLanguage?.useCookie\n ? config.detectBrowserLanguage\n : null\n const cookieKey = cookieCfg?.cookieKey ?? 'fluenti_locale'\n const localeCookie = cookieCfg ? useCookie(cookieKey) : null\n\n // Hoist all server-side header/cookie reads BEFORE any await.\n // Nuxt composables rely on async local storage that is dropped after await.\n let host: string | undefined\n let acceptLanguage: string | undefined\n if (import.meta.server) {\n try {\n const reqHeaders = useRequestHeaders(['host', 'accept-language'])\n acceptLanguage = reqHeaders['accept-language']\n if (config.strategy === 'domains') {\n host = reqHeaders['host']\n }\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Header read failed:', err)\n }\n } else if (config.strategy === 'domains') {\n try {\n host = window.location.host\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Domain detection failed:', err)\n }\n }\n\n let detectedLocale: string\n\n if (import.meta.server) {\n // --- Server (SSR / SSG / ISR): run full detection chain ---\n detectedLocale = await runDetectors(\n route.path,\n config,\n undefined,\n async (ctx: LocaleDetectContext) => {\n await (nuxtApp.callHook as Function)('fluenti:detect-locale', ctx)\n },\n host,\n localeCookie?.value ?? undefined,\n acceptLanguage,\n )\n // Store in payload — Nuxt serializes this to HTML automatically.\n // The client reads it back to ensure hydration uses the same locale.\n nuxtApp.payload['fluentiLocale'] = detectedLocale\n // Also set on event context so other plugins (e.g. i18n.ts) can read it\n try {\n const event = (nuxtApp as unknown as { ssrContext?: { event?: { context: Record<string, unknown> } } }).ssrContext?.event\n if (event) event.context['locale'] = detectedLocale\n } catch (err) {\n if (import.meta.dev) console.debug('[fluenti] Event context not available:', err)\n }\n } else if (nuxtApp.payload['fluentiLocale']) {\n // --- Client (SSR hydration): read from payload to avoid mismatch ---\n detectedLocale = nuxtApp.payload['fluentiLocale'] as string\n } else {\n // --- Client (SPA mode / no payload): detect from path and cookie ---\n if (config.strategy === 'domains' && host && config.domains?.length) {\n const cleanHost = host.toLowerCase().replace(/:\\d+$/, '')\n const domainMatch = config.domains.find((d) => d.domain.toLowerCase() === cleanHost)\n if (domainMatch) {\n detectedLocale = domainMatch.locale\n } else {\n detectedLocale = config.defaultLocale\n }\n } else {\n const { locale: pathLocale } = extractLocaleFromPath(route.path, config.locales)\n if (pathLocale) {\n detectedLocale = pathLocale\n } else if (localeCookie) {\n detectedLocale = (localeCookie.value && config.locales.includes(localeCookie.value))\n ? localeCookie.value\n : config.defaultLocale\n } else {\n detectedLocale = config.defaultLocale\n }\n }\n }\n\n const currentLocale = ref(detectedLocale)\n\n // Sync locale when route changes (path-based detection)\n if (config.strategy !== 'no_prefix' && config.strategy !== 'domains') {\n watch(() => route.path, (newPath) => {\n const { locale } = extractLocaleFromPath(newPath, config.locales)\n if (locale) {\n currentLocale.value = locale\n } else if (config.strategy === 'prefix_except_default') {\n // No locale prefix found — this means we're on a default locale route\n currentLocale.value = config.defaultLocale\n }\n })\n }\n\n // Persist locale in cookie if detectBrowserLanguage is configured\n if (localeCookie) {\n watch(currentLocale, (newLocale) => {\n localeCookie.value = newLocale\n })\n }\n\n // --- Inject global helpers ---\n if (config.injectGlobalProperties) {\n const gp = nuxtApp.vueApp.config.globalProperties\n gp.$localePath = (path: string, locale?: string) => {\n return localePath(\n path,\n locale ?? currentLocale.value,\n config.defaultLocale,\n config.strategy,\n )\n }\n gp.$switchLocalePath = (newLocale: string) => {\n return switchLocalePath(\n route.path,\n newLocale,\n config.locales,\n config.defaultLocale,\n config.strategy,\n )\n }\n\n // $t/$d/$n are injected by the @fluenti/vue plugin via globalProperties.\n // No additional injection needed here — useI18n() cannot be called outside\n // a component setup() context.\n }\n\n return {\n provide: {\n fluentiLocale: currentLocale,\n fluentiConfig: config,\n },\n }\n})\n"],"mappings":";;;;;AAYA,IAAA,IAAe,EAAiB,OAAO,MAAY;CACjD,IAAM,IAAS,GAAkB,CAAC,OAAO,SACnC,IAAQ,GAAU,EAIlB,IAAY,EAAO,uBAAuB,YAC5C,EAAO,wBACP,MACE,IAAY,GAAW,aAAa,kBACpC,IAAe,IAAY,EAAU,EAAU,GAAG,MAIpD,GACA;AACJ,KAAI,OAAO,KAAK,OACd,KAAI;EACF,IAAM,IAAa,EAAkB,CAAC,QAAQ,kBAAkB,CAAC;AAEjE,EADA,IAAiB,EAAW,oBACxB,EAAO,aAAa,cACtB,IAAO,EAAW;UAEb,GAAK;AACZ,EAAI,OAAO,KAAK,OAAK,QAAQ,MAAM,iCAAiC,EAAI;;UAEjE,EAAO,aAAa,UAC7B,KAAI;AACF,MAAO,OAAO,SAAS;UAChB,GAAK;AACZ,EAAI,OAAO,KAAK,OAAK,QAAQ,MAAM,sCAAsC,EAAI;;CAIjF,IAAI;AAEJ,KAAI,OAAO,KAAK,QAAQ;AAetB,EAbA,IAAiB,MAAM,EACrB,EAAM,MACN,GACA,KAAA,GACA,OAAO,MAA6B;AAClC,SAAO,EAAQ,SAAsB,yBAAyB,EAAI;KAEpE,GACA,GAAc,SAAS,KAAA,GACvB,EACD,EAGD,EAAQ,QAAQ,gBAAmB;AAEnC,MAAI;GACF,IAAM,IAAS,EAAyF,YAAY;AACpH,GAAI,MAAO,EAAM,QAAQ,SAAY;WAC9B,GAAK;AACZ,GAAI,OAAO,KAAK,OAAK,QAAQ,MAAM,0CAA0C,EAAI;;YAE1E,EAAQ,QAAQ,cAEzB,KAAiB,EAAQ,QAAQ;UAG7B,EAAO,aAAa,aAAa,KAAQ,EAAO,SAAS,QAAQ;EACnE,IAAM,IAAY,EAAK,aAAa,CAAC,QAAQ,SAAS,GAAG,EACnD,IAAc,EAAO,QAAQ,MAAM,MAAM,EAAE,OAAO,aAAa,KAAK,EAAU;AACpF,EAGE,IAHE,IACe,EAAY,SAEZ,EAAO;QAErB;EACL,IAAM,EAAE,QAAQ,MAAe,EAAsB,EAAM,MAAM,EAAO,QAAQ;AAChF,EAOE,IAPE,MAEO,KACS,EAAa,SAAS,EAAO,QAAQ,SAAS,EAAa,MAAM,GAC/E,EAAa,QACb,EAAO;;CAOjB,IAAM,IAAgB,EAAI,EAAe;AAuBzC,KApBI,EAAO,aAAa,eAAe,EAAO,aAAa,aACzD,QAAY,EAAM,OAAO,MAAY;EACnC,IAAM,EAAE,cAAW,EAAsB,GAAS,EAAO,QAAQ;AACjE,EAAI,IACF,EAAc,QAAQ,IACb,EAAO,aAAa,4BAE7B,EAAc,QAAQ,EAAO;GAE/B,EAIA,KACF,EAAM,IAAgB,MAAc;AAClC,IAAa,QAAQ;GACrB,EAIA,EAAO,wBAAwB;EACjC,IAAM,IAAK,EAAQ,OAAO,OAAO;AASjC,EARA,EAAG,eAAe,GAAc,MACvB,EACL,GACA,KAAU,EAAc,OACxB,EAAO,eACP,EAAO,SACR,EAEH,EAAG,qBAAqB,MACf,EACL,EAAM,MACN,GACA,EAAO,SACP,EAAO,eACP,EAAO,SACR;;AAQL,QAAO,EACL,SAAS;EACP,eAAe;EACf,eAAe;EAChB,EACF;EACD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require(`../../module.cjs`);let e=require(`h3`);var t=(0,e.defineEventHandler)(t=>{let i=t.path??`/`;if(i.startsWith(`/_nuxt/`)||i.startsWith(`/api/`)||i.startsWith(`/__nuxt`)||/\.\w{2,5}$/.test(i))return;let a=t.context.__fluenti_config??r(t);if(!a||a.strategy!==`prefix`&&a.strategy!==`prefix_and_default`)return;let o=i.split(`/`).filter(Boolean)[0];if(o&&a.locales.includes(o))return;let s=a.defaultLocale,c=a.queryParamKey??`locale`,l=(0,e.getQuery)(t)[c];if(typeof l==`string`&&a.locales.includes(l)&&(s=l),!
|
|
1
|
+
require(`../../module.cjs`);let e=require(`h3`);var t=(0,e.defineEventHandler)(t=>{let i=t.path??`/`;if(i.startsWith(`/_nuxt/`)||i.startsWith(`/api/`)||i.startsWith(`/__nuxt`)||/\.\w{2,5}$/.test(i))return;let a=t.context.__fluenti_config??r(t);if(!a||a.strategy!==`prefix`&&a.strategy!==`prefix_and_default`)return;let o=i.split(`/`).filter(Boolean)[0];if(o&&a.locales.includes(o))return;let s=a.defaultLocale,c=a.queryParamKey??`locale`,l=(0,e.getQuery)(t)[c],u=!1;if(typeof l==`string`&&a.locales.includes(l)&&(s=l,u=!0),!u){let n=(0,e.getCookie)(t,a.detectBrowserLanguage?.cookieKey??`fluenti_locale`);n&&a.locales.includes(n)&&(s=n)}if(!u){let r=(0,e.getHeader)(t,`accept-language`);if(r){let e=n(r,a.locales);e&&(s=e)}}return(0,e.sendRedirect)(t,`/${s}${i===`/`?``:i}`,302)});function n(e,t){let n=e.split(`,`).map(e=>{let[t=``,n=``]=e.trim().split(`;q=`),r=n?parseFloat(n):1,i=Number.isFinite(r)?Math.min(1,Math.max(0,r)):0;return{lang:t.trim().toLowerCase(),quality:i}}).filter(e=>e.quality>0).sort((e,t)=>t.quality-e.quality);for(let e of n){let n=t.find(t=>t.toLowerCase()===e.lang);if(n)return n;let r=t.find(t=>t.toLowerCase().startsWith(e.lang)||e.lang.startsWith(t.toLowerCase()));if(r)return r}return null}function r(e){try{let t=(((e.context.nitro??e.context.__nitro)?.runtimeConfig??{}).public??{}).fluenti;return t&&(e.context.__fluenti_config=t),t}catch{return}}module.exports=t;
|
|
2
2
|
//# sourceMappingURL=locale-redirect.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-redirect.cjs","names":[],"sources":["../../../src/runtime/server/locale-redirect.ts"],"sourcesContent":["import { defineEventHandler, sendRedirect, getHeader, getCookie, getQuery } from 'h3'\n\n/**\n * Nitro server middleware for locale-based redirects.\n *\n * Runs at the Nitro layer (before Vue Router), which is earlier in the\n * request lifecycle. This prevents any flash of wrong-locale content\n * during SSR, as the redirect happens before page rendering starts.\n *\n * Only active when strategy is 'prefix' or 'prefix_and_default'.\n */\nexport default defineEventHandler((event) => {\n const url = event.path ?? '/'\n\n // Skip non-page requests (assets, API routes, etc.)\n if (url.startsWith('/_nuxt/') || url.startsWith('/api/') || url.startsWith('/__nuxt')) {\n return\n }\n\n // Skip if URL already has a file extension (static assets)\n if (/\\.\\w{2,5}$/.test(url)) {\n return\n }\n\n // Read config from runtime config\n const config = (event.context['__fluenti_config'] ??\n useRuntimeConfigFromEvent(event)) as {\n locales: string[]\n defaultLocale: string\n strategy: string\n detectOrder?: string[]\n queryParamKey?: string\n detectBrowserLanguage?: { useCookie?: boolean; cookieKey?: string; fallbackLocale?: string }\n } | undefined\n\n if (!config) return\n\n // Only handle prefix/prefix_and_default strategies\n if (config.strategy !== 'prefix' && config.strategy !== 'prefix_and_default') {\n return\n }\n\n // Check if the URL already has a locale prefix\n const pathSegments = url.split('/').filter(Boolean)\n const firstSegment = pathSegments[0]\n\n if (firstSegment && config.locales.includes(firstSegment)) {\n // URL already has a valid locale prefix\n return\n }\n\n // For prefix_and_default, unprefixed URLs are allowed for the default locale\n // (they will be served without redirect)\n // For prefix strategy, we must redirect\n\n // Detect locale from various sources\n let detectedLocale = config.defaultLocale\n\n // 1. Query parameter\n const queryKey = config.queryParamKey ?? 'locale'\n const query = getQuery(event)\n const queryLocale = query[queryKey]\n if (typeof queryLocale === 'string' && config.locales.includes(queryLocale)) {\n detectedLocale = queryLocale\n }\n\n // 2. Cookie\n if (!
|
|
1
|
+
{"version":3,"file":"locale-redirect.cjs","names":[],"sources":["../../../src/runtime/server/locale-redirect.ts"],"sourcesContent":["import { defineEventHandler, sendRedirect, getHeader, getCookie, getQuery } from 'h3'\n\n/**\n * Nitro server middleware for locale-based redirects.\n *\n * Runs at the Nitro layer (before Vue Router), which is earlier in the\n * request lifecycle. This prevents any flash of wrong-locale content\n * during SSR, as the redirect happens before page rendering starts.\n *\n * Only active when strategy is 'prefix' or 'prefix_and_default'.\n */\nexport default defineEventHandler((event) => {\n const url = event.path ?? '/'\n\n // Skip non-page requests (assets, API routes, etc.)\n if (url.startsWith('/_nuxt/') || url.startsWith('/api/') || url.startsWith('/__nuxt')) {\n return\n }\n\n // Skip if URL already has a file extension (static assets)\n if (/\\.\\w{2,5}$/.test(url)) {\n return\n }\n\n // Read config from runtime config\n const config = (event.context['__fluenti_config'] ??\n useRuntimeConfigFromEvent(event)) as {\n locales: string[]\n defaultLocale: string\n strategy: string\n detectOrder?: string[]\n queryParamKey?: string\n detectBrowserLanguage?: { useCookie?: boolean; cookieKey?: string; fallbackLocale?: string }\n } | undefined\n\n if (!config) return\n\n // Only handle prefix/prefix_and_default strategies\n if (config.strategy !== 'prefix' && config.strategy !== 'prefix_and_default') {\n return\n }\n\n // Check if the URL already has a locale prefix\n const pathSegments = url.split('/').filter(Boolean)\n const firstSegment = pathSegments[0]\n\n if (firstSegment && config.locales.includes(firstSegment)) {\n // URL already has a valid locale prefix\n return\n }\n\n // For prefix_and_default, unprefixed URLs are allowed for the default locale\n // (they will be served without redirect)\n // For prefix strategy, we must redirect\n\n // Detect locale from various sources\n let detectedLocale = config.defaultLocale\n\n // 1. Query parameter\n const queryKey = config.queryParamKey ?? 'locale'\n const query = getQuery(event)\n const queryLocale = query[queryKey]\n // Use a flag: queryLocale may be a string array (e.g. ?locale=en&locale=ja)\n // in which case it is truthy but not a valid match — must not skip cookie/header detection\n let queryMatched = false\n if (typeof queryLocale === 'string' && config.locales.includes(queryLocale)) {\n detectedLocale = queryLocale\n queryMatched = true\n }\n\n // 2. Cookie\n if (!queryMatched) {\n const cookieKey = config.detectBrowserLanguage?.cookieKey ?? 'fluenti_locale'\n const cookieLocale = getCookie(event, cookieKey)\n if (cookieLocale && config.locales.includes(cookieLocale)) {\n detectedLocale = cookieLocale\n }\n }\n\n // 3. Accept-Language header\n if (!queryMatched) {\n const acceptLang = getHeader(event, 'accept-language')\n if (acceptLang) {\n const preferred = parseAcceptLanguage(acceptLang, config.locales)\n if (preferred) {\n detectedLocale = preferred\n }\n }\n }\n\n // Redirect to locale-prefixed URL\n const cleanUrl = url === '/' ? '' : url\n const redirectUrl = `/${detectedLocale}${cleanUrl}`\n\n return sendRedirect(event, redirectUrl, 302)\n})\n\n/**\n * Parse Accept-Language header and find the best matching locale.\n */\nfunction parseAcceptLanguage(header: string, locales: string[]): string | null {\n const entries = header\n .split(',')\n .map((part) => {\n const [lang = '', q = ''] = part.trim().split(';q=')\n const parsed = q ? parseFloat(q) : 1.0\n const quality = Number.isFinite(parsed) ? Math.min(1, Math.max(0, parsed)) : 0\n return {\n lang: lang!.trim().toLowerCase(),\n quality,\n }\n })\n .filter((e) => e.quality > 0)\n .sort((a, b) => b.quality - a.quality)\n\n for (const entry of entries) {\n // Exact match\n const exact = locales.find((l) => l.toLowerCase() === entry.lang)\n if (exact) return exact\n\n // Prefix match (e.g., 'en' matches 'en-US')\n const prefix = locales.find(\n (l) => l.toLowerCase().startsWith(entry.lang) || entry.lang.startsWith(l.toLowerCase()),\n )\n if (prefix) return prefix\n }\n\n return null\n}\n\n/**\n * Read Fluenti runtime config from the event context.\n */\nfunction useRuntimeConfigFromEvent(event: { context: Record<string, unknown> }) {\n try {\n const nitroConfig = (event.context['nitro'] ?? event.context['__nitro']) as Record<string, unknown> | undefined\n const runtimeConfig = (nitroConfig?.['runtimeConfig'] ?? {}) as Record<string, unknown>\n const publicConfig = (runtimeConfig['public'] ?? {}) as Record<string, unknown>\n const fluentiConfig = publicConfig['fluenti']\n if (fluentiConfig) {\n event.context['__fluenti_config'] = fluentiConfig\n }\n return fluentiConfig\n } catch {\n return undefined\n }\n}\n"],"mappings":"gDAWA,IAAA,GAAA,EAAA,EAAA,oBAAmC,GAAU,CAC3C,IAAM,EAAM,EAAM,MAAQ,IAQ1B,GALI,EAAI,WAAW,UAAU,EAAI,EAAI,WAAW,QAAQ,EAAI,EAAI,WAAW,UAAU,EAKjF,aAAa,KAAK,EAAI,CACxB,OAIF,IAAM,EAAU,EAAM,QAAQ,kBAC5B,EAA0B,EAAM,CAYlC,GAHI,CAAC,GAGD,EAAO,WAAa,UAAY,EAAO,WAAa,qBACtD,OAKF,IAAM,EADe,EAAI,MAAM,IAAI,CAAC,OAAO,QAAQ,CACjB,GAElC,GAAI,GAAgB,EAAO,QAAQ,SAAS,EAAa,CAEvD,OAQF,IAAI,EAAiB,EAAO,cAGtB,EAAW,EAAO,eAAiB,SAEnC,GAAA,EAAA,EAAA,UADiB,EAAM,CACH,GAGtB,EAAe,GAOnB,GANI,OAAO,GAAgB,UAAY,EAAO,QAAQ,SAAS,EAAY,GACzE,EAAiB,EACjB,EAAe,IAIb,CAAC,EAAc,CAEjB,IAAM,GAAA,EAAA,EAAA,WAAyB,EADb,EAAO,uBAAuB,WAAa,iBACb,CAC5C,GAAgB,EAAO,QAAQ,SAAS,EAAa,GACvD,EAAiB,GAKrB,GAAI,CAAC,EAAc,CACjB,IAAM,GAAA,EAAA,EAAA,WAAuB,EAAO,kBAAkB,CACtD,GAAI,EAAY,CACd,IAAM,EAAY,EAAoB,EAAY,EAAO,QAAQ,CAC7D,IACF,EAAiB,IASvB,OAAA,EAAA,EAAA,cAAoB,EAFA,IAAI,IADP,IAAQ,IAAM,GAAK,IAGI,IAAI,EAC5C,CAKF,SAAS,EAAoB,EAAgB,EAAkC,CAC7E,IAAM,EAAU,EACb,MAAM,IAAI,CACV,IAAK,GAAS,CACb,GAAM,CAAC,EAAO,GAAI,EAAI,IAAM,EAAK,MAAM,CAAC,MAAM,MAAM,CAC9C,EAAS,EAAI,WAAW,EAAE,CAAG,EAC7B,EAAU,OAAO,SAAS,EAAO,CAAG,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,EAAO,CAAC,CAAG,EAC7E,MAAO,CACL,KAAM,EAAM,MAAM,CAAC,aAAa,CAChC,UACD,EACD,CACD,OAAQ,GAAM,EAAE,QAAU,EAAE,CAC5B,MAAM,EAAG,IAAM,EAAE,QAAU,EAAE,QAAQ,CAExC,IAAK,IAAM,KAAS,EAAS,CAE3B,IAAM,EAAQ,EAAQ,KAAM,GAAM,EAAE,aAAa,GAAK,EAAM,KAAK,CACjE,GAAI,EAAO,OAAO,EAGlB,IAAM,EAAS,EAAQ,KACpB,GAAM,EAAE,aAAa,CAAC,WAAW,EAAM,KAAK,EAAI,EAAM,KAAK,WAAW,EAAE,aAAa,CAAC,CACxF,CACD,GAAI,EAAQ,OAAO,EAGrB,OAAO,KAMT,SAAS,EAA0B,EAA6C,CAC9E,GAAI,CAIF,IAAM,KAHe,EAAM,QAAQ,OAAY,EAAM,QAAQ,UACxB,eAAoB,EAAE,EACvB,QAAa,EAAE,EAChB,QAInC,OAHI,IACF,EAAM,QAAQ,iBAAsB,GAE/B,OACD,CACN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-redirect.d.ts","sourceRoot":"","sources":["../../../src/runtime/server/locale-redirect.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;;AACH,
|
|
1
|
+
{"version":3,"file":"locale-redirect.d.ts","sourceRoot":"","sources":["../../../src/runtime/server/locale-redirect.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;;AACH,wBAoFE"}
|
|
@@ -7,12 +7,12 @@ var a = e((e) => {
|
|
|
7
7
|
if (!c || c.strategy !== "prefix" && c.strategy !== "prefix_and_default") return;
|
|
8
8
|
let l = a.split("/").filter(Boolean)[0];
|
|
9
9
|
if (l && c.locales.includes(l)) return;
|
|
10
|
-
let u = c.defaultLocale, d = c.queryParamKey ?? "locale", f = r(e)[d];
|
|
11
|
-
if (typeof f == "string" && c.locales.includes(f) && (u = f), !
|
|
10
|
+
let u = c.defaultLocale, d = c.queryParamKey ?? "locale", f = r(e)[d], p = !1;
|
|
11
|
+
if (typeof f == "string" && c.locales.includes(f) && (u = f, p = !0), !p) {
|
|
12
12
|
let n = t(e, c.detectBrowserLanguage?.cookieKey ?? "fluenti_locale");
|
|
13
13
|
n && c.locales.includes(n) && (u = n);
|
|
14
14
|
}
|
|
15
|
-
if (!
|
|
15
|
+
if (!p) {
|
|
16
16
|
let t = n(e, "accept-language");
|
|
17
17
|
if (t) {
|
|
18
18
|
let e = o(t, c.locales);
|
|
@@ -23,10 +23,10 @@ var a = e((e) => {
|
|
|
23
23
|
});
|
|
24
24
|
function o(e, t) {
|
|
25
25
|
let n = e.split(",").map((e) => {
|
|
26
|
-
let [t = "", n = ""] = e.trim().split(";q=");
|
|
26
|
+
let [t = "", n = ""] = e.trim().split(";q="), r = n ? parseFloat(n) : 1, i = Number.isFinite(r) ? Math.min(1, Math.max(0, r)) : 0;
|
|
27
27
|
return {
|
|
28
28
|
lang: t.trim().toLowerCase(),
|
|
29
|
-
quality:
|
|
29
|
+
quality: i
|
|
30
30
|
};
|
|
31
31
|
}).filter((e) => e.quality > 0).sort((e, t) => t.quality - e.quality);
|
|
32
32
|
for (let e of n) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-redirect.js","names":[],"sources":["../../../src/runtime/server/locale-redirect.ts"],"sourcesContent":["import { defineEventHandler, sendRedirect, getHeader, getCookie, getQuery } from 'h3'\n\n/**\n * Nitro server middleware for locale-based redirects.\n *\n * Runs at the Nitro layer (before Vue Router), which is earlier in the\n * request lifecycle. This prevents any flash of wrong-locale content\n * during SSR, as the redirect happens before page rendering starts.\n *\n * Only active when strategy is 'prefix' or 'prefix_and_default'.\n */\nexport default defineEventHandler((event) => {\n const url = event.path ?? '/'\n\n // Skip non-page requests (assets, API routes, etc.)\n if (url.startsWith('/_nuxt/') || url.startsWith('/api/') || url.startsWith('/__nuxt')) {\n return\n }\n\n // Skip if URL already has a file extension (static assets)\n if (/\\.\\w{2,5}$/.test(url)) {\n return\n }\n\n // Read config from runtime config\n const config = (event.context['__fluenti_config'] ??\n useRuntimeConfigFromEvent(event)) as {\n locales: string[]\n defaultLocale: string\n strategy: string\n detectOrder?: string[]\n queryParamKey?: string\n detectBrowserLanguage?: { useCookie?: boolean; cookieKey?: string; fallbackLocale?: string }\n } | undefined\n\n if (!config) return\n\n // Only handle prefix/prefix_and_default strategies\n if (config.strategy !== 'prefix' && config.strategy !== 'prefix_and_default') {\n return\n }\n\n // Check if the URL already has a locale prefix\n const pathSegments = url.split('/').filter(Boolean)\n const firstSegment = pathSegments[0]\n\n if (firstSegment && config.locales.includes(firstSegment)) {\n // URL already has a valid locale prefix\n return\n }\n\n // For prefix_and_default, unprefixed URLs are allowed for the default locale\n // (they will be served without redirect)\n // For prefix strategy, we must redirect\n\n // Detect locale from various sources\n let detectedLocale = config.defaultLocale\n\n // 1. Query parameter\n const queryKey = config.queryParamKey ?? 'locale'\n const query = getQuery(event)\n const queryLocale = query[queryKey]\n if (typeof queryLocale === 'string' && config.locales.includes(queryLocale)) {\n detectedLocale = queryLocale\n }\n\n // 2. Cookie\n if (!
|
|
1
|
+
{"version":3,"file":"locale-redirect.js","names":[],"sources":["../../../src/runtime/server/locale-redirect.ts"],"sourcesContent":["import { defineEventHandler, sendRedirect, getHeader, getCookie, getQuery } from 'h3'\n\n/**\n * Nitro server middleware for locale-based redirects.\n *\n * Runs at the Nitro layer (before Vue Router), which is earlier in the\n * request lifecycle. This prevents any flash of wrong-locale content\n * during SSR, as the redirect happens before page rendering starts.\n *\n * Only active when strategy is 'prefix' or 'prefix_and_default'.\n */\nexport default defineEventHandler((event) => {\n const url = event.path ?? '/'\n\n // Skip non-page requests (assets, API routes, etc.)\n if (url.startsWith('/_nuxt/') || url.startsWith('/api/') || url.startsWith('/__nuxt')) {\n return\n }\n\n // Skip if URL already has a file extension (static assets)\n if (/\\.\\w{2,5}$/.test(url)) {\n return\n }\n\n // Read config from runtime config\n const config = (event.context['__fluenti_config'] ??\n useRuntimeConfigFromEvent(event)) as {\n locales: string[]\n defaultLocale: string\n strategy: string\n detectOrder?: string[]\n queryParamKey?: string\n detectBrowserLanguage?: { useCookie?: boolean; cookieKey?: string; fallbackLocale?: string }\n } | undefined\n\n if (!config) return\n\n // Only handle prefix/prefix_and_default strategies\n if (config.strategy !== 'prefix' && config.strategy !== 'prefix_and_default') {\n return\n }\n\n // Check if the URL already has a locale prefix\n const pathSegments = url.split('/').filter(Boolean)\n const firstSegment = pathSegments[0]\n\n if (firstSegment && config.locales.includes(firstSegment)) {\n // URL already has a valid locale prefix\n return\n }\n\n // For prefix_and_default, unprefixed URLs are allowed for the default locale\n // (they will be served without redirect)\n // For prefix strategy, we must redirect\n\n // Detect locale from various sources\n let detectedLocale = config.defaultLocale\n\n // 1. Query parameter\n const queryKey = config.queryParamKey ?? 'locale'\n const query = getQuery(event)\n const queryLocale = query[queryKey]\n // Use a flag: queryLocale may be a string array (e.g. ?locale=en&locale=ja)\n // in which case it is truthy but not a valid match — must not skip cookie/header detection\n let queryMatched = false\n if (typeof queryLocale === 'string' && config.locales.includes(queryLocale)) {\n detectedLocale = queryLocale\n queryMatched = true\n }\n\n // 2. Cookie\n if (!queryMatched) {\n const cookieKey = config.detectBrowserLanguage?.cookieKey ?? 'fluenti_locale'\n const cookieLocale = getCookie(event, cookieKey)\n if (cookieLocale && config.locales.includes(cookieLocale)) {\n detectedLocale = cookieLocale\n }\n }\n\n // 3. Accept-Language header\n if (!queryMatched) {\n const acceptLang = getHeader(event, 'accept-language')\n if (acceptLang) {\n const preferred = parseAcceptLanguage(acceptLang, config.locales)\n if (preferred) {\n detectedLocale = preferred\n }\n }\n }\n\n // Redirect to locale-prefixed URL\n const cleanUrl = url === '/' ? '' : url\n const redirectUrl = `/${detectedLocale}${cleanUrl}`\n\n return sendRedirect(event, redirectUrl, 302)\n})\n\n/**\n * Parse Accept-Language header and find the best matching locale.\n */\nfunction parseAcceptLanguage(header: string, locales: string[]): string | null {\n const entries = header\n .split(',')\n .map((part) => {\n const [lang = '', q = ''] = part.trim().split(';q=')\n const parsed = q ? parseFloat(q) : 1.0\n const quality = Number.isFinite(parsed) ? Math.min(1, Math.max(0, parsed)) : 0\n return {\n lang: lang!.trim().toLowerCase(),\n quality,\n }\n })\n .filter((e) => e.quality > 0)\n .sort((a, b) => b.quality - a.quality)\n\n for (const entry of entries) {\n // Exact match\n const exact = locales.find((l) => l.toLowerCase() === entry.lang)\n if (exact) return exact\n\n // Prefix match (e.g., 'en' matches 'en-US')\n const prefix = locales.find(\n (l) => l.toLowerCase().startsWith(entry.lang) || entry.lang.startsWith(l.toLowerCase()),\n )\n if (prefix) return prefix\n }\n\n return null\n}\n\n/**\n * Read Fluenti runtime config from the event context.\n */\nfunction useRuntimeConfigFromEvent(event: { context: Record<string, unknown> }) {\n try {\n const nitroConfig = (event.context['nitro'] ?? event.context['__nitro']) as Record<string, unknown> | undefined\n const runtimeConfig = (nitroConfig?.['runtimeConfig'] ?? {}) as Record<string, unknown>\n const publicConfig = (runtimeConfig['public'] ?? {}) as Record<string, unknown>\n const fluentiConfig = publicConfig['fluenti']\n if (fluentiConfig) {\n event.context['__fluenti_config'] = fluentiConfig\n }\n return fluentiConfig\n } catch {\n return undefined\n }\n}\n"],"mappings":";;AAWA,IAAA,IAAe,GAAoB,MAAU;CAC3C,IAAM,IAAM,EAAM,QAAQ;AAQ1B,KALI,EAAI,WAAW,UAAU,IAAI,EAAI,WAAW,QAAQ,IAAI,EAAI,WAAW,UAAU,IAKjF,aAAa,KAAK,EAAI,CACxB;CAIF,IAAM,IAAU,EAAM,QAAQ,oBAC5B,EAA0B,EAAM;AAYlC,KAHI,CAAC,KAGD,EAAO,aAAa,YAAY,EAAO,aAAa,qBACtD;CAKF,IAAM,IADe,EAAI,MAAM,IAAI,CAAC,OAAO,QAAQ,CACjB;AAElC,KAAI,KAAgB,EAAO,QAAQ,SAAS,EAAa,CAEvD;CAQF,IAAI,IAAiB,EAAO,eAGtB,IAAW,EAAO,iBAAiB,UAEnC,IADQ,EAAS,EAAM,CACH,IAGtB,IAAe;AAOnB,KANI,OAAO,KAAgB,YAAY,EAAO,QAAQ,SAAS,EAAY,KACzE,IAAiB,GACjB,IAAe,KAIb,CAAC,GAAc;EAEjB,IAAM,IAAe,EAAU,GADb,EAAO,uBAAuB,aAAa,iBACb;AAChD,EAAI,KAAgB,EAAO,QAAQ,SAAS,EAAa,KACvD,IAAiB;;AAKrB,KAAI,CAAC,GAAc;EACjB,IAAM,IAAa,EAAU,GAAO,kBAAkB;AACtD,MAAI,GAAY;GACd,IAAM,IAAY,EAAoB,GAAY,EAAO,QAAQ;AACjE,GAAI,MACF,IAAiB;;;AASvB,QAAO,EAAa,GAFA,IAAI,IADP,MAAQ,MAAM,KAAK,KAGI,IAAI;EAC5C;AAKF,SAAS,EAAoB,GAAgB,GAAkC;CAC7E,IAAM,IAAU,EACb,MAAM,IAAI,CACV,KAAK,MAAS;EACb,IAAM,CAAC,IAAO,IAAI,IAAI,MAAM,EAAK,MAAM,CAAC,MAAM,MAAM,EAC9C,IAAS,IAAI,WAAW,EAAE,GAAG,GAC7B,IAAU,OAAO,SAAS,EAAO,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,EAAO,CAAC,GAAG;AAC7E,SAAO;GACL,MAAM,EAAM,MAAM,CAAC,aAAa;GAChC;GACD;GACD,CACD,QAAQ,MAAM,EAAE,UAAU,EAAE,CAC5B,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,QAAQ;AAExC,MAAK,IAAM,KAAS,GAAS;EAE3B,IAAM,IAAQ,EAAQ,MAAM,MAAM,EAAE,aAAa,KAAK,EAAM,KAAK;AACjE,MAAI,EAAO,QAAO;EAGlB,IAAM,IAAS,EAAQ,MACpB,MAAM,EAAE,aAAa,CAAC,WAAW,EAAM,KAAK,IAAI,EAAM,KAAK,WAAW,EAAE,aAAa,CAAC,CACxF;AACD,MAAI,EAAQ,QAAO;;AAGrB,QAAO;;AAMT,SAAS,EAA0B,GAA6C;AAC9E,KAAI;EAIF,IAAM,OAHe,EAAM,QAAQ,SAAY,EAAM,QAAQ,UACxB,iBAAoB,EAAE,EACvB,UAAa,EAAE,EAChB;AAInC,SAHI,MACF,EAAM,QAAQ,mBAAsB,IAE/B;SACD;AACN"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../path-utils-BQIsp_or.cjs`),t=require(`../locale-head-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../path-utils-BQIsp_or.cjs`),t=require(`../locale-head-CwFSeJqY.cjs`);require(`../module.cjs`);let n=require(`vue`);function r(t,n){return(r,i)=>e.n(r,i??t.value,n.defaultLocale,n.strategy)}function i(t,n){return r=>e.r(t.value,r,n.locales,n.defaultLocale,n.strategy)}function a(t,n,r){return(i,a)=>{let o=a??t.value;if(typeof i==`string`){let t=e.n(i,o,r.defaultLocale,r.strategy);return n.resolve(t)}if(`path`in i&&i.path){let t=e.n(i.path,o,r.defaultLocale,r.strategy);return n.resolve({...i,path:t})}return n.resolve(i)}}function o(e,r,i,a){return(0,n.computed)(()=>t.t(e.value,r.value,i,a))}exports.useLocaleHead=o,exports.useLocalePath=r,exports.useLocaleRoute=a,exports.useSwitchLocalePath=i;
|
|
2
2
|
//# sourceMappingURL=standalone-composables.cjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e, r as t } from "../path-utils-BcvXLCGi.js";
|
|
2
|
-
import { t as n } from "../locale-head-
|
|
2
|
+
import { t as n } from "../locale-head-CV660rxz.js";
|
|
3
3
|
import { computed as r } from "vue";
|
|
4
4
|
//#region src/runtime/standalone-composables.ts
|
|
5
5
|
function i(t, n) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluenti/nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-rc.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Nuxt module for Fluenti — locale-prefixed routes, SEO helpers, auto locale detection",
|
|
6
6
|
"homepage": "https://fluenti.dev",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@nuxt/kit": "^4.4.2",
|
|
72
72
|
"@nuxt/schema": "^4.4.2",
|
|
73
|
-
"@fluenti/core": "0.
|
|
74
|
-
"@fluenti/vue": "0.
|
|
73
|
+
"@fluenti/core": "0.4.0-rc.0",
|
|
74
|
+
"@fluenti/vue": "0.4.0-rc.0"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"typescript": "^5.9",
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require(`./path-utils-BQIsp_or.cjs`);require(`./module.cjs`);const t=require(`./runtime/detectors/domain.cjs`);let n=require(`#imports`);function r(t){if(t.strategy===`no_prefix`)return;let{locale:n}=e.t(t.path,t.locales);n&&t.setLocale(n)}function i(e){if(!e.detectBrowserLanguage?.useCookie)return;if(e.cookieValue!==void 0){e.cookieValue&&e.locales.includes(e.cookieValue)&&e.setLocale(e.cookieValue);return}let t=e.detectBrowserLanguage.cookieKey??`fluenti_locale`;try{let r=(0,n.useCookie)(t);r.value&&e.locales.includes(r.value)&&e.setLocale(r.value)}catch{}}function a(e){if(!e.isServer)return;let t=e.acceptLanguage??o();if(t){let n=s(t,e.locales);n&&e.setLocale(n)}}function o(){try{return(0,n.useRequestHeaders)([`accept-language`])[`accept-language`]}catch{return}}function s(e,t){let n=e.split(`,`).map(e=>{let[t,n]=e.trim().split(`;q=`);return{lang:t.trim().toLowerCase(),q:n?parseFloat(n):1}}).sort((e,t)=>t.q-e.q);for(let{lang:e}of n){if(t.includes(e))return e;let n=e.split(`-`)[0];if(t.includes(n))return n}return null}function c(e){try{let t=(0,n.useRoute)(),r=(0,n.useRuntimeConfig)().public.fluenti.queryParamKey??`locale`,i=t.query[r];i&&e.locales.includes(i)&&e.setLocale(i)}catch{}}var l={path:r,cookie:i,header:a,query:c,domain:t};async function u(e,t,n,r,i,a,o){let s=null,c=!1,u={path:e,locales:t.locales,defaultLocale:t.defaultLocale,strategy:t.strategy,...t.detectBrowserLanguage?{detectBrowserLanguage:t.detectBrowserLanguage}:{},detectedLocale:null,setLocale(e){t.locales.includes(e)&&(s=e,u.detectedLocale=e,c=!0)},isServer:{}.server??!1,...i?{host:i}:{},...a==null?{}:{cookieValue:a},...o?{acceptLanguage:o}:{}};t.domains&&Object.assign(u,{domains:t.domains});for(let e of t.detectOrder){if(c)break;let t=l[e]??n?.get(e);t&&await t(u)}return r&&!c&&await r(u),s??t.detectBrowserLanguage?.fallbackLocale??t.defaultLocale}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return u}});
|
|
2
|
-
//# sourceMappingURL=detectors-BnmzZTww.cjs.map
|