aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/i18n
diff options
context:
space:
mode:
Diffstat (limited to 'src/i18n')
-rwxr-xr-xsrc/i18n/gen.py172
-rw-r--r--src/i18n/i18n.go428
-rw-r--r--src/i18n/locales.gen.go257
3 files changed, 857 insertions, 0 deletions
diff --git a/src/i18n/gen.py b/src/i18n/gen.py
new file mode 100755
index 0000000..9271cc0
--- /dev/null
+++ b/src/i18n/gen.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+
+import concurrent.futures
+import dataclasses
+import json
+import os
+import re
+import subprocess
+import sys
+import urllib.request
+from dataclasses import dataclass
+from typing import Any, TextIO
+
+
+FILENAME = "locales.gen.go"
+
+class Rune(int):
+ pass
+
+
+@dataclass
+class Locale:
+ bcp: str
+ eurozonep: bool
+ enabledp: bool
+ territory: str | None = dataclasses.field(default=None)
+ name: str = dataclasses.field(init=False)
+ date_format: str = dataclasses.field(init=False)
+ group_separator: Rune = dataclasses.field(init=False)
+ decimal_separator: Rune = dataclasses.field(init=False)
+ monetary_formats: tuple[str, str] = dataclasses.field(init=False)
+ percent_format: str = dataclasses.field(init=False)
+
+
+LOCALES = (
+ Locale(bcp="ca", eurozonep=True, enabledp=False),
+ Locale(bcp="de", eurozonep=True, enabledp=False),
+ Locale(bcp="el", eurozonep=True, enabledp=False),
+ Locale(bcp="en", eurozonep=True, enabledp=True, territory="GB"),
+ Locale(bcp="es", eurozonep=True, enabledp=False),
+ Locale(bcp="et", eurozonep=True, enabledp=False),
+ Locale(bcp="fi", eurozonep=True, enabledp=False),
+ Locale(bcp="fr", eurozonep=True, enabledp=False),
+ Locale(bcp="ga", eurozonep=True, enabledp=False),
+ Locale(bcp="hr", eurozonep=True, enabledp=False),
+ Locale(bcp="it", eurozonep=True, enabledp=False),
+ Locale(bcp="lb", eurozonep=True, enabledp=False),
+ Locale(bcp="lt", eurozonep=True, enabledp=False),
+ Locale(bcp="lv", eurozonep=True, enabledp=False),
+ Locale(bcp="mt", eurozonep=True, enabledp=False),
+ Locale(bcp="nl", eurozonep=True, enabledp=True),
+ Locale(bcp="pt", eurozonep=True, enabledp=False, territory="PT"),
+ Locale(bcp="sk", eurozonep=True, enabledp=False),
+ Locale(bcp="sl", eurozonep=True, enabledp=False),
+ Locale(bcp="sv", eurozonep=True, enabledp=True),
+ Locale(bcp="tr", eurozonep=True, enabledp=False),
+ Locale(bcp="bg", eurozonep=False, enabledp=False),
+ Locale(bcp="ro", eurozonep=False, enabledp=False),
+ Locale(bcp="uk", eurozonep=False, enabledp=False),
+)
+
+BASELINK = "https://raw.githubusercontent.com/unicode-org/cldr-json/refs/heads/main/cldr-json/%s/main/%%s/%s"
+NUMBERS_LINK, DATES_LINK, LANGUAGES_LINK = (
+ BASELINK % ("cldr-numbers-full", "numbers.json"),
+ BASELINK % ("cldr-dates-full", "ca-gregorian.json"),
+ BASELINK % ("cldr-localenames-full", "languages.json"),
+)
+
+
+def main() -> int:
+ rv = 0
+ nprocs = os.cpu_count()
+ with concurrent.futures.ThreadPoolExecutor(max_workers=nprocs) as executor:
+ for x in [executor.submit(write_locale, l) for l in LOCALES]:
+ try:
+ x.result()
+ except Exception as e:
+ print(f"gen.py: {e}", file=sys.stderr)
+ rv = 1
+
+ with open(FILENAME, "w") as f:
+ f.write("""// Code generated by gen.py. DO NOT EDIT.
+
+package i18n
+
+import "github.com/leonelquinteros/gotext"
+
+type LocaleInfo struct {
+ Bcp, Name string
+ Eurozonep, Enabledp bool
+ DateFormat string
+ GroupSeparator, DecimalSeparator rune
+ MonetaryFormats [2]string
+ PercentFormat string
+}
+
+var locales = [...]LocaleInfo{
+""")
+ for x in LOCALES:
+ f.write("{\n")
+ for k, v in x.__dict__.items():
+ if not v or k == "territory":
+ continue
+ if k == "name":
+ f.write('Name: gotext.GetC(%s, "Language Name"),\n' % val_to_go(v))
+ else:
+ f.write("%s: %s,\n" % (pascal(k), val_to_go(v)))
+ f.write("},\n")
+ f.write("}")
+
+ subprocess.run(["gofmt", "-w", FILENAME])
+ return rv
+
+
+def write_locale(l: Locale) -> None:
+ bcp = '%s-%s' % (l.bcp, l.territory) if l.territory else l.bcp
+ jn, jd, jl = map(json.load, (
+ urllib.request.urlopen(NUMBERS_LINK % bcp),
+ urllib.request.urlopen(DATES_LINK % bcp),
+ urllib.request.urlopen(LANGUAGES_LINK % bcp),
+ ))
+ name = jl["main"][bcp]["localeDisplayNames"]["languages"][l.bcp]
+ l.name = name.capitalize()
+ syms = jn["main"][bcp]["numbers"]["symbols-numberSystem-latn"]
+ l.group_separator = Rune(ord(syms["group"]))
+ l.decimal_separator = Rune(ord(syms["decimal"]))
+
+ fmt = jn["main"][bcp]["numbers"]["percentFormats-numberSystem-latn"]["standard"]
+ l.percent_format = numfmt_subst(fmt)
+
+ fmt = jd["main"][bcp]["dates"]["calendars"]["gregorian"]["dateFormats"]["short"]
+ l.date_format = (
+ fmt
+ .replace("yy", "06")
+ .replace("MM", "01")
+ .replace("dd", "02")
+ .replace("y", "2006")
+ .replace("M", "1")
+ .replace("d", "2")
+ .replace("'", "")
+ )
+
+ fmt = jn["main"][bcp]["numbers"]["currencyFormats-numberSystem-latn"]["standard"]
+ parts = list(map(numfmt_subst, fmt.replace("¤", "€").split(";")))
+ if len(parts) == 1:
+ parts.append('-' + parts[0])
+ l.monetary_formats = tuple(parts)
+
+
+def numfmt_subst(s: str) -> str:
+ return re.sub(r"[0#,.]+", "123", s)
+
+
+def pascal(s: str) -> str:
+ return ''.join(map(str.capitalize, s.split('_')))
+
+
+def val_to_go(x: Any) -> str:
+ match x:
+ case bool():
+ return "true" if x else "false"
+ case Rune():
+ return "'%s'" % chr(x)
+ case str():
+ return '"%s"' % x
+ case (str(), str()):
+ return "[2]string{%s, %s}" % (val_to_go(x[0]), val_to_go(x[1]))
+
+
+if __name__ == "__main__":
+ os.chdir(os.path.dirname(sys.argv[0]))
+ sys.exit(main())
diff --git a/src/i18n/i18n.go b/src/i18n/i18n.go
new file mode 100644
index 0000000..93b8d63
--- /dev/null
+++ b/src/i18n/i18n.go
@@ -0,0 +1,428 @@
+//go:generate ./gen.py
+
+package i18n
+
+import (
+ "errors"
+ "fmt"
+ "io/fs"
+ "log"
+ "maps"
+ "slices"
+ "strings"
+ "time"
+ "unicode/utf8"
+
+ "git.thomasvoss.com/euro-cash.eu/pkg/atexit"
+ "git.thomasvoss.com/euro-cash.eu/pkg/watch"
+ "github.com/leonelquinteros/gotext"
+
+ "git.thomasvoss.com/euro-cash.eu/src/wikipedia"
+)
+
+type Printer struct {
+ LocaleInfo
+ inner *gotext.Locale
+}
+
+type number interface {
+ int | float64
+}
+
+type sprintfFunc func(LocaleInfo, *strings.Builder, any) error
+
+var (
+ handlers map[rune]sprintfFunc = map[rune]sprintfFunc{
+ -1: sprintfGeneric,
+ 'E': sprintfE,
+ 'L': sprintfL,
+ 'e': sprintfe,
+ 'l': sprintfl,
+ 'm': sprintfm,
+ 'p': sprintfp,
+ 'r': sprintfr,
+ }
+
+ Printers = make(map[string]Printer, len(locales))
+ DefaultPrinter Printer
+)
+
+func Init(dir fs.FS, debugp bool) {
+ gotext.FallbackLocale = "en"
+ i := slices.IndexFunc(locales[:], func(li LocaleInfo) bool {
+ return li.Bcp == gotext.FallbackLocale
+ })
+ if i == -1 {
+ atexit.Exec()
+ log.Fatalf("No translation file default locale ‘%s’\n",
+ gotext.FallbackLocale)
+ }
+ if !locales[i].Enabledp {
+ atexit.Exec()
+ log.Fatalf("Default locale ‘%s’ is not enabled\n",
+ locales[i].Name)
+ }
+
+ initLocale(dir, locales[i], locales[i].Name, debugp)
+ DefaultPrinter = Printers[gotext.FallbackLocale]
+
+ for j, li := range locales {
+ if li.Enabledp && i != j {
+ name := DefaultPrinter.GetC(li.Name, "Language Name")
+ initLocale(dir, li, name, debugp)
+ }
+ }
+}
+
+func initLocale(dir fs.FS, li LocaleInfo, name string, debugp bool) {
+ gl := gotext.NewLocaleFS(li.Bcp, dir)
+ gl.AddDomain("messages")
+ Printers[li.Bcp] = Printer{li, gl}
+
+ if debugp {
+ subdir, err := fs.Sub(dir, li.Bcp)
+ if err != nil {
+ log.Printf("No translations directory for ‘%s’\n", name)
+ return
+ }
+ go watch.FileFS(subdir, "messages.po", func() {
+ Printers[li.Bcp].inner.AddDomain("messages")
+ log.Printf("Translations for ‘%s’ updated\n", name)
+ })
+ }
+
+ log.Printf("Initialized printer for ‘%s’\n", name)
+}
+
+func Locales() []LocaleInfo {
+ return locales[:]
+}
+
+func (p Printer) Wikipedia(title string) string {
+ return wikipedia.Url(title, p.Bcp)
+}
+
+func (p Printer) Get(fmt string, args ...map[string]any) string {
+ return p.Sprintf(p.inner.Get(fmt), args...)
+}
+
+func (p Printer) GetC(fmt, ctx string, args ...map[string]any) string {
+ return p.Sprintf(p.inner.GetC(fmt, ctx), args...)
+}
+
+func (p Printer) GetN(fmtS, fmtP string, n int, args ...map[string]any) string {
+ return p.Sprintf(p.inner.GetN(fmtS, fmtP, n), args...)
+}
+
+/* Transform ‘en-US’ to ‘en’ */
+func (l LocaleInfo) Language() string {
+ return l.Bcp[:2]
+}
+
+func (p Printer) Itoa(n int) string {
+ var bob strings.Builder
+ writeInt(&bob, n, p.LocaleInfo)
+ return bob.String()
+}
+
+func (p Printer) Ftoa(n float64) string {
+ var bob strings.Builder
+ writeFloat(&bob, n, p.LocaleInfo)
+ return bob.String()
+}
+
+func (p Printer) Itop(n int) string {
+ var bob strings.Builder
+ sprintfp(p.LocaleInfo, &bob, n)
+ return bob.String()
+}
+
+func (p Printer) Ftop(n float64) string {
+ var bob strings.Builder
+ sprintfp(p.LocaleInfo, &bob, n)
+ return bob.String()
+}
+
+func (p Printer) Itom(n int) string {
+ var bob strings.Builder
+ sprintfm(p.LocaleInfo, &bob, n)
+ return bob.String()
+}
+
+func (p Printer) Ftom(n float64) string {
+ var bob strings.Builder
+ sprintfm(p.LocaleInfo, &bob, n)
+ return bob.String()
+}
+
+func (p Printer) Sprintf(format string, args ...map[string]any) string {
+ var bob strings.Builder
+ vars := map[string]any{
+ "-": "a",
+ "Null": "",
+ }
+ for _, arg := range args {
+ maps.Copy(vars, arg)
+ }
+
+ for {
+ i := strings.IndexByte(format, '{')
+ if i == -1 {
+ htmlesc(&bob, format)
+ break
+ }
+ htmlesc(&bob, format[:i])
+
+ format = format[i+1:]
+ i = strings.IndexRune(format, '}')
+ if i == -1 {
+ /* TODO: Handle error: unterminated { */
+ return "unterminated {"
+ }
+
+ parts := strings.Split(format[:i], ":")
+ format = format[i+1:]
+
+ var flag rune
+ switch len(parts) {
+ case 1:
+ flag = -1
+ case 2:
+ f, n := utf8.DecodeRune([]byte(parts[1]))
+ if n != len(parts[1]) {
+ /* TODO: Handle error: flag too long or empty */
+ return "flag too long or empty"
+ }
+ flag = f
+ default:
+ /* TODO: Handle error: too many colons */
+ return "too many colons"
+ }
+
+ h, ok := handlers[flag]
+ if !ok {
+ /* TODO: Handle error: no such handler */
+ return "no such handler"
+ }
+
+ v, ok := vars[parts[0]]
+ if !ok {
+ /* TODO: Handle error: no such key */
+ return "no such key"
+ }
+ h(p.LocaleInfo, &bob, v)
+ }
+
+ return bob.String()
+}
+
+func sprintfGeneric(li LocaleInfo, bob *strings.Builder, v any) error {
+ switch v.(type) {
+ case time.Time:
+ htmlesc(bob, v.(time.Time).Format(li.DateFormat))
+ case int:
+ writeInt(bob, v.(int), li)
+ case float64:
+ writeFloat(bob, v.(float64), li)
+ case string:
+ htmlesc(bob, v.(string))
+ default:
+ htmlesc(bob, fmt.Sprint(v))
+ }
+ return nil
+}
+
+func sprintfe(li LocaleInfo, bob *strings.Builder, v any) error {
+ s, ok := v.(string)
+ if !ok {
+ return errors.New("TODO")
+ }
+ bob.WriteString("<a href=\"mailto:")
+ htmlesc(bob, s)
+ bob.WriteString("\">")
+ htmlesc(bob, s)
+ bob.WriteString("</a>")
+ return nil
+}
+
+func sprintfE(li LocaleInfo, bob *strings.Builder, v any) error {
+ s, ok := v.(string)
+ if !ok {
+ return errors.New("TODO")
+ }
+ for tag := range strings.SplitSeq(s, ",") {
+ bob.WriteString("</")
+ bob.WriteString(tag)
+ bob.WriteByte('>')
+ }
+ return nil
+}
+
+func sprintfl(li LocaleInfo, bob *strings.Builder, v any) error {
+ s, ok := v.(string)
+ if !ok {
+ return errors.New("TODO")
+ }
+ bob.WriteString("<a href=\"")
+ htmlesc(bob, s)
+ bob.WriteString("\">")
+ return nil
+}
+
+func sprintfL(li LocaleInfo, bob *strings.Builder, v any) error {
+ s, ok := v.(string)
+ if !ok {
+ return errors.New("TODO")
+ }
+ bob.WriteString("<a href=\"")
+ htmlesc(bob, s)
+ bob.WriteString("\" target=\"_blank\">")
+ return nil
+}
+
+func sprintfm(li LocaleInfo, bob *strings.Builder, v any) error {
+ var (
+ fmt string
+ negp bool
+ )
+ switch v.(type) {
+ case int:
+ negp = v.(int) < 0
+ case float64:
+ negp = v.(float64) < 0
+ }
+
+ fmt = li.MonetaryFormats[btoi(negp)]
+ pre, suf, _ := strings.Cut(fmt, "123")
+ htmlesc(bob, pre)
+
+ switch v.(type) {
+ case int:
+ writeInt(bob, abs(v.(int)), li)
+ case float64:
+ writeFloat(bob, abs(v.(float64)), li)
+ }
+
+ htmlesc(bob, suf)
+ return nil
+}
+
+func sprintfp(li LocaleInfo, bob *strings.Builder, v any) error {
+ pre, suf, _ := strings.Cut(li.PercentFormat, "123")
+ htmlesc(bob, pre)
+
+ switch v.(type) {
+ case int:
+ writeInt(bob, v.(int), li)
+ case float64:
+ writeFloat(bob, v.(float64), li)
+ }
+
+ htmlesc(bob, suf)
+ return nil
+}
+
+func sprintfr(li LocaleInfo, bob *strings.Builder, v any) error {
+ s, ok := v.(string)
+ if !ok {
+ return errors.New("TODO")
+ }
+ bob.WriteString(s)
+ return nil
+}
+
+func writeInt(bob *strings.Builder, num int, li LocaleInfo) {
+ s := fmt.Sprintf("%d", num)
+ if s[0] == '-' {
+ bob.WriteByte('-')
+ s = s[1:]
+ }
+ n := len(s)
+ c := 3 - n%3
+ if c == 3 {
+ c = 0
+ }
+ for i := 0; i < n; i++ {
+ c++
+ bob.WriteByte(s[i])
+ if c == 3 && i+1 < n {
+ bob.WriteRune(li.GroupSeparator)
+ c = 0
+ }
+ }
+}
+
+func writeFloat(bob *strings.Builder, num float64, li LocaleInfo) {
+ s := fmt.Sprintf("%.2f", num)
+ if s[0] == '-' {
+ bob.WriteByte('-')
+ s = s[1:]
+ }
+
+ n := strings.IndexByte(s, '.')
+ c := 3 - n%3
+ if c == 3 {
+ c = 0
+ }
+ for i := 0; i < n; i++ {
+ c++
+ bob.WriteByte(s[i])
+ if c == 3 && i+1 < n {
+ bob.WriteRune(li.GroupSeparator)
+ c = 0
+ }
+ }
+
+ bob.WriteRune(li.DecimalSeparator)
+ bob.WriteString(s[n+1:])
+}
+
+func abs[T number](x T) T {
+ if x < 0 {
+ return -x
+ }
+ return x
+}
+
+func btoi(b bool) int {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+func htmlesc(bob *strings.Builder, s string) {
+ for _, r := range s {
+ switch r {
+ case '<':
+ bob.WriteString("&lt;")
+ case '>':
+ bob.WriteString("&gt;")
+ case '&':
+ bob.WriteString("&amp;")
+ case '"':
+ bob.WriteString("&#34;")
+ case '\'':
+ bob.WriteString("&#39;")
+ default:
+ bob.WriteRune(r)
+ }
+ }
+}
+
+func htmlescByte(bob *strings.Builder, b byte) {
+ switch b {
+ case '<':
+ bob.WriteString("&lt;")
+ case '>':
+ bob.WriteString("&gt;")
+ case '&':
+ bob.WriteString("&amp;")
+ case '"':
+ bob.WriteString("&#34;")
+ case '\'':
+ bob.WriteString("&#39;")
+ default:
+ bob.WriteByte(b)
+ }
+}
diff --git a/src/i18n/locales.gen.go b/src/i18n/locales.gen.go
new file mode 100644
index 0000000..58d059e
--- /dev/null
+++ b/src/i18n/locales.gen.go
@@ -0,0 +1,257 @@
+// Code generated by gen.py. DO NOT EDIT.
+
+package i18n
+
+import "github.com/leonelquinteros/gotext"
+
+type LocaleInfo struct {
+ Bcp, Name string
+ Eurozonep, Enabledp bool
+ DateFormat string
+ GroupSeparator, DecimalSeparator rune
+ MonetaryFormats [2]string
+ PercentFormat string
+}
+
+var locales = [...]LocaleInfo{
+ {
+ Bcp: "ca",
+ Eurozonep: true,
+ Name: gotext.GetC("Català", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2/1/06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "de",
+ Eurozonep: true,
+ Name: gotext.GetC("Deutsch", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "02.01.06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "el",
+ Eurozonep: true,
+ Name: gotext.GetC("Ελληνικά", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "2/1/06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "en",
+ Eurozonep: true,
+ Enabledp: true,
+ Name: gotext.GetC("English", "Language Name"),
+ GroupSeparator: ',',
+ DecimalSeparator: '.',
+ PercentFormat: "123%",
+ DateFormat: "02/01/2006",
+ MonetaryFormats: [2]string{"€123", "-€123"},
+ },
+ {
+ Bcp: "es",
+ Eurozonep: true,
+ Name: gotext.GetC("Español", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2/1/06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "et",
+ Eurozonep: true,
+ Name: gotext.GetC("Eesti", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "02.01.06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "fi",
+ Eurozonep: true,
+ Name: gotext.GetC("Suomi", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2.1.2006",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "fr",
+ Eurozonep: true,
+ Name: gotext.GetC("Français", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "02/01/2006",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "ga",
+ Eurozonep: true,
+ Name: gotext.GetC("Gaeilge", "Language Name"),
+ GroupSeparator: ',',
+ DecimalSeparator: '.',
+ PercentFormat: "123%",
+ DateFormat: "02/01/2006",
+ MonetaryFormats: [2]string{"€123", "-€123"},
+ },
+ {
+ Bcp: "hr",
+ Eurozonep: true,
+ Name: gotext.GetC("Hrvatski", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "02. 01. 2006.",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "it",
+ Eurozonep: true,
+ Name: gotext.GetC("Italiano", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "02/01/06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "lb",
+ Eurozonep: true,
+ Name: gotext.GetC("Lëtzebuergesch", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "02.01.06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "lt",
+ Eurozonep: true,
+ Name: gotext.GetC("Lietuvių", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2006-01-02",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "lv",
+ Eurozonep: true,
+ Name: gotext.GetC("Latviešu", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "02.01.06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "mt",
+ Eurozonep: true,
+ Name: gotext.GetC("Malti", "Language Name"),
+ GroupSeparator: ',',
+ DecimalSeparator: '.',
+ PercentFormat: "123%",
+ DateFormat: "02/01/2006",
+ MonetaryFormats: [2]string{"€123", "-€123"},
+ },
+ {
+ Bcp: "nl",
+ Eurozonep: true,
+ Enabledp: true,
+ Name: gotext.GetC("Nederlands", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "02-01-2006",
+ MonetaryFormats: [2]string{"€ 123", "€ -123"},
+ },
+ {
+ Bcp: "pt",
+ Eurozonep: true,
+ Name: gotext.GetC("Português", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "02/01/06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "sk",
+ Eurozonep: true,
+ Name: gotext.GetC("Slovenčina", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2. 1. 2006",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "sl",
+ Eurozonep: true,
+ Name: gotext.GetC("Slovenščina", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2. 1. 06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "sv",
+ Eurozonep: true,
+ Enabledp: true,
+ Name: gotext.GetC("Svenska", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "2006-01-02",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "tr",
+ Eurozonep: true,
+ Name: gotext.GetC("Türkçe", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "%123",
+ DateFormat: "2.01.2006",
+ MonetaryFormats: [2]string{"€123", "-€123"},
+ },
+ {
+ Bcp: "bg",
+ Name: gotext.GetC("Български", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "2.01.06 г.",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "ro",
+ Name: gotext.GetC("Română", "Language Name"),
+ GroupSeparator: '.',
+ DecimalSeparator: ',',
+ PercentFormat: "123 %",
+ DateFormat: "02.01.2006",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+ {
+ Bcp: "uk",
+ Name: gotext.GetC("Українська", "Language Name"),
+ GroupSeparator: ' ',
+ DecimalSeparator: ',',
+ PercentFormat: "123%",
+ DateFormat: "02.01.06",
+ MonetaryFormats: [2]string{"123 €", "-123 €"},
+ },
+}