v0.14.0 Latest Latest

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

Go to latest
Published: Oct 11, 2023 License: BSD-3-Clause Imports: 6 Imported by: 224



Package catalog defines collections of translated format strings.

This package mostly defines types for populating catalogs with messages. The catmsg package contains further definitions for creating custom message and dictionary types as well as packages that use Catalogs.

Package catalog defines various interfaces: Dictionary, Loader, and Message. A Dictionary maintains a set of translations of format strings for a single language. The Loader interface defines a source of dictionaries. A translation of a format string is represented by a Message.


A Catalog defines a programmatic interface for setting message translations. It maintains a set of per-language dictionaries with translations for a set of keys. For message translation to function properly, a translation should be defined for each key for each supported language. A dictionary may be underspecified, though, if there is a parent language that already defines the key. For example, a Dictionary for "en-GB" could leave out entries that are identical to those in a dictionary for "en".


A Message is a format string which varies on the value of substitution variables. For instance, to indicate the number of results one could want "no results" if there are none, "1 result" if there is 1, and "%d results" for any other number. Catalog is agnostic to the kind of format strings that are used: for instance, messages can follow either the printf-style substitution from package fmt or use templates.

A Message does not substitute arguments in the format string. This job is reserved for packages that render strings, such as message, that use Catalogs to selected string. This separation of concerns allows Catalog to be used to store any kind of formatting strings.

Selecting messages based on linguistic features of substitution arguments

Messages may vary based on any linguistic features of the argument values. The most common one is plural form, but others exist.

Selection messages are provided in packages that provide support for a specific linguistic feature. The following snippet uses plural.Selectf:

catalog.Set(language.English, "You are %d minute(s) late.",
	plural.Selectf(1, "",
		plural.One, "You are 1 minute late.",
		plural.Other, "You are %d minutes late."))

In this example, a message is stored in the Catalog where one of two messages is selected based on the first argument, a number. The first message is selected if the argument is singular (identified by the selector "one") and the second message is selected in all other cases. The selectors are defined by the plural rules defined in CLDR. The selector "other" is special and will always match. Each language always defines one of the linguistic categories to be "other." For English, singular is "one" and plural is "other".

Selects can be nested. This allows selecting sentences based on features of multiple arguments or multiple linguistic properties of a single argument.

String interpolation

There is often a lot of commonality between the possible variants of a message. For instance, in the example above the word "minute" varies based on the plural catogory of the argument, but the rest of the sentence is identical. Using interpolation the above message can be rewritten as:

catalog.Set(language.English, "You are %d minute(s) late.",
		plural.Selectf(1, "", plural.One, "minute", plural.Other, "minutes")),
	catalog.String("You are %[1]d ${minutes} late."))

Var is defined to return the variable name if the message does not yield a match. This allows us to further simplify this snippet to

catalog.Set(language.English, "You are %d minute(s) late.",
	catalog.Var("minutes", plural.Selectf(1, "", plural.One, "minute")),
	catalog.String("You are %d ${minutes} late."))

Overall this is still only a minor improvement, but things can get a lot more unwieldy if more than one linguistic feature is used to determine a message variant. Consider the following example:

// argument 1: list of hosts, argument 2: list of guests
catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.",
		plural.Selectf(1, ""
			plural.One, gender.Select(1, "female", "her", "other", "his"))),
	catalog.Var("invites", plural.Selectf(1, "", plural.One, "invite"))
	catalog.String("%[1]v ${invites} %[2]v to ${their} party.")),

Without variable substitution, this would have to be written as

// argument 1: list of hosts, argument 2: list of guests
catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.",
	plural.Selectf(1, "",
		plural.One, gender.Select(1,
			"female", "%[1]v invites %[2]v to her party."
			"other", "%[1]v invites %[2]v to his party."),
		plural.Other, "%[1]v invites %[2]v to their party."))

Not necessarily shorter, but using variables there is less duplication and the messages are more maintenance friendly. Moreover, languages may have up to six plural forms. This makes the use of variables more welcome.

Different messages using the same inflections can reuse variables by moving them to macros. Using macros we can rewrite the message as:

// argument 1: list of hosts, argument 2: list of guests
catalog.SetString(language.English, "%[1]v invite(s) %[2]v to their party.",
	"%[1]v ${invites(1)} %[2]v to ${their(1)} party.")

Where the following macros were defined separately.

catalog.SetMacro(language.English, "invites", plural.Selectf(1, "",
	plural.One, "invite"))
catalog.SetMacro(language.English, "their", plural.Selectf(1, "",
	plural.One, gender.Select(1, "female", "her", "other", "his"))),

Placeholders use parentheses and the arguments to invoke a macro.

Looking up messages

Message lookup using Catalogs is typically only done by specialized packages and is not something the user should be concerned with. For instance, to express the tardiness of a user using the related message we defined earlier, the user may use the package message like so:

p := message.NewPrinter(language.English)
p.Printf("You are %d minute(s) late.", 5)

Which would print:

You are 5 minutes late.

This package is UNDER CONSTRUCTION and its API may change.



This section is empty.


View Source
var ErrNotFound = errors.New("catalog: message not found")

ErrNotFound indicates there was no message for the given key.


This section is empty.


type Builder added in v0.2.0

type Builder struct {
	// contains filtered or unexported fields

A Builder allows building a Catalog programmatically.

func NewBuilder added in v0.2.0

func NewBuilder(opts ...Option) *Builder

NewBuilder returns an empty mutable Catalog.

func (*Builder) Context added in v0.2.0

func (b *Builder) Context(tag language.Tag, r catmsg.Renderer) *Context

Context returns a Context for formatting messages. Only one Message may be formatted per context at any given time.

func (*Builder) Languages added in v0.2.0

func (b *Builder) Languages() []language.Tag

Languages returns all languages for which the Catalog contains variants.

func (*Builder) Matcher added in v0.2.0

func (c *Builder) Matcher() language.Matcher

func (*Builder) Set added in v0.2.0

func (c *Builder) Set(tag language.Tag, key string, msg ...Message) error

Set sets the translation for the given language and key.

When evaluation this message, the first Message in the sequence to msgs to evaluate to a string will be the message returned.

func (*Builder) SetMacro added in v0.2.0

func (c *Builder) SetMacro(tag language.Tag, name string, msg ...Message) error

SetMacro defines a Message that may be substituted in another message. The arguments to a macro Message are passed as arguments in the placeholder the form "${foo(arg1, arg2)}".

func (*Builder) SetString added in v0.2.0

func (c *Builder) SetString(tag language.Tag, key string, msg string) error

SetString is shorthand for Set(tag, key, String(msg)).

type Catalog

type Catalog interface {
	// Languages returns all languages for which the Catalog contains variants.
	Languages() []language.Tag

	// Matcher returns a Matcher for languages from this Catalog.
	Matcher() language.Matcher

	// A Context is used for evaluating Messages.
	Context(tag language.Tag, r catmsg.Renderer) *Context
	// contains filtered or unexported methods

A Catalog allows lookup of translated messages.

func NewFromMap added in v0.2.0

func NewFromMap(dictionaries map[string]Dictionary, opts ...Option) (Catalog, error)

NewFromMap creates a Catalog from the given map. If a Dictionary is underspecified the entry is retrieved from a parent language.

type Context

type Context struct {
	// contains filtered or unexported fields

A Context is used for evaluating Messages. Only one Message may be formatted per context at any given time.

func (*Context) Execute

func (c *Context) Execute(key string) error

Execute looks up and executes the message with the given key. It returns ErrNotFound if no message could be found in the index.

type Dictionary added in v0.2.0

type Dictionary interface {
	// Lookup returns a message compiled with catmsg.Compile for the given key.
	// It returns false for ok if such a message could not be found.
	Lookup(key string) (data string, ok bool)

A Dictionary is a source of translations for a single language.

type Message

type Message = catmsg.Message

A Message holds a collection of translations for the same phrase that may vary based on the values of substitution arguments.

func String

func String(name string) Message

String specifies a plain message string. It can be used as fallback if no other strings match or as a simple standalone message.

It is an error to pass more than one String in a message sequence.

func Var

func Var(name string, msg ...Message) Message

Var sets a variable that may be substituted in formatting patterns using named substitution of the form "${name}". The name argument is used as a fallback if the statements do not produce a match. The statement sequence may not contain any Var calls.

The name passed to a Var must be unique within message sequence.

type Option

type Option func(*options)

An Option configures Catalog behavior.

func Fallback added in v0.2.0

func Fallback(tag language.Tag) Option

Fallback specifies the default fallback language. The default is Und.

Jump to

Keyboard shortcuts

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