diff --git a/general_test.go b/general_test.go index 1e50c251..c135986c 100644 --- a/general_test.go +++ b/general_test.go @@ -52,6 +52,11 @@ func gloinit() error { return err } + err = initPhrases() + if err != nil { + log.Fatal(err) + } + if config.CacheTopicUser == CACHE_STATIC { users = NewMemoryUserStore(config.UserCacheCapacity) topics = NewMemoryTopicStore(config.TopicCacheCapacity) diff --git a/langs/english.json b/langs/english.json new file mode 100644 index 00000000..73f7c2cb --- /dev/null +++ b/langs/english.json @@ -0,0 +1,43 @@ +{ + "Name": "english", + "Levels": { + "Level": "Level {0}", + "LevelMax": "" + }, + "GlobalPerms": { + "BanUsers": "Can ban users", + "ActivateUsers": "Can activate users", + "EditUser": "Can edit users", + "EditUserEmail": "Can change a user's email", + "EditUserPassword": "Can change a user's password", + "EditUserGroup": "Can change a user's group", + "EditUserGroupSuperMod": "Can edit super-mods", + "EditUserGroupAdmin": "Can edit admins", + "EditGroup": "Can edit groups", + "EditGroupLocalPerms": "Can edit a group's minor perms", + "EditGroupGlobalPerms": "Can edit a group's global perms", + "EditGroupSuperMod": "Can edit super-mod groups", + "EditGroupAdmin": "Can edit admin groups", + "ManageForums": "Can manage forums", + "EditSettings": "Can edit settings", + "ManageThemes": "Can manage themes", + "ManagePlugins": "Can manage plugins", + "ViewAdminLogs": "Can view the administrator action logs", + "ViewIPs": "Can view IP addresses" + }, + "LocalPerms": { + "ViewTopic": "Can view topics", + "LikeItem": "Can like items", + "CreateTopic": "Can create topics", + "EditTopic": "Can edit topics", + "DeleteTopic": "Can delete topics", + "CreateReply": "Can create replies", + "EditReply": "Can edit replies", + "DeleteReply": "Can delete replies", + "PinTopic": "Can pin topics", + "CloseTopic": "Can lock topics" + }, + "SettingLabels": { + "activation_type": "Activate All,Email Activation,Admin Approval" + } +} \ No newline at end of file diff --git a/main.go b/main.go index 97ab107c..cf0992a6 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,8 @@ var enableWebsockets = false // Don't change this, the value is overwritten by a var router *GenRouter var startTime time.Time + +// ? - Make this more customisable? var externalSites = map[string]string{ "YT": "https://www.youtube.com/", } @@ -133,6 +135,11 @@ func main() { log.Fatal(err) } + err = initPhrases() + if err != nil { + log.Fatal(err) + } + if config.CacheTopicUser == CACHE_STATIC { users = NewMemoryUserStore(config.UserCacheCapacity) topics = NewMemoryTopicStore(config.TopicCacheCapacity) diff --git a/phrases.go b/phrases.go index 3aa9ab28..c5221890 100644 --- a/phrases.go +++ b/phrases.go @@ -7,88 +7,96 @@ package main import ( + "encoding/json" + "errors" + "io/ioutil" + "log" + "os" + "path/filepath" "sync" "sync/atomic" ) // TODO: Let the admin edit phrases from inside the Control Panel? How should we persist these? Should we create a copy of the langpack or edit the primaries? Use the changeLangpack mutex for this? // nolint Be quiet megacheck, this *is* used -var changeLangpackMutex sync.Mutex var currentLanguage = "english" var currentLangPack atomic.Value +var langpackCount int // TODO: Use atomics for this +// We'll be implementing the level phrases in the software proper very very soon! type LevelPhrases struct { Level string - LevelMax string + LevelMax string // ? Add a max level setting? // Override the phrase for individual levels, if the phrases exist Levels []string // index = level } type LanguagePack struct { - Name string - Phrases map[string]string // Should we use a sync map or a struct for these? It would be nice, if we could keep all the phrases consistent. - LevelPhrases LevelPhrases - GlobalPermPhrases map[string]string - LocalPermPhrases map[string]string - SettingLabels map[string]string + Name string + Phrases map[string]string // Should we use a sync map or a struct for these? It would be nice, if we could keep all the phrases consistent. + Levels LevelPhrases + GlobalPerms map[string]string + LocalPerms map[string]string + SettingLabels map[string]string } // TODO: Add the ability to edit language JSON files from the Control Panel and automatically scan the files for changes // TODO: Move the english language pack into a JSON file and load that on start-up -var langpacks = map[string]*LanguagePack{ - "english": &LanguagePack{ - Name: "english", +////var langpacks = map[string]*LanguagePack +var langpacks sync.Map // nolint it is used - // We'll be implementing the level phrases in the software proper very very soon! - LevelPhrases: LevelPhrases{ - Level: "Level {0}", - LevelMax: "", // Add a max level setting? - }, +func initPhrases() error { + log.Print("Loading the language packs") + err := filepath.Walk("./langs", func(path string, f os.FileInfo, err error) error { + if f.IsDir() { + return nil + } - GlobalPermPhrases: map[string]string{ - "BanUsers": "Can ban users", - "ActivateUsers": "Can activate users", - "EditUser": "Can edit users", - "EditUserEmail": "Can change a user's email", - "EditUserPassword": "Can change a user's password", - "EditUserGroup": "Can change a user's group", - "EditUserGroupSuperMod": "Can edit super-mods", - "EditUserGroupAdmin": "Can edit admins", - "EditGroup": "Can edit groups", - "EditGroupLocalPerms": "Can edit a group's minor perms", - "EditGroupGlobalPerms": "Can edit a group's global perms", - "EditGroupSuperMod": "Can edit super-mod groups", - "EditGroupAdmin": "Can edit admin groups", - "ManageForums": "Can manage forums", - "EditSettings": "Can edit settings", - "ManageThemes": "Can manage themes", - "ManagePlugins": "Can manage plugins", - "ViewAdminLogs": "Can view the administrator action logs", - "ViewIPs": "Can view IP addresses", - }, + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } - LocalPermPhrases: map[string]string{ - "ViewTopic": "Can view topics", - "LikeItem": "Can like items", - "CreateTopic": "Can create topics", - "EditTopic": "Can edit topics", - "DeleteTopic": "Can delete topics", - "CreateReply": "Can create replies", - "EditReply": "Can edit replies", - "DeleteReply": "Can delete replies", - "PinTopic": "Can pin topics", - "CloseTopic": "Can lock topics", - }, + var ext = filepath.Ext("/langs/" + path) + if ext != ".json" { + if dev.DebugMode { + log.Print("Found a " + ext + "in /langs/") + } + return nil + } - SettingLabels: map[string]string{ - "activation_type": "Activate All,Email Activation,Admin Approval", - }, - }, + var langPack LanguagePack + err = json.Unmarshal(data, &langPack) + if err != nil { + return err + } + + log.Print("Adding the '" + langPack.Name + "' language pack") + langpacks.Store(langPack.Name, &langPack) + langpackCount++ + + return nil + }) + + if err != nil { + return err + } + if langpackCount == 0 { + return errors.New("You don't have any language packs") + } + + langPack, ok := langpacks.Load(currentLanguage) + if !ok { + return errors.New("Couldn't find the " + currentLanguage + " language pack") + } + currentLangPack.Store(langPack) + return nil } -func init() { - currentLangPack.Store(langpacks[currentLanguage]) +func LoadLangPack(name string) error { + _ = name + return nil } // We might not need to use a mutex for this, we shouldn't need to change the phrases after start-up, and when we do we could overwrite the entire map @@ -98,7 +106,7 @@ func GetPhrase(name string) (string, bool) { } func GetGlobalPermPhrase(name string) string { - res, ok := currentLangPack.Load().(*LanguagePack).GlobalPermPhrases[name] + res, ok := currentLangPack.Load().(*LanguagePack).GlobalPerms[name] if !ok { return "{name}" } @@ -106,7 +114,7 @@ func GetGlobalPermPhrase(name string) string { } func GetLocalPermPhrase(name string) string { - res, ok := currentLangPack.Load().(*LanguagePack).LocalPermPhrases[name] + res, ok := currentLangPack.Load().(*LanguagePack).LocalPerms[name] if !ok { return "{name}" } @@ -140,13 +148,10 @@ func DeletePhrase() { // TODO: Use atomics to store the pointer of the current active langpack? // nolint func ChangeLanguagePack(name string) (exists bool) { - changeLangpackMutex.Lock() - pack, ok := langpacks[name] + pack, ok := langpacks.Load(name) if !ok { - changeLangpackMutex.Unlock() return false } currentLangPack.Store(pack) - changeLangpackMutex.Unlock() return true }