fluent.syntax

The Python parser, serializer, and AST toolkit for reading, writing, and transforming Fluent localization files.

Library
PyPI
v0.19.0
245 stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
48 /100 Fair
Development Activity 12
Maintenance 32
Community 68
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
79 /100 Good
Architecture 85
Code Quality 92
Innovation 62
Learning Curve 75

fluent.syntax is the foundational parsing layer of the Project Fluent Python ecosystem. It turns Fluent (.ftl) source text into a fully-typed abstract syntax tree, serializes that tree back to spec-compliant Fluent source, and exposes Visitor/Transformer classes for walking and rewriting the tree — the same ergonomics Python developers already know from the standard library’s ast module.

It underpins fluent.runtime (the localization library that actually resolves translated strings at runtime) and any tooling — linters, formatters, migration scripts, editor plugins — that needs to read or manipulate .ftl files programmatically rather than treat them as opaque text.

What You Get

  • A recursive-descent FluentParser that turns Fluent source text into a typed ast.Resource tree
  • A FluentSerializer that converts an AST back into spec-compliant Fluent source text
  • Visitor and Transformer base classes for read-only traversal or in-place rewriting of the AST, modeled on Python’s own ast.NodeVisitor/ast.NodeTransformer
  • Full AST coverage of the Fluent grammar: messages, terms, attributes, patterns, placeables, select expressions, comments, and junk (malformed) entries
  • Optional source Span tracking on every node for building tools that need accurate source positions
  • to_json/from_json helpers for serializing the AST itself to and from JSON
  • Full type hints and a py.typed marker for static-analysis-friendly integration

Common Use Cases

  • Powering fluent.runtime’s message resolution by parsing .ftl translation files into an AST it can evaluate
  • Building linters or validators that catch malformed Fluent syntax before it ships
  • Writing migration or refactoring scripts that programmatically rewrite .ftl files (renaming messages, restructuring attributes) via Transformer
  • Building editor tooling (syntax highlighting, autocomplete, go-to-definition) that needs accurate source spans for Fluent files
  • Round-tripping Fluent files through automated formatters that reparse and reserialize source to a canonical style

Under The Hood

Architecture The package is organized as a tight, layered pipeline with a small surface area: stream.py provides a character-level ParserStream/FluentParserStream cursor, parser.py’s FluentParser consumes that stream via a recursive-descent grammar (decorated with a with_span wrapper that attaches source positions to every node), ast.py defines the resulting BaseNode-derived tree (with clone, equals, to_json/from_json built in), and serializer.py’s FluentSerializer walks that same tree back into source text. visitor.py adds an orthogonal Visitor/Transformer layer that traverses any AST via vars() introspection rather than hardcoded per-node logic, so it stays correct as the grammar evolves. The __init__.py facade exposes just parse()/serialize() plus the AST module for typical callers, while fluent.runtime and other consumers reach into the lower layers directly. Because ast.BaseNode’s field introspection is load-bearing for cloning, equality, JSON (de)serialization, and traversal alike, it’s the one abstraction the rest of the package is built around.

Tech Stack Pure Python 3.9+ with zero runtime dependencies — only the standard library (re, json, typing, sys). It ships a py.typed marker, meaning it’s fully type-hinted and safe for downstream static analysis. The build backend is setuptools via a standard pyproject.toml, and the project (part of the python-fluent monorepo alongside fluent.runtime and fluent.pygments) uses uv for dependency and environment management in CI.

Code Quality Testing is extensive and fixture-driven: tests/syntax/ pairs .ftl source fixtures with expected .json AST output across dedicated suites for structure, references, literals, entries, serialization, equality, AST JSON round-tripping, and visitor behavior, including deliberately malformed input to exercise junk-node recovery. CI runs flake8 and mypy for linting and type checking, then runs the full pytest suite across a matrix of three operating systems and six Python versions (3.9–3.14), plus a separate compatibility job that installs older published fluent.syntax releases against the current fluent.runtime to catch cross-version breakage. Naming is consistent and idiomatic (snake_case functions, PascalCase AST classes), and parse failures are represented explicitly via a typed ParseError rather than swallowed.

What Makes It Unique Rather than a generic parser-combinator toolkit, this is a purpose-built implementation of Fluent’s specific grammar — including its distinctive select-expression/plural-variant branching, the message/term distinction, and attribute placeables — with per-node source spans available throughout, which is what makes source-accurate tooling (editors, linters, formatters) practical to build on top of it. Its Visitor/Transformer pair deliberately mirrors the ergonomics of Python’s own ast.NodeVisitor/ast.NodeTransformer, so anyone who has written a Python AST transform already knows how to extend Fluent files programmatically.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers