136 lines
3.8 KiB
Go
136 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"embed"
|
|
"flag"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
|
|
omni "git.yuntuo.hk/k2safe/go-omni"
|
|
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
|
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
|
"git.yuntuo.hk/k2safe/go-omni/i18n"
|
|
browseri18n "git.yuntuo.hk/k2safe/go-omni/i18n/browser"
|
|
"git.yuntuo.hk/k2safe/go-omni/i18n/errori18n"
|
|
"git.yuntuo.hk/k2safe/go-omni/i18n/httpi18n"
|
|
"git.yuntuo.hk/k2safe/go-omni/response"
|
|
)
|
|
|
|
//go:embed config.json locales/*.json index.html
|
|
var resources embed.FS
|
|
|
|
func catalog() apierrors.Catalog {
|
|
return errori18n.Bind(apierrors.Catalog{Definitions: map[string]apierrors.Definition{
|
|
"LIMIT_EXCEEDED": {Status: 409, Code: 400001, Message: "Count must not exceed {max}", Params: []apierrors.Parameter{{Name: "max", Type: "int64"}}},
|
|
}}, "errors")
|
|
}
|
|
|
|
func bundle() (*i18n.Bundle, error) {
|
|
raw, err := resources.ReadFile("config.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var cfg i18n.Config
|
|
if err := i18n.DecodeJSON(raw, &cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
docs, err := i18n.LoadFS(resources, "locales/ui.en.json", "locales/ui.zh-Hans.json", "locales/errors.zh-Hans.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
source, err := errori18n.Source(catalog(), cfg.SourceLocale)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
docs = append(docs, source...)
|
|
return i18n.New(cfg, docs...)
|
|
}
|
|
|
|
func application(b *i18n.Bundle) (*omni.App, error) {
|
|
policy, err := httpi18n.New(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
localizer := errori18n.New(b, nil)
|
|
if err := localizer.Validate(catalog()); err != nil {
|
|
return nil, err
|
|
}
|
|
a := omni.New(omni.WithErrors(catalog()), omni.WithResponse(response.Config{CodeType: "int32", SuccessCode: 0, ErrorCode: 9999}), omni.WithLanguagePolicy(policy), omni.WithErrorLocalizer(localizer))
|
|
a.GET("/", func(c *httpx.Context) error {
|
|
data, err := resources.ReadFile("index.html")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Bytes(200, "text/html; charset=utf-8", data)
|
|
})
|
|
a.GET("/runtime.mjs", func(c *httpx.Context) error {
|
|
data, err := fs.ReadFile(browseri18n.Files(), "runtime.mjs")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Bytes(200, "text/javascript; charset=utf-8", data)
|
|
})
|
|
a.GET("/locales/:file", func(c *httpx.Context) error {
|
|
var locale string
|
|
switch c.Param("file") {
|
|
case "en.json":
|
|
locale = "en"
|
|
case "zh-Hans.json":
|
|
locale = "zh-Hans"
|
|
default:
|
|
return apierrors.NotFound("NOT_FOUND", "language pack not found")
|
|
}
|
|
var out bytes.Buffer
|
|
if err := b.Export(&out, locale, "ui"); err != nil {
|
|
return err
|
|
}
|
|
return c.Bytes(200, "application/json; charset=utf-8", out.Bytes())
|
|
})
|
|
a.GET("/api/limit", func(*httpx.Context) error {
|
|
return apierrors.ByCode("LIMIT_EXCEEDED").WithParams(map[string]any{"max": int64(100)})
|
|
})
|
|
a.POST("/api/action", func(c *httpx.Context) error { return c.OK(map[string]bool{"accepted": true}) })
|
|
return a, nil
|
|
}
|
|
|
|
func main() {
|
|
serve := flag.String("serve", "", "optional local HTTP listen address")
|
|
locale := flag.String("export-locale", "", "export a UI language pack to stdout")
|
|
exportCatalog := flag.Bool("catalog", false, "export the Go error catalog to stdout")
|
|
flag.Parse()
|
|
if err := run(*serve, *locale, *exportCatalog); err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
func run(serve, locale string, exportCatalog bool) error {
|
|
if exportCatalog {
|
|
return apierrors.ExportCatalog(os.Stdout, catalog())
|
|
}
|
|
b, err := bundle()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if locale != "" {
|
|
return b.Export(os.Stdout, locale, "ui")
|
|
}
|
|
if serve != "" {
|
|
a, err := application(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer a.Close()
|
|
return a.Run(serve)
|
|
}
|
|
for _, l := range b.Config().Locales {
|
|
result, err := b.Render(l, i18n.Ref{Namespace: "ui", Key: "greeting"}, map[string]any{"name": "Alex"})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Println(result.Locale + ": " + result.Text)
|
|
}
|
|
return nil
|
|
}
|