{"id":30420688,"url":"https://github.com/macabeus/fluent-typescript","last_synced_at":"2025-08-22T08:19:53.399Z","repository":{"id":51480555,"uuid":"256850364","full_name":"macabeus/fluent-typescript","owner":"macabeus","description":"📦 Automatically generate TypeScript declarations for Fluent files","archived":false,"fork":false,"pushed_at":"2021-05-11T17:31:19.000Z","size":1906,"stargazers_count":14,"open_issues_count":12,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-29T08:56:12.065Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/macabeus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-18T20:49:28.000Z","updated_at":"2025-04-30T15:12:08.000Z","dependencies_parsed_at":"2022-08-21T08:10:46.833Z","dependency_job_id":null,"html_url":"https://github.com/macabeus/fluent-typescript","commit_stats":null,"previous_names":["macabeus/fluent-typescript-loader"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/macabeus/fluent-typescript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macabeus%2Ffluent-typescript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macabeus%2Ffluent-typescript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macabeus%2Ffluent-typescript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macabeus%2Ffluent-typescript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/macabeus","download_url":"https://codeload.github.com/macabeus/fluent-typescript/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/macabeus%2Ffluent-typescript/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271606604,"owners_count":24788981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-22T08:19:53.335Z","updated_at":"2025-08-22T08:19:53.390Z","avatar_url":"https://github.com/macabeus.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fluent-typescript\n\u003e 📦 Generate automatically TypeScript declarations for Fluent files\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/9501115/79704023-26c7d080-82a7-11ea-962e-82b90bdf89f1.png\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/9501115/79704154-e3ba2d00-82a7-11ea-988e-c0d568a46015.png\"\u003e\n\u003c/p\u003e\n\n**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?\n\nFluent client supported:\n- [x] vanilla (just [`@fluent/bundle`](https://www.npmjs.com/package/@fluent/bundle))\n- [x] [`react-18next`](https://www.npmjs.com/package/react-i18next)\n- [x] [`fluent-react`](https://github.com/projectfluent/fluent.js/tree/master/fluent-react)\n\n\u003e :warning: It's a working in process project! At this moment, **you should not use it on production**!\n\n- [Official Fluent's website](https://projectfluent.org/)\n- [Fluent's Playground](https://projectfluent.org/play/)\n\n## How to use\n\nAs the first step, you need to install this package, of course:\n\n```\n\u003e npm install fluent-typescript --save-dev\n- or -\n\u003e yarn add fluent-typescript --dev\n```\n\nThe following steps depends on which Fluent client that you are using:\n\n### vanilla\n\n\u003e You could check a complete example on [`/example-vanilla`](/example-vanilla) folder. Check its readme.\n\nStep by step:\n\n1 - Add this script on your `package.json` config:\n\n```js\n{\n  \"scripts\": {\n    \"fluent-typescript\": \"./node_modules/.bin/fluent-typescript vanilla ./assets/locales/\"\n  }\n},\n```\n\nThe argument `./assets/locales/` is the path where the type definition file will be saved.\n\n2 - Run `fluent-typescript`:\n\n```\n\u003e npm run fluent-typescript\n```\n\nNow, your FTL files will be compiled into a `.d.ts`. The last remaining step is import it on our code.\n\n3 - Add a cast on `FluentBundle` call:\n\n```ts\nconst bundle = new FluentBundle('pt-br') as FluentBundleTyped\n```\n\nFinish! Now you have amazing types on your translations messages 🎉\n\n### react-18next\n\n\u003e You could check a complete example on [`/example-react-18next`](/example-react-18next) folder. Check its readme.\n\n1 - You also need to install `@fluent/bundle`\n\n```\n\u003e npm install @fluent/bundle --save-dev\n- or -\n\u003e yarn add @fluent/bundle --dev\n```\n\n2 - Add this script on your `package.json` config:\n\n```js\n{\n  \"scripts\": {\n    \"fluent-typescript\": \"./node_modules/.bin/fluent-typescript react-18next ./assets/locales/\"\n  }\n},\n```\n\nThe argument `./assets/locales/` is the path where the type definition file will be saved.\n\n3 - Run `fluent-typescript`:\n\n```\n\u003e npm run fluent-typescript\n```\n\nNow, 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!\n\n\u003e :warning: At this moment, it only works with `useTranslation`. Always when possible, prefer to use that instead of `Trans` or `withTranslation`, because you have type safe only with `t` function.\n\nFinish! Now you have amazing types on your translations messages 🎉\n\n### fluent-react\n\n\u003e You could check a complete example on [`/example-fluent-react`](/example-fluent-react) folder. Check its readme.\n\n1 - Add this script on your `package.json` config:\n\n```js\n{\n  \"scripts\": {\n    \"fluent-typescript\": \"./node_modules/.bin/fluent-typescript fluent-react ./assets/locales/\"\n  }\n},\n```\n\nThe argument `./assets/locales/` is the path where the type definition file will be saved.\n\n2 - Run `fluent-typescript`:\n\n```\n\u003e npm run fluent-typescript\n```\n\nNow, your FTL files will be compiled into a `.d.ts`, and the type of `Localized` component from `@fluent/react` will be patched!\n\nTo use the patched version of `Localized`, you should add the prop `typed`. For example:\n\n```diff\n-\u003cLocalized id='hello' vars={{ firstName, lastName }}\u003e\n+\u003cLocalized typed id='hello' vars={{ firstName, lastName }}\u003e\n  \u003ch1\u003eHello!\u003c/h1\u003e\n\u003c/Localized\u003e\n```\n\n\u003e :warning: At this moment, it only works with `Localized`. Always when possible, prefer to use that instead of `useLocalization`, because you have type safe only with `Localized` component.\n\nFinish! Now you have amazing types on your translations messages 🎉\n\n## Flags\n\n### --no-watch\n\nIf you just want to emit the type definition, without running the watcher, you can use the flag `--no-watch`.\n\nFor instance:\n\n```\n\u003e fluent-typescript vanilla ./assets/locales/ --no-watcha\n```\n\n# How types are compiled\n\n## Asymmetric translations\n\n**tl;dr:** You should always use all variables that a message could need.\n\n**Detailed explanation:**\n\nLet'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:\n\n```ftl\n# locales/jp/translations.ftl\nhello = こんにちは{ $lastName }\n\n# locales/pt-br/translations.ftl\nhello = Olá { $firstName }\n```\n\nDespite 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:\n\n```ts\nbundle.formatPattern(helloMessage.value, { firstName: 'Macabeus', lastName: 'Aquino' }) // ok\nbundle.formatPattern(helloMessage.value, { firstName: 'Macabeus' }) // error\nbundle.formatPattern(helloMessage.value, { lastName: 'Aquino' }) // error\n```\n\nAnalogously on a message with selector. You should always use all variables:\n\n```ftl\naward =\n  { $place -\u003e\n     [first]  You won first! Your prize is { $amount } bitcoins\n    *[other] You won { $place }! Congratulations!\n  }\n```\n\n```ts\nbundle.formatPattern(helloMessage.value, { place: 'first', amount: 0.1 }) // ok\nbundle.formatPattern(helloMessage.value, { place: 'second', amount: 0 }) // ok\nbundle.formatPattern(helloMessage.value, { place: 'first' }) // error\nbundle.formatPattern(helloMessage.value, { place: 'second' }) // error\n```\n\n# Developing fluent-typescript\n\nWhen developing `fluent-typescript`, is important to build and watch, so you could check the changes automatically on the examples apps:\n\n```\n\u003e npm run start\n```\n\nCheck the readme on each example's folders to learn how to run them.\n\nYou also could and run tests:\n\n```\n\u003e npm run test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacabeus%2Ffluent-typescript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmacabeus%2Ffluent-typescript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacabeus%2Ffluent-typescript/lists"}