Open nkev opened 7 years ago
Hi nkev, welcome!
package main import ( "fmt" "log" "os" "strings" "time" "runtime/debug" "github.com/CloudyKit/jet" "github.com/fasthttp-contrib/sessions" "github.com/patrickmn/go-cache" "github.com/valyala/fasthttp" "gopkg.in/mgo.v2" "gopkg.in/mgo.v2/bson" ) //config.json { "Locales": [["zh","中文"],["en","English"]], "Port": ":80", "Database": "mymongodb", "Admin": "admin", "Password": "admin#2016", "Debug": true } //globals ...... var myConfig Config var mapLocale map[string](map[string]string) //locale strings var mongo *mgo.Session //auto run before main func init() { if !LoadConfig() { fmt.Println("Load Config failed. ") os.Exit(1) } var err error mongo, err = mgo.Dial("127.0.0.1:27017") if err != nil { fmt.Println("MongoDB connection failed:", err.Error()) os.Exit(1) } mapLocale = LoadLocales() } type Config struct { Locales [][]string `json:"Locales"` Port string `json:"Port"` Database string `json:"Database"` Admin string `json:"Admin"` Password string `json:"Password"` Debug bool `json:"Debug"` } //use the package of "encoding/json" to unmarshal config.json file //you can do in this way to render json: //jsondata, err := json.Marshal(jsonstruct) //if err!=nil...else //ctx.SetBody(jsondata) func LoadConfig() bool { fd, err := ioutil.ReadFile("config.json") if err != nil { return false } err = json.Unmarshal(fd, &myConfig) if err != nil { return false } return true } func LoadLocales() map[string](map[string]string) { ms := mongo.Clone() defer ms.Close() co := ms.DB(myConfig.Database).C("locales") LoadLocalesFromSource(co) docs := []LocaleData{} co.Find(bson.M{}).All(&docs) locs := make(map[string](map[string]string)) for _, doc := range docs { locs[doc.Key] = doc.Locales } return locs } func LoadFileLocales(co *mgo.Collection, fn string) { var reg = regexp.MustCompile(`LS\([^\)]+\)`) data, err := ioutil.ReadFile(fn) if err != nil { panic(err) } ss := reg.FindAllString(string(data), -1) for _, s := range ss { f := strings.Index(s, "\"") t := strings.LastIndex(s, "\"") if f < 0 || t <= f { continue } k := strings.TrimSpace(s[f+1 : t]) if k == "" { continue } ld := LocaleData{} err := co.Find(bson.M{"key": k}).One(&ld) if err != nil { co.Insert(LocaleData{Id: bson.NewObjectId(), Key: k, Locales: make(map[string]string)}) } } } //load strings need to be translated from program and template files func LoadLocalesFromSource(co *mgo.Collection) { paths := []string{"./", "./views/admin/", "./views/public/", "./views/shared/"} for _, p := range paths { files, _ := ioutil.ReadDir(p) for _, f := range files { if f.IsDir() || f.Name() == "locale.go" { continue } if strings.HasSuffix(f.Name(), ".go") || strings.HasSuffix(f.Name(), ".jet.html") { LoadFileLocales(co, p+f.Name()) } } } } //locale data saved in mongodb type LocaleData struct { Id bson.ObjectId `bson:"_id"` Key string `bson:"key"` Locales map[string]string `bson:"lcs"` } //the function to translate string func LS(l, s string) string { v, ok := mapLocale[s] if ok { ls, ok := v[l] if ok && ls != "" { return ls } } return s } //functions to get locale from user's browser type LangQ struct { Lang string Q float64 } func ParseAcceptLanguage(AcceptLangs string) []LangQ { var lqs []LangQ arrLang := strings.Split(AcceptLangs, ",") for _, lang := range arrLang { sLang := strings.TrimSpace(lang) langQ := strings.Split(sLang, ";") ln := len(langQ) if ln == 0 { continue } if ln == 1 { lq := LangQ{langQ[0], 1} lqs = append(lqs, lq) } else { qp := strings.Split(langQ[1], "=") if len(qp) > 1 { q, err := strconv.ParseFloat(qp[1], 64) if err != nil { continue } lq := LangQ{langQ[0], q} lqs = append(lqs, lq) } } } return lqs } func GetAgentLocale(AcceptLangs string) string { lqs := ParseAcceptLanguage(AcceptLangs) q := 0.0 l := myConfig.Locales[0][0] //default locale for _, lq := range lqs { for _, lc := range myConfig.Locales { if lq.Q > q && strings.HasPrefix(lq.Lang, lc[0]) { q = lq.Q l = lc[0] } } } return l } func GetLocale(ctx *fasthttp.RequestCtx) string { langs := string(ctx.Request.Header.Peek("Accept-Language")) if langs != "" { return GetAgentLocale(langs) //return the browser's best accepted locale } return myConfig.Locales[0][0], "" //return default locale } //middleware is just a wrapper func run above router handler //in func main if err := fasthttp.ListenAndServe(myConfig.Port, middleFunc); err != nil { log.Fatalf("Error in ListenAndServe: %s", err) } //middleware func middleFunc(ctx *fasthttp.RequestCtx){ //middleware codes here, you can save middle variables in "context" ... //router handler requestHandler(ctx) //middleware codes also may be here ... } func requestHandler(ctx *fasthttp.RequestCtx) { defer func() { if err := recover(); err != nil { log.Fatalf("Recovery error: %s", err) log.Fatalf("Stack: %s", debug.Stack()) } }() path := strings.ToLower(string(ctx.Path())) //set handle funcs according to path and use context in these funcs if path=="/"|| path=="/home"{ home(ctx) }else if ... ... }
Hi, I'm still learning so much from your code. Thank you so much. I think you should share more of your talent :) I have a few questions if you don't mind:
Could I study your GetUserLocale(ctx) and LS() functions please?
What marshal/unmarshal library do you use to render JSON API calls?
How do you use middleware in your request chain with fasthttp?
Thank you!