Skip to content

Instantly share code, notes, and snippets.

@u007
Last active March 10, 2017 11:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save u007/fda1dd4f92f424242732b5f7a82d5fc3 to your computer and use it in GitHub Desktop.
Save u007/fda1dd4f92f424242732b5f7a82d5fc3 to your computer and use it in GitHub Desktop.
buffalo i18n locale
// in actions/app.go
/*
directory structure
app/
locales/en-us.yaml
assets/js/locales/
middleware/
actions/tools
*/
import(
///...
ownmiddleware "project/middleware"
"project/actions/tools"
)
func App() *buffalo.App {
///...
translation.SetupLocale("en-US")
app.Use(ownmiddleware.LanguageMiddleware)
//...
return app;
}
# in locales/en-us.yaml
# https://github.com/nicksnyder/go-i18n/blob/64786dc4f56b1cceffc2ce90a7f512d9ab70bba2/goi18n/testdata/en-us.yaml
- id: Hi
translation: Hello
- id: Another name
translation: Something else
<!-- in views/index.html -->
{{T "Hi"}}
// middleware/language.go
package middleware
import (
"project/actions/tools"
"fmt"
"github.com/gobuffalo/buffalo"
)
func LanguageMiddleware(next buffalo.Handler) buffalo.Handler {
return func(c buffalo.Context) error {
locale := c.Request().Header.Get("Accept-Language")
c.Logger().Info(fmt.Sprintf("locale: %s", locale))
translation.LoadTranslation(locale)
return next(c)
}
}
// in actions/tools/translation.go
package translation
import (
"encoding/json"
"fmt"
"github.com/gobuffalo/velvet"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/nicksnyder/go-i18n/i18n/bundle"
"gopkg.in/yaml.v2"
"io/ioutil"
"log"
"os"
"reflect"
"strings"
"time"
)
var DefaultLocale = "en-US"
func SetupLocale(defaultLocale string) {
DefaultLocale = defaultLocale
LoadLocaleFile("en-us")
}
// this load translation and convert it to i18n-react js file
func LoadLocaleFile(locale string) {
path := "./locales/" + locale + ".yaml"
dest_json := "./assets/js/locales/" + locale + ".jsx"
bundle := bundle.New()
bundle.MustLoadTranslationFile(path)
if 1 == 2 && !FileChanged(path, dest_json) {
return
}
data, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Unable to load yaml")
}
log.Printf("yaml: %#v\n", string(data))
// m := make(map[string][]interface{})
var m []map[string]string
// m := make(map[interface{}]interface{})
err = yaml.Unmarshal((data), &m)
if err != nil {
log.Fatalf("error: %v", err)
}
// log.Printf(fmt.Sprintf("yaml: %#v\n", m))
jsonMap := make(map[string]interface{})
// translations := bundle.Translations()
// // log.Printf("translations: %#v", translations["en-us"])
// r, _ := regexp.Compile("p([a-z]+)ch")
for c := range m {
name := m[c]["id"]
names := strings.Split(name, ".")
value := strings.Replace(m[c]["translation"], "{{.", "{", -1)
value = strings.Replace(value, "}}", "}", -1)
if len(names) > 1 {
name = names[0]
}
if _, ok := jsonMap[name]; ok {
// has existing key
if _, ok := jsonMap[name].(string); ok {
//replace by nested array, or value after it
jsonMap[name] = NestedValue(names[1:], value)
log.Printf("was string, result: %#v\n", jsonMap[name])
} else {
// source := make(map[string]interface{})
rv := reflect.ValueOf(jsonMap[name])
if rv.Kind() == reflect.Map {
source, ok := jsonMap[name].(map[string]interface{})
if !ok {
log.Fatalf("unable to convert to map[string]interface{} of %#v", jsonMap)
}
log.Printf("b4---%#v\n", jsonMap)
jsonMap[name] = JoinNested(source, NestedValue(names[1:], value))
} else {
log.Fatalf("Unsupported type: %#v", rv.Kind())
}
}
} else {
if len(names) > 1 {
jsonMap[name] = NestedValue(names[1:], value)
log.Printf("first nested: %#v\n", jsonMap)
} else {
jsonMap[name] = value
}
}
}
jsonResult, err := json.Marshal(jsonMap)
if err != nil {
log.Panicf("Unable to create json from yaml")
}
jsContent := `import T from 'i18n-react';
T.setTexts(` + string(jsonResult) + `)
export default T`
// jsonResult, err = json.MarshalIndent(jsonResult, "", " ")
// if err != nil {
// log.Panicf("Unable to indent json")
// }
err = ioutil.WriteFile(dest_json, []byte(jsContent), 0644)
if err != nil {
log.Panicf("Unable to write %s", dest_json)
}
log.Printf("Written to %s\n", dest_json)
}
func NestedValue(names []string, value string) map[string]interface{} {
res := make(map[string]interface{})
if len(names) > 1 {
res[names[0]] = NestedValue(names[1:], value)
} else {
res[names[0]] = value
}
log.Printf("nestedvalue: %#v = %#v\n", names, res)
return res
}
func JoinNested(existing map[string]interface{}, values map[string]interface{}) map[string]interface{} {
fmt.Printf("joining nested %#v\n", existing)
fmt.Printf("joining nested2 %#v\n", values)
res := make(map[string]interface{})
for i := range existing {
res[i] = existing[i]
}
for i := range values {
if _, ok := res[i].(string); ok {
//replace by nested array, or value after it
res[i] = values[i]
} else {
name := i
value := values[i]
if _, ok := res[name]; ok {
// has existing key
if _, ok := res[name].(string); ok {
//replace by nested array, or value after it
res[name] = value
} else {
rv := reflect.ValueOf(res[name])
rv2 := reflect.ValueOf(value)
if rv.Kind() == reflect.Map && rv2.Kind() == reflect.Map {
source, ok := res[name].(map[string]interface{})
if !ok {
log.Fatalf("unable to convert to map[string]interface{} of %#v", res)
}
destination, ok := value.(map[string]interface{})
res[name] = JoinNested(source, destination)
} else {
log.Fatalf("Unsupported type: %#v and %#v", rv.Kind(), rv2.Kind())
}
// source := make(map[string]interface{})
// rv := reflect.ValueOf(res[name])
// if rv.Kind() == reflect.Map {
// for _, key := range rv.MapKeys() {
// log.Printf("rv-nested-key: %#v", key)
// source[key.String()] = rv.MapIndex(key)
// }
// }
// destination := make(map[string]interface{})
// rv = reflect.ValueOf(value)
// if rv.Kind() == reflect.Map {
// for _, key := range rv.MapKeys() {
// log.Printf("rv-destination-nested-key: %#v", key)
// destination[key.String()] = rv.MapIndex(key)
// }
// }
}
} else {
res[name] = value
}
}
}
fmt.Printf("result nested: %#v\n", res)
return res
}
func FileChanged(source string, destination string) bool {
file1Info, err := os.Stat(source)
if err != nil {
log.Panicf("%s is not a file. \n", source)
}
file2Info, err := os.Stat(destination)
if err != nil && os.IsNotExist(err) {
return true
} else if err != nil {
log.Panicf("%s is not a file %s", destination, err.Error())
}
modTime1 := file1Info.ModTime()
modTime2 := file2Info.ModTime()
log.Printf("source: %#v, destination: %#v", modTime1, modTime2)
diff := modTime1.Sub(modTime2)
if diff > (time.Duration(0) * time.Second) {
log.Printf("Locale changed %s\n", source)
return true
}
return false
}
func LoadTranslation(locale string) {
err := velvet.Helpers.Add("T", func(name string, a ...interface{}) string {
T, _ := i18n.Tfunc(locale, DefaultLocale)
return T(name, a...)
})
if err != nil {
msg := fmt.Sprintf("unable to add velvet helper: %#v\n", err.Error())
log.Fatalf(msg)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment