fluent-typescript
v0.0.6
Published
CLI tool to automatically generate TypeScript declarations for Fluent files
Downloads
3
Readme
fluent-typescript
📦 Generate automatically TypeScript declarations for Fluent files
Fluent is a Mozilla's programming language for natural-sounding translations. And fluent-typescript is a tool to automatically generate type definitions for its mensagens. So you'll have safer changes on your translates messages by types safes provided by TS. Never more will have a missing variable or forget to delete an old message. Sounds like magic, right?
Fluent client supported:
- [x] vanilla (just
@fluent/bundle
) - [x]
react-18next
- [x]
fluent-react
:warning: It's a working in process project! At this moment, you should not use it on production!
How to use
As the first step, you need to install this package, of course:
> npm install fluent-typescript --save-dev
- or -
> yarn add fluent-typescript --dev
The following steps depends on which Fluent client that you are using:
vanilla
You could check a complete example on
/example-vanilla
folder. Check its readme.
Step by step:
1 - Add this script on your package.json
config:
{
"scripts": {
"fluent-typescript": "./node_modules/.bin/fluent-typescript vanilla ./assets/locales/"
}
},
The argument ./assets/locales/
is the path where the type definition file will be saved.
2 - Run fluent-typescript
:
> npm run fluent-typescript
Now, your FTL files will be compiled into a .d.ts
. The last remaining step is import it on our code.
3 - Add a cast on FluentBundle
call:
const bundle = new FluentBundle('pt-br') as FluentBundleTyped
Finish! Now you have amazing types on your translations messages 🎉
react-18next
You could check a complete example on
/example-react-18next
folder. Check its readme.
1 - You also need to install @fluent/bundle
> npm install @fluent/bundle --save-dev
- or -
> yarn add @fluent/bundle --dev
2 - Add this script on your package.json
config:
{
"scripts": {
"fluent-typescript": "./node_modules/.bin/fluent-typescript react-18next ./assets/locales/"
}
},
The argument ./assets/locales/
is the path where the type definition file will be saved.
3 - Run fluent-typescript
:
> npm run fluent-typescript
Now, your FTL files will be compiled into a .d.ts
, and the type of t
function returned by useTranslation
will be patched, working out-of-the-box!
:warning: At this moment, it only works with
useTranslation
. Always when possible, prefer to use that instead ofTrans
orwithTranslation
, because you have type safe only witht
function.
Finish! Now you have amazing types on your translations messages 🎉
fluent-react
You could check a complete example on
/example-fluent-react
folder. Check its readme.
1 - Add this script on your package.json
config:
{
"scripts": {
"fluent-typescript": "./node_modules/.bin/fluent-typescript fluent-react ./assets/locales/"
}
},
The argument ./assets/locales/
is the path where the type definition file will be saved.
2 - Run fluent-typescript
:
> npm run fluent-typescript
Now, your FTL files will be compiled into a .d.ts
, and the type of Localized
component from @fluent/react
will be patched!
To use the patched version of Localized
, you should add the prop typed
. For example:
-<Localized id='hello' vars={{ firstName, lastName }}>
+<Localized typed id='hello' vars={{ firstName, lastName }}>
<h1>Hello!</h1>
</Localized>
:warning: At this moment, it only works with
Localized
. Always when possible, prefer to use that instead ofuseLocalization
, because you have type safe only withLocalized
component.
Finish! Now you have amazing types on your translations messages 🎉
Flags
--no-watch
If you just want to emit the type definition, without running the watcher, you can use the flag --no-watch
.
For instance:
> fluent-typescript vanilla ./assets/locales/ --no-watcha
How types are compiled
Asymmetric translations
tl;dr: You should always use all variables that a message could need.
Detailed explanation:
Let's say that we have a hello
message on our application and we should translate that to Japanese and Portuguese. Since in Japanese is more common to use the last name, and in Portuguese is more natural to use the first name, we'll have that:
# locales/jp/translations.ftl
hello = こんにちは{ $lastName }
# locales/pt-br/translations.ftl
hello = Olá { $firstName }
Despite that in practice we could just use firstName
or lastName
, our type definition file want to be most safe that could, so you'll always need to use all possibles arguments required by a message:
bundle.formatPattern(helloMessage.value, { firstName: 'Macabeus', lastName: 'Aquino' }) // ok
bundle.formatPattern(helloMessage.value, { firstName: 'Macabeus' }) // error
bundle.formatPattern(helloMessage.value, { lastName: 'Aquino' }) // error
Analogously on a message with selector. You should always use all variables:
award =
{ $place ->
[first] You won first! Your prize is { $amount } bitcoins
*[other] You won { $place }! Congratulations!
}
bundle.formatPattern(helloMessage.value, { place: 'first', amount: 0.1 }) // ok
bundle.formatPattern(helloMessage.value, { place: 'second', amount: 0 }) // ok
bundle.formatPattern(helloMessage.value, { place: 'first' }) // error
bundle.formatPattern(helloMessage.value, { place: 'second' }) // error
Developing fluent-typescript
When developing fluent-typescript
, is important to build and watch, so you could check the changes automatically on the examples apps:
> npm run start
Check the readme on each example's folders to learn how to run them.
You also could and run tests:
> npm run test