mirror of
				https://github.com/TeaOSLab/EdgeCommon.git
				synced 2025-11-04 13:10:24 +08:00 
			
		
		
		
	
		
			
	
	
		
			277 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			277 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package main
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"encoding/json"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"github.com/TeaOSLab/EdgeCommon/pkg/langs"
							 | 
						||
| 
								 | 
							
									"github.com/iwind/TeaGo/Tea"
							 | 
						||
| 
								 | 
							
									_ "github.com/iwind/TeaGo/bootstrap"
							 | 
						||
| 
								 | 
							
									"github.com/iwind/TeaGo/lists"
							 | 
						||
| 
								 | 
							
									"github.com/iwind/TeaGo/types"
							 | 
						||
| 
								 | 
							
									"go/format"
							 | 
						||
| 
								 | 
							
									"os"
							 | 
						||
| 
								 | 
							
									"path/filepath"
							 | 
						||
| 
								 | 
							
									"regexp"
							 | 
						||
| 
								 | 
							
									"sort"
							 | 
						||
| 
								 | 
							
									"strconv"
							 | 
						||
| 
								 | 
							
									"strings"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func main() {
							 | 
						||
| 
								 | 
							
									var args = os.Args
							 | 
						||
| 
								 | 
							
									if len(args) >= 2 {
							 | 
						||
| 
								 | 
							
										switch args[1] {
							 | 
						||
| 
								 | 
							
										case "generate":
							 | 
						||
| 
								 | 
							
											runGenerate()
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										fmt.Println("Usage: langs [generate]")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func runGenerate() {
							 | 
						||
| 
								 | 
							
									var rootDir = filepath.Clean(Tea.Root + "/../pkg/langs/protos")
							 | 
						||
| 
								 | 
							
									dir, err := os.Open(rootDir)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										fmt.Println("[ERROR]read dir failed: " + err.Error())
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									defer func() {
							 | 
						||
| 
								 | 
							
										_ = dir.Close()
							 | 
						||
| 
								 | 
							
									}()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									files, err := dir.Readdir(0)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										fmt.Println("[ERROR]read dir failed: " + err.Error())
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var dirRegexp = regexp.MustCompile(`^[a-z]+-[a-z]+$`)
							 | 
						||
| 
								 | 
							
									var jsonFileNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]+)(_([a-zA-Z0-9]+))+\.json$`)
							 | 
						||
| 
								 | 
							
									var messageCodeRegexp = regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var messageCodes = []string{}
							 | 
						||
| 
								 | 
							
									var messageMaps = map[string]map[string]string{} // lang => { K:V }
							 | 
						||
| 
								 | 
							
									var defaultLang = langs.DefaultManager().DefaultLang()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for _, file := range files {
							 | 
						||
| 
								 | 
							
										var dirName = file.Name()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if !file.IsDir() || !dirRegexp.MatchString(dirName) {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										var langCode = dirName
							 | 
						||
| 
								 | 
							
										var isBaseLang = langCode == defaultLang
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										func() {
							 | 
						||
| 
								 | 
							
											jsonFiles, err := filepath.Glob(rootDir + "/" + dirName + "/*.json")
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												fmt.Println("[ERROR]list json files failed: " + err.Error())
							 | 
						||
| 
								 | 
							
												return
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for _, jsonFile := range jsonFiles {
							 | 
						||
| 
								 | 
							
												var jsonFileName = filepath.Base(jsonFile)
							 | 
						||
| 
								 | 
							
												if len(jsonFileName) == 0 || !jsonFileNameRegexp.MatchString(jsonFileName) {
							 | 
						||
| 
								 | 
							
													continue
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												var module = strings.TrimSuffix(jsonFileName, ".json")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												data, err := os.ReadFile(jsonFile)
							 | 
						||
| 
								 | 
							
												if err != nil {
							 | 
						||
| 
								 | 
							
													fmt.Println("[ERROR]read json file '" + jsonFile + "' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
													return
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												var m = map[string]string{} // code => value
							 | 
						||
| 
								 | 
							
												err = json.Unmarshal(data, &m)
							 | 
						||
| 
								 | 
							
												if err != nil {
							 | 
						||
| 
								 | 
							
													fmt.Println("[ERROR]decode json file '" + jsonFile + "' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
													return
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												var newM = map[string]string{}
							 | 
						||
| 
								 | 
							
												for code, value := range m {
							 | 
						||
| 
								 | 
							
													if !messageCodeRegexp.MatchString(code) {
							 | 
						||
| 
								 | 
							
														fmt.Println("[ERROR]invalid message code '" + code + "'")
							 | 
						||
| 
								 | 
							
														return
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													var fullCode = module + "_" + code
							 | 
						||
| 
								 | 
							
													if isBaseLang {
							 | 
						||
| 
								 | 
							
														messageCodes = append(messageCodes, fullCode)
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
													newM[fullCode] = value
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												finalMap, ok := messageMaps[langCode]
							 | 
						||
| 
								 | 
							
												if !ok {
							 | 
						||
| 
								 | 
							
													finalMap = map[string]string{}
							 | 
						||
| 
								 | 
							
													messageMaps[langCode] = finalMap
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												for code, value := range newM {
							 | 
						||
| 
								 | 
							
													finalMap[code] = value
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// check message codes
							 | 
						||
| 
								 | 
							
									fmt.Println("checking message codes ...")
							 | 
						||
| 
								 | 
							
									var defaultMessageMap = map[string]string{}
							 | 
						||
| 
								 | 
							
									for langCode, messageMap := range messageMaps {
							 | 
						||
| 
								 | 
							
										if langCode == defaultLang { // only check lang not equal to 'en-us'
							 | 
						||
| 
								 | 
							
											defaultMessageMap = messageMap
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for messageCode := range messageMap {
							 | 
						||
| 
								 | 
							
											if !lists.ContainsString(messageCodes, messageCode) {
							 | 
						||
| 
								 | 
							
												fmt.Println("[ERROR]message code '" + messageCode + "' in lang '" + langCode + "' not exist in default lang file ('" + defaultLang + "')")
							 | 
						||
| 
								 | 
							
												return
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									fmt.Println("found '" + types.String(len(messageCodes)) + "' message codes")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// generate codes/codes.go
							 | 
						||
| 
								 | 
							
									sort.Strings(messageCodes)
							 | 
						||
| 
								 | 
							
									var codesSource = `
							 | 
						||
| 
								 | 
							
								// generated by run 'langs generate'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package codes
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import(
							 | 
						||
| 
								 | 
							
									"github.com/TeaOSLab/EdgeCommon/pkg/langs"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for _, messageCode := range messageCodes {
							 | 
						||
| 
								 | 
							
										// add comment to message code
							 | 
						||
| 
								 | 
							
										comment, _, _ := strings.Cut(defaultMessageMap[messageCode], "\n")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										codesSource += upperWords(messageCode) + " langs.MessageCode = " + strconv.Quote(messageCode) + " // " + comment + "\n"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									codesSource += `
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									formattedCodesSource, err := format.Source([]byte(codesSource))
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										fmt.Println("[ERROR]format 'codes.go' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									fmt.Println("generating 'codes/codes.go' ...")
							 | 
						||
| 
								 | 
							
									err = os.WriteFile(Tea.Root+"/../pkg/langs/codes/codes.go", formattedCodesSource, 0666)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										fmt.Println("[ERROR]write to 'codes.go' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// generate messages_LANG.go
							 | 
						||
| 
								 | 
							
									for langCode, messageMap := range messageMaps {
							 | 
						||
| 
								 | 
							
										var langFile = strings.ReplaceAll("messages/messages_"+langCode+".go", "-", "_")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										fmt.Println("generating '" + langFile + "' ...")
							 | 
						||
| 
								 | 
							
										var source = `
							 | 
						||
| 
								 | 
							
								// generated by run 'langs generate'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package messages
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import(
							 | 
						||
| 
								 | 
							
									"github.com/TeaOSLab/EdgeCommon/pkg/langs"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func init() {
							 | 
						||
| 
								 | 
							
									langs.Load("` + langCode + `", map[string]string{
							 | 
						||
| 
								 | 
							
									`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for code, value := range messageMap {
							 | 
						||
| 
								 | 
							
											source += strconv.Quote(code) + ": " + strconv.Quote(value) + ",\n"
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										source += `
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										formattedSource, err := format.Source([]byte(source))
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											fmt.Println("[ERROR]format '" + langFile + "' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										err = os.WriteFile(Tea.Root+"/../pkg/langs/"+langFile, formattedSource, 0666)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											fmt.Println("[ERROR]write file '" + langFile + "' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
											return
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// generate language javascript files for EdgeAdmin
							 | 
						||
| 
								 | 
							
									for lang, messageMap := range messageMaps {
							 | 
						||
| 
								 | 
							
										if lang != defaultLang {
							 | 
						||
| 
								 | 
							
											// TODO merge messageMap with default message map
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for _, component := range []string{"EdgeAdmin", "EdgeUser"} {
							 | 
						||
| 
								 | 
							
											fmt.Println("generating '" + lang + ".js' for " + component + " ...")
							 | 
						||
| 
								 | 
							
											var targetFile = filepath.Clean(Tea.Root + "/../../" + component + "/web/public/js/langs/" + lang + ".js")
							 | 
						||
| 
								 | 
							
											var targetDir = filepath.Dir(targetFile)
							 | 
						||
| 
								 | 
							
											dirStat, _ := os.Stat(targetDir)
							 | 
						||
| 
								 | 
							
											if dirStat != nil {
							 | 
						||
| 
								 | 
							
												messageMapJSON, err := json.Marshal(messageMap)
							 | 
						||
| 
								 | 
							
												if err != nil {
							 | 
						||
| 
								 | 
							
													fmt.Println("[ERROR]marshal message map failed: " + err.Error())
							 | 
						||
| 
								 | 
							
													return
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												err = os.WriteFile(targetFile, []byte(`// generated by 'langs generate'
							 | 
						||
| 
								 | 
							
								window.LANG_MESSAGES = `+string(messageMapJSON)+";\n"), 0666)
							 | 
						||
| 
								 | 
							
												if err != nil {
							 | 
						||
| 
								 | 
							
													fmt.Println("[ERROR]write file '" + targetFile + "' failed: " + err.Error())
							 | 
						||
| 
								 | 
							
													return
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									fmt.Println("success")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func upperWords(s string) string {
							 | 
						||
| 
								 | 
							
									var words = strings.Split(s, "_")
							 | 
						||
| 
								 | 
							
									for index, word := range words {
							 | 
						||
| 
								 | 
							
										words[index] = upperWord(word)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return strings.Join(words, "")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func upperWord(word string) string {
							 | 
						||
| 
								 | 
							
									var l = len(word)
							 | 
						||
| 
								 | 
							
									if l == 0 {
							 | 
						||
| 
								 | 
							
										return ""
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if l == 1 {
							 | 
						||
| 
								 | 
							
										return strings.ToUpper(word)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// special words
							 | 
						||
| 
								 | 
							
									switch word {
							 | 
						||
| 
								 | 
							
									case "api", "http", "https", "tcp", "udp", "ip", "dns", "ns", "waf", "acme", "ssh", "toa":
							 | 
						||
| 
								 | 
							
										return strings.ToUpper(word)
							 | 
						||
| 
								 | 
							
									case "ipv6":
							 | 
						||
| 
								 | 
							
										return "IPv6"
							 | 
						||
| 
								 | 
							
									case "ddos":
							 | 
						||
| 
								 | 
							
										return "DDoS"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return strings.ToUpper(word[:1]) + word[1:]
							 | 
						||
| 
								 | 
							
								}
							 |