122 lines
2.2 KiB
Go
122 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/parser"
|
|
"go/token"
|
|
"os"
|
|
"sort"
|
|
"strconv"
|
|
)
|
|
|
|
func main() {
|
|
const goFile = "i18n/messages.go"
|
|
const outFile = "resources/src/messages.json"
|
|
|
|
keys, err := extractStringConsts(goFile)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
existing := map[string]string{}
|
|
if data, err := os.ReadFile(outFile); err == nil {
|
|
if len(bytes.TrimSpace(data)) > 0 {
|
|
if err := json.Unmarshal(data, &existing); err != nil {
|
|
panic(fmt.Errorf("parse %s: %w", outFile, err))
|
|
}
|
|
}
|
|
} else if !os.IsNotExist(err) {
|
|
panic(err)
|
|
}
|
|
|
|
merged := map[string]string{}
|
|
for _, key := range keys {
|
|
if val, ok := existing[key]; ok {
|
|
merged[key] = val
|
|
} else {
|
|
merged[key] = "TODO: " + key
|
|
}
|
|
}
|
|
|
|
// Detect stale keys.
|
|
for key := range existing {
|
|
found := false
|
|
for _, k := range keys {
|
|
if k == key {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
fmt.Fprintf(os.Stderr, "stale key in %s: %s\n", outFile, key)
|
|
}
|
|
}
|
|
|
|
// Write stable sorted JSON.
|
|
sorted := make([]string, 0, len(merged))
|
|
for k := range merged {
|
|
sorted = append(sorted, k)
|
|
}
|
|
sort.Strings(sorted)
|
|
|
|
buf := &bytes.Buffer{}
|
|
buf.WriteString("{\n")
|
|
for i, k := range sorted {
|
|
kj, _ := json.Marshal(k)
|
|
vj, _ := json.Marshal(merged[k])
|
|
comma := ","
|
|
if i == len(sorted)-1 {
|
|
comma = ""
|
|
}
|
|
fmt.Fprintf(buf, " %s: %s%s\n", kj, vj, comma)
|
|
}
|
|
buf.WriteString("}\n")
|
|
|
|
if err := os.WriteFile(outFile, buf.Bytes(), 0644); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func extractStringConsts(path string) ([]string, error) {
|
|
fset := token.NewFileSet()
|
|
file, err := parser.ParseFile(fset, path, nil, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var keys []string
|
|
|
|
for _, decl := range file.Decls {
|
|
gen, ok := decl.(*ast.GenDecl)
|
|
if !ok || gen.Tok != token.CONST {
|
|
continue
|
|
}
|
|
|
|
for _, spec := range gen.Specs {
|
|
vs, ok := spec.(*ast.ValueSpec)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
for _, value := range vs.Values {
|
|
lit, ok := value.(*ast.BasicLit)
|
|
if !ok || lit.Kind != token.STRING {
|
|
continue
|
|
}
|
|
|
|
s, err := strconv.Unquote(lit.Value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
keys = append(keys, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
return keys, nil
|
|
}
|