Vite plugin to transform Fluent files into JavaScript modules with inferred TypeScript types. Never typo a translation key or translation argument again!
pnpm install vite-plugin-fluent
# or using npm or yarn
npm install vite-plugin-fluent
yarn add vite-plugin-fluent
Configure the Vite plugin in your vite.config.ts
file. The plugin accepts no
options.
import { defineConfig } from "vite";
import { fluent } from "vite-plugin-fluent";
export default defineConfig({
plugins: [fluent()],
});
You can now import the Fluent file in your JavaScript or TypeScript files. The
plugin generates the corresponding FluentResource
object, and a fully
type-safe formatMessage
specific to the imported Fluent file.
# app.ftl
greet = Hello, { $name }!
import { resource, formatMessage } from "./app.ftl";
import { FluentBundle } from "@fluent/bundle";
const bundle = new FluentBundle("en-US");
bundle.addResource(resource);
// 100% type-safe!
const message = formatMessage(bundle, "greet", { name: "World" });
// The following will cause a type error because age is not a valid argument
const message = formatMessage(bundle, "greet", { name: "World", age: 42 });
// The following will cause a type error because welcome is not a valid message
const message = formatMessage(bundle, "welcome", { name: "World" });
The generated types accept FluentVariable
from @fluent/bundle
as the input
to all message functions. This means we can pass strings, dates, numbers, and
even temporal objects. It also supports FluentType<T>
.
When a Fluent message has no variable expressions, the plugin will infer the
arguments as none. This means that the formatMessage
function will not accept
arguments as its third argument, and the optional Error list will instead be
the third argument.
demo = Look ma', no arguments!
formatMessage(bundle, "demo");
Fluent supports message attributes to add sub-messages to a translation message for better organization. The plugin will provide the attribute messages as "dot indexed" keys.
choices = What do you want to do?
.create = Create a new document
.open = Open an existing document
formatMessage(bundle, "choices");
formatMessage(bundle, "choices.create");
formatMessage(bundle, "choices.open");
See the integration test suite files for complete examples of FTL inputs and generated TypeScript .d.ts output.
The plugin uses both the Fluent parser, and the TypeScript compiler API in order to parse the Fluent file, and generate the corresponding TypeScript types.
Whenever a .ftl
file is imported, the plugin performs the transform, as well
as outputting a .d.ts
file with the corresponding types next to the .ftl
file. These .d.ts
files do not need to be committed to version control, but
they are required for tsc
to type-check the project. Therefore we suggest
adding them to git.
The plugin is easiest to test using the setup in the e2e folder. For this, you'll want to link the plugin to the e2e folder.
cd e2e
pnpm link ..
# Start the Vite server
pnpm dev
The plugin also has good test coverage over the generated types and code, all of which are runnable through Vitest.
pnpm test
The project is licensed under the Apache 2.0 License