lpax

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

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

Go to latest
Published: Aug 8, 2021 License: Apache-2.0 Imports: 9 Imported by: 8

README

lpax

Strong keyed string repository supporting internationalisation and separation of text definition from usage.

Status

Status Build Status Release Coveralls License GoReportCard Go Doc Conventional Commits

Installation

To add lpax to a project run:

go get github.com/nehemming/cirocket@latest

lpax supports modules.

Features

Applications and library packages typically embed string and error messages within the code. Placing strings inline within the code can make it harder to internationalise the code or to extract a list of all error messages generated by an application. lpax provides method of registering strings that can be accessed via decentralised keys. The key system uses Go's strong typing to allow each package to create its own key system without risking overlapping with other packages keys. multiple languages can be supported for key, with fallback logic to us the default english language.

  • String registration is implemented via the Registry interface. Packages can use their own registry instance but in most cases will use the shared Default registry.
  • Strongly typed keys (TextID's) ensure each package has isolated keys. Keys may be of int, uint, string or struct kinds.
  • Keys may be registered in multiple languages, allowing localized versions of the text to be used within an application.
  • Single and plural versions of a text message can be stored.
  • Applications can register overrides for messages registered by a package using the priority parameter of Register
  • Attach a TextFinder instance to a context, allowing different contexts to operate in different languages.
  • Helper Sprintf and Errorf functions supporting TextID implemented.
Typical implementation

Packages / applications wishing to use lpax will typically implement their own sub package containing the messages, or load them from an external source.

The example pack_example_test.go source shows a typical language package implementation.

It creates package PackID and TextID types (used as the package unique id amd message keys respectively) and registers the messages against the default registry using the init function.

type (
	// PackID is the local package id.
	// Each package should implement its own PackID type.
	// They are typically derived from the `int` type.
	PackID int

	// TextID is the id type for all messages defined by this package.
	// the TextID type must implement the lpax.TextID interface, but is typically
	// based on a `int` type.  As the package defines its own TextID it is
	// unique from other package types, and thus so are the ids.
	TextID int
)
var pack = lpax.TextMap{
	Hello:  "Hello World",
	-Hello: "Hello Worlds",
}

// register is the text registry callback function used to return the text mappings.
func register(packID lpax.PackID, langTag lpax.Tag) lpax.TextMap {
	return pack
}

func init() {
	// register the text mappings with the share test registry.
	lpax.Default().Register(ExamplePackID, register, lpax.DefaultPriority, language.English)
}

Users of the messages can then use the lpax Sprintf, CtxSprintf, Errorf or CtxErrorf methods to output the messages.

func Example() {
	fmt.Println(lpax.Sprintf(Hello))
	fmt.Println(lpax.Sprintf(Hello.Plural()))

	// Output:
	// Hello World
	// Hello Worlds
}

Messages can also be retrieved by calling Default().Text(id)

Contributing

We would welcome contributions to this project. Please read our CONTRIBUTION file for further details on how you can participate or report any issues.

License

FOSSA Status

This software is licensed under the Apache License.

Documentation

Overview

Package lpax is a strong keyed string repository implementation supporting internationalisation and separation of text definition from usage.

Applications and library packages typically embed string and error messages within the code. Placing strings inline within the code can make it harder to internationalise the code or to extract a list of all error messages generated by an application. `lpax` provides method of registering strings that can be accessed via decentralised keys. The key system uses Go's strong typing to allow each package to create its own key system without risking overlapping with other packages keys. multiple languages can be supported for key, with fallback logic to us the default `english` language.

The example below shows how to implement a typical language package.

Example
package main

import (
	"fmt"

	"github.com/nehemming/lpax"
	"golang.org/x/text/language"
)

type (
	// PackID is the local package id.
	// Each package should implement its own PackID type.
	// They are typically derived from the `int` type.
	PackID int

	// TextID is the id type for all messages defined by this package.
	// the TextID type must implement the lpax.TextID interface, but is typically
	// based on a `int` type.  As the package defines its own TextID it is
	// unique from other package types, and thus so are the ids.
	TextID int
)

// Single returns the id of for a single version of a message.
// Typical implementations use the lpax helper functions to implement the id system.
// Positive id's are used for single messages while -ve id's areused for plural versions.
func (id TextID) Single() lpax.TextID {
	return TextID(lpax.IntTypeSingle(int(id)))
}

// Plural returns the plural version of the id.
func (id TextID) Plural() lpax.TextID {
	return TextID(lpax.IntTypePlural(int(id)))
}

// String implements stringer function.
// ReflectCoderString reflects the package name used
// by the parent package along with the +ve integer id of the key.
func (id TextID) String() string {
	return lpax.ReflectCoderString(id.Single(), 1)
}

const (
	// ExamplePackID is the unique typed id for this pack.
	ExamplePackID = PackID(1)

	// None is a default empty message (id 0).
	None = TextID(iota)

	// Hello is an example message.
	Hello
)

var pack = lpax.TextMap{
	Hello:  "Hello World",
	-Hello: "Hello Worlds",
}

// register is the text registry callback function used to return the text mappings.
func register(packID lpax.PackID, langTag lpax.Tag) lpax.TextMap {
	return pack
}

func init() {
	// register the text mappings with the share test registry.
	lpax.Default().Register(ExamplePackID, register, lpax.DefaultPriority, language.English)
}

func main() {
	fmt.Println(lpax.Sprintf(Hello))
	fmt.Println(lpax.Sprintf(Hello.Plural()))

}
Output:

Hello World
Hello Worlds

Index

Examples

Constants

View Source
const (

	// AdditionalPacks are added after the original packs.
	AdditionalPacks = Priority(iota)

	// Package standard priority when a language included
	// its own messages, these are treated as the default.
	Package

	// Override use when registration wants preference over
	// the default implementation.
	// This should only be done by applications (package main's).
	Override

	// DefaultPriority default type priority.
	DefaultPriority = Package
)
View Source
const DefaultLanguage = "en"

DefaultLanguage is the default fallback language.

Variables

This section is empty.

Functions

func CtxErrorf

func CtxErrorf(ctx context.Context, id TextID, args ...interface{}) error

CtxErrorf is identical to fmt.Errorf except the format string is taken from the text finder linked to the passed context. If the context has no finder the default finder is used. If the string is not found the string version of the id is printed along with a space separated %v version of each arg.

func CtxSprintf

func CtxSprintf(ctx context.Context, id TextID, args ...interface{}) string

CtxSprintf is identical to fmt.Sprintf except the format string is taken from the text finder linked to the passed context. If the context has no finder the default finder is used. If the string is not found the string version of the id is printed along with a space separated %v version of each arg.

func DetectLocaleLanguage

func DetectLocaleLanguage() (language.Tag, error)

DetectLocaleLanguage returns the language of the current process or an error if it cannot be found.

func Errorf

func Errorf(id TextID, args ...interface{}) error

Errorf is identical to fmt.Errorf except the format string is taken from the default text finder. If the string is not found the string version of the id is printed along with a space separated %v version of each arg.

func IntTypePlural

func IntTypePlural(id int) int

IntTypePlural returns the integer id for a plural message. This is a helper function for implementors of TextID.

func IntTypeSingle

func IntTypeSingle(id int) int

IntTypeSingle returns the integer id for a single message. This is a helper function for implementors of TextID.

func MustDetectLocaleLanguage

func MustDetectLocaleLanguage(fallback string) language.Tag

MustDetectLocaleLanguage attempts to get the current the users language. If this is not discoverable the fallback language string will be tried. If this also fails or is not provided the function panics.

func ReflectCoderString

func ReflectCoderString(v interface{}, level ...int) string

ReflectCoderString supports the Coder interface by generating a description for an error code from its package path. v must be a int value kind, otherwise v is returned as a "%v" formatted string level is a single variadic value optionally specifying how many levels to traverse to get the path name. eg. package/path/here/place would return 0 - place, 1 - here etc.

func Sprintf

func Sprintf(id TextID, args ...interface{}) string

Sprintf is identical to fmt.Sprintf except the format string is taken from the default text finder. If the string is not found the string version of the id is printed along with a space separated %v version of each arg.

func WithContext

func WithContext(ctx context.Context, tf TextFinder) context.Context

WithContext creates a new context based off the passed ctx with the textFinder bound into the new context.

Types

type OnRegister

type OnRegister = func(packID PackID, langTag Tag) TextMap

OnRegister is the a callback function signature used to locate a registered language pack and return a TextMap containing its contents. The callback will only be called for pack IDs and languages that were registered with the registry. OnRegister may be called each time Registry New is called.

type PackID

type PackID = interface{}

PackID uses Go's strong typing system to create a unique identifier for a collection of string resources The pack ID is used to link different language version of the same pack together.

type Priority

type Priority int

Priority type to specify pack registration priority Priority is used by Text Registration types to prioritize their stored items. Items registered by an implementing package should register with Package priority If registering additional languages can use AdditionalPacks priority There packs will not take priority over the package implementors text map for a language defined in both. However AdditionalPacks priority allows extra languages to be added. Override priority can (and should only) be used by main application registrations where there is a need to replace a package registrations.

type Tag

type Tag = language.Tag

Tag alias language.Tag.

type TextFinder

type TextFinder interface {
	// Text looks up a text ID and returns the string associated with it or an empty string.
	Text(textID TextID) string

	// Find looks up the passed textID key and returns true if found
	Find(textID TextID) (t string, found bool)
}

TextFinder looks up a text ID and returns the string associated with it or an empty string, found.

func FromContext

func FromContext(ctx context.Context) TextFinder

FromContext returns the TextFinder bound into the context or if none if sound returns the Default TextFinder.

type TextID

type TextID interface {
	fmt.Stringer
	// Single is the id for the singular version of the text.
	Single() TextID
	// Plural is the id for the plural version of the text.
	Plural() TextID
}

TextID is a unique identifier for a text message. Source/package family should use a unique type to identify its messages valid types must be of an integer (intX or UIntX) type, a string or a struct The provider will panic if any other type is used If the identifier supports exterr.ErrorCoder or fmt.Stringer these interfaces will be used when rasing errors using Errorf or Sprintf.

func ByCount

func ByCount(id TextID, count int) TextID

ByCount returns the plural version of a count if count 1= 1.

type TextMap

type TextMap map[TextID]string

TextMap maps TextID keys to strings.

func NewTextMap

func NewTextMap(texts ...TextMap) TextMap

NewTextMap creates a new text map by merging zero or more exiting maps.

func (TextMap) Find

func (tm TextMap) Find(textID TextID) (t string, found bool)

Find looks up the passed textID key and returns true if found.

func (TextMap) Merge

func (tm TextMap) Merge(texts ...TextMap) TextMap

Merge combines tha passed TextMap's with the receiver TextMap. Items are merged left to right. Duplicate keys are overridden subsequent maps.

func (TextMap) Text

func (tm TextMap) Text(textID TextID) string

Text returns the text identified by the textID or an empty string.

type TextRegistry

type TextRegistry interface {
	TextFinder

	// Register maintains a collection of supported language packs by language.
	// The callback OnRegister function will be called if one of the registered language packs
	// needs to be loaded
	// The priority allows multiple overlapping TextMaps to be multiply registered for the same
	// language, giving increasing priority registrations in the order AdditionalPacks, Package and finally Override.
	// langTags is a list of languages that are being registered.  The first language has highest priority.
	Register(packID PackID, callback OnRegister, priority Priority, langTags ...Tag) TextRegistry

	// New returns a new text finder created from the registry.  Each call creates a new finder
	// options can be language Tags and additional TextMaps
	// language Tags must be supplied with the fallback language being first language in the list, if no language is provided the
	// DefaultLanguage is used.
	New(options ...interface{}) TextFinder
}

TextRegistry maintains a list of registered resource TextMaps by language. The registries New function builds language specifc TextProviders from the registered resource strings THe registry also creates a shared runtime TextProvider using the process owners detected language.

func Default

func Default() TextRegistry

Default returns the default text registry.

func NewRegistry

func NewRegistry() TextRegistry

NewRegistry creates a new text registry.

Jump to

Keyboard shortcuts

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