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 ¶
- Constants
- func MakeOpeners(getFileSystem func(string) http.FileSystem) []func(string) http.FileSystem
- func SortLocal(locale string, toBeSorted []interface{}, ...)
- func SortUniversal(toBeSorted []interface{}, getComparisonValueFunction func(interface{}) string)
- type Translator
- func (t *Translator) Direction() (direction string)
- func (f *Translator) Fallback() *Translator
- func (t *Translator) FormatCurrency(number float64, currency string) (formatted string, err error)
- func (t *Translator) FormatCurrencyWhole(number float64, currency string) (formatted string, err error)
- func (t *Translator) FormatDateTime(format int, datetime time.Time) (string, error)
- func (t *Translator) FormatNumber(number float64) string
- func (t *Translator) FormatNumberWhole(number float64) string
- func (t *Translator) FormatPercent(number float64) string
- func (f *Translator) Locale() string
- func (f *Translator) Messages() map[string]string
- func (t *Translator) Pluralize(key string, number float64, numberStr string) (translation string, errors []error)
- func (t *Translator) Rules() TranslatorRules
- func (t *Translator) Sort(toBeSorted []interface{}, getComparisonValueFunction func(interface{}) string)
- func (t *Translator) Translate(key string, substitutions map[string]string) (translation string, errors []error)
- type TranslatorFactory
- type TranslatorRules
Examples ¶
Constants ¶
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 ¶
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.
Place *.yaml files in that directory directly, named after locale codes -
messages/ en.yaml fr.yaml
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.