fluent

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 10, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

gofluent

Go Reference CI Go Report Card License

A Go implementation of Project Fluent — a localization system for natural-sounding translations. You write .ftl files, load them into a per-locale Bundle, and format messages whose plurals, numbers, and dates follow the rules of each language. gofluent ports the reference JavaScript implementation (@fluent/syntax and @fluent/bundle); the locale-aware formatting is CLDR-backed by the github.com/hakastein/gocldr module (validated against Node's Intl.*) and wired into every bundle by default.

Status: pre-1.0. The library is feature-complete and tested against the upstream conformance and Intl.* suites, but the public API may still change between minor versions until 1.0.

Install

go get github.com/hakastein/gofluent

Requires Go 1.23 or newer.

Quickstart

This example renders one Russian message across the plural categories Russian actually uses — one (1, 21), few (2), many (5) — plus a grouped number and a localized date. It is verified by a runnable example (ExampleBundle_pluralRussian in example_test.go), so the output below is exactly what go test asserts.

package main

import (
	"fmt"
	"time"

	_ "github.com/hakastein/gocldr/locales/ru" // Russian number + date data (see "Locale data")

	fluent "github.com/hakastein/gofluent"
)

const src = `
apples =
    { $n ->
        [one] { $n } яблоко
        [few] { $n } яблока
       *[many] { $n } яблок
    }
total = Итого: { NUMBER($total) }
updated = Обновлено { DATETIME($at, dateStyle: "long") }
`

func main() {
	// NewBundle wires the CLDR plural rules, number, and date formatters by
	// default. useIsolating is disabled here so the output is plain text;
	// the default (true) wraps placeables in Unicode bidi isolation marks.
	b := fluent.NewBundle("ru", fluent.WithUseIsolating(false))
	b.AddResource(fluent.NewResource(src))

	apples, _ := b.Message("apples")
	for _, n := range []int{1, 2, 5, 21} {
		out, _ := b.FormatPattern(apples.Value, map[string]any{"n": n})
		fmt.Println(out)
	}

	total, _ := b.Message("total")
	out, _ := b.FormatPattern(total.Value, map[string]any{"total": 1234567})
	fmt.Println(out)

	updated, _ := b.Message("updated")
	at := time.Date(2023, 1, 5, 14, 9, 7, 0, time.UTC)
	out, _ = b.FormatPattern(updated.Value, map[string]any{"at": at})
	fmt.Println(out)
}

Output:

1 яблоко
2 яблока
5 яблок
21 яблоко
Итого: 1 234 567
Обновлено 5 января 2023 г.

The number 1 234 567 is grouped with no-break spaces and the date reads 5 января 2023 г. — both Russian conventions, matching Intl.*. The plural select picks [one] for 1 and 21, [few] for 2, and the default *[many] for 5, following CLDR's Russian cardinal rules.

The same shape works for English — fluent.NewBundle("en") with an FTL whose select uses English's [one]/*[other] categories.

How it works

  1. A Bundle holds the translations for one locale (fluent.NewBundle("ru")). The locale string drives every locale-aware decision below.
  2. FTL source is parsed once with fluent.NewResource and added with b.AddResource. A resource is a set of messages; each message has a value (a Pattern) and optional .attributes.
  3. A { $n -> [one] … [few] … *[many] … } select expression asks the bundle's PluralRules for the CLDR plural category of $n in this locale, then renders the matching variant (falling back to the * default).
  4. NUMBER($n) and DATETIME($d) format their argument through the bundle's NumberFormatter / DateTimeFormatter, honoring options such as dateStyle: "long" or useGrouping.
  5. fluent.NewBundle installs those three formatters — the CLDR-backed plural rules, number, and date implementations — by default, matching ECMA-402 Intl.* (and therefore fluent.js). No opt-in step is needed. To override the default for a bundle, pass your own implementation through fluent.WithPluralRules / WithNumberFormatter / WithDateTimeFormatter.

CLDR-backed formatting is the default, so a bare fluent.NewBundle("en") already formats numbers, dates, and plurals locale-aware. The locale data that drives real number/date rendering is still opt-in — see "Locale data" below.

The resolver is fault-tolerant: FormatPattern never panics. It returns a best-effort string together with the errors it encountered — missing references and other problems render as fluent.js-style placeholders (for example {$name}) and come back classified by the ErrReference / ErrRange / ErrType sentinels (errors.Is). A Bundle is also safe for concurrent use across all of its read and Add* methods.

Locale data

Plural-category selection (the [one]/[few]/[many] choice) uses CLDR rules that are always linked — Russian plurals are correct with no extra import.

Number and date formatting data is opt-in: a program links only the locales it blank-imports. For each locale you format, import its data:

import _ "github.com/hakastein/gocldr/locales/ru" // numbers + dates for ru
import _ "github.com/hakastein/gocldr/locales/en" // numbers + dates for en

Each locales/<lang> package registers both the number and the date data for that language. (If you only ever format numbers, gocldr/number/locales/ru alone is enough; for dates, gocldr/datetime/locales/ru.) With no locale data imported, formatting degrades gracefully: dates render as RFC3339 and numbers use the ASCII root (e.g. 1,234,567), while plural selection still works.

The gocldr formatters are also usable on their own, independent of Fluent (gocldr/number, gocldr/plural, gocldr/datetime); see that module's docs.

Loading .ftl files

In a real app the FTL lives in files, one directory per locale, loaded through the localization package. localization.FSLoader accepts any fs.FS — typically an embed.FS (translations compiled into the binary) or os.DirFS("./locales") (read from disk at runtime).

Directory layout (the path template tells the loader where to look):

locales/
  en/
    main.ftl   # apples = { $n -> [one] … *[other] … }
  ru/
    main.ftl   # apples = { $n -> [one] … [few] … *[many] … }
import (
	"embed"

	_ "github.com/hakastein/gocldr/locales/en"
	_ "github.com/hakastein/gocldr/locales/ru"

	"github.com/hakastein/gofluent/localization"
)

//go:embed locales
var localesFS embed.FS

// "{locale}" and "{resource}" are substituted per (locale, resource) pair:
// e.g. "locales/ru/main.ftl".
loader := localization.FSLoader(localesFS, "locales/{locale}/{resource}.ftl")

l10n, _ := localization.NewFromLocales(localization.Config{
	Requested: []string{"ru-RU"},    // e.g. from Accept-Language
	Available: []string{"ru", "en"}, // locales you ship
	Default:   "en",                 // ultimate fallback
	Resources: []string{"main"},     // resource ids (file basenames)
	Loader:    loader,
})

// Walks the negotiated chain (ru, then en) and returns the first match.
val, _ := l10n.FormatValue("apples", map[string]any{"n": 5}) // "5 яблок"

NewFromLocales negotiates the requested locales against the ones you ship, builds one Bundle per negotiated locale (each with the default CLDR-backed formatters), and resolves a message from the first bundle in the chain that defines it. Missing files and parse errors are non-fatal: the failing resource is skipped and the rest of the chain still works.

Packages

Package Purpose
github.com/hakastein/gofluent Runtime: fast FTL parser, fault-tolerant resolver, Bundle (one locale).
.../syntax (+ .../syntax/ast) Full AST, recursive-descent parser, serializer, visitor — for tooling.
.../langneg Language negotiation (port of @fluent/langneg).
.../localization High-level fallback layer that loads .ftl files and formats across an ordered chain of locale bundles.

Provenance & verification

gofluent is generated code — it was ported from fluent.js with the assistance of large language models — and that is stated plainly, because the project's credibility rests on verification rather than authorship. Correctness is pinned to executable references, all run under go test ./...:

  • The syntax parser and serializer are checked against the upstream Project Fluent conformance fixtures (62/62 structure, 35/36 reference — the single skip matches fluent.js).
  • The CLDR formatters live in github.com/hakastein/gocldr and are checked there against Node's Intl.* (Intl.PluralRules, Intl.NumberFormat, and Intl.DateTimeFormat golden fixtures).

Read the code and the tests, not just the prose — ARCHITECTURE.md explains the design and where each guarantee is enforced.

Contributing

Contributions are welcome. See CONTRIBUTING.md for build, test, and linting mechanics, and ARCHITECTURE.md for how the codebase is organized and why. By participating you agree to the Code of Conduct.

License

Licensed under the Apache License, Version 2.0. See NOTICE for attribution of the fluent.js port lineage and the CLDR data.

Documentation

Overview

Package fluent is a Go implementation of Project Fluent (https://projectfluent.org), a localization system for natural-sounding translations.

It is a port of the reference JavaScript implementation (@fluent/syntax and @fluent/bundle) with one deliberate change: where fluent.js relies on the JavaScript Intl.* objects, this port exposes locale-aware formatting (plural rules, numbers, dates) through pluggable interfaces. NewBundle installs CLDR-backed defaults — matching Intl.* — from the external github.com/hakastein/gocldr module; callers can override any of them with WithPluralRules, WithNumberFormatter and WithDateTimeFormatter.

Layers

  • Package fluent (this package): the runtime — a fast FTL parser (NewResource), a fault-tolerant resolver, and Bundle (one locale). NewBundle wires the CLDR-backed number/date/plural formatters by default.
  • Package fluent/syntax: the full AST, recursive-descent parser, and serializer used by tooling and conformance.
  • Package fluent/langneg: language negotiation (a port of @fluent/langneg).
  • Package fluent/localization: a high-level layer that formats messages across an ordered chain of locale bundles with fallback.

Locale-aware formatting is backed by github.com/hakastein/gocldr, whose output matches ECMA-402 Intl.*. Its tables are opt-in: blank-import the locale data you format, e.g. import _ "github.com/hakastein/gocldr/locales/en" (or .../locales/all). With none imported, formatting degrades to the CLDR root.

Basic use

res := fluent.NewResource("hello = Hello, { $name }!")
b := fluent.NewBundle("en")
b.AddResource(res)
msg, _ := b.Message("hello")
out, errs := b.FormatPattern(msg.Value, map[string]any{"name": "World"})

The resolver is fault-tolerant: it never panics. Missing references and other problems are reported in the returned errors and rendered as fluent.js-style placeholders (for example {$name}); a best-effort string is always returned.

By default placeables are wrapped in Unicode bidirectional isolation marks (FSI/PDI). Disable this with WithUseIsolating(false).

A Bundle is safe for concurrent use: FormatPattern, Message, and the Add* methods (AddFunction, AddResource, AddResourceOverriding) may run from multiple goroutines at once.

Example

Example shows the minimal flow: parse a resource, add it to a bundle, look up a message, and format its pattern with arguments.

package main

import (
	"fmt"

	_ "github.com/hakastein/gocldr/locales/ru"
	fluent "github.com/hakastein/gofluent"
)

func main() {
	res := fluent.NewResource("hello = Hello, { $name }!")

	// useIsolating is disabled here so the output is plain ASCII; in production
	// the default (true) wraps placeables in Unicode bidi isolation marks.
	b := fluent.NewBundle("en", fluent.WithUseIsolating(false))
	b.AddResource(res)

	msg, ok := b.Message("hello")
	if !ok {
		panic("message not found")
	}

	out, _ := b.FormatPattern(msg.Value, map[string]any{"name": "World"})
	fmt.Println(out)
}
Output:
Hello, World!

Index

Examples

Constants

View Source
const MaxPlaceables = 100

MaxPlaceables is the maximum number of placeables which can be expanded in a single FormatPattern call. The limit protects against the Billion Laughs and Quadratic Blowup attacks.

Variables

View Source
var (
	// ErrReference: an unknown message, term, variable, function, or attribute
	// was referenced.
	ErrReference = errors.New("fluent: reference error")
	// ErrRange: no variant matched a selector, a value is out of range, a
	// reference is cyclic, or the placeable limit was exceeded.
	ErrRange = errors.New("fluent: range error")
	// ErrType: a value cannot be used in the position it appears (e.g. a
	// non-numeric selector argument, or a term used as a placeable).
	ErrType = errors.New("fluent: type error")
)

Error kinds collected by FormatPattern, mirroring the JS error classes fluent.js reports (ReferenceError / RangeError / TypeError). Every resolution error wraps one of these sentinels, so a caller can classify a failure with errors.Is, e.g. errors.Is(err, fluent.ErrReference).

Functions

This section is empty.

Types

type Bundle

type Bundle struct {
	// contains filtered or unexported fields
}

Bundle is a single-language store of translation resources, responsible for formatting message values and attributes to strings.

A Bundle is safe for concurrent use: FormatPattern, Message, AddFunction, AddResource, and AddResourceOverriding may be called from multiple goroutines simultaneously. The locale and the injected formatters are set once at construction and never mutated afterwards.

Example (PluralRussian)

ExampleBundle_pluralRussian shows a Russian bundle: the { $n -> [one] … [few] … *[many] … } select picks the correct CLDR plural category, and NUMBER()/ DATETIME() render with Russian conventions. CLDR formatting is the NewBundle default, so no extra wiring is needed.

The blank import _ "github.com/hakastein/gocldr/locales/ru" supplies Russian number and date data; CLDR plural rules are always linked, so the category selection (one/few/many) is correct even without it.

package main

import (
	"fmt"
	"time"

	_ "github.com/hakastein/gocldr/locales/ru"
	fluent "github.com/hakastein/gofluent"
)

func main() {
	const src = `
apples =
    { $n ->
        [one] { $n } яблоко
        [few] { $n } яблока
       *[many] { $n } яблок
    }
total = Итого: { NUMBER($total) }
updated = Обновлено { DATETIME($at, dateStyle: "long") }
`
	// CLDR formatters are installed by default; useIsolating is disabled so the
	// output is plain text.
	b := fluent.NewBundle("ru", fluent.WithUseIsolating(false))
	b.AddResource(fluent.NewResource(src))

	apples, _ := b.Message("apples")
	for _, n := range []int{1, 2, 5, 21} {
		out, _ := b.FormatPattern(apples.Value, map[string]any{"n": n})
		fmt.Println(out)
	}

	total, _ := b.Message("total")
	out, _ := b.FormatPattern(total.Value, map[string]any{"total": 1234567})
	fmt.Println(out)

	updated, _ := b.Message("updated")
	at := time.Date(2023, 1, 5, 14, 9, 7, 0, time.UTC)
	out, _ = b.FormatPattern(updated.Value, map[string]any{"at": at})
	fmt.Println(out)

}
Output:
1 яблоко
2 яблока
5 яблок
21 яблоко
Итого: 1 234 567
Обновлено 5 января 2023 г.
Example (SelectExpression)

ExampleBundle_selectExpression demonstrates a select expression. A numeric selector matches a variant key by exact value before falling back to the CLDR plural category, so the literal key "1" is selected for the number 1 while 5 falls through to *[other].

package main

import (
	"fmt"

	_ "github.com/hakastein/gocldr/locales/ru"
	fluent "github.com/hakastein/gofluent"
)

func main() {
	src := `
emails =
    { $count ->
        [1] You have one new email.
       *[other] You have { $count } new emails.
    }
`
	b := fluent.NewBundle("en", fluent.WithUseIsolating(false))
	b.AddResource(fluent.NewResource(src))

	msg, _ := b.Message("emails")
	one, _ := b.FormatPattern(msg.Value, map[string]any{"count": 1})
	five, _ := b.FormatPattern(msg.Value, map[string]any{"count": 5})
	fmt.Println(one)
	fmt.Println(five)
}
Output:
You have one new email.
You have 5 new emails.

func NewBundle

func NewBundle(locale string, opts ...Option) *Bundle

NewBundle creates a Bundle for the given primary locale. useIsolating defaults to true; NUMBER and DATETIME are always available; the three formatters default to the CLDR-backed implementations (matching Intl.*). Applications must blank-import the locale data they format, e.g. import _ "github.com/hakastein/gocldr/locales/ru" (or .../locales/all); with none imported, formatting degrades to the CLDR root / RFC 3339.

func (*Bundle) AddFunction

func (b *Bundle) AddFunction(name string, fn Function)

AddFunction registers (or overrides) a runtime function by name.

func (*Bundle) AddResource

func (b *Bundle) AddResource(res *Resource) []error

AddResource adds a parsed resource to the bundle without allowing overrides. It returns errors for any attempted overrides of existing messages/terms.

func (*Bundle) AddResourceOverriding

func (b *Bundle) AddResourceOverriding(res *Resource) []error

AddResourceOverriding adds a parsed resource, allowing it to override existing messages and terms.

func (*Bundle) FormatPattern

func (b *Bundle) FormatPattern(pattern Pattern, args map[string]any) (result string, errs []error)

FormatPattern formats a Pattern — a Message value or attribute — to a string. args resolves variable references; pass nil for none. Argument values may be strings, any integer or float type, time.Time, or a Value (e.g. a Number carrying formatting options); other types render as a missing-variable fallback with an error.

Formatting is fault-tolerant: a best-effort string is always returned, and every problem encountered (missing references, type mismatches, ...) is reported in errs, each classified by one of the ErrReference / ErrRange / ErrType sentinels.

Precision note: integer arguments are stored as float64 (Fluent's only numeric type, matching JS). int64/uint64 magnitudes above 2^53 cannot be represented exactly and may be rounded; pass a preformatted string (or a custom Value) when exact rendering of such large integers matters.

func (*Bundle) Locale

func (b *Bundle) Locale() string

Locale returns the bundle's primary locale string.

func (*Bundle) Message added in v0.4.0

func (b *Bundle) Message(id string) (*Message, bool)

Message returns the message with the given id, if present.

type DateTime

type DateTime struct {
	Time    time.Time
	Options DateTimeOptions
}

DateTime is the Value for a date/time (FluentDateTime in fluent.js): a time.Time plus the option bag passed to the DateTimeFormatter.

func NewDateTime

func NewDateTime(t time.Time, opts DateTimeOptions) *DateTime

NewDateTime constructs a DateTime with the given time and options.

func (*DateTime) Format

func (d *DateTime) Format(scope *Scope) string

Format renders the datetime using the bundle's DateTimeFormatter.

type DateTimeFormatter

type DateTimeFormatter interface {
	FormatDateTime(locale string, t time.Time, opts DateTimeOptions) string
}

DateTimeFormatter renders a time to a string for a given locale and options.

type DateTimeOptions

type DateTimeOptions struct {
	Hour12                 *bool
	Weekday                string
	Era                    string
	Year                   string
	Month                  string
	Day                    string
	Hour                   string
	Minute                 string
	Second                 string
	TimeZoneName           string
	DateStyle              string
	TimeStyle              string
	DayPeriod              string
	FractionalSecondDigits *int
	Calendar               string
	NumberingSystem        string
	TimeZone               string
}

DateTimeOptions carries the options that the DATETIME() builtin and FluentDateTime accept. It mirrors the subset of Intl.DateTimeFormatOptions used by fluent.js. Pointer fields distinguish "unset" from a zero value.

type Function

type Function func(positional []Value, named map[string]Value) (Value, error)

Function is the signature of a Fluent builtin/runtime function. It receives positional and named Value arguments and returns a Value. Returning a non-nil error (or panicking) routes through the resolver's fault-tolerant error path, rendering `{NAME()}`. Mirrors FluentFunction in fluent.js.

type Message

type Message struct {
	ID         string
	Value      Pattern // nil when the message has only attributes
	Attributes map[string]Pattern
}

Message is a compiled message: its id, an optional value, and attributes. Treat it as read-only; it is shared by all formatting calls on the Bundle.

type None

type None struct {
	// contains filtered or unexported fields
}

None is the Value representing a missing or invalid value (FluentNone in fluent.js). It renders using the fluent.js fallback convention: a missing variable as `{$name}`, a missing message as `{message}`, a missing term as `{-term}`, a failed function as `{FUNC()}`. The default fallback is `???`, rendering as `{???}`.

func NewNone

func NewNone(fallback string) *None

NewNone constructs a None with the given fallback. An empty fallback defaults to "???".

func (*None) Fallback added in v0.4.0

func (n *None) Fallback() string

Fallback returns the raw fallback string (without braces).

func (*None) Format

func (n *None) Format(_ *Scope) string

Format renders the None as `{fallback}`.

type Number

type Number struct {
	Value   float64
	Options NumberOptions
	// contains filtered or unexported fields
}

Number is the Value for a number (FluentNumber in fluent.js): a float64 plus the option bag passed to the NumberFormatter.

func NewNumber

func NewNumber(value float64, opts NumberOptions) *Number

NewNumber constructs a Number with the given value and options.

func (*Number) Format

func (n *Number) Format(scope *Scope) string

Format renders the number using the bundle's NumberFormatter.

type NumberFormatter

type NumberFormatter interface {
	FormatNumber(locale string, n float64, opts NumberOptions) string
}

NumberFormatter renders a number to a string for a given locale and options.

type NumberOptions

type NumberOptions struct {
	Style                    string // "decimal" | "currency" | "percent" | "unit"
	Currency                 string
	CurrencyDisplay          string
	Unit                     string
	UnitDisplay              string
	UseGrouping              *bool
	MinimumIntegerDigits     *int
	MinimumFractionDigits    *int
	MaximumFractionDigits    *int
	MinimumSignificantDigits *int
	MaximumSignificantDigits *int

	// Type selects the plural ruleset: "cardinal" (default) or "ordinal".
	Type string
}

NumberOptions carries the options that the NUMBER() builtin and FluentNumber accept. It mirrors the subset of Intl.NumberFormatOptions used by fluent.js. Pointer fields distinguish "unset" from a zero value, mirroring how fluent.js merges option bags.

type Option added in v0.4.0

type Option func(*Bundle)

Option configures a Bundle in NewBundle.

func WithDateTimeFormatter

func WithDateTimeFormatter(f DateTimeFormatter) Option

WithDateTimeFormatter injects a DateTimeFormatter (replaces the CLDR-backed default).

func WithFunctions

func WithFunctions(fns map[string]Function) Option

WithFunctions registers additional builtin functions, merged over NUMBER and DATETIME.

func WithLocales

func WithLocales(locales ...string) Option

WithLocales sets the full locale fallback list. The first entry becomes the primary locale passed to formatters.

func WithNumberFormatter

func WithNumberFormatter(f NumberFormatter) Option

WithNumberFormatter injects a NumberFormatter (replaces the CLDR-backed default).

func WithPluralRules

func WithPluralRules(p PluralRules) Option

WithPluralRules injects a PluralRules implementation (replaces the CLDR-backed default).

func WithTransform

func WithTransform(t TextTransform) Option

WithTransform sets the text transform applied to string parts of patterns.

func WithUseIsolating

func WithUseIsolating(v bool) Option

WithUseIsolating sets whether to wrap interpolations in Unicode isolation marks (FSI/PDI). Default is true.

type Pattern

type Pattern interface {
	// contains filtered or unexported methods
}

Pattern is a compiled message value or attribute. Obtain one from a Message (its Value field or an Attributes entry) and render it with Bundle.FormatPattern. Pattern is opaque: all implementations live in this package. A nil Pattern represents the absence of a value (e.g. a message with only attributes).

type PluralRules

type PluralRules interface {
	// Cardinal returns the cardinal plural category for n.
	Cardinal(locale string, n float64, opts NumberOptions) string
	// Ordinal returns the ordinal plural category for n.
	Ordinal(locale string, n float64, opts NumberOptions) string
}

PluralRules returns CLDR plural categories for a number in a given locale. Implementations return one of: "zero", "one", "two", "few", "many", "other".

type Resource

type Resource struct {
	// contains filtered or unexported fields
}

Resource is a parsed set of FTL entries, ready to be added to a Bundle with AddResource. It mirrors FluentResource in fluent.js.

func NewResource

func NewResource(source string) *Resource

NewResource parses an FTL source into a Resource. The runtime parser is fault-tolerant, matching fluent.js: entries that fail to parse are silently skipped. Use the syntax package to diagnose malformed sources.

type Scope

type Scope struct {
	// contains filtered or unexported fields
}

Scope carries the state of a single pattern resolution: the bundle, the caller's arguments, and the errors collected so far. Library users only meet it as the argument to Value.Format; its only public surface is Locale.

func (*Scope) Locale added in v0.4.0

func (s *Scope) Locale() string

Locale returns the locale of the bundle this resolution formats for. It is the locale custom Value implementations should render with.

type String added in v0.4.0

type String string

String is the Value for a plain string.

func (String) Format added in v0.4.0

func (s String) Format(_ *Scope) string

Format returns the string unchanged.

type TextTransform

type TextTransform func(string) string

TextTransform transforms the text parts of patterns.

type Value

type Value interface {
	// Format renders this value to a string. The scope carries the bundle's
	// locale and formatters; it may be nil when formatting outside a
	// resolution (implementations must tolerate that).
	Format(scope *Scope) string
}

Value is the base of Fluent's runtime type system. Every expression resolves to a Value; Format renders it to its final string. Custom argument types implement Value directly (mirroring user subclasses of FluentType in fluent.js).

Directories

Path Synopsis
Package langneg is a faithful Go port of @fluent/langneg.
Package langneg is a faithful Go port of @fluent/langneg.
Package localization is the high-level localization layer for gofluent.
Package localization is the high-level localization layer for gofluent.
Package syntax is an idiomatic Go port of @fluent/syntax (Project Fluent): a parser, serializer, and AST visitor for the Fluent localization format.
Package syntax is an idiomatic Go port of @fluent/syntax (Project Fluent): a parser, serializer, and AST visitor for the Fluent localization format.
ast
Package ast defines the Fluent abstract syntax tree, a faithful port of the data model from @fluent/syntax (ast.ts).
Package ast defines the Fluent abstract syntax tree, a faithful port of the data model from @fluent/syntax (ast.ts).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL