messages

package module
v0.0.0-...-c1297b5 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2024 License: MIT Imports: 18 Imported by: 0

README

Messages

This repository handles message translations using simple JSON files for Go (Golang) projects. The messages can be specific to a language or a combination of language and region.

# Example translation file en.json
{
    "welcome.message": "Welcome :user!"
}

Message extraction

Users can use the msgextractor tool to extract translation keys from your go source files. This will collect every value of type github.com/wvell/messages.Key from the src directory.

msgextractor -dst path_to_translation_files --src path_to_go_source_files

// Use -default-language to set the default language as source for the translations. Missing translations for other languages will use this as the source.
msgextractor -dst path_to_translation_files -src path_to_go_source_files -default-language en

Usage

// Parse translations.
translations, err := messages.FromDir("directory with translation files")
if err != nil {
    // Handle error
    log.Fatalf("Failed to parse translations: %v", err)
}

// Setting the language context per request.
// Parse the language from a user request. This can be from a header or user settings, for example the http Accept-Language header.
ctx := context.Background()
ctx, err := messages.WithLanguage(ctx, r.Header.Get("Accept-Language"))
if err != nil {
    // Handle error...
}
// Translate the message.
// If the user requested "en-US" but you only have "en" translations available, the translator will use the "en" translations.
msg := translations.Translate(ctx, "welcome.message", map[string]any{"user": "wvell"})
fmt.Println(msg) // prints: Welcome wvell!

Capitalization

You can use a capitalized replacement to to capitalize the replacement value:

{
    "welcome.message": "Welcome :User!"
}

This will change the replacement value "john" to "John".

Attributes

Attributes allow you to reuse placeholder values, which is particularly useful for validation messages. The following example illutrates the required validation message. Without attributes you would have to create a translation for each field(required.first_name, required.street).

# es.json
{
  "required": ":Attribute es requerido"
  "attributes": {
    "field" : {
      "first_name": "nombre",
      "street": "calle"
    }
  }
}
tr.Translate(ctx, "required", map[string]any{"attribute": "first_name"}) // Nombre es requerido
tr.Translate(ctx, "required", map[string]any{"attribute": "street"}) // Calle es requerido

As you can see this also takes the title case for the translation message into account.

Documentation

Index

Constants

View Source
const (

	// AttributeKey is the key that is used for the :attribute replacement.
	AttributeKey = "attribute"
)

Variables

View Source
var (
	ErrDuplicateReplacementWithDifferentCase = fmt.Errorf("duplicate replacement with different case")
)
View Source
var (
	ErrInvalidTranslationKey = fmt.Errorf("restricted translation key: attributes")
)

Functions

func ToCtx

func ToCtx(ctx context.Context, lang string) context.Context

ToCtx is comparable to WithLanguage, but does not return an error when parsing the language fails. On failure it will return the context as is.

func TranslationKeysFromSourceCode

func TranslationKeysFromSourceCode(dir string) ([]string, error)

TranslationKeysFromSourceCode finds all translation key's used in go source files. It will parse dir and every subdirectory recursively for go files and search for instances of messages.Key.

func WithLanguage

func WithLanguage(ctx context.Context, lang string) (context.Context, error)

WithLanguage sets the language in the ctx. Language is parsed to retrieve the language and region. If the region can not reliably be parsed, it is set to an empty string. An error is returned if the language can not be parsed.

Types

type Key

type Key string

Key is a type that represents a translation key. Msgextractor will look for this type in the source code to extract all keys.

type LanguageID

type LanguageID struct {
	Language string
	Region   string
}

LanguageID holds the language and an optional region.

func FromCtx

func FromCtx(ctx context.Context) LanguageID

LanguageFromCtx returns the language from the ctx.

func ParseLanguage

func ParseLanguage(lang string) (LanguageID, error)

ParseLanguage parses the language string into a LanguageID.

func (LanguageID) Empty

func (l LanguageID) Empty() bool

func (LanguageID) String

func (l LanguageID) String() string

type Opt

type Opt func(*Translator)

Opt is a functional option for the Translator.

func WithDefaultLanguage

func WithDefaultLanguage(lang LanguageID) Opt

Use the given default language when the ctx has no language set or the language has no translations.

type Parser

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

func NewParser

func NewParser(fs afero.Fs) *Parser

func (*Parser) MessagesFromFile

func (p *Parser) MessagesFromFile(filename string) (*RawMessages, error)

RawTranslationsFromFile reads the translations from the given file and returns them as a map.

func (*Parser) TranslationFilesFromDir

func (p *Parser) TranslationFilesFromDir(dir string) (map[string]string, error)

TranslationFilesFromDir returns all translation files from the given directory.

type RawMessages

type RawMessages struct {
	Messages   map[string]string
	Attributes map[string]string
}

func (*RawMessages) MarshalJSON

func (r *RawMessages) MarshalJSON() ([]byte, error)

func (*RawMessages) UnmarshalJSON

func (r *RawMessages) UnmarshalJSON(data []byte) error

type Translator

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

Translator holds translations for all Languages. Use the Translate message to look up translations.

func NewTranslator

func NewTranslator(fs afero.Fs, dir string, opts ...Opt) (*Translator, error)

NewTranslator reads all translations from the given directory and returns a new Translator. The directory should contain simple json files with the translations. The filename should be the language code, e.g. en.json.

Translations should be in the format:

{
	"validation.required": ":Attribute is required.",
	"attributes": {
		"addr_street" : "street"
	}
}

A translation file can have attributes. An attribute changes the replacement value before it is inserted into the translation. This can be useful for validation rules. Field names often have name like first_name or last_name. When using the translation example above:

translator.Translate("validation.required", map[string]any{"attribute": "addr_street"})
Output: Street is required.

func (*Translator) Translate

func (t *Translator) Translate(ctx context.Context, key Key, replacements map[string]any) string

Translate translates the key for the given lang(in ctx).

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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