{"id":35715373,"url":"https://github.com/formatjs/rules_formatjs","last_synced_at":"2026-04-02T14:53:29.058Z","repository":{"id":331517834,"uuid":"1127834827","full_name":"formatjs/rules_formatjs","owner":"formatjs","description":"Repo for rules_formatjs","archived":false,"fork":false,"pushed_at":"2026-03-15T13:56:02.000Z","size":306,"stargazers_count":1,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-16T03:08:36.081Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Starlark","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/formatjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-04T17:26:27.000Z","updated_at":"2026-01-29T18:58:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/formatjs/rules_formatjs","commit_stats":null,"previous_names":["formatjs/rules_formatjs"],"tags_count":13,"template":false,"template_full_name":"bazel-contrib/rules-template","purl":"pkg:github/formatjs/rules_formatjs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/formatjs%2Frules_formatjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/formatjs%2Frules_formatjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/formatjs%2Frules_formatjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/formatjs%2Frules_formatjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/formatjs","download_url":"https://codeload.github.com/formatjs/rules_formatjs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/formatjs%2Frules_formatjs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31308447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":"2026-01-06T05:19:44.443Z","updated_at":"2026-04-02T14:53:29.038Z","avatar_url":"https://github.com/formatjs.png","language":"Starlark","readme":"# rules_formatjs\n\nBazel rules for [FormatJS](https://formatjs.io/) - Internationalize your web apps on the client \u0026 server.\n\n## Features\n\n- Extract messages from source files (TypeScript, JavaScript, JSX, TSX)\n- Compile messages for optimized runtime performance\n- Verify translations for completeness\n- Aggregate messages across multiple modules\n- Native Rust CLI toolchain for fast builds\n- Type-safe message extraction and compilation\n\n## Installation\n\nAdd `rules_formatjs` to your `MODULE.bazel`:\n\n```starlark\nbazel_dep(name = \"rules_formatjs\", version = \"0.1.0\")\n```\n\nOr use a specific commit from GitHub:\n\n```starlark\ngit_override(\n    module_name = \"rules_formatjs\",\n    remote = \"https://github.com/formatjs/rules_formatjs.git\",\n    commit = \"\u003ccommit-sha\u003e\",\n)\n```\n\n## Usage\n\n### Extract Messages\n\nExtract internationalized messages from your source code:\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"formatjs_extract\")\n\nformatjs_extract(\n    name = \"messages_extracted\",\n    srcs = glob([\"src/**/*.tsx\", \"src/**/*.ts\"]),\n    out = \"en.json\",\n    id_interpolation_pattern = \"[sha512:contenthash:base64:6]\",\n)\n```\n\n### Compile Messages\n\nCompile extracted messages for optimized runtime:\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"formatjs_compile\")\n\nformatjs_compile(\n    name = \"messages_compiled\",\n    src = \":messages_extracted\",\n    out = \"en-compiled.json\",\n    ast = True,  # Compile to AST for better performance\n)\n```\n\n### Verify Translations\n\nVerify that translations are complete and correctly formatted:\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"formatjs_verify\")\n\nformatjs_verify(\n    name = \"verify_translations\",\n    reference = \":messages_extracted\",  # Base language\n    translations = [\n        \"translations/es.json\",\n        \"translations/fr.json\",\n    ],\n)\n```\n\n### Aggregate Messages\n\nAggregate messages from multiple modules into a single file:\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"formatjs_extract\", \"formatjs_aggregate\")\n\n# Extract from multiple modules\nformatjs_extract(name = \"module1_msgs\", srcs = [\"module1/**/*.tsx\"])\nformatjs_extract(name = \"module2_msgs\", srcs = [\"module2/**/*.tsx\"])\nformatjs_extract(name = \"module3_msgs\", srcs = [\"module3/**/*.tsx\"])\n\n# Create aggregation target\nformatjs_aggregate(\n    name = \"all_messages\",\n    deps = [\":module1_msgs\", \":module2_msgs\", \":module3_msgs\"],\n)\n```\n\nThen build with the aspect:\n\n```bash\nbazel build //:all_messages \\\n  --aspects=@rules_formatjs//formatjs:aggregate.bzl%formatjs_aggregate_aspect \\\n  --output_groups=aggregated_messages\n```\n\n### Complete Example\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"formatjs_extract\", \"formatjs_compile\", \"formatjs_verify\")\n\n# Extract messages from source files\nformatjs_extract(\n    name = \"extract_en\",\n    srcs = glob([\n        \"src/**/*.ts\",\n        \"src/**/*.tsx\",\n    ]),\n    out = \"lang/en.json\",\n    id_interpolation_pattern = \"[sha512:contenthash:base64:6]\",\n    extract_from_format_message_call = True,\n)\n\n# Compile for production\nformatjs_compile(\n    name = \"compile_en\",\n    src = \":extract_en\",\n    out = \"lang/en-compiled.json\",\n    ast = True,\n)\n\n# Compile translations\nformatjs_compile(\n    name = \"compile_es\",\n    src = \"translations/es.json\",\n    out = \"lang/es-compiled.json\",\n    ast = True,\n)\n\n# Verify translations are complete\nformatjs_verify(\n    name = \"verify_es\",\n    reference = \":extract_en\",\n    translations = [\"translations/es.json\"],\n)\n```\n\n## API Reference\n\n### formatjs_extract\n\nExtract messages from source files. This is a **custom Bazel rule** (not a macro), which means you can attach aspects to it for advanced build graph analysis.\n\n**Attributes:**\n\n- `name` (required): Target name\n- `srcs` (required): List of source files to extract from\n- `out` (optional): Output JSON file (defaults to `name + \".json\"`)\n- `id_interpolation_pattern` (optional): Pattern for message ID generation\n  - Example: `\"[sha512:contenthash:base64:6]\"` for content-based IDs\n- `extract_from_format_message_call` (optional): Extract from `formatMessage()` calls\n- `additional_component_names` (optional): Additional component names to extract from\n- `additional_function_names` (optional): Additional function names to extract from\n- `ignore` (optional): List of glob patterns to ignore\n\n**Providers:**\n\n- `DefaultInfo`: Contains the extracted messages JSON file\n- `FormatjsExtractInfo`: Custom provider with:\n  - `messages`: File containing extracted messages\n  - `srcs`: Depset of source files\n  - `id_interpolation_pattern`: Pattern used for ID generation\n\n### formatjs_compile\n\nCompile extracted messages for optimized runtime.\n\n**Attributes:**\n\n- `name` (required): Target name\n- `src` (required): Source JSON file with extracted messages\n- `out` (optional): Output compiled JSON file (defaults to `name + \".json\"`)\n- `ast` (optional): Compile to AST format for better runtime performance\n- `format` (optional): Input format (`simple`, `crowdin`, `smartling`, `transifex`)\n\n### formatjs_verify\n\nVerify that translations are complete and correctly formatted.\n\n**Attributes:**\n\n- `name` (required): Target name\n- `reference` (required): Reference messages file (typically the base language)\n- `translations` (required): List of translation files to verify\n\n## Integration with React\n\nUse compiled messages with `react-intl`:\n\n```typescript\nimport { createIntl, createIntlCache, RawIntlProvider } from 'react-intl';\nimport messages from './lang/en-compiled.json';\n\nconst cache = createIntlCache();\nconst intl = createIntl(\n  {\n    locale: 'en',\n    messages,\n  },\n  cache\n);\n\nfunction App() {\n  return (\n    \u003cRawIntlProvider value={intl}\u003e\n      {/* Your app */}\n    \u003c/RawIntlProvider\u003e\n  );\n}\n```\n\n## Advanced: Using Aspects\n\nSince `formatjs_extract` is a custom rule, you can attach Bazel aspects to it for advanced analysis and transformations. This is useful for:\n\n- Collecting statistics about extracted messages\n- Validating message format and completeness\n- Aggregating messages across multiple targets\n- Custom reporting and analysis\n\n### Message Aggregation Aspect\n\nThe `formatjs_aggregate_aspect` collects and merges extracted messages from a target and all its dependencies into a single JSON file using `jq`.\n\n#### Example\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"formatjs_extract\", \"formatjs_aggregate\")\n\n# Extract from multiple modules\nformatjs_extract(name = \"module1_msgs\", srcs = [\"module1/**/*.tsx\"])\nformatjs_extract(name = \"module2_msgs\", srcs = [\"module2/**/*.tsx\"])\nformatjs_extract(name = \"module3_msgs\", srcs = [\"module3/**/*.tsx\"])\n\n# Create aggregation target\nformatjs_aggregate(\n    name = \"all_messages\",\n    deps = [\":module1_msgs\", \":module2_msgs\", \":module3_msgs\"],\n)\n```\n\nThen build with the aspect:\n\n```bash\nbazel build //:all_messages \\\n  --aspects=@rules_formatjs//formatjs:aggregate.bzl%formatjs_aggregate_aspect \\\n  --output_groups=aggregated_messages\n```\n\nOutput: `bazel-bin/all_messages_aggregated_messages.json` containing all merged messages.\n\n**Merge Strategy**: Uses `jq` to merge JSON objects. Later files overwrite earlier ones for duplicate keys.\n\n### Example Aspects\n\nThe library also includes demonstration aspects in `formatjs/aspects.bzl`:\n\n#### Message Statistics\n\n```bash\nbazel build //path/to:target \\\n  --aspects=@rules_formatjs//formatjs:aspects.bzl%message_stats_aspect \\\n  --output_groups=message_stats\n```\n\n#### Message Validation\n\n```bash\nbazel build //path/to:target \\\n  --aspects=@rules_formatjs//formatjs:aspects.bzl%message_validator_aspect \\\n  --output_groups=message_validation\n```\n\n#### Message Collection (across dependencies)\n\n```bash\nbazel build //path/to:target \\\n  --aspects=@rules_formatjs//formatjs:aspects.bzl%message_collector_aspect \\\n  --output_groups=all_messages\n```\n\n### Creating Custom Aspects\n\n```starlark\nload(\"@rules_formatjs//formatjs:defs.bzl\", \"FormatjsExtractInfo\")\n\ndef _my_aspect_impl(target, ctx):\n    if FormatjsExtractInfo not in target:\n        return []\n\n    info = target[FormatjsExtractInfo]\n\n    # Access extracted message file\n    messages_file = info.messages\n\n    # Access source files\n    src_files = info.srcs.to_list()\n\n    # Perform custom analysis...\n\n    return [OutputGroupInfo(...)]\n\nmy_aspect = aspect(\n    implementation = _my_aspect_impl,\n    doc = \"My custom aspect for formatjs_extract\",\n)\n```\n\n## Toolchain\n\nrules_formatjs uses a native Rust CLI toolchain that is automatically downloaded for your platform. The toolchain supports:\n\n- macOS (Apple Silicon and Intel)\n- Linux (x86_64)\n\nThe toolchain is registered automatically when you add the MODULE.bazel dependency. Binaries are fetched from GitHub releases and cached by Bazel.\n\n## Examples\n\nSee the [examples](examples/) directory for complete working examples:\n\n- [examples/simple](examples/simple) - Basic message extraction, compilation, and verification\n- [examples/aggregate](examples/aggregate) - Aggregating messages from multiple modules\n\n## Resources\n\n- [FormatJS Documentation](https://formatjs.io/)\n- [FormatJS CLI](https://formatjs.io/docs/tooling/cli)\n- [React Intl](https://formatjs.io/docs/react-intl)\n- [Bazel](https://bazel.build/)\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development instructions.\n\n## License\n\nApache License 2.0\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fformatjs%2Frules_formatjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fformatjs%2Frules_formatjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fformatjs%2Frules_formatjs/lists"}