Fluent Vue Internationalization Unplugin
unplugin-fluent-vue is a build tool plugin that integrates Fluent.js for internationalization (i18n) into Vue.js projects. It provides support for defining Fluent messages directly within Vue Single File Components (SFCs) using custom blocks, or by referencing external `.ftl` (Fluent Translation List) files. It currently stands at version 1.4.1 and sees regular maintenance releases, with the latest update in April 2026. This unplugin differentiates itself by offering a unified API for Vite, Webpack, and Rollup, leveraging the unplugin ecosystem. Key features include syntax checking for Fluent messages, optional in-build FTL parsing, and dedicated plugins for SFC-based or external file-based message definitions, making it a flexible choice for Vue i18n with Fluent.
Common errors
-
Error: Cannot find module 'unplugin-fluent-vue/vite'
cause Incorrect bundler-specific import path or missing unplugin-fluent-vue package.fixEnsure 'unplugin-fluent-vue' is installed. Verify the import path matches your bundler (e.g., `/vite` for Vite, `/webpack` for Webpack). -
Failed to resolve import "@fluent/vue" from "src/main.js". The package "@fluent/vue" is not exported by "node_modules/unplugin-fluent-vue/package.json"
cause Attempting to import `@fluent/vue` from `unplugin-fluent-vue`. They are separate packages.fixInstall `@fluent/vue` as a direct dependency: `npm install @fluent/vue` and import from `@fluent/vue` instead. -
[unplugin-fluent-vue] No locales defined for ExternalFluentPlugin.
cause The `locales` option is missing or empty in the `ExternalFluentPlugin` configuration.fixProvide an array of locale strings to the `locales` option, e.g., `locales: ['en', 'es']`. -
[Vue warn]: A plugin must either be an object with an install method or a function. Did you forget to call .use()?
cause Attempting to use `unplugin-fluent-vue`'s build-time plugins directly as a Vue plugin.fixThe plugins from `unplugin-fluent-vue` are for your build configuration (e.g., `vite.config.js`). For runtime Vue integration, use `@fluent/vue` and its `createFluent` function.
Warnings
- gotcha The import path for the unplugin changes based on your bundler. Ensure you use `/vite`, `/webpack`, or `/rollup` suffix for the import.
- breaking The `parseFtl` option for `SFCFluentPlugin` and `ExternalFluentPlugin` was introduced in v1.4.0. Prior versions did not support build-time parsing of FTL, relying solely on runtime parsing.
- gotcha If you are using this plugin with Nuxt, you must ensure `@nuxt/kit` is installed, although it's listed as an optional peer dependency. Without it, the Nuxt module integration will not function.
- gotcha The plugin's primary role is build-time transformation. You still need the `@fluent/vue` package for the runtime integration within your Vue application (e.g., `useFluent`, `$t`).
Install
-
npm install unplugin-fluent-vue -
yarn add unplugin-fluent-vue -
pnpm add unplugin-fluent-vue
Imports
- SFCFluentPlugin
import { SFCFluentPlugin } from 'unplugin-fluent-vue'import { SFCFluentPlugin } from 'unplugin-fluent-vue/vite' - ExternalFluentPlugin
import { ExternalFluentPlugin } from 'unplugin-fluent-vue'import { ExternalFluentPlugin } from 'unplugin-fluent-vue/webpack' - FluentVue
import { FluentVue } from 'unplugin-fluent-vue'import FluentVue from '@fluent/vue'
Quickstart
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { ExternalFluentPlugin, SFCFluentPlugin } from 'unplugin-fluent-vue/vite';
import path from 'path';
export default defineConfig({
plugins: [
vue(),
// Option 1: Define messages within Vue SFCs using <fluent> blocks
SFCFluentPlugin({
blockType: 'fluent', // default 'fluent'
checkSyntax: true, // default true
parseFtl: false // default false
}),
// Option 2: Define messages in external .ftl files
ExternalFluentPlugin({
baseDir: path.resolve(__dirname, 'src'), // required: base directory for Vue files
ftlDir: path.resolve(__dirname, 'src/locales'), // required: directory with ftl files
locales: ['en', 'da'], // required: list of supported locales
checkSyntax: true, // default true
parseFtl: false // default false. Set to true to pre-parse ftl at build time.
})
]
});
// Example Vue SFC (src/App.vue):
// <template>
// <p>{{ $t('greeting', { name: 'World' }) }}</p>
// </template>
// <script setup>
// import { useFluent } from 'fluent-vue';
// const { $t } = useFluent();
// </script>
// <fluent>
// greeting = Hello, { $name }!
// </fluent>
// Example FTL file (src/locales/en/messages.ftl):
// greeting = Hello, { $name } from FTL!