i18n

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Feb 18, 2024 License: MIT Imports: 19 Imported by: 4

README

i18n

i18n support for golang applications. Supports message translation with placeholders and plurals, locale-specific string sorting, and number/currency formatting.

Copyright 2014 Vubeology, Inc.

Released under the MIT License (see LICENSE).

Usage

Read the full documentation here: http://godoc.org/github.com/vube/i18n

License

As stated about this golang package is released under the MIT License (see LICENSE).

Third Party Package Licenses

This i18n package makes use of third party packages in addition to the golang standard library and supplemental libraries. This package however does not modify or redistribute any third party package material.

While this i18n package is released under the MIT License, you must ensure that your use of this package also complies with the licenses under which each third party dependency is released.

launchpad.net/gocheck

This i18n package makes use of the launchpad.net/gocheck package, released under a Simplified BSD License. For specific license details, refer directly to the the gocheck package.

gopkg.in/yaml.v1

This i18n package makes use of the gopkg.in/yaml.v1 package, released under the LGPLv3 License. For specific license details, refer directly to the yaml package.

Call for open source help!

We could use some help. We do however have some guidelines if you want to contribute to our package.

For supplementing locale data:

If you have locale rules data that we are missing, we welcome all additional rules data in our standard yaml format. Please include comments in the yaml on how you sourced the data - AKA, you are a native speaker of a language, you got it from XYZ website, a professional translator provided the data, etc.

When supplementing locale data, you may add a locale who's language uses a set of plural rules that this package does not support. In this case, please add an additional plural rule function to the plurals.go file and add it to the plural rule map.

There is a unit test in rules_test.go that checks loading every single locale in this package. If you are adding a brand new locale to the list, please add it to this unit test.

For fixing bugs:

If you find a bug that you'd like to fix, please include a unit test that validates your work. This test should fail without the fix you provide and pass with the fix you provide.

For new features:

If you've decided to either tackle a feature on our wish list or you have a feature that you need in order to use our package, please provide a minimum of 80% unit test coverge over the code written for this new feature.

A note on unit testing:

We use the launchpad.net/gocheck package in our unit tests. We ask that you also use this package for tests that you write, for consistency sake.

Documentation

Overview

Package i18n offers the following basic internationalization functionality:

  • message translation
  • with placeholder support
  • with plural support
  • number formatting
  • with currency support
  • with percentage support
  • locale-aware string sorting

There's more we'd like to add in the future, including:

  • datetime formatting
  • ordinals
  • CLDR xml to yaml rules generation
  • data caching with size limitations
  • nestable message categories
  • small-string number formatting
  • 7m : about 7 million
  • 1.2k : about 1,200
  • 253 : exactly 253
  • 25b : about 25 billion
  • etc.
  • out-of-the-box CLDR messages
  • date/time units
  • calendar/month/day names
  • languages
  • geographic region and country names
  • currencies
  • etc.

How the i18n Package Works

In order to interact with this package, you must first get a TranslatorFactory instace. Through the TranslatorFactory, you can get a Translator instance. Almost everything in this package is accessed through methods on the Translator struct.

About the rules and messages paths: This package ships with built-in rules, and you are welcome to use those directly. However, if there are locales or rules that are missing from what ships directly with this package, or if you desire to use different rules than those that ship with this package, then you can specify additional rules paths. At this time, this package does not ship with built-in messages, other than a few used for the unit tests. You will need to specify your own messages path(s). For both rules and messages paths, you can specify multiple. Paths later in the slice take precedence over packages earlier in the slice.

For a basic example of getting a TranslatorFactory instance:

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en")

	_ = tEn
}

Simple Message Translation

For simple message translation, use the Translate function, and send an empty map as the second argument (we'll explain that argument in the next section).

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en")

	// WELCOME_MSG => "Welcome!"
	translation, _ := tEn.Translate("WELCOME_MSG", map[string]string{})

	_ = translation
}

Message Translation with Placeholders

You can also pass placeholder values to the translate function. That's what the second argument is for. In this example, we will inject a username into the translation.

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en")

	// WELCOME_USER => "Welcome, {user}!"
	username := "Mother Goose"
	translation, _ := tEn.Translate("WELCOME_USER", map[string]string{
		"user" : username
	})

	// results in "Welcome, Mother Goose!"

	_ = translation
}

Plural Message Translation

You can also translate strings with plurals. However, any one message can contain at most one plural. If you want to translate "I need 5 apples and 3 oranges" you are out of luck.

The Pluralize method takes 3 arguments. The first is the message key - just like the Translate method. The second argument is a float which is used to determine which plural form to use. The third is a string representation of the number. Why two arguments for the number instead of one? This allows you ultimate flexibility in number formatting to use in the translation while eliminating the need for string number parsing.

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en")

	// DAYS_AGO => "{n} day ago|{n} days ago"
	translation1, _ := tEn.Pluralize("DAYS_AGO", 1, "1")
	translation2, _ := tEn.Pluralize("DAYS_AGO", 2, "two")

	// results in "1 day ago" and "two days ago"

	_ = translation1
	_ = translation2
}

Number Formatting

You can use the "FomatNumber", "FormatCurrency" and "FormatPercent" methods to do locale-based number formatting for numbers, currencies and percentages.

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en")

	number := float64(1234.5678)
	numberStr := tEn.FormatNumber(number)
	currencyStr := tEn.FormatCurrency(number, "USD")
	percentStr := tEn.FormatPercent(number)

	// results in 1,234.567, $1,234.56, 123,456%

	_ = numberStr
	_ = currencyStr
	_ = percentStr
}

Alphabetic String Sorting

If you need to sort a list of strings alphabetically, then you should not use a simple string comparison to do so - this will often result in incorrect results. "ȧ" would normally evaluate as greater than "z", which is not correct in any latin writing system alphabet. Use can use the Sort method on the Translator struct to do an alphabetic sorting that is correct for that locale. Alternatively, you can access the SortUniversal and the SortLocale functions directly without a Translator instance. SortUniversal does not take a specific locale into account when doing the alphabetic sorting, which means it might be slightly less accurate than the SortLocal function. However, there are cases in which the collation rules for a specific locale are unknown, or the sorting needs to be done in a local-agnostic way. For these cases, the SortUniversal function performs a unicode normalization in order to best sort the strings.

In order to be flexible, these functions take a generic interface slice and a function for retrieving the value on which to perform the sorting. For example:

type Food struct {
	Name string
}

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en")

	toSort := []interface{}{
		Food{Name: "apple"},
		Food{Name: "beet"},
		Food{Name: "carrot"},
		Food{Name: "ȧpricot"},
		Food{Name: "ḃanana"},
		Food{Name: "ċlementine"},
	}

	tEn.Sort(toSort1, func(i interface{}) string {
		if food, ok := i.(Food); ok {
			return food.Name
		}
		return ""
	})

	// results in "apple", "ȧpricot", "ḃanana", "beet", "carrot", "ċlementine"

	// Can also do this:
	i18n.SortLocal("en", toSort1, func(i interface{}) string {
		if food, ok := i.(Food); ok {
			return food.Name
		}
		return ""
	})

	// Or this:
	i18n.SortUniversal(toSort1, func(i interface{}) string {
		if food, ok := i.(Food); ok {
			return food.Name
		}
		return ""
	})

	_ = toSort
}

Fallback Translators

When getting a Translator instance, the TranslatorFactory will automatically attempt to determine an appropriate fallback Translator for the locale you specify. For locales with specific "flavors", like "en-au" or "zh-hans", the "vanilla" version of that locale will be used if it exists. In these cases that would be "en" and "zh".

When creating a TranslatorFactory instance, you can optionally specify a final fallback locale. This will be used if it exists.

When determining a fallback, the the factory first checks the less specific versions of the specified locale, if they exist and will ultimate fallback to the global fallback if specified.

func main() {

	rulesPath := "/usr/local/lib/i18n/locales/rules"
	messagesPath := "/usr/local/lib/i18n/locales/messages"

	f, _ := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	tEn, _ := i18n.GetTranslator("en") // no fallback

	tPt, _ := i18n.GetTranslator("pt") // fallback is "en"

	tPtBr, _ := i18n.GetTranslator("pt-br") // fallback is "pt"

	_, _, _ = tEn, tPt, tPtBr
}

Handling Errors

All of the examples above conveniently ignore errors. We recommend that you DO handle errors. The system is designed to give you a valid result if at all possible, even in errors occur in the process. However, the errors are still returned and may provide you helpful information you might otherwise miss - like missing files, file permissions problems, yaml format problems, missing translations, etc. We recommend that you do some sort of logging of these errors.

func main() {

	f, errs := i18n.NewTranslatorFactory(
		[]string{rulesPath},
		[]string{messagesPath},
		"en",
	)

	for _, err := range errs {
		Log(err)
	}

	tEn, errs := i18n.GetTranslator("en")

	for _, err := range errs {
		Log(err)
	}

	translation1, err := tEn.Translate("WELCOME_MSG", map[string]string{})

	for _, err := range errs {
		Log(err)
	}

	translation2, err := tEn.Pluralize("DAYS_AGO", 1, "1")

	for _, err := range errs {
		Log(err)
	}

	number := float64(1234.5678)
	currencyStr, err := tEn.FormatCurrency(number, "USD")

	if err != nil {
		Log(err)
	}

	_ = translation1
	_ = translation2
	_ = currencyStr
}

Index

Examples

Constants

View Source
const (
	DateFormatFull = iota
	DateFormatLong
	DateFormatMedium
	DateFormatShort
	TimeFormatFull
	TimeFormatLong
	TimeFormatMedium
	TimeFormatShort
	DateTimeFormatFull
	DateTimeFormatLong
	DateTimeFormatMedium
	DateTimeFormatShort
)

Standard Formats for Dates, Times & DateTimes These are the options to pass to the FormatDateTime method.

Variables

This section is empty.

Functions

func MakeOpeners added in v0.2.0

func MakeOpeners(getFileSystem func(string) http.FileSystem) []func(string) http.FileSystem

func SortLocal

func SortLocal(locale string, toBeSorted []interface{}, getComparisonValueFunction func(interface{}) string)

SortLocal sorts a generic slice alphabetically for a specific locale. It uses collation information if available for the specific locale requested. It falls back to SortUniversal otherwise. The func argument tells this function what string value to do the comparisons on.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

type Food struct {
	Name string
}

func main() {

	toSort := []interface{}{
		Food{Name: "apple"},
		Food{Name: "beet"},
		Food{Name: "carrot"},
		Food{Name: "ȧpricot"},
		Food{Name: "ḃanana"},
		Food{Name: "ċlementine"},
	}

	fmt.Printf("Before Sort : %v\n", toSort)

	// sorts the list
	i18n.SortLocal("en", toSort, func(i interface{}) string {
		if food, ok := i.(Food); ok {
			return food.Name
		}
		return ""
	})
	fmt.Printf("After Sort  : %v\n", toSort)

}
Output:

Before Sort : [{apple} {beet} {carrot} {ȧpricot} {ḃanana} {ċlementine}]
After Sort  : [{apple} {ȧpricot} {ḃanana} {beet} {carrot} {ċlementine}]

func SortUniversal

func SortUniversal(toBeSorted []interface{}, getComparisonValueFunction func(interface{}) string)

SortUniversal sorts a generic slice alphabetically in such a way that it should be mostly correct for most locales. It should be used in the following 2 cases:

  • As a fallback for SortLocale, when a collator for a specific locale cannot be found
  • When a locale is not available, or a sorting needs to be done in a locale-agnostic way

It uses unicode normalization. The func argument tells this function what string value to do the comparisons on.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

type Food struct {
	Name string
}

func main() {

	toSort := []interface{}{
		Food{Name: "apple"},
		Food{Name: "beet"},
		Food{Name: "carrot"},
		Food{Name: "ȧpricot"},
		Food{Name: "ḃanana"},
		Food{Name: "ċlementine"},
	}

	fmt.Printf("Before Sort : %v\n", toSort)

	// sorts the list
	i18n.SortUniversal(toSort, func(i interface{}) string {
		if food, ok := i.(Food); ok {
			return food.Name
		}
		return ""
	})
	fmt.Printf("After Sort  : %v\n", toSort)

}
Output:

Before Sort : [{apple} {beet} {carrot} {ȧpricot} {ḃanana} {ċlementine}]
After Sort  : [{apple} {ȧpricot} {beet} {ḃanana} {carrot} {ċlementine}]

Types

type Translator

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

Translator is a struct which contains all the rules and messages necessary to do internationalization for a specific locale. Most functionality in this package is accessed through a Translator instance.

func (*Translator) Direction

func (t *Translator) Direction() (direction string)

Direction returns the text directionality of the locale's writing system

func (*Translator) Fallback added in v0.0.2

func (f *Translator) Fallback() *Translator

func (*Translator) FormatCurrency

func (t *Translator) FormatCurrency(number float64, currency string) (formatted string, err error)

FormatCurrency takes a float number and a currency key and returns a string with a properly formatted currency amount with the correct currency symbol. If a symbol cannot be found for the reqested currency, the the key is used instead. If the currency key requested is not recognized, it is used as the symbol, and an error is returned with the formatted string.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	tEn, _ := f.GetTranslator("en")

	// performs 2 currency formats - one positive, one negative
	c1, _ := tEn.FormatCurrency(12345000000000.6789, "USD")
	c2, _ := tEn.FormatCurrency(-12345000000000.6789, "USD")

	fmt.Printf("Currency : %s\n", c1)
	fmt.Printf("Currency : %s\n", c2)

}
Output:

Currency : $12,345,000,000,000.68
Currency : ($12,345,000,000,000.68)

func (*Translator) FormatCurrencyWhole

func (t *Translator) FormatCurrencyWhole(number float64, currency string) (formatted string, err error)

FormatCurrencyWhole does exactly what FormatCurrency does, but it leaves off any decimal places. AKA, it would return $100 rather than $100.00.

func (*Translator) FormatDateTime

func (t *Translator) FormatDateTime(format int, datetime time.Time) (string, error)

FormatDateTime takes a time struct and a format and returns a formatted string. Callers should use a DateFormat, TimeFormat, or DateTimeFormat constant.

func (*Translator) FormatNumber

func (t *Translator) FormatNumber(number float64) string

FormatNumber takes a float number and returns a properly formatted string representation of that number according to the locale's number format.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	tEn, _ := f.GetTranslator("en")

	// performs 2 number formats - one positive, one negative
	n1 := tEn.FormatNumber(12345000000000.6789)
	n2 := tEn.FormatNumber(-12345000000000.6789)

	fmt.Printf("Number : %s\n", n1)
	fmt.Printf("Number : %s\n", n2)

}
Output:

Number : 12,345,000,000,000.679
Number : -12,345,000,000,000.679

func (*Translator) FormatNumberWhole

func (t *Translator) FormatNumberWhole(number float64) string

FormatNumberWhole does exactly what FormatNumber does, but it leaves off any decimal places. AKA, it would return 100 rather than 100.01.

func (*Translator) FormatPercent

func (t *Translator) FormatPercent(number float64) string

FormatPercent takes a float number and returns a properly formatted string representation of that number as a percentage according to the locale's percentage format.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	tEn, _ := f.GetTranslator("en")

	// performs 3 percent formats
	p1 := tEn.FormatPercent(0.01234)
	p2 := tEn.FormatPercent(0.5678)
	p3 := tEn.FormatPercent(12.34)

	fmt.Printf("Percent : %s\n", p1)
	fmt.Printf("Percent : %s\n", p2)
	fmt.Printf("Percent : %s\n", p3)

}
Output:

Percent : 1%
Percent : 57%
Percent : 1,234%

func (*Translator) Locale added in v0.0.2

func (f *Translator) Locale() string

func (*Translator) Messages added in v0.0.2

func (f *Translator) Messages() map[string]string

func (*Translator) Pluralize

func (t *Translator) Pluralize(key string, number float64, numberStr string) (translation string, errors []error)

Pluralize returns the translation for a message containing a plural. The plural form used is based on the number float64 and the number displayed in the translated string is the numberStr string. If neither this translator nor its fallback translator (or the fallback's fallback and so on) have a translation for the requested key, and empty string and an error will be returned.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	tFr, _ := f.GetTranslator("fr")

	// performs 4 plural translations
	p1, _ := tFr.Pluralize("UNIT_DAY", 0, "0")
	p2, _ := tFr.Pluralize("UNIT_DAY", 0.5, "0,5")
	p3, _ := tFr.Pluralize("UNIT_DAY", 1, "one")
	p4, _ := tFr.Pluralize("UNIT_DAY", 2000, "2K")

	fmt.Printf("Plurilization : %s\n", p1)
	fmt.Printf("Plurilization : %s\n", p2)
	fmt.Printf("Plurilization : %s\n", p3)
	fmt.Printf("Plurilization : %s\n", p4)

}
Output:

Plurilization : 0 jour
Plurilization : 0,5 jour
Plurilization : one jour
Plurilization : 2K jours

func (*Translator) Rules

func (t *Translator) Rules() TranslatorRules

Rules Translate returns the translated message, performang any substitutions requested in the substitutions map. If neither this translator nor its fallback translator (or the fallback's fallback and so on) have a translation for the requested key, and empty string and an error will be returned.

func (*Translator) Sort

func (t *Translator) Sort(toBeSorted []interface{}, getComparisonValueFunction func(interface{}) string)

Sort sorts a generic slice alphabetically for this translator's locale. It uses collation information if available for the specific locale requested. It falls back to SortUniversal otherwise. The func argument tells this function what string value to do the comparisons on.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

type Food struct {
	Name string
}

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	tEn, _ := f.GetTranslator("en")

	toSort := []interface{}{
		Food{Name: "apple"},
		Food{Name: "beet"},
		Food{Name: "carrot"},
		Food{Name: "ȧpricot"},
		Food{Name: "ḃanana"},
		Food{Name: "ċlementine"},
	}

	fmt.Printf("Before Sort : %v\n", toSort)

	// sorts the food list
	tEn.Sort(toSort, func(i interface{}) string {
		if food, ok := i.(Food); ok {
			return food.Name
		}
		return ""
	})
	fmt.Printf("After Sort  : %v\n", toSort)

}
Output:

Before Sort : [{apple} {beet} {carrot} {ȧpricot} {ḃanana} {ċlementine}]
After Sort  : [{apple} {ȧpricot} {ḃanana} {beet} {carrot} {ċlementine}]

func (*Translator) Translate

func (t *Translator) Translate(key string, substitutions map[string]string) (translation string, errors []error)

Translate returns the translated message, performang any substitutions requested in the substitutions map. If neither this translator nor its fallback translator (or the fallback's fallback and so on) have a translation for the requested key, and empty string and an error will be returned.

Example
package main

import (
	"fmt"
	"github.com/admpub/i18n"
)

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	tEn, _ := f.GetTranslator("en")

	// performs 2 translations, one with a substitution
	t1, _ := tEn.Translate("WELCOME", map[string]string{})
	t2, _ := tEn.Translate("WELCOME_USER", map[string]string{"user": "Mother Goose"})

	fmt.Printf("Basic Translation : %s\n", t1)
	fmt.Printf("Substitution      : %s\n", t2)

}
Output:

Basic Translation : Welcome!
Substitution      : Welcome, Mother Goose!

type TranslatorFactory

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

TranslatorFactory is a struct which contains the info necessary for creating Translator "instances". It also "caches" previously created Translators. Because of this caching, you can request a Translator for a specific locale multiple times and always get a pointer to the same Translator instance.

func NewTranslatorFactory

func NewTranslatorFactory(rulesPaths []string, messagesPaths []string, fallbackLocale string, fs ...func(file string) http.FileSystem) (f *TranslatorFactory, errors []error)

NewTranslatorFactory returns a TranslatorFactory instance with the specified paths and fallback locale. If a fallback locale is specified, it automatically creates the fallback Translator instance. Several errors can occur during this process, and those are all returned in the errors slice. Even if errors are returned, this function should still return a working Translator if the fallback works.

If multiple rulesPaths or messagesPaths are provided, they loaded in the order they appear in the slice, with values added later overriding any rules or messages loaded earlier.

One lat thing about the messagesPaths. You can organize your locale messages files in this messagesPaths directory in 2 different ways.

  1. Place *.yaml files in that directory directly, named after locale codes -

    messages/ en.yaml fr.yaml

  2. Place subdirectores in that directory, named after locale codes and containing *.yaml files

    messages/ en/ front-end.yaml email.yaml fr/ front-end.yaml email.yaml

    Using the second way allows you to organize your messages into multiple files.

Example
package main

import (
	"github.com/admpub/i18n"
)

func main() {
	// creates a new Factory using "en" as the global fallback locale
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	_ = f
}
Output:

func NewTranslatorFactoryWith added in v0.1.2

func NewTranslatorFactoryWith(project string, rulesPaths []string, messagesPaths []string, fallbackLocale string, fs ...func(file string) http.FileSystem) (f *TranslatorFactory, errors []error)

func (*TranslatorFactory) GetTranslator

func (f *TranslatorFactory) GetTranslator(localeCode string) (t *Translator, errors []error)

GetTranslator returns an Translator instance for the requested locale. If you request the same locale multiple times, a pointed to the same Translator will be returned each time.

Example
package main

import (
	"github.com/admpub/i18n"
)

func main() {
	f, _ := i18n.NewTranslatorFactory(
		[]string{"data/rules"},
		[]string{"data/messages"},
		"en",
	)

	// gets a translator for the Canadian French locale
	tFrCa, _ := f.GetTranslator("fr-ca")

	_ = tFrCa
}
Output:

func (*TranslatorFactory) LocaleExists

func (f *TranslatorFactory) LocaleExists(localeCode string) (exists bool, errs []error)

LocaleExists checks to see if any messages files exist for the requested locale string.

func (*TranslatorFactory) Reload

func (f *TranslatorFactory) Reload(localeCode string) (t *Translator, errors []error)

type TranslatorRules

type TranslatorRules struct {
	Plural         string     `json:"plural,omitempty" yaml:"plural,omitempty"`
	PluralRuleFunc pluralRule `json:"-" yaml:"-"`
	Direction      string     `json:"direction,omitempty" yaml:"direction,omitempty"`
	Numbers        struct {
		Symbols struct {
			Decimal  string `json:"decimal,omitempty" yaml:"decimal,omitempty"`
			Group    string `json:"group,omitempty" yaml:"group,omitempty"`
			Negative string `json:"negative,omitempty" yaml:"negative,omitempty"`
			Percent  string `json:"percent,omitempty" yaml:"percent,omitempty"`
			Permille string `json:"permille,omitempty" yaml:"permille,omitempty"`
		} `json:"symbols,omitempty" yaml:"symbols,omitempty"`
		Formats struct {
			Decimal  string `json:"decimal,omitempty" yaml:"decimal,omitempty"`
			Currency string `json:"currency,omitempty" yaml:"currency,omitempty"`
			Percent  string `json:"percent,omitempty" yaml:"percent,omitempty"`
		} `json:"formats,omitempty" yaml:"formats,omitempty"`
	} `json:"numbers,omitempty" yaml:"numbers,omitempty"`
	Currencies map[string]currency `json:"currencies,omitempty" yaml:"currencies,omitempty"`
	DateTime   struct {
		TimeSeparator string `json:"timeSeparator,omitempty" yaml:"timeSeparator,omitempty"`
		Formats       struct {
			Date struct {
				Full   string `json:"full,omitempty" yaml:"full,omitempty"`
				Long   string `json:"long,omitempty" yaml:"long,omitempty"`
				Medium string `json:"medium,omitempty" yaml:"medium,omitempty"`
				Short  string `json:"short,omitempty" yaml:"short,omitempty"`
			} `json:"date,omitempty" yaml:"date,omitempty"`
			Time struct {
				Full   string `json:"full,omitempty" yaml:"full,omitempty"`
				Long   string `json:"long,omitempty" yaml:"long,omitempty"`
				Medium string `json:"medium,omitempty" yaml:"medium,omitempty"`
				Short  string `json:"short,omitempty" yaml:"short,omitempty"`
			} `json:"time,omitempty" yaml:"time,omitempty"`
			DateTime struct {
				Full   string `json:"full,omitempty" yaml:"full,omitempty"`
				Long   string `json:"long,omitempty" yaml:"long,omitempty"`
				Medium string `json:"medium,omitempty" yaml:"medium,omitempty"`
				Short  string `json:"short,omitempty" yaml:"short,omitempty"`
			} `json:"datetime,omitempty" yaml:"datetime,omitempty"`
		} `json:"formats,omitempty" yaml:"formats,omitempty"`
		FormatNames struct {
			Months struct {
				Abbreviated struct {
					Month1  string `json:"1,omitempty" yaml:"1,omitempty"`
					Month2  string `json:"2,omitempty" yaml:"2,omitempty"`
					Month3  string `json:"3,omitempty" yaml:"3,omitempty"`
					Month4  string `json:"4,omitempty" yaml:"4,omitempty"`
					Month5  string `json:"5,omitempty" yaml:"5,omitempty"`
					Month6  string `json:"6,omitempty" yaml:"6,omitempty"`
					Month7  string `json:"7,omitempty" yaml:"7,omitempty"`
					Month8  string `json:"8,omitempty" yaml:"8,omitempty"`
					Month9  string `json:"9,omitempty" yaml:"9,omitempty"`
					Month10 string `json:"10,omitempty" yaml:"10,omitempty"`
					Month11 string `json:"11,omitempty" yaml:"11,omitempty"`
					Month12 string `json:"12,omitempty" yaml:"12,omitempty"`
				} `json:"abbreviated,omitempty" yaml:"abbreviated,omitempty"`
				Narrow struct {
					Month1  string `json:"1,omitempty" yaml:"1,omitempty"`
					Month2  string `json:"2,omitempty" yaml:"2,omitempty"`
					Month3  string `json:"3,omitempty" yaml:"3,omitempty"`
					Month4  string `json:"4,omitempty" yaml:"4,omitempty"`
					Month5  string `json:"5,omitempty" yaml:"5,omitempty"`
					Month6  string `json:"6,omitempty" yaml:"6,omitempty"`
					Month7  string `json:"7,omitempty" yaml:"7,omitempty"`
					Month8  string `json:"8,omitempty" yaml:"8,omitempty"`
					Month9  string `json:"9,omitempty" yaml:"9,omitempty"`
					Month10 string `json:"10,omitempty" yaml:"10,omitempty"`
					Month11 string `json:"11,omitempty" yaml:"11,omitempty"`
					Month12 string `json:"12,omitempty" yaml:"12,omitempty"`
				} `json:"narrow,omitempty" yaml:"narrow,omitempty"`
				Wide struct {
					Month1  string `json:"1,omitempty" yaml:"1,omitempty"`
					Month2  string `json:"2,omitempty" yaml:"2,omitempty"`
					Month3  string `json:"3,omitempty" yaml:"3,omitempty"`
					Month4  string `json:"4,omitempty" yaml:"4,omitempty"`
					Month5  string `json:"5,omitempty" yaml:"5,omitempty"`
					Month6  string `json:"6,omitempty" yaml:"6,omitempty"`
					Month7  string `json:"7,omitempty" yaml:"7,omitempty"`
					Month8  string `json:"8,omitempty" yaml:"8,omitempty"`
					Month9  string `json:"9,omitempty" yaml:"9,omitempty"`
					Month10 string `json:"10,omitempty" yaml:"10,omitempty"`
					Month11 string `json:"11,omitempty" yaml:"11,omitempty"`
					Month12 string `json:"12,omitempty" yaml:"12,omitempty"`
				} `json:"wide,omitempty" yaml:"wide,omitempty"`
			} `json:"months,omitempty" yaml:"months,omitempty"`
			Days struct {
				Abbreviated struct {
					Sun string `json:"sun,omitempty" yaml:"sun,omitempty"`
					Mon string `json:"mon,omitempty" yaml:"mon,omitempty"`
					Tue string `json:"tue,omitempty" yaml:"tue,omitempty"`
					Wed string `json:"wed,omitempty" yaml:"wed,omitempty"`
					Thu string `json:"thu,omitempty" yaml:"thu,omitempty"`
					Fri string `json:"fri,omitempty" yaml:"fri,omitempty"`
					Sat string `json:"sat,omitempty" yaml:"sat,omitempty"`
				} `json:"abbreviated,omitempty" yaml:"abbreviated,omitempty"`
				Narrow struct {
					Sun string `json:"sun,omitempty" yaml:"sun,omitempty"`
					Mon string `json:"mon,omitempty" yaml:"mon,omitempty"`
					Tue string `json:"tue,omitempty" yaml:"tue,omitempty"`
					Wed string `json:"wed,omitempty" yaml:"wed,omitempty"`
					Thu string `json:"thu,omitempty" yaml:"thu,omitempty"`
					Fri string `json:"fri,omitempty" yaml:"fri,omitempty"`
					Sat string `json:"sat,omitempty" yaml:"sat,omitempty"`
				} `json:"narrow,omitempty" yaml:"narrow,omitempty"`
				Short struct {
					Sun string `json:"sun,omitempty" yaml:"sun,omitempty"`
					Mon string `json:"mon,omitempty" yaml:"mon,omitempty"`
					Tue string `json:"tue,omitempty" yaml:"tue,omitempty"`
					Wed string `json:"wed,omitempty" yaml:"wed,omitempty"`
					Thu string `json:"thu,omitempty" yaml:"thu,omitempty"`
					Fri string `json:"fri,omitempty" yaml:"fri,omitempty"`
					Sat string `json:"sat,omitempty" yaml:"sat,omitempty"`
				} `json:"short,omitempty" yaml:"short,omitempty"`
				Wide struct {
					Sun string `json:"sun,omitempty" yaml:"sun,omitempty"`
					Mon string `json:"mon,omitempty" yaml:"mon,omitempty"`
					Tue string `json:"tue,omitempty" yaml:"tue,omitempty"`
					Wed string `json:"wed,omitempty" yaml:"wed,omitempty"`
					Thu string `json:"thu,omitempty" yaml:"thu,omitempty"`
					Fri string `json:"fri,omitempty" yaml:"fri,omitempty"`
					Sat string `json:"sat,omitempty" yaml:"sat,omitempty"`
				} `json:"wide,omitempty" yaml:"wide,omitempty"`
			} `json:"days,omitempty" yaml:"days,omitempty"`
			Periods struct {
				Abbreviated struct {
					AM string `json:"am,omitempty" yaml:"am,omitempty"`
					PM string `json:"pm,omitempty" yaml:"pm,omitempty"`
				} `json:"abbreviated,omitempty" yaml:"abbreviated,omitempty"`
				Narrow struct {
					AM string `json:"am,omitempty" yaml:"am,omitempty"`
					PM string `json:"pm,omitempty" yaml:"pm,omitempty"`
				} `json:"narrow,omitempty" yaml:"narrow,omitempty"`
				Wide struct {
					AM string `json:"am,omitempty" yaml:"am,omitempty"`
					PM string `json:"pm,omitempty" yaml:"pm,omitempty"`
				} `json:"wide,omitempty" yaml:"wide,omitempty"`
			} `json:"periods,omitempty" yaml:"periods,omitempty"`
		} `json:"formatNames,omitempty" yaml:"formatNames,omitempty"`
	} `json:"datetime,omitempty" yaml:"datetime,omitempty"`
}

TranslatorRules is a struct containing all of the information unmarshalled from a locale rules file.

Directories

Path Synopsis
cmd
fetchtext
提取待翻译的文本
提取待翻译的文本

Jump to

Keyboard shortcuts

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