From 0fceb7cca00b7f458604d3c577c83122ea6a67b9 Mon Sep 17 00:00:00 2001 From: cpojer Date: Thu, 12 Dec 2024 11:23:46 +0900 Subject: [PATCH] Build improvements. --- .gitignore | 2 + README.md | 77 +++++++++++++++---- ...g_started_on_web.md => getting_started.md} | 0 package.json | 3 +- packages/babel-plugin-fbtee/src/JSFbtUtil.tsx | 2 +- .../src/{Types.tsx => Types.d.ts} | 0 .../src/bin/FbtCollector.tsx | 2 +- .../src/bin/TextPackager.tsx | 2 +- .../src/bin/translateUtils.tsx | 2 +- packages/babel-plugin-fbtee/src/index.tsx | 2 +- .../replaceClearTokensWithTokenAliases.tsx | 2 +- .../src/translate/FbtSite.tsx | 2 +- .../src/translate/FbtSiteBase.tsx | 2 +- .../src/translate/TranslationBuilder.tsx | 2 +- packages/fbtee/src/FbtResult.tsx | 4 +- packages/fbtee/src/FbtResultBase.tsx | 4 +- packages/fbtee/src/FbtTable.tsx | 2 +- packages/fbtee/src/Hooks.tsx | 4 +- packages/fbtee/src/{Types.tsx => Types.d.ts} | 0 packages/fbtee/src/__mocks__/getFbtResult.tsx | 2 +- .../fbtee/src/__tests__/FbtResult-test.tsx | 2 +- packages/fbtee/src/__tests__/fbt-test.tsx | 4 +- packages/fbtee/src/fbt.tsx | 2 +- packages/fbtee/src/getAllSubstitutions.tsx | 2 +- packages/fbtee/src/getFbsResult.tsx | 2 +- packages/fbtee/src/index.tsx | 4 +- packages/fbtee/src/init.tsx | 2 +- packages/fbtee/src/substituteTokens.tsx | 2 +- 28 files changed, 96 insertions(+), 40 deletions(-) rename docs/{getting_started_on_web.md => getting_started.md} (100%) rename packages/babel-plugin-fbtee/src/{Types.tsx => Types.d.ts} (100%) rename packages/fbtee/src/{Types.tsx => Types.d.ts} (100%) diff --git a/.gitignore b/.gitignore index 469d56dd..ab6d2e11 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ example/src/translatedFbts example/src/translatedFbts.json node_modules packages/*/lib +packages/*/LICENSE +packages/*/README.md packages/fbt/lib packages/fbt/LICENSE tsconfig.tsbuildinfo diff --git a/README.md b/README.md index 8b8dce34..0fedcb8d 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,74 @@ -

- fbt -

+# fbtee -**fbtee** (Far Better Translations, Extended Edition) is an internationalization framework for JavaScript designed to be **powerful**, **flexible**, and **intuitive**. +**fbtee** (Far Better Translations, _Extended Edition_) is an internationalization framework for JavaScript & React designed to be **powerful**, **flexible**, and **intuitive**. -It helps with the following: +## Why fbtee? -- - -* Organizing your source text for translation -* Composing grammatically correct translatable User Interfaces -* Eliminating verbose boilerplate for generating User Interfaces +- **Inline Translations for Better Developer Experience:** Embed translations directly into your code. No need to manage translation keys or wrap your code with `t()` functions. **fbtee** uses a compiler to extract strings from your code and prepare them for translation providers. +- **Proven in Production:** Built on Facebook's `fbt`, with over a decade of production usage, serving billions of users and one year of production usage in [Athena Crisis](https://athenacrisis.com). +- **Optimized Performance with IR:** Compiles translations into an Intermediate Representation (IR) for extracting strings, and optimizes the runtime output for performance. +- **Easy Setup:** Quick integration with tools like Babel and Vite means you can get started instantly. ## Status: Ready for Early Adopters -This is a fork of Facebook's original fbt library, which has been archived. The aim of this fork is to create the best and most modern internationalization library for JavaScript & React. +This is a fork of Facebook's original `fbt` library, which has been archived. The aim of this fork is to create the best and most modern internationalization library for JavaScript & React. + +## Getting Started + +```bash +npm install fbtee @nkzw/babel-fbtee +``` + +In your `vite.config.ts`: + +```ts +import fbteePreset from '@nkzw/babel-fbtee'; +import react from '@vitejs/plugin-react'; + +export default { + plugins: [ + react({ + babel: { + presets: [fbteePreset], + }, + }), + ], +}; +``` + +_You’re now ready to go!_ + +## Usage + +## What's better about fbtee than fbt? + +Facebook has done an amazing job with `fbt`, an internationalization library that has been successfully used in production at Facebook for over 10 years. Their work provided a strong foundation for modern localization tools. + +The open-source version of `fbt`, however, became unmaintained, difficult to set up, and incompatible with modern tools. It was eventually archived in November 2024. **fbtee** builds on this foundation with several improvements: + +- **Easier Setup:** fbtee works with modern tools like Vite. +- **Improved React Compatibility:** Removed React-specific hacks and added support for implicit React fragments (`<>`). +- **Enhanced Features:** Fixed and exported `intlList`, which was not functional in the original `fbt`. +- **Modernized Codebase:** Rewritten using TypeScript, ES modules (ESM), eslint, and modern JavaScript standards. Removed cruft and legacy code. +- **Updated Tooling:** Uses modern tools like pnpm, Vite, and esbuild for faster and more efficient development of **fbtee**. + +**fbtee** remains compatible with `fbt` and migration is straightforward. + +## Migration from `fbt`: + +**fbtee** is compatible with `fbt`. If you are already using `fbt`, migrating to fbtee is straightforward: + +- Replace `import { fbt } from 'fbt'` with `import { fbt } from 'fbtee'`. +- Rename commands from `fbt-collect`, `fbt-manifest` and `fbt-translate` to `fbtee-collect`, `fbtee-manifest` and `fbtee-translate`. +- If you were using CommonJS modules for common strings or enums, convert them to ES modules. +- Ensure you are using the latest version of Node.js 22 or later. + +After these changes, your project should work seamlessly with **fbtee**. + +_Note: Some legacy behavior and options were removed from `fbtee`. If you have a complex setup, please consider [reaching out to us for help](mailto:fbtee@nakazawa.dev)._ ## Credits - `fbt` was originally created by [Facebook](https://github.com/facebook/fbt). -- The auto-import plugin was created by @alexandernanberg. -- [Nakazawa Tech](https://nkzw.tech) rewrote fbt into fbtee and is maintaining this project. +- The auto-import plugin was created by [@alexandernanberg](https://github.com/alexandernanberg). +- [Nakazawa Tech](https://nkzw.tech) rewrote `fbt` into `fbtee` and continues to maintain this project. diff --git a/docs/getting_started_on_web.md b/docs/getting_started.md similarity index 100% rename from docs/getting_started_on_web.md rename to docs/getting_started.md diff --git a/package.json b/package.json index fd0c9dc3..a74519bf 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "type": "module", "scripts": { "build": "pnpm -r build", - "build:all": "pnpm -r build && pnpm -r build:types && pnpm install && cd example && pnpm build:fbtee", + "build:all": "pnpm -r build && pnpm -r build:types && pnpm install && pnpm copy-files && cd example && pnpm build:fbtee", + "copy-files": "find packages/* -type d -maxdepth 0 -exec cp README.md LICENSE {} \\;", "clean": "rm -rf packages/*/lib; cd example pnpm clean", "dev": "cd example && pnpm build:fbtee && pnpm dev", "lint:format": "prettier --cache --check .", diff --git a/packages/babel-plugin-fbtee/src/JSFbtUtil.tsx b/packages/babel-plugin-fbtee/src/JSFbtUtil.tsx index e8b75fad..3731f339 100644 --- a/packages/babel-plugin-fbtee/src/JSFbtUtil.tsx +++ b/packages/babel-plugin-fbtee/src/JSFbtUtil.tsx @@ -5,7 +5,7 @@ import type { TableJSFBTTreeLeaf, } from './index.tsx'; import nullthrows from './nullthrows.tsx'; -import type { FbtTableKey } from './Types.tsx'; +import type { FbtTableKey } from './Types.d.ts'; export function isTableJSFBTTreeLeaf( value: Partial, diff --git a/packages/babel-plugin-fbtee/src/Types.tsx b/packages/babel-plugin-fbtee/src/Types.d.ts similarity index 100% rename from packages/babel-plugin-fbtee/src/Types.tsx rename to packages/babel-plugin-fbtee/src/Types.d.ts diff --git a/packages/babel-plugin-fbtee/src/bin/FbtCollector.tsx b/packages/babel-plugin-fbtee/src/bin/FbtCollector.tsx index da987b7c..2db091f3 100644 --- a/packages/babel-plugin-fbtee/src/bin/FbtCollector.tsx +++ b/packages/babel-plugin-fbtee/src/bin/FbtCollector.tsx @@ -13,7 +13,7 @@ import fbt, { getExtractedStrings, getFbtElementNodes, } from '../index.tsx'; -import type { PatternHash, PatternString } from '../Types.tsx'; +import type { PatternHash, PatternString } from '../Types.d.ts'; export type ExternalTransform = ( src: string, diff --git a/packages/babel-plugin-fbtee/src/bin/TextPackager.tsx b/packages/babel-plugin-fbtee/src/bin/TextPackager.tsx index 9aa6e90c..36289453 100644 --- a/packages/babel-plugin-fbtee/src/bin/TextPackager.tsx +++ b/packages/babel-plugin-fbtee/src/bin/TextPackager.tsx @@ -1,5 +1,5 @@ import { onEachLeaf } from '../JSFbtUtil.tsx'; -import type { PatternHash, PatternString } from '../Types.tsx'; +import type { PatternHash, PatternString } from '../Types.d.ts'; import type { HashToLeaf, PackagerPhrase } from './FbtCollector.tsx'; export type HashFunction = ( diff --git a/packages/babel-plugin-fbtee/src/bin/translateUtils.tsx b/packages/babel-plugin-fbtee/src/bin/translateUtils.tsx index 967ee81c..7747aeef 100644 --- a/packages/babel-plugin-fbtee/src/bin/translateUtils.tsx +++ b/packages/babel-plugin-fbtee/src/bin/translateUtils.tsx @@ -10,7 +10,7 @@ import TranslationBuilder from '../translate/TranslationBuilder.tsx'; import TranslationConfig from '../translate/TranslationConfig.tsx'; import type { SerializedTranslationData } from '../translate/TranslationData.tsx'; import TranslationData from '../translate/TranslationData.tsx'; -import type { PatternHash, PatternString } from '../Types.tsx'; +import type { PatternHash, PatternString } from '../Types.d.ts'; import type { CollectFbtOutput, CollectFbtOutputPhrase } from './collect.tsx'; export type Options = Readonly<{ diff --git a/packages/babel-plugin-fbtee/src/index.tsx b/packages/babel-plugin-fbtee/src/index.tsx index bf34549a..82e71d79 100644 --- a/packages/babel-plugin-fbtee/src/index.tsx +++ b/packages/babel-plugin-fbtee/src/index.tsx @@ -22,7 +22,7 @@ import FbtEnumRegistrar from './FbtEnumRegistrar.tsx'; import FbtNodeChecker from './FbtNodeChecker.tsx'; import { checkOption, errorAt } from './FbtUtil.tsx'; import { FbtVariationType } from './translate/IntlVariations.tsx'; -import { FbtTableKey, PatternHash, PatternString } from './Types.tsx'; +import type { FbtTableKey, PatternHash, PatternString } from './Types.d.ts'; export { SENTINEL } from './FbtConstants.tsx'; export { default as fbtHashKey } from './fbtHashKey.tsx'; diff --git a/packages/babel-plugin-fbtee/src/replaceClearTokensWithTokenAliases.tsx b/packages/babel-plugin-fbtee/src/replaceClearTokensWithTokenAliases.tsx index 140f9166..f9ec4145 100644 --- a/packages/babel-plugin-fbtee/src/replaceClearTokensWithTokenAliases.tsx +++ b/packages/babel-plugin-fbtee/src/replaceClearTokensWithTokenAliases.tsx @@ -1,6 +1,6 @@ import { tokenNameToTextPattern } from './fbt-nodes/FbtNodeUtil.tsx'; import { TokenAliases } from './index.tsx'; -import { PatternString } from './Types.tsx'; +import type { PatternString } from './Types.d.ts'; /** * Clear token names in translations and runtime call texts need to be replaced diff --git a/packages/babel-plugin-fbtee/src/translate/FbtSite.tsx b/packages/babel-plugin-fbtee/src/translate/FbtSite.tsx index e3bcbda2..05e11d6a 100644 --- a/packages/babel-plugin-fbtee/src/translate/FbtSite.tsx +++ b/packages/babel-plugin-fbtee/src/translate/FbtSite.tsx @@ -8,7 +8,7 @@ import type { } from '../index.tsx'; import { isTableJSFBTTreeLeaf, onEachLeaf } from '../JSFbtUtil.tsx'; import nullthrows from '../nullthrows.tsx'; -import type { PatternHash, PatternString } from '../Types.tsx'; +import type { PatternHash, PatternString } from '../Types.d.ts'; import type { FbtSiteHashifiedTableJSFBTTree, FbtSiteHashToTextAndDesc, diff --git a/packages/babel-plugin-fbtee/src/translate/FbtSiteBase.tsx b/packages/babel-plugin-fbtee/src/translate/FbtSiteBase.tsx index 794e265c..aeb32cad 100644 --- a/packages/babel-plugin-fbtee/src/translate/FbtSiteBase.tsx +++ b/packages/babel-plugin-fbtee/src/translate/FbtSiteBase.tsx @@ -1,5 +1,5 @@ import type { HashToLeaf } from '../bin/FbtCollector.tsx'; -import type { FbtTableKey, PatternHash, PatternString } from '../Types.tsx'; +import type { FbtTableKey, PatternHash, PatternString } from '../Types.d.ts'; import type { IntlFbtVariationTypeValue, IntlVariationMaskValue, diff --git a/packages/babel-plugin-fbtee/src/translate/TranslationBuilder.tsx b/packages/babel-plugin-fbtee/src/translate/TranslationBuilder.tsx index bcb280fe..446215a6 100644 --- a/packages/babel-plugin-fbtee/src/translate/TranslationBuilder.tsx +++ b/packages/babel-plugin-fbtee/src/translate/TranslationBuilder.tsx @@ -2,7 +2,7 @@ import invariant from 'invariant'; import { varDump } from '../FbtUtil.tsx'; import nullthrows from '../nullthrows.tsx'; import replaceClearTokensWithTokenAliases from '../replaceClearTokensWithTokenAliases.tsx'; -import type { FbtTableKey, PatternHash } from '../Types.tsx'; +import type { FbtTableKey, PatternHash } from '../Types.d.ts'; import { FbtSite, FbtSiteMetaEntry } from './FbtSite.tsx'; import type { FbtSiteHashifiedTableJSFBTTree } from './FbtSiteBase.tsx'; import type { diff --git a/packages/fbtee/src/FbtResult.tsx b/packages/fbtee/src/FbtResult.tsx index 23714088..d05be084 100644 --- a/packages/fbtee/src/FbtResult.tsx +++ b/packages/fbtee/src/FbtResult.tsx @@ -1,9 +1,9 @@ import FbtResultBase from './FbtResultBase.tsx'; -import { +import type { BaseResult, IFbtErrorListener, NestedFbtContentItems, -} from './Types.tsx'; +} from './Types.d.ts'; type Props = Readonly<{ content: NestedFbtContentItems; diff --git a/packages/fbtee/src/FbtResultBase.tsx b/packages/fbtee/src/FbtResultBase.tsx index 76577629..a2e2b9bc 100644 --- a/packages/fbtee/src/FbtResultBase.tsx +++ b/packages/fbtee/src/FbtResultBase.tsx @@ -1,9 +1,9 @@ -import { +import type { BaseResult, FbtContentItem, IFbtErrorListener, NestedFbtContentItems, -} from './Types.tsx'; +} from './Types.d.ts'; export default class FbtResultBase implements BaseResult { _contents: NestedFbtContentItems; diff --git a/packages/fbtee/src/FbtTable.tsx b/packages/fbtee/src/FbtTable.tsx index a2dbbe12..293777c8 100644 --- a/packages/fbtee/src/FbtTable.tsx +++ b/packages/fbtee/src/FbtTable.tsx @@ -1,4 +1,4 @@ -import { FbtTableKey } from '@nkzw/babel-plugin-fbtee/src/Types.tsx'; +import type { FbtTableKey } from '@nkzw/babel-plugin-fbtee/src/Types.d.ts'; import invariant from 'invariant'; import type { FbtRuntimeInput, FbtTableArgs } from './Hooks.tsx'; diff --git a/packages/fbtee/src/Hooks.tsx b/packages/fbtee/src/Hooks.tsx index f22339b9..82dc137c 100644 --- a/packages/fbtee/src/Hooks.tsx +++ b/packages/fbtee/src/Hooks.tsx @@ -6,13 +6,13 @@ import type { import FbtResult from './FbtResult.tsx'; import type { FbtTableArg } from './FbtTableAccessor.tsx'; import IntlViewerContext from './IntlViewerContext.tsx'; -import { +import type { BaseResult, FbtErrorContext, IFbtErrorListener, NestedFbtContentItems, PureStringResult, -} from './Types.tsx'; +} from './Types.d.ts'; export type ResolverFn = ( contents: NestedFbtContentItems, diff --git a/packages/fbtee/src/Types.tsx b/packages/fbtee/src/Types.d.ts similarity index 100% rename from packages/fbtee/src/Types.tsx rename to packages/fbtee/src/Types.d.ts diff --git a/packages/fbtee/src/__mocks__/getFbtResult.tsx b/packages/fbtee/src/__mocks__/getFbtResult.tsx index 8b592715..79f55925 100644 --- a/packages/fbtee/src/__mocks__/getFbtResult.tsx +++ b/packages/fbtee/src/__mocks__/getFbtResult.tsx @@ -1,5 +1,5 @@ import FbtResult from '../FbtResult.tsx'; -import { NestedFbtContentItems } from '../Types.tsx'; +import type { NestedFbtContentItems } from '../Types.d.ts'; export default function getFbtResult( contents: NestedFbtContentItems, diff --git a/packages/fbtee/src/__tests__/FbtResult-test.tsx b/packages/fbtee/src/__tests__/FbtResult-test.tsx index 39f653dc..03c57359 100644 --- a/packages/fbtee/src/__tests__/FbtResult-test.tsx +++ b/packages/fbtee/src/__tests__/FbtResult-test.tsx @@ -1,7 +1,7 @@ import { describe, expect, it, jest } from '@jest/globals'; import FbtResult from '../FbtResult.tsx'; import Hooks from '../Hooks.tsx'; -import { IFbtErrorListener } from '../Types.tsx'; +import type { IFbtErrorListener } from '../Types.d.ts'; let errorListener: IFbtErrorListener | null; diff --git a/packages/fbtee/src/__tests__/fbt-test.tsx b/packages/fbtee/src/__tests__/fbt-test.tsx index 95099325..59a4c062 100644 --- a/packages/fbtee/src/__tests__/fbt-test.tsx +++ b/packages/fbtee/src/__tests__/fbt-test.tsx @@ -13,11 +13,11 @@ import Hooks, { FbtRuntimeCallInput, FbtTranslatedInput } from '../Hooks.tsx'; import { fbt, FbtResult } from '../index.tsx'; import init from '../init.tsx'; import IntlVariations from '../IntlVariations.tsx'; -import { +import type { BaseResult, IFbtErrorListener, NestedFbtContentItems, -} from '../Types.tsx'; +} from '../Types.d.ts'; init({ translations: { en_US: {} }, diff --git a/packages/fbtee/src/fbt.tsx b/packages/fbtee/src/fbt.tsx index b6ec0418..1d7764b3 100644 --- a/packages/fbtee/src/fbt.tsx +++ b/packages/fbtee/src/fbt.tsx @@ -23,7 +23,7 @@ import { getNumberVariations, } from './IntlVariationResolver.tsx'; import substituteTokens, { Substitutions } from './substituteTokens.tsx'; -import { BaseResult, NestedFbtContentItems } from './Types.tsx'; +import type { BaseResult, NestedFbtContentItems } from './Types.d.ts'; const ParamVariation: ParamVariationType = { gender: 1, diff --git a/packages/fbtee/src/getAllSubstitutions.tsx b/packages/fbtee/src/getAllSubstitutions.tsx index c0b4c307..f39e5a60 100644 --- a/packages/fbtee/src/getAllSubstitutions.tsx +++ b/packages/fbtee/src/getAllSubstitutions.tsx @@ -2,7 +2,7 @@ import invariant from 'invariant'; import FbtTable from './FbtTable.tsx'; import { FbtTableArgs } from './Hooks.tsx'; import { Substitutions } from './substituteTokens.tsx'; -import { FbtContentItem } from './Types.tsx'; +import type { FbtContentItem } from './Types.d.ts'; export default function getAllSubstitutions(args: FbtTableArgs) { let substitutions: Substitutions | null = null; diff --git a/packages/fbtee/src/getFbsResult.tsx b/packages/fbtee/src/getFbsResult.tsx index a36c33dc..660225fc 100644 --- a/packages/fbtee/src/getFbsResult.tsx +++ b/packages/fbtee/src/getFbsResult.tsx @@ -1,6 +1,6 @@ import { PatternHash } from '@nkzw/babel-plugin-fbtee'; import FbtPureStringResult from './FbtPureStringResult.tsx'; -import { IFbtErrorListener, NestedFbtContentItems } from './Types.tsx'; +import type { IFbtErrorListener, NestedFbtContentItems } from './Types.d.ts'; export default function getFbsResult( contents: NestedFbtContentItems, diff --git a/packages/fbtee/src/index.tsx b/packages/fbtee/src/index.tsx index be6b5e35..c58ca577 100644 --- a/packages/fbtee/src/index.tsx +++ b/packages/fbtee/src/index.tsx @@ -1,11 +1,13 @@ import fbsInternal from './fbs.tsx'; import fbtInternal from './fbt.tsx'; -import { FbsAPI, FbtAPI } from './Types.tsx'; +import type { FbsAPI, FbtAPI } from './Types.d.ts'; export { default as IntlVariations } from './IntlVariations.tsx'; export { default as init } from './init.tsx'; export { default as GenderConst } from './GenderConst.tsx'; export { default as FbtTranslations } from './FbtTranslations.tsx'; export { default as FbtResult } from './FbtResult.tsx'; +export { default as intlList } from './intlList.tsx'; + export const fbt = fbtInternal as unknown as FbtAPI; export const fbs = fbsInternal as unknown as FbsAPI; diff --git a/packages/fbtee/src/init.tsx b/packages/fbtee/src/init.tsx index 36b99d86..103adace 100644 --- a/packages/fbtee/src/init.tsx +++ b/packages/fbtee/src/init.tsx @@ -4,7 +4,7 @@ import FbtTranslations, { TranslationDict } from './FbtTranslations.tsx'; import getFbsResult from './getFbsResult.tsx'; import Hook, { Hooks } from './Hooks.tsx'; import IntlViewerContext from './IntlViewerContext.tsx'; -import { IFbtErrorListener, NestedFbtContentItems } from './Types.tsx'; +import type { IFbtErrorListener, NestedFbtContentItems } from './Types.d.ts'; const getFbtResult = ( contents: NestedFbtContentItems, diff --git a/packages/fbtee/src/substituteTokens.tsx b/packages/fbtee/src/substituteTokens.tsx index 0eb201b5..ce76b728 100644 --- a/packages/fbtee/src/substituteTokens.tsx +++ b/packages/fbtee/src/substituteTokens.tsx @@ -3,7 +3,7 @@ import { dedupeStops, PUNCT_CHAR_CLASS, } from './IntlPunctuation.tsx'; -import { FbtContentItem, NestedFbtContentItems } from './Types.tsx'; +import type { FbtContentItem, NestedFbtContentItems } from './Types.d.ts'; // This pattern finds tokens inside a string: 'string with {token} inside'. // It also grabs any punctuation that may be present after the token, such as