Bunyip a game engine in Go GitHub

Package github.com/matjam/bunyip/locale

locale

Package locale translates a game's strings. It provides tables of messages by language with placeholders and plural forms, a fallback chain so a half-translated language falls back to a configured source rather than showing keys, and the plural rules of the common languages.

A Bundle holds one Table per language, loaded from JSON files a translator edits:

{
  "menu.play": "Play",
  "hud.gold": "{n} gold",
  "inv.arrows": {"one": "{n} arrow", "other": "{n} arrows"}
}

To translate a string, get a language's Translator from the bundle and call T with a key and the values for its placeholders. A plural entry picks its form from the value named "n", or from the first number given. Keys missing from a language come from the fallbacks in order, and a key missing everywhere returns itself in brackets so it is visible and can be fixed. Right-to-left layout of the interface is the game's responsibility; the text itself shapes correctly through gfx. Bundles and tables have no internal locks. Finish loading them before sharing translators, or synchronize mutations with all readers.

Index

Types

type Bundle source

type Bundle struct {

	// Fallbacks are tried in order for keys a language lacks; the
	// source language, usually "en", goes last.
	Fallbacks []string
	// contains filtered or unexported fields
}

Bundle holds every language's table and the fallback order.

NewBundle source

func NewBundle(fallbacks ...string) *Bundle

NewBundle makes an empty bundle with fallbacks, the source language last.

Add source

func (b *Bundle) Add(t *Table)

Add puts a table in the bundle, replacing any for its language.

For source

func (b *Bundle) For(lang string) *Translator

For returns a translator for a language ("de", "pt-BR"): the language itself, then its base language without the region, then the bundle's fallbacks.

Languages source

func (b *Bundle) Languages() []string

Languages lists the loaded languages, sorted.

Load source

func (b *Bundle) Load(lang string, data []byte) error

Load parses JSON for a language and adds it.

Missing source

func (b *Bundle) Missing(lang, source string) []string

Missing lists the keys a language lacks that the source language has, for a translator's to-do list.

Table source

func (b *Bundle) Table(lang string) *Table

Table returns a language's table, nil when none is loaded.

type Category source

type Category string

Category is a plural form a language distinguishes.

const (
	Zero  Category = "zero"
	One   Category = "one"
	Two   Category = "two"
	Few   Category = "few"
	Many  Category = "many"
	Other Category = "other"
)

Plural-category names used in translation JSON. Which counts belong to a category depends on the language; Other is the fallback form.

Plural source

func Plural(lang string, n float64) Category

Plural returns the plural category of a count in a language, by the language's rules ("en", "fr", "ru", "ar", ...; a region suffix such as "pt-BR" is ignored except where it matters). Unknown languages use the one/other rule.

type Table source

type Table struct {
	Lang string // language tag used for plural rules and Bundle lookup
	// contains filtered or unexported fields
}

Table is one language's messages.

NewTable source

func NewTable(lang string) *Table

NewTable makes an empty table for a language.

ParseTable source

func ParseTable(lang string, data []byte) (*Table, error)

ParseTable reads a language's messages from JSON: a string per key, or an object of plural forms ("one", "other", ...). Keys may be nested objects, which flatten with dots: {"menu": {"play": "Play"}} is "menu.play".

Has source

func (t *Table) Has(key string) bool

Has reports whether the table has a key.

Keys source

func (t *Table) Keys() []string

Keys lists the table's keys, sorted, for checking a translation's coverage against the source language.

Set source

func (t *Table) Set(key, message string)

Set adds or replaces a plain message.

SetPlural source

func (t *Table) SetPlural(key string, forms map[Category]string)

SetPlural adds or replaces a message with plural forms. Include Other as a fallback: it is not validated, and when both the selected form and Other are absent, lookup chooses an unspecified available form. The map is retained, not copied. A plain entry of the same key takes precedence until the table is replaced.

type Translator source

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

Translator translates for one language. Get one with Bundle.For and keep it; changing language means asking for another.

Lang source

func (t *Translator) Lang() string

Lang is the language the translator was made for.

N source

func (t *Translator) N(key string, n int) string

N is T for the common case of one count: T(key, "n", n).

T source

func (t *Translator) T(key string, args ...any) string

T translates a key, filling {name} placeholders from args given as alternating names and values ("n", 3, "who", "Ada"). A plural entry picks its form from the value named "n", or the first number given. A missing key returns "[key]". Without a numeric argument a plural entry uses the category for 1. Unmatched placeholders stay as written; a trailing unpaired argument is ignored. Duplicate placeholder names use the last value.

Source files

bench_test.go locale.go locale_test.go review_test.go