Skip to content
fluenti

Configuration

Fluenti uses a fluenti.config.ts file at your project root. It is auto-loaded via jiti — no build step needed.

fluenti.config.ts
import { defineConfig } from '@fluenti/cli'
export default defineConfig({
sourceLocale: 'en',
locales: ['en', 'zh-CN', 'ja'],
catalogDir: './locales',
format: 'po',
include: ['./src/**/*.vue', './src/**/*.tsx', './src/**/*.jsx', './src/**/*.ts'],
exclude: ['./src/**/*.test.*'],
compileOutDir: './src/locales/compiled',
fallbackChain: { 'zh-TW': ['zh-CN', 'en'], '*': ['en'] },
splitting: 'dynamic',
defaultBuildLocale: 'en',
})

defineConfig is an identity function that provides full type inference and IDE autocompletion for all config options.

OptionTypeDefaultDescription
sourceLocalestring'en'The locale used in source code
localesLocaleDefinition[]['en']All target locales. Each entry can be a string ('en') or an object ({ code: 'en', name: 'English' })
catalogDirstring'./locales'Directory for translation catalogs
format'json' | 'po''po'Catalog file format. PO is recommended — compatible with Poedit, Weblate, Crowdin and other translation tools
includestring[]['./src/**/*.vue', './src/**/*.tsx', './src/**/*.jsx']Glob patterns for source files
excludestring[]['./src/**/*.test.*']Glob patterns to exclude
compileOutDirstring'./src/locales/compiled'Output directory for compiled messages
fallbackChainRecord<string, string[]>{}Locale fallback chains
splitting'dynamic' | 'static' | falsefalseCode-splitting strategy
defaultBuildLocalestring?Default locale embedded in the bundle
devWarningsboolean?Enable development-mode warnings for missing translations and format errors
extendsstring?Path to parent config file for monorepo inheritance
defaultLocalestring?Default locale for routing/detection (defaults to sourceLocale)
parallelCompileboolean?falseEnable parallel compilation using worker threads
idGenerator(message: string, context?: string) => stringCustom message ID hash function
catalogExtensionstring?'.js'File extension for compiled catalog output files
devAutoCompileboolean?trueAuto extract+compile in dev mode
buildAutoCompileboolean?trueAuto extract+compile before production build
devAutoCompileDelaynumber?500Debounce delay in ms for dev auto-compile
onBeforeCompile() => boolean | void | Promise<...>Lifecycle hook called before auto-compile
onAfterCompile() => void | Promise<void>Lifecycle hook called after auto-compile
POJSON
Best forTeams with translators, Crowdin/WeblateSolo devs, programmatic manipulation
ToolingPoedit, Crowdin, Weblate, LokaliseAny text editor, jq
CommentsFirst-class #. translator commentNot supported
RecommendationDefault choice for productionQuick prototyping

Compiled catalogs are build artifacts. Regenerate them in CI instead of committing:

.gitignore
locales/compiled/

For the full API reference, see @fluenti/cli and @fluenti/vite-plugin.

Use the extends option to inherit from a shared base config:

packages/app-web/fluenti.config.ts
export default defineConfig({
extends: '../../fluenti.config.ts',
include: ['./src/**/*.tsx', './src/**/*.ts'],
splitting: 'dynamic',
})

Child configs inherit all options from the parent and can override any field. Relative paths in the parent are automatically rebased to the child’s directory.

See Scaling & Enterprise for a full monorepo setup guide.

Enable parallel compilation and incremental caching for large projects:

export default defineConfig({
// ...
parallelCompile: true, // Worker threads for 5+ locales
devAutoCompileDelay: 1000, // Increase debounce for large codebases
})

Use --no-cache flags on extract and compile to force full rebuilds when needed. See Scaling & Enterprise for details.

Hook into the auto-compile process for custom build integration:

export default defineConfig({
// ...
onBeforeCompile: () => {
// Return false to skip compilation
console.log('Compiling translations...')
},
onAfterCompile: async () => {
// Post-compile: notifications, uploads, validation
},
})

See Scaling & Enterprise for details.

export default defineConfig({
sourceLocale: 'en',
locales: ['en', 'ja', 'zh-CN'],
catalogDir: './locales',
format: 'po',
include: ['./src/**/*.vue', './src/**/*.ts'],
compileOutDir: './src/locales/compiled',
})
export default defineConfig({
sourceLocale: 'en',
locales: ['en', 'es', 'fr'],
catalogDir: './locales',
format: 'po',
include: ['./src/**/*.tsx', './src/**/*.jsx', './src/**/*.ts'],
compileOutDir: './src/locales/compiled',
splitting: 'dynamic',
})
export default defineConfig({
sourceLocale: 'en',
locales: ['en', 'ja'],
catalogDir: './locales',
format: 'po',
include: ['./app/**/*.tsx', './components/**/*.tsx'],
compileOutDir: './src/locales/compiled',
})
export default defineConfig({
sourceLocale: 'en',
locales: ['en', 'fr', 'de'],
catalogDir: './locales',
format: 'po',
include: ['./components/**/*.vue', './pages/**/*.vue', './layouts/**/*.vue'],
compileOutDir: './locales/compiled',
})

Fluenti provides strict type safety for translation calls via the FluentiTypeConfig interface and auto-generated type declarations.

When you run fluenti compile, Fluenti generates a messages.d.ts file alongside your compiled catalogs. This file narrows the t() function signature to only accept valid message IDs and their expected interpolation values:

// locales/compiled/messages.d.ts (auto-generated)
declare module '@fluenti/core' {
interface FluentiTypeConfig {
messageIds: 'greeting' | 'item_count' | 'welcome_back'
messageValues: {
greeting: { name: string }
item_count: { count: number }
welcome_back: Record<string, never>
}
}
}

After compilation, your IDE will autocomplete message IDs and flag missing or incorrect interpolation values:

const { t } = useI18n()
t('greeting', { name: 'Alice' }) // ✅ Valid
t('greeting', {}) // ❌ Missing required 'name'
t('unknown_key') // ❌ Not a valid message ID
  1. Run fluenti compile to generate the type declarations
  2. Ensure compileOutDir is included in your tsconfig.json:
{
"compilerOptions": {
"strict": true,
"verbatimModuleSyntax": true
},
"include": ["src", "locales/compiled"]
}

The types update automatically on each fluenti compile run. In dev mode with devAutoCompile: true (the default), types stay in sync as you edit messages.

The FluentiTypeConfig interface has three fields you can augment:

FieldDefaultPurpose
localizedStringLocalizedString (branded)The return type of t(). Override to string to disable the branded type
messageIdsstringUnion of all valid message IDs (auto-narrowed by messages.d.ts)
messageValuesRecord<string, Record<string, unknown>>Map of message ID → interpolation values (auto-narrowed by messages.d.ts)

By default, t() returns a LocalizedString branded type — a string that has been marked as translated. This prevents accidentally passing untranslated strings where translated ones are expected.

If this is too strict for your project, disable it:

fluenti.d.ts
declare module '@fluenti/core' {
interface FluentiTypeConfig {
localizedString: string
}
}

For more on type safety at scale, see Scaling & Enterprise. For type-safe message authoring patterns, see Best Practices.