Troubleshooting
Build Errors
Section titled “Build Errors”t is not a function at runtime
Section titled “t is not a function at runtime”The Vite plugin was not configured. Ensure the framework-specific plugin is added to your vite.config.ts:
// Use the import matching your framework:import fluentiVue from '@fluenti/vue/vite-plugin'// import fluentiReact from '@fluenti/react/vite-plugin'// import fluentiSolid from '@fluenti/solid/vite-plugin'
export default defineConfig({ plugins: [fluentiVue()],})For Next.js, use withFluenti() in next.config.ts instead. For Nuxt, add @fluenti/nuxt to your nuxt.config.ts modules.
Build fails with “Cannot resolve virtual:fluenti/*”
Section titled “Build fails with “Cannot resolve virtual:fluenti/*””The Vite plugin must be loaded before framework-specific plugins. Ensure fluenti() appears early in your plugins array:
export default defineConfig({ plugins: [ fluentiVue(), // before vue() vue(), ],})If you are using a monorepo with hoisted dependencies, ensure @fluenti/vite-plugin is installed at the correct level. The plugin resolves virtual modules prefixed with \0 following Vite conventions, so other plugins that modify resolveId hooks can interfere.
”runtimeGenerator is required” error
Section titled “”runtimeGenerator is required” error”[fluenti] vite-plugin: runtimeGenerator is required.Use a framework-specific plugin (e.g. @fluenti/vue/vite-plugin).You imported @fluenti/vite-plugin directly instead of the framework wrapper. Always use the framework-specific plugin:
import fluentiVue from '@fluenti/vue/vite-plugin'import fluentiReact from '@fluenti/react/vite-plugin'import fluentiSolid from '@fluenti/solid/vite-plugin'The framework plugins call createFluentiPlugins() internally and provide the runtime generator for your framework.
”catalogDir must not contain backticks or $ characters”
Section titled “”catalogDir must not contain backticks or $ characters””[fluenti] vite-plugin: catalogDir must not contain backticks or $ charactersYour catalogDir path contains characters that would break generated code. Rename the directory to use only alphanumeric characters, hyphens, underscores, and path separators.
fluenti extract finds no messages
Section titled “fluenti extract finds no messages”Check that your include patterns in fluenti.config.ts match your source file paths:
export default defineConfig({ include: [ './src/**/*.vue', // Vue SFCs './src/**/*.tsx', // React/Solid TSX './src/**/*.jsx', // JSX './src/**/*.ts', // TypeScript files with t`` or msg`` ],})Also verify you are using supported extraction patterns: v-t, t`...`, t(), <Trans>, <Plural>, or msg.
Missing translations in production
Section titled “Missing translations in production”Compiled catalogs are build artifacts. Since v0.1.4, both the Vite plugin and withFluenti() automatically run extract + compile before production builds (buildAutoCompile is enabled by default). If you still see missing translations:
- Ensure you are using the latest plugin version
- Check that
buildAutoCompileis not explicitly set tofalse
If you need to run the steps manually (e.g. custom CI pipeline with buildAutoCompile: false):
pnpm fluenti extractpnpm fluenti compilepnpm buildConfig file not found or circular extends
Section titled “Config file not found or circular extends”Config extends "base.config.ts" but file not found: /path/to/base.config.tsThe extends field in fluenti.config.ts resolves relative to the config file itself. Verify the path exists. If you see Circular extends detected, your config chain loops back on itself — remove the circular reference.
Runtime Errors
Section titled “Runtime Errors”Console warning: “Missing translation for {id}”
Section titled “Console warning: “Missing translation for {id}””[fluenti] Missing translation for "abc123" in locale "ja"This means the message ID exists in your source code but has no translation in the compiled catalog for the active locale. Common causes:
- Catalog not compiled — run
pnpm fluenti extract && pnpm fluenti compile - New message not extracted — the message was added after the last extraction
- Locale file incomplete — the
.poor.jsonfile for that locale is missing the entry
Plural forms not working correctly
Section titled “Plural forms not working correctly”Ensure you are passing a number to plural arguments, not a string:
// Correct -- numbert`{count, plural, one {# item} other {# items}}`, { count: 5 })
// Wrong -- string "5" won't match plural rulest`{count, plural, one {# item} other {# items}}`, { count: "5" })Custom formatter errors
Section titled “Custom formatter errors”[fluenti] Custom formatter "currency" threw for variable "price": ...A custom formatter registered via createFluentiCore({ formatters }) threw an error. The runtime catches the error and falls back to the raw value, but you should fix the formatter. Check that it handles all expected input types including undefined and null.
”locale must be a valid BCP 47 tag”
Section titled “”locale must be a valid BCP 47 tag””[fluenti] setLocale: locale must be a valid BCP 47 tag (e.g. "en", "en-US"), got "english"Fluenti validates locale strings against a BCP 47 pattern. Use standard codes like en, en-US, zh-CN, or ja — not full language names.
”No messages for locale and no loadMessages function”
Section titled “”No messages for locale and no loadMessages function””[fluenti] No messages for locale "fr" and no loadMessages function providedYou called setLocale('fr') but no messages are loaded for that locale and no dynamic loader is configured. Either:
- Pre-load messages for all locales at startup
- Configure
loadMessagesin your provider/plugin options so catalogs are loaded on demand - Ensure
fris listed in thelocalesarray influenti.config.ts
SSR and Hydration
Section titled “SSR and Hydration”Hydration mismatch after locale switch
Section titled “Hydration mismatch after locale switch”The server and client are resolving different locales. This typically happens when the locale is stored in localStorage (not visible to the server).
See Best Practices — SSR & Hydration for the recommended setup.
window.__FLUENTI_LOCALE__ is undefined on the client
Section titled “window.__FLUENTI_LOCALE__ is undefined on the client”The SSR locale script was not injected into the HTML. Ensure you call getSSRLocaleScript() and include the result in your HTML template:
import { getSSRLocaleScript } from '@fluenti/core'
// In your server handler:const html = ` <head> ${getSSRLocaleScript(detectedLocale)} </head>`On the client, getHydratedLocale() reads this value. If the script tag is missing, it falls back to 'en'.
SSR locale detection priority
Section titled “SSR locale detection priority”detectLocale() checks sources in this order: cookie > query > path > Accept-Language header > fallback. If the wrong locale is being detected:
- Check that the cookie value is a valid BCP 47 tag
- Verify the
availablearray contains the expected locale codes - Inspect the
Accept-Languageheader — it may contain unexpected preferences
import { detectLocale } from '@fluenti/core'
const locale = detectLocale({ cookie: getCookie('locale'), headers: request.headers, available: ['en', 'ja', 'zh-CN'], fallback: 'en',})Multi-instance SSR key collisions
Section titled “Multi-instance SSR key collisions”If you run multiple Fluenti instances on the same page (e.g. micro-frontends), use unique keys:
// ServergetSSRLocaleScript('ja', { key: '__MY_APP_LOCALE__' })
// ClientgetHydratedLocale('en', { key: '__MY_APP_LOCALE__' })The key must be a valid JavaScript identifier (letters, numbers, _, $).
Code Splitting
Section titled “Code Splitting”Lazy-loaded locale chunks fail to load
Section titled “Lazy-loaded locale chunks fail to load”If you see network errors loading locale chunks in production:
- Check base path — if your app is deployed under a subpath, ensure
baseis set invite.config.ts - Check server routing — the server must serve
.jschunk files from the build output directory - Preload critical locales — call
preloadLocale()early to avoid waterfall requests
Stale chunks after deployment
Section titled “Stale chunks after deployment”After deploying a new version, users with cached HTML may request old chunk filenames that no longer exist. Configure your server to return the current HTML for chunk 404s, or use a service worker to handle cache invalidation.
Next.js
Section titled “Next.js””withFluenti() must be configured in next.config.ts”
Section titled “”withFluenti() must be configured in next.config.ts””[fluenti] `withFluenti()` must be configured in next.config.tsbefore importing from "@fluenti/next".The @fluenti/next package exports runtime stubs that throw this error. At build time, webpack replaces @fluenti/next imports with a generated server module via resolve.alias. This error means the alias is not active — typically because withFluenti() is missing from next.config.ts:
import { withFluenti } from '@fluenti/next'export default withFluenti()({ reactStrictMode: true })Compiled catalogs not found warning
Section titled “Compiled catalogs not found warning”[fluenti] Compiled catalogs not found at src/locales/compiled.Run: npx fluenti extract && npx fluenti compileThis is a startup warning, not a build failure. It means the compiled output directory does not exist yet. Run the suggested commands, or rely on buildAutoCompile: true (the default) to compile automatically during production builds.
Turbopack loader conflicts
Section titled “Turbopack loader conflicts”[fluenti] Your turbopack.rules override Fluenti's loader for: *.tsx, *.ts.Fluenti's t`` transform will NOT run on these file types.Your custom turbopack.rules in next.config.ts override the rules that Fluenti adds. Fluenti’s rules are applied first and then merged with yours, with your rules taking precedence. Either remove the conflicting rules or integrate Fluenti’s loader into your custom rule configuration.
Webpack loader transform failures
Section titled “Webpack loader transform failures”[fluenti] Transform failed in /app/components/Header.tsx: ...The webpack loader that transforms t` ` calls encountered an error. Common causes:
- Syntax error in source file — fix the TypeScript/JSX syntax first
- Unsupported pattern — the loader only transforms
t` `,t(),<Trans>,<Plural>, and<Select>patterns - Conflicting Babel/SWC transforms — another loader may have transformed the code before Fluenti’s loader reaches it. Set
loaderEnforce: 'pre'(the default) to ensure Fluenti runs first
Server components and 'use client'
Section titled “Server components and 'use client'”The Fluenti loader detects whether a file is a server component or client component:
- Files with
'use client'use the client-sideuseI18nhook - Files under
app/without'use client'use the server-sidegetServerI18n
If translations are not rendering in a server component, verify that the file does not have 'use client' at the top. If you need translations in a client component, ensure I18nProvider wraps your app in the root layout.
Module not registered
Section titled “Module not registered”If Fluenti features are not available in your Nuxt app, verify the module is added to nuxt.config.ts:
export default defineNuxtConfig({ modules: ['@fluenti/nuxt'], fluenti: { locales: ['en', 'ja'], defaultLocale: 'en', },})The module name must be the string '@fluenti/nuxt', not a path to the package.
SSR context errors with useCookie
Section titled “SSR context errors with useCookie”useCookie failed outside Nuxt contextFluenti’s Nuxt locale detection uses useCookie() internally, which must be called within a Nuxt composable context (setup function, middleware, or plugin). If you are calling locale detection code outside these contexts (e.g. in a standalone utility function), wrap it in callWithNuxt() or restructure your code to run within the Nuxt lifecycle.
Locale detection not working
Section titled “Locale detection not working”Nuxt uses a priority chain for locale detection: cookie, navigator language, default locale. If the detected locale is unexpected:
- Check browser cookies — look for the locale cookie (default name:
i18n_locale) - Verify
detectBrowserLanguagesettings in your module config - Test with the cookie explicitly set:
document.cookie = 'i18n_locale=ja'
Vite plugin loaded twice
Section titled “Vite plugin loaded twice”If you see duplicate translations or build warnings, ensure you are not adding the Vite plugin manually in nuxt.config.ts when using @fluenti/nuxt. The Nuxt module adds the Vite plugin automatically. Remove any manual fluentiVue() calls from your Vite plugins.
TypeScript Errors
Section titled “TypeScript Errors”TypeScript errors with message IDs
Section titled “TypeScript errors with message IDs”If your IDE shows type errors for message IDs, regenerate the type declarations:
pnpm fluenti compileThis generates messages.d.ts in your compileOutDir. Ensure your tsconfig.json includes it:
{ "include": ["src", "src/locales/compiled/messages.d.ts"]}“Cannot find module ‘virtual:fluenti/runtime’”
Section titled ““Cannot find module ‘virtual:fluenti/runtime’””TypeScript does not know about virtual modules by default. Add a type declaration file:
// src/env.d.ts or src/vite-env.d.tsdeclare module 'virtual:fluenti/runtime' { export const t: import('@fluenti/core').CompileTimeT export function setLocale(locale: string): Promise<void> export function preloadLocale(locale: string): Promise<void>}The exact exports depend on your framework. Check the generated runtime module for the full list.
Type mismatch with verbatimModuleSyntax
Section titled “Type mismatch with verbatimModuleSyntax”If you see errors like Re-exporting a type when 'verbatimModuleSyntax' is enabled, ensure all type-only re-exports use export type:
// Correctexport type { Locale, Messages } from '@fluenti/core'
// Wrong with verbatimModuleSyntaxexport { Locale, Messages } from '@fluenti/core'Fluenti packages follow verbatimModuleSyntax conventions. If you see this error in your own code, add the type keyword to the re-export.
Generic type constraints with t()
Section titled “Generic type constraints with t()”The t() function and t` ` tagged template have different type signatures. The tagged template form is preferred for compile-time optimization. If TypeScript complains about argument types with t(), check that you are passing values as a plain object:
// Correctt('greeting', { name: 'World' })
// Wrong -- second argument must be an objectt('greeting', 'World')PO File and Catalog Issues
Section titled “PO File and Catalog Issues”PO file encoding issues
Section titled “PO file encoding issues”PO files must be saved as UTF-8 without BOM. Some editors (notably older versions of Poedit on Windows) may add a BOM, which can cause parsing errors.
Check your file encoding:
file locales/ja.po# Should output: UTF-8 Unicode textVite HMR not picking up catalog changes
Section titled “Vite HMR not picking up catalog changes”If translations are not updating during development, check that devAutoCompile is enabled (it is by default):
fluentiVue({ devAutoCompile: true })Also verify that your source files match the include patterns in fluenti.config.ts. The dev watcher monitors source files for changes and triggers re-extraction and compilation automatically.
If HMR still does not work, check the terminal for warnings:
[fluenti] Extract/compile failed: ...These warnings indicate the auto-compile step failed silently. Fix the reported error and save again.
Migration Issues
Section titled “Migration Issues”Migrating from vue-i18n
Section titled “Migrating from vue-i18n”Use the @fluenti/vue-i18n-compat bridge package for gradual migration:
pnpm add @fluenti/vue-i18n-compatThe compat package provides useI18n() and $t() with a vue-i18n-compatible API that delegates to Fluenti under the hood. You can migrate file by file:
- Install
@fluenti/vue-i18n-compatalongsidevue-i18n - Switch imports from
vue-i18nto@fluenti/vue-i18n-compatone component at a time - Replace
$t('key')calls witht`message`tagged templates - Remove
@fluenti/vue-i18n-compatonce migration is complete
Common pitfalls during migration:
- Named interpolation syntax differs: vue-i18n uses
{name}, Fluenti uses the same ICU syntax{name}— but plural syntax is different. vue-i18n uses{'|'}pipe syntax, while Fluenti uses ICU{count, plural, one {...} other {...}} - Locale messages structure: vue-i18n uses nested JSON objects (
messages.en.greeting), Fluenti uses flat PO catalogs or compiled modules. Runpnpm fluenti migrateif available, or convert manually
Migrating from other i18n libraries
Section titled “Migrating from other i18n libraries”General steps for migrating from react-intl, i18next, or similar libraries:
- Extract messages — export your existing messages to JSON or PO format
- Map to ICU format — Fluenti uses standard ICU MessageFormat. Most libraries use a subset of ICU, so conversion is usually straightforward
- Replace API calls:
intl.formatMessage({ id })becomest`message text`<FormattedMessage id="..." />becomes<Trans>message text</Trans>t('key', { count })becomest`{count, plural, one {# item} other {# items}}`
- Update configuration — replace library-specific config with
fluenti.config.ts - Test thoroughly — run extraction and compilation, then verify all translated strings render correctly
Performance
Section titled “Performance”Large catalog causing slow startup
Section titled “Large catalog causing slow startup”If your app has thousands of messages and startup feels slow:
- Enable code splitting — set
splitting: 'dynamic'in your plugin config to load only the messages needed for the current route - Preload strategically — use
preloadLocale()to load the next most likely locale in the background - Check cache size — the default LRU cache holds 500 compiled messages. For very large apps, increase it:
import { setMessageCacheSize } from '@fluenti/core'setMessageCacheSize(1000)Memory usage on long-running servers
Section titled “Memory usage on long-running servers”For Node.js servers handling many locales, the compiled message cache can grow. Call clearInterpolationCache() periodically or during low-traffic periods:
import { clearInterpolationCache } from '@fluenti/core'
// Clear cache every hoursetInterval(() => clearInterpolationCache(), 60 * 60 * 1000)Getting Help
Section titled “Getting Help”If your issue is not covered here:
- Search the GitHub Issues for similar problems
- Enable diagnostics (
warnMissing: true,warnFallback: true) for detailed runtime warnings - Check the browser console and terminal for
[fluenti]-prefixed warnings - Open a new issue with your Fluenti version, framework, and a minimal reproduction