spreak

package module
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Dec 7, 2023 License: BSD-3-Clause, MIT Imports: 14 Imported by: 5

README

Spreak Test status MIT license PkgGoDev Go Report Card codecov MinVersion

Flexible translation and humanization library for Go, based on the concepts behind gettext. Requires Go 1.19+.

Why another library?

There are already many good libraries for Go, which allow localizing an application. However, I always came to a point where I was dissatisfied. Either they use a self defined format, which could not be edited with common tools. Some libraries only support one language at a time or are using a lot of mutexes. And no tool could easily extract the strings to be translated. I wanted to solve these problems for myself, and so spreak was born.

Features
Usage

Using spreak is easy. First, use go get to install the latest version of the library.

go get -u github.com/vorlif/spreak

After that, spreak offers you a comprehensive interface to load and query your translations.

package main

import (
	"fmt"

	"golang.org/x/text/language"

	"github.com/vorlif/spreak"
	"github.com/vorlif/spreak/localize"
)

func main() {
	// Create a bundle that loads the translations for the required languages.
	// Typically, you only need one bundle in an application.
	bundle, err := spreak.NewBundle(
		// Set the language used in the program code/templates
		spreak.WithSourceLanguage(language.English),
		// Set the path from which the translations should be loaded
		spreak.WithDomainPath(spreak.NoDomain, "./locale"),
		// Specify the languages you want to load
		spreak.WithLanguage(language.German, language.Spanish, language.Chinese),
	)
	if err != nil {
		panic(err)
	}

	// Create a Localizer to select the language to translate.
	t := spreak.NewLocalizer(bundle, language.Spanish)

	// Translate
	fmt.Println(t.Get("Hello world"))
	fmt.Println(t.NGetf("I have %d dog", "I have %d dogs", 2, 2))
	fmt.Println(t.Localize(GetPlanet()))

	// Output: 
	// Hola Mundo
	// Tengo 2 perros
	// No conozco ningún planeta
}

func GetPlanet() *localize.Message {
	return &localize.Message{
		Singular: "I do not know any planet",
		Plural:   "I do not know any planets",
	}
}
Extract strings

Strings for the translations can be extracted via the command line program xspreak. Use a pre-built binary or install it from source:

go install github.com/vorlif/xspreak@latest

Tests installation with:

xspreak --help

xspreak extracts the strings from the program code and creates a template which can be used for new translations. Before you extract your strings, you have to decide on a format.

It can either create a .pot (PO Templates) file in po format or a .json file. If you are not sure which format to use, I would recommend you to use po format, because it is supported by almost all translation programs, which makes your life and the life of your translators much easier.

With -D you specify the path to your source code and with -p the one where the translation template should be saved.

# for .pot
xspreak -D path/to/source/ -p path/to/source/locale
# for .json
xspreak -D path/to/source/ -p path/to/source/locale -f json

This creates a new .pot or .json file representing the translation template.

Translate

po files

The generated POT files can be easily imported by most translation tools. If you are dealing with Po files for the first time, I recommend the application Poedit for a quick start.

After translation .po or .mo files are generated, which are used by spreak for looking up translations. Attention, do not translate the .pot file directly, as this is only a template.

json files

You can open and edit the JSON files with any text editor. The extracted template always uses only the plural categories one and other. To create a template with the plural categories suitable for your language, you can use xspreak.

xspreak merge -i locale/template.json -o locale/de.json -l de
Update translation files

⚠ It would be wise before making any move to keep a backup.

When you add, edit or delete text in your program code, you should also update the translation files. To achieve this, you must first update the template:

# for .pot
xspreak -D path/to/source/ -p path/to/source/locale
# for .json
xspreak -D path/to/source/ -p path/to/source/locale -f json

This creates a new .pot or .json file representing the new translation template.

po files

For PO files, almost every translation tool offers the possibility to update the files from a POT file. With Poedit you can do it via Translation -> Update from POT file. If you use the gettext utilities, you can use msgmerge -U es.po template.pot. For all other tools, it is worth taking a look at the documentation.

json files

For JSON files, xspreak offers a simple way to update the translation files.

xspreak merge -i locale/template.json -o locale/de.json -l de

This copies new keys and existing translations from template.json to de.json and deletes keys from de.json that are not present in template.json.

Structure translations

How you structure the files with the translations is up to you. Assuming you load the domain "helloworld" from the path "./locale" and the language language.Spanish

spreak.WithDomainPath("helloworld", "./locale"),
spreak.WithLanguage(language.Spanish),

Then spreak searches for the following files by default

./locale/es/helloworld.po
./locale/helloworld/es.po
./locale/es.po
./locale/LC_MESSAGES/es/helloworld.po

Where es is an example from the list [es-ES, es_ES, spa, es] and the file extension .po is an example from the list [po, mo, json]. If you don't like this behavior, you can implement your own Resolver. For special cases you can also implement your own Loader.

How to use in tests?

Just create a Bundle without options. This will never return an error and can be used to create Localizer which then simply return the input.

bundle, _ := spreak.NewBundle()
t := spreak.NewLocalizer(bundle, language.English)
What's next
  • Read what you can extract with xspreak
  • Take a look in the examples folder for more examples of using spreak.
  • Use it!

Package humanize PkgGoDev

The humanize package provides a collection of functions to convert Go data structures into a human-readable format. It was widely adapted from the Django project and also uses the Django translations. It should therefore be noted that the translations are under the Django's 3-clause BSD license.

To use the humanize package, you first need to load the languages you want to use. You can find a list of all supported languages under humanize/locale/

package main

import (
	"fmt"
	"time"

	"golang.org/x/text/language"

	"github.com/vorlif/spreak/humanize"
	"github.com/vorlif/spreak/humanize/locale/ar"
	"github.com/vorlif/spreak/humanize/locale/es"
	"github.com/vorlif/spreak/humanize/locale/zhHans"
)

func main() {
	// Load the translations for the desired languages
	collection := humanize.MustNew(
		humanize.WithLocale(es.New(), ar.New(), zhHans.New()),
	)

	// Create a humanizer.
	// A humanizer features a collection of humanize functions for a language.
	h := collection.CreateHumanizer(language.English)

	// Uses the functions...
	fmt.Println(h.Intword(1_000_000_000))
	// Output: 1.0 billion

	fmt.Println(h.NaturalDay(time.Now()))
	// Output: today

	t := time.Now().Add(5 * time.Minute)
	fmt.Println(h.NaturalTime(t))
	// Output: 5 minutes from now

	d := -80 * time.Hour
	fmt.Println(h.TimeSince(d))
	// Output: 3 days, 8 hours

	// ... for different languages
	h = collection.CreateHumanizer(language.Spanish)
	fmt.Println(h.TimeSince(d))
	// Output: 3 días, 8 horas
}

A collection of all functions and further examples can be found in the documentation.

Add translations

If you would like to add a translation or add a new language, do not do so in this repository. The translations in this repository are automatically generated from the Django translations and additions should also be made there. Use the following link to do so: https://www.transifex.com/django/django/. For all non-translation related errors, this repository must be used.

License

spreak is available under the MIT license. See the LICENSE file for more info. The translations of the humanize packages are licensed under Django's BSD license.

Documentation

Overview

Package spreak provides a simple translation facility based on the concepts of gettext.

Fundamentals

Domain: A message domain is a set of translatable messages. Usually, every software package has its own message domain. The domain name is used to determine the message catalog where the translation is looked up.

Default domain: The default domain is used if a domain is not explicitly specified for a requested translation. If no default domain is specified, the default domain of the bundle is used. If this was not specified either, the domain is NoDomain (an empty string).

Context: Context can be added to strings to be translated. A context dependent translation lookup is when a translation for a given string is searched, that is limited to a given context. The translation for the same string in a different context can be different. The different translations of the same string in different contexts can be stored in the same MO file, and can be edited by the translator in the same PO file. The Context string is visible in the PO file to the translator. You should try to make it somehow canonical and never changing. Because every time you change an Context, the translator will have to review the translation of msgid.

Plurals

For JSON files only the CLDR plural rules are supported. For po and mo files both gettext plural forms and CLDR plural rules are supported. The CLDR rules provides better support when floating point numbers are used. When using the CLDR plural rules with po files, a notation increasing from "Zero" to "Other" should be used. For example, if the used language supports "Zero", "Few" and "Other", Zero should be notated as entry 0, Few as entry 1 and Other as entry 2. It is also recommended to define a gettext compatible plural rule. On the website https://php-gettext.github.io/Languages/ you can find a list of gettext plural rules which are compatible to the CLDR plural rules.

To use the CLDR rules in po/mo files you can either add a header "X-spreak-use-CLDR: true" or create a decoder with catalog.NewPoCLDRDecoder() / catalog.NewMoCLDRDecoder().

For Polish with One, Few and Other, the structure of a Po file according to this convention could look like this:

msgid ""
msgstr ""
"Plural-Forms: n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : 2;\n"
"X-spreak-use-CLDR: true\n"

msgid "id"
msgid_plural "plural id"
msgstr[0] "Translation with the plural form One"
msgstr[1] "Translation with the plural form Few"
msgstr[2] "Translation with the plural form Other"

If floating point numbers are used, it is recommended to pass them formatted as strings as they will be displayed later. For example, if the number n is to be displayed with two numbers after the decimal point, it should be formatted with fmt.Sprintf("%.2f", n).

Index

Examples

Constants

View Source
const (
	// Deprecated: Will be removed in a future version.
	// Has only been used for tests so far.
	UnknownFile = "unknown"
	// PoFile is the file extension of Po files.
	// Deprecated: Will be removed in a future version.
	// The string should be kept in your own program code.
	PoFile = ".po"
	// MoFile is the file extension of Mo files.
	// Deprecated: Will be removed in a future version.
	// The string should be kept in your own program code.
	MoFile = ".mo"
	// JSONFile is the file extension of JSON files.
	// Deprecated: Will be removed in a future version.
	// The string should be kept in your own program code.
	JSONFile = ".json"
)
View Source
const ErrorsCtx = "errors"

ErrorsCtx ist the context under which translations for extracted errors are searched. Can be changed when creating a bundle with WithErrorContext.

View Source
const NoCtx = ""

NoCtx is the context which is used if no context is stored.

View Source
const NoDomain = ""

NoDomain is the domain which is used if no default domain is stored.

Variables

View Source
var (
	ErrRequireStringTag = errors.New("spreak: unsupported type, expecting string or language.Tag")
)

Functions

func ExpandLanguage

func ExpandLanguage(lang language.Tag) []string

ExpandLanguage returns possible filenames for a language tag without extension.

Example
package main

import (
	"fmt"

	"golang.org/x/text/language"

	"github.com/vorlif/spreak"
)

func main() {
	expanded := spreak.ExpandLanguage(language.MustParse("zh-Hans"))
	fmt.Println(expanded)
}
Output:

[zh-Hans zh_Hans zh-CN zh_CN zho zh]

func NewMoDecoder deprecated

func NewMoDecoder() catalog.Decoder

Deprecated: Moved to catalog.NewMoDecoder and will be removed with v1.0.

func NewPoDecoder deprecated

func NewPoDecoder() catalog.Decoder

Deprecated: Moved to catalog.NewPoDecoder and will be removed with v1.0.

Types

type Bundle

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

A Bundle is the central place to load and manage translations. It holds all catalogs for all domains and all languages. The bundle cannot be edited after creation and is goroutine safe. Typically, an application contains a bundle as a singleton. The catalog of the specified domains and languages will be loaded during the creation.

func NewBundle

func NewBundle(opts ...BundleOption) (*Bundle, error)

NewBundle creates a new bundle and returns it. An error is returned if something fails during creation. This is only the case if one of the options returns an error. A call without options will never return an error and can thus be used for testing or as a fallback. The catalog of the specified domains and languages will be loaded during the creation.

Example
package main

import (
	"fmt"

	"golang.org/x/text/language"

	"github.com/vorlif/spreak"
)

func main() {
	bundle, err := spreak.NewBundle(
		spreak.WithSourceLanguage(language.English),
		spreak.WithDefaultDomain("helloworld"),
		spreak.WithDomainPath("helloworld", "./examples/locale/"),
		spreak.WithLanguage(language.German, language.Spanish, language.French),
	)
	if err != nil {
		panic(err)
	}

	t := spreak.NewLocalizer(bundle, language.Spanish)

	fmt.Println(t.Get("Hello world"))
}
Output:

Hola Mundo

func (*Bundle) CanLocalize

func (b *Bundle) CanLocalize() bool

CanLocalize indicates whether locales and domains have been loaded for translation.

func (*Bundle) Domains

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

Domains returns a list of loaded domains. A domain is only loaded if at least one catalog is found in one language.

func (*Bundle) IsLanguageSupported

func (b *Bundle) IsLanguageSupported(lang language.Tag) bool

IsLanguageSupported indicates whether a language can be translated. The check is done by the bundle's matcher and therefore languages that are not returned by SupportedLanguages can be supported.

func (*Bundle) SupportedLanguages

func (b *Bundle) SupportedLanguages() []language.Tag

SupportedLanguages returns all languages for which a catalog was found for at least one domain.

type BundleOption

type BundleOption func(opts *bundleBuilder) error

BundleOption is an option which can be passed when creating a bundle to customize its configuration.

func WithDefaultDomain

func WithDefaultDomain(domain string) BundleOption

WithDefaultDomain sets the default domain which will be used if no domain is specified. By default, NoDomain (the empty string) is used.

func WithDomainFs

func WithDomainFs(domain string, fsys fs.FS) BundleOption

WithDomainFs loads a domain from a fs.FS.

This is a shorthand for WithFilesystemLoader(domain, WithFs(fsys)).

func WithDomainLoader

func WithDomainLoader(domain string, l Loader) BundleOption

WithDomainLoader loads a domain via a specified loader.

func WithDomainPath

func WithDomainPath(domain string, path string) BundleOption

WithDomainPath loads a domain from a specified path.

This is a shorthand for WithFilesystemLoader(domain, WithPath(path)).

func WithErrorContext

func WithErrorContext(ctx string) BundleOption

WithErrorContext set a context, which is used for the translation of errors. If no context is set, ErrorsCtx is used.

func WithFallbackLanguage

func WithFallbackLanguage(lang interface{}) BundleOption

WithFallbackLanguage sets the fallback language to be used when creating Localizer if no suitable language is available. Should be used only if the fallback language is different from source language. Otherwise, it should not be set.

func WithFilesystemLoader

func WithFilesystemLoader(domain string, fsOpts ...FsOption) BundleOption

WithFilesystemLoader Loads a domain via a FilesystemLoader. The loader can be customized with options.

func WithLanguage

func WithLanguage(languages ...interface{}) BundleOption

WithLanguage loads the catalogs of the domains for one or more languages. The passed languages must be of type string or language.Tag, all other values will abort the initialization of the bundle with an error. If a catalog file for a domain is not found for a language, it will be ignored. If a catlaog file for a domain is found but cannot be loaded, the bundle creation will fail and return errors.

If you want to use a Localizer, you should pay attention to the order in which the languages are specified, otherwise unexpected behavior may occur. This is because the matching algorithm of the language.matcher can give unexpected results. See https://github.com/golang/go/issues/49176

func WithLanguageMatcherBuilder

func WithLanguageMatcherBuilder(mc LanguageMatcherBuilder) BundleOption

WithLanguageMatcherBuilder sets a LanguageMatcherBuilder.

func WithMissingTranslationCallback

func WithMissingTranslationCallback(cb MissingTranslationCallback) BundleOption

WithMissingTranslationCallback stores a MissingTranslationCallback which is called when a translation, domain or something else is missing. The call is not goroutine safe.

func WithPrintFunction

func WithPrintFunction(printFunc PrintFunc) BundleOption

WithPrintFunction sets a PrintFunc which converts a formatted string and variables to a string. (Like fmt.Sprintf).

func WithPrinter

func WithPrinter(p Printer) BundleOption

WithPrinter sets a printer which creates a function for a language which converts a formatted string and variables into a string. (Like fmt.Sprintf).

func WithRequiredLanguage

func WithRequiredLanguage(languages ...interface{}) BundleOption

WithRequiredLanguage works like WithLanguage except that the creation of the bundle fails if a catalog for a language could not be found.

func WithSourceLanguage

func WithSourceLanguage(tag language.Tag) BundleOption

WithSourceLanguage sets the source language used for programming. If it is set, it will be considered as a matching language when creating a Localizer. Also, it will try to use the appropriate plural form and will not trigger any missing callbacks for the language. It is recommended to always set the source language.

type Catalog deprecated

type Catalog = catalog.Catalog

Catalog represents a collection of messages (translations) for a language and a domain. Normally it is a PO or MO file.

Deprecated: Moved to catalog.Catalog. This alias will be removed in version 1.0.

type Decoder deprecated

type Decoder = catalog.Decoder

A Decoder reads and decodes catalogs for a language and a domain from a byte array.

Deprecated: Moved to catalog.Decoder and will be removed with v1.0.

type ErrMissingContext deprecated

type ErrMissingContext = catalog.ErrMissingContext

Deprecated: Moved to catalog.ErrMissingContext and will be removed with v1.0.

type ErrMissingDomain

type ErrMissingDomain struct {
	Language language.Tag
	Domain   string
}

ErrMissingDomain is the error returned when a domain does not exist for a language.

func (*ErrMissingDomain) Error

func (e *ErrMissingDomain) Error() string

func (*ErrMissingDomain) String

func (e *ErrMissingDomain) String() string

type ErrMissingLanguage

type ErrMissingLanguage struct {
	Language language.Tag
}

ErrMissingLanguage is the error returned when a locale should be created and the matching language is not loaded or has no Catalog.

func (*ErrMissingLanguage) Error

func (e *ErrMissingLanguage) Error() string

func (*ErrMissingLanguage) String

func (e *ErrMissingLanguage) String() string

type ErrMissingMessageID deprecated

type ErrMissingMessageID = catalog.ErrMissingMessageID

Deprecated: Moved to catalog.ErrMissingMessageID and will be removed with v1.0.

type ErrMissingTranslation deprecated

type ErrMissingTranslation = catalog.ErrMissingTranslation

Deprecated: Moved to catalog.ErrMissingTranslation and will be removed with v1.0.

type ErrNotFound

type ErrNotFound struct {
	Language   language.Tag
	Type       string
	Identifier string
}

ErrNotFound is the error returned by a loader if no matching context was found. If a loader returns any other error, the bundle creation will abort.

func NewErrNotFound

func NewErrNotFound(lang language.Tag, source string, format string, vars ...interface{}) *ErrNotFound

func (*ErrNotFound) Error

func (e *ErrNotFound) Error() string

func (*ErrNotFound) String

func (e *ErrNotFound) String() string

type FilesystemLoader

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

FilesystemLoader is a Loader which loads and decodes files from a file system. A file system here means an implementation of fs.FS.

func NewFilesystemLoader

func NewFilesystemLoader(opts ...FsOption) (*FilesystemLoader, error)

NewFilesystemLoader creates a new FileSystemLoader. If no file system was stored during the creation, an error is returned. If no decoder has been stored, the Po and Mo decoders are automatically used. Otherwise, only the stored decoders are used.

func (*FilesystemLoader) Load

func (l *FilesystemLoader) Load(lang language.Tag, domain string) (catalog.Catalog, error)

type FsOption

type FsOption func(l *FilesystemLoader) error

FsOption is an option which can be used when creating the FilesystemLoader.

func WithDecoder

func WithDecoder(ext string, decoder catalog.Decoder) FsOption

WithDecoder stores a decoder for a file extension.

The file extension should begin with a dot. For example ".po" or ".json".

func WithFs added in v0.1.1

func WithFs(fsys fs.FS) FsOption

WithFs stores a fs.FS as filesystem. The file system can only be accessed with paths which are separated by slashes (Unix style). If a different behavior is desired, a separate resolver must be stored with WithResolver. Lets the creation of the FilesystemLoader fail, if a filesystem was already deposited.

func WithJSONDecoder added in v0.6.0

func WithJSONDecoder() FsOption

WithJSONDecoder stores the JSON file decoder.

Shorthand for WithDecoder(".json", catalog.NewJSONDecoder()).

func WithMoDecoder

func WithMoDecoder() FsOption

WithMoDecoder stores the mo file decoder.

Shorthand for WithDecoder(".mo", catalog.NewMoDecoder()).

func WithPath added in v0.1.1

func WithPath(path string) FsOption

WithPath stores a path as filesystem. Lets the creation of the FilesystemLoader fail, if a filesystem was already deposited.

func WithPoDecoder

func WithPoDecoder() FsOption

WithPoDecoder stores the mo file decoder.

Shorthand for WithDecoder(".po", catalog.NewPoDecoder()).

func WithResolver added in v0.2.1

func WithResolver(resolver Resolver) FsOption

WithResolver stores the resolver of a FilesystemLoader. Lets the creation of the FilesystemLoader fail, if a Resolver was already deposited.

func WithSystemFs

func WithSystemFs() FsOption

WithSystemFs stores the root path as filesystem. Lets the creation of the FilesystemLoader fail, if a filesystem was already deposited.

Shorthand for WithPath("").

type KeyLocalizer added in v0.3.0

type KeyLocalizer struct {
	*Localizer
}

A KeyLocalizer is a wrapper for a Localizer, which can be used when looking up translations by key and not by source language. It provides the same methods as a Localizer, but does not require the specification of a plural text. The usage is useful for example when the translations are loaded from JSON files with a key-value structure.

func NewKeyLocalizer added in v0.3.0

func NewKeyLocalizer(bundle *Bundle, langs ...interface{}) *KeyLocalizer

NewKeyLocalizer creates a new Localizer with NewLocalizer which is then wrapped by a KeyLocalizer.

func NewKeyLocalizerForDomain added in v0.3.0

func NewKeyLocalizerForDomain(bundle *Bundle, domain string, lang ...interface{}) *KeyLocalizer

NewKeyLocalizerForDomain creates a new Localizer with NewLocalizerForDomain which is then wrapped by a KeyLocalizer.

func (*KeyLocalizer) DGet added in v0.3.0

func (l *KeyLocalizer) DGet(domain localize.Domain, key localize.Key) string

DGet operates like Get, but look the message up in the specified domain.

func (*KeyLocalizer) DGetf added in v0.3.0

func (l *KeyLocalizer) DGetf(domain localize.Domain, key localize.Key, vars ...interface{}) string

DGetf operates like Get, but look the message up in the specified domain and formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) DNGet added in v0.3.0

func (l *KeyLocalizer) DNGet(domain localize.Domain, key localize.PluralKey, n interface{}) string

DNGet operates like NGet, but look the message up in the specified domain.

func (*KeyLocalizer) DNGetf added in v0.3.0

func (l *KeyLocalizer) DNGetf(domain localize.Domain, key localize.PluralKey, n interface{}, vars ...interface{}) string

DNGetf operates like DNGet, but formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) DNPGet added in v0.3.0

func (l *KeyLocalizer) DNPGet(domain localize.Domain, context localize.Context, key localize.PluralKey, n interface{}) string

DNPGet operates like NGet, but look the message up in the specified domain and with the specified context.

func (*KeyLocalizer) DNPGetf added in v0.3.0

func (l *KeyLocalizer) DNPGetf(domain localize.Domain, context localize.Context, key localize.PluralKey, n interface{}, vars ...interface{}) string

DNPGetf operates like DNPGet, but formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) DPGet added in v0.3.0

func (l *KeyLocalizer) DPGet(domain localize.Domain, context localize.Context, key localize.Key) string

DPGet operates like Get, but look the message up in the specified domain and with the specified context.

func (*KeyLocalizer) DPGetf added in v0.3.0

func (l *KeyLocalizer) DPGetf(domain localize.Domain, context localize.Context, key localize.Key, vars ...interface{}) string

DPGetf operates like DPGet, but formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) Get added in v0.3.0

func (l *KeyLocalizer) Get(key localize.Key) string

func (*KeyLocalizer) Getf added in v0.3.0

func (l *KeyLocalizer) Getf(key localize.Key, vars ...interface{}) string

Getf operates like Get, but formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) NGet added in v0.3.0

func (l *KeyLocalizer) NGet(key localize.PluralKey, n interface{}) string

NGet acts like Get, but consider plural forms. The plural formula is applied to n and return the resulting message (some languages have more than two plurals).

func (*KeyLocalizer) NGetf added in v0.3.0

func (l *KeyLocalizer) NGetf(key localize.PluralKey, n interface{}, vars ...interface{}) string

NGetf operates like NGet, but formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) NPGet added in v0.3.0

func (l *KeyLocalizer) NPGet(context localize.Context, key localize.PluralKey, n interface{}) string

NPGet operates like NGet, but restricted to the specified context.

func (*KeyLocalizer) NPGetf added in v0.3.0

func (l *KeyLocalizer) NPGetf(context localize.Context, key localize.PluralKey, n interface{}, vars ...interface{}) string

NPGetf operates like NPGet, but formats the message according to a format identifier and returns the resulting string.

func (*KeyLocalizer) PGet added in v0.3.0

func (l *KeyLocalizer) PGet(context localize.Context, key localize.Key) string

PGet operates like Get, but restricted to the specified context.

func (*KeyLocalizer) PGetf added in v0.3.0

func (l *KeyLocalizer) PGetf(context localize.Context, key localize.Key, vars ...interface{}) string

PGetf operates like PGet, but formats the message according to a format identifier and returns the resulting string.

type LanguageMatcherBuilder

type LanguageMatcherBuilder func(t []language.Tag, options ...language.MatchOption) language.Matcher

LanguageMatcherBuilder is a builder which creates a language matcher. It is an abstraction of language.NewMatcher of the language package and should return the same values. Can be set when creating a bundle with WithLanguageMatcherBuilder for a bundle. The matcher is used, for example, when a new Localizer is created to determine the best matching language.

type Loader

type Loader interface {
	Load(lang language.Tag, domain string) (catalog.Catalog, error)
}

Loader is responsible for loading Catalogs for a language and a domain. A bundle loads each domain through its own loader.

If a loader cannot find a matching catalog for it must return error spreak.ErrNotFound, otherwise the bundle creation will be aborted with the returned error.

type Locale deprecated

type Locale = Localizer

Deprecated: Will be removed with v1.0. A Localizer should be used, as it offers the same functionalities.

func NewLocale

func NewLocale(bundle *Bundle, lang language.Tag) (*Locale, error)

NewLocale creates a new locale for a language and the default domain of the bundle. If a locale is not found, an error is returned. Deprecated: Will be removed with v1.0. Use NewLocalizer instead.

func NewLocaleWithDomain

func NewLocaleWithDomain(bundle *Bundle, lang language.Tag, domain string) (*Locale, error)

NewLocaleWithDomain creates a new locale for a language and a default domain. If no locale is found, an error is returned. Deprecated: Will be removed with v1.0. Use NewLocalizerForDomain instead.

type Localizer

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

A Localizer holds the catalogs of all domains for a language and provides an interface for their use. It has a default domain, which can differ from the bundle default domain and is used if no domain is specified for translations. A number of supported languages can be specified at creation time, where the language matcher of the bundle decides which language fits best. For this language the Localizer then offers the possibility to translate. If no language fits, the fallback language is used. If no fallback language is specified, the source language is used. For web applications, a Localizer can be created for each request, which can be disposed of at the end of the request.

func NewLocalizer

func NewLocalizer(bundle *Bundle, lang ...interface{}) *Localizer

NewLocalizer operates like NewLocalizerForDomain, with the default domain of the bundle as domain.

func NewLocalizerForDomain

func NewLocalizerForDomain(bundle *Bundle, domain string, lang ...interface{}) *Localizer

NewLocalizerForDomain creates a new Localizer for a language and a default domain, which is used if no domain is specified. Multiple languages can be passed and the best matching language is searched for. If no matching language is found, a Localizer is created which returns the original messages. Valid languages are strings or language.Tag. All other inputs are dropped.

func (*Localizer) DGet

func (l *Localizer) DGet(domain localize.Domain, message localize.Singular) string

DGet operates like Get, but look the message up in the specified domain.

func (*Localizer) DGetf

func (l *Localizer) DGetf(domain localize.Domain, message localize.Singular, vars ...interface{}) string

DGetf operates like Get, but look the message up in the specified domain and formats the message according to a format identifier and returns the resulting string.

func (*Localizer) DNGet

func (l *Localizer) DNGet(domain localize.Domain, singular localize.Singular, plural localize.Plural, n interface{}) string

DNGet operates like NGet, but look the message up in the specified domain.

func (*Localizer) DNGetf

func (l *Localizer) DNGetf(domain localize.Domain, singular localize.Singular, plural localize.Plural, n interface{}, vars ...interface{}) string

DNGetf operates like DNGet, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) DNPGet

func (l *Localizer) DNPGet(domain localize.Domain, context localize.Context, singular localize.Singular, plural localize.Plural, n interface{}) string

DNPGet operates like NGet, but look the message up in the specified domain and with the specified context.

func (*Localizer) DNPGetf

func (l *Localizer) DNPGetf(domain localize.Domain, context localize.Context, singular localize.Singular, plural localize.Plural, n interface{}, vars ...interface{}) string

DNPGetf operates like DNPGet, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) DPGet

func (l *Localizer) DPGet(domain localize.Domain, context localize.Context, message localize.Singular) string

DPGet operates like Get, but look the message up in the specified domain and with the specified context.

func (*Localizer) DPGetf

func (l *Localizer) DPGetf(domain localize.Domain, context localize.Context, message localize.Singular, vars ...interface{}) string

DPGetf operates like DPGet, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) DefaultDomain

func (l *Localizer) DefaultDomain() string

DefaultDomain returns the default domain. The default domain is used if a domain is not explicitly specified for a requested translation. If no default domain is specified, the default domain of the bundle is used.

func (*Localizer) Domains added in v0.3.0

func (l *Localizer) Domains() []string

Domains returns a list of all domains for which a catalog was found.

func (*Localizer) Get

func (l *Localizer) Get(message localize.Singular) string

The Get function return the localized translation of message, based on the used locale current default domain and language of the locale. The message argument identifies the message to be translated. If no suitable translation exists and a fallback language has been provided, the text of this language will be returned. If no fallback is provided or no translation exists for the fallback language, the source message is returned.

Example
package main

import (
	"fmt"

	"golang.org/x/text/language"

	"github.com/vorlif/spreak"
)

func main() {
	bundle, err := spreak.NewBundle(
		spreak.WithSourceLanguage(language.English),
		spreak.WithDefaultDomain("helloworld"),
		spreak.WithDomainPath("helloworld", "./examples/locale/"),
		spreak.WithLanguage(language.German, language.Spanish, language.French),
	)
	if err != nil {
		panic(err)
	}

	t := spreak.NewLocalizer(bundle, language.Spanish)

	fmt.Println(t.Get("Hello world"))
}
Output:

Hola Mundo

func (*Localizer) Getf

func (l *Localizer) Getf(message localize.Singular, vars ...interface{}) string

Getf operates like Get, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) HasDomain added in v0.3.0

func (l *Localizer) HasDomain(domain string) bool

HasDomain checks whether a catalog has been loaded for a specified domain.

func (*Localizer) HasLocale

func (l *Localizer) HasLocale() bool

HasLocale returns whether a matching locale has been found and message translation can take place.

func (*Localizer) Language

func (l *Localizer) Language() language.Tag

Language returns the language into which the translation of messages is performed. If no language is present, language.Und is returned.

func (*Localizer) Localize

func (l *Localizer) Localize(t localize.Localizable) string

Localize acts like LocalizeWithError, but does not return an error.

Example
package main

import (
	"fmt"

	"golang.org/x/text/language"

	"github.com/vorlif/spreak"
	"github.com/vorlif/spreak/localize"
)

func main() {
	bundle, err := spreak.NewBundle(
		spreak.WithDefaultDomain("helloworld"),
		spreak.WithDomainPath("helloworld", "./examples/locale/"),
		spreak.WithLanguage(language.German, language.Spanish, language.French),
	)
	if err != nil {
		panic(err)
	}

	t := spreak.NewLocalizer(bundle, language.Spanish)

	msg := &localize.Message{Singular: "Hello world"}
	fmt.Println(t.Localize(msg))
}
Output:

Hola Mundo

func (*Localizer) LocalizeError

func (l *Localizer) LocalizeError(err error) error

LocalizeError translates the passed error and returns a new error of type localize.Error which wraps the original error. If no suitable translation is found, the original error is returned. By default, localized messages with the context "errors" are searched for. The query is limited to the current domain and the error context specified in the corresponding bundle. By default, this is the context "errors". Using WithErrorContext("other") during bundle creation to change the error context for a bundle.

func (*Localizer) LocalizeWithError

func (l *Localizer) LocalizeWithError(t localize.Localizable) (string, error)

LocalizeWithError translates structs that implement the interface localize.Localizable. If a suitable translation is found, it will be returned. If no matching translation is found, the original string with the matching plural form and an error are returned.

func (*Localizer) NGet

func (l *Localizer) NGet(singular localize.Singular, plural localize.Plural, n interface{}) string

NGet acts like Get, but consider plural forms. The plural formula is applied to n and return the resulting message (some languages have more than two plurals). If n is a floating-point number and the CLDR rules are used, the floating-point number should be represented and passed as a string for the best result.

func (*Localizer) NGetf

func (l *Localizer) NGetf(singular localize.Singular, plural localize.Plural, n interface{}, vars ...interface{}) string

NGetf operates like NGet, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) NPGet

func (l *Localizer) NPGet(context localize.Context, singular localize.Singular, plural localize.Plural, n interface{}) string

NPGet operates like NGet, but restricted to the specified context.

func (*Localizer) NPGetf

func (l *Localizer) NPGetf(context localize.Context, singular localize.Singular, plural localize.Plural, n interface{}, vars ...interface{}) string

NPGetf operates like NPGet, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) PGet

func (l *Localizer) PGet(context localize.Context, message localize.Singular) string

PGet operates like Get, but restricted to the specified context.

func (*Localizer) PGetf

func (l *Localizer) PGetf(context localize.Context, message localize.Singular, vars ...interface{}) string

PGetf operates like PGet, but formats the message according to a format identifier and returns the resulting string.

func (*Localizer) Print added in v0.2.0

func (l *Localizer) Print(format string, vars ...interface{}) string

type MissingTranslationCallback

type MissingTranslationCallback func(err error)

MissingTranslationCallback is a callback which can be stored with WithMissingTranslationCallback for a bundle. Called when translations, domains, or other are missing. The call is not goroutine safe.

type PrintFunc

type PrintFunc func(str string, vars ...interface{}) string

PrintFunc formats according to a format specifier and returns the resulting string. Like fmt.Sprintf(...)

type Printer

type Printer interface {
	Init(languages []language.Tag)
	GetPrintFunc(lang language.Tag) PrintFunc
}

A Printer creates a PrintFunc for a language. Can be stored with WithPrinter when creating a bundle.

func NewDefaultPrinter

func NewDefaultPrinter() Printer

NewDefaultPrinter creates a printer which will be used if no printer was defined with WithPrinter when creating a bundle.

type Resolver added in v0.2.1

type Resolver interface {
	Resolve(fsys fs.FS, extensions string, lang language.Tag, domain string) (string, error)
}

A Resolver is used by the FilesystemLoader to resolve the appropriate path for a file. If a file was not found, os.ErrNotExist should be returned. All other errors cause the loaders search to stop.

fsys represents the file system from which the FilesystemLoader wants to load the file. extensions is the file extension for which the file is to be resolved. Language and Domain indicate for which domain in which language the file is searched.

func NewDefaultResolver added in v0.2.1

func NewDefaultResolver(opts ...ResolverOption) (Resolver, error)

NewDefaultResolver create a resolver which can be used for a FilesystemLoader. It is the Resolver that is used if no separate resolver has been set. He tries to find the files in different directories and returns the file that it found first.

For example, if a Mo file is to be found, an attempt is made to resolve the following paths.

  • .../locale/category/domain.mo
  • .../locale/LC_MESSAGES/domain.mo
  • .../locale/domain.mo
  • .../domain/locale.mo
  • .../locale.mo
  • .../category/locale.mo
  • .../LC_MESSAGES/locale.mo

type ResolverOption added in v0.2.1

type ResolverOption func(r *defaultResolver)

ResolverOption is an option which can be used when creating the DefaultResolver.

func WithCategory

func WithCategory(category string) ResolverOption

WithCategory defines an additional category which is included in the search. For Gettext files, LC_MESSAGES is often used for this.

func WithDisabledSearch

func WithDisabledSearch() ResolverOption

Directories

Path Synopsis
cldrplural
This file is generated by cldrplural/generator/generate.sh; DO NOT EDIT
This file is generated by cldrplural/generator/generate.sh; DO NOT EDIT
po
Package po allows to read and write gettext po files.
Package po allows to read and write gettext po files.
poplural
This file is generated by poplural/generator/main.go; DO NOT EDIT
This file is generated by poplural/generator/main.go; DO NOT EDIT
Package humanize provides a collection of functions to convert Go data structures into a human-readable format.
Package humanize provides a collection of functions to convert Go data structures into a human-readable format.
internal
mo
xspreak module

Jump to

Keyboard shortcuts

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