dynamic translations
This commit is contained in:
parent
579bf619f4
commit
e25b84c686
@ -113,7 +113,7 @@ namespace nntpchan
|
|||||||
QueueLine("STREAMING");
|
QueueLine("STREAMING");
|
||||||
QueueLine(".");
|
QueueLine(".");
|
||||||
} else if (cmd == "CHECK") {
|
} else if (cmd == "CHECK") {
|
||||||
if(cmdlen == 2) {
|
if(cmdlen >= 2) {
|
||||||
const std::string & msgid = command[1];
|
const std::string & msgid = command[1];
|
||||||
if(IsValidMessageID(msgid) && m_store.Accept(msgid))
|
if(IsValidMessageID(msgid) && m_store.Accept(msgid))
|
||||||
{
|
{
|
||||||
|
@ -90,15 +90,16 @@ namespace nntpchan
|
|||||||
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
||||||
IServerConn * self = (IServerConn*) s->data;
|
IServerConn * self = (IServerConn*) s->data;
|
||||||
if(self == nullptr) {
|
if(self == nullptr) {
|
||||||
|
if(b->base)
|
||||||
delete [] b->base;
|
delete [] b->base;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nread > 0) {
|
if(nread > 0) {
|
||||||
b->base[nread] = 0;
|
|
||||||
self->m_handler->OnData(b->base, nread);
|
self->m_handler->OnData(b->base, nread);
|
||||||
self->SendNextReply();
|
self->SendNextReply();
|
||||||
if(self->m_handler->ShouldClose())
|
if(self->m_handler->ShouldClose())
|
||||||
self->Close();
|
self->Close();
|
||||||
|
delete [] b->base;
|
||||||
} else {
|
} else {
|
||||||
if (nread != UV_EOF) {
|
if (nread != UV_EOF) {
|
||||||
std::cerr << "error in nntp server conn alloc: ";
|
std::cerr << "error in nntp server conn alloc: ";
|
||||||
@ -108,7 +109,6 @@ namespace nntpchan
|
|||||||
// got eof or error
|
// got eof or error
|
||||||
self->Close();
|
self->Close();
|
||||||
}
|
}
|
||||||
delete [] b->base;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,11 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CacheHandler interface {
|
||||||
|
http.Handler
|
||||||
|
GetI18N(r *http.Request) *I18N
|
||||||
|
}
|
||||||
|
|
||||||
type CacheInterface interface {
|
type CacheInterface interface {
|
||||||
RegenAll()
|
RegenAll()
|
||||||
RegenFrontPage()
|
RegenFrontPage()
|
||||||
@ -17,7 +22,7 @@ type CacheInterface interface {
|
|||||||
|
|
||||||
Start()
|
Start()
|
||||||
Close()
|
Close()
|
||||||
GetHandler() http.Handler
|
GetHandler() CacheHandler
|
||||||
|
|
||||||
SetRequireCaptcha(required bool)
|
SetRequireCaptcha(required bool)
|
||||||
}
|
}
|
||||||
@ -26,6 +31,7 @@ type CacheInterface interface {
|
|||||||
func NewCache(cache_type, host, port, user, password string, cache_config, config map[string]string, db Database, store ArticleStore) CacheInterface {
|
func NewCache(cache_type, host, port, user, password string, cache_config, config map[string]string, db Database, store ArticleStore) CacheInterface {
|
||||||
prefix := config["prefix"]
|
prefix := config["prefix"]
|
||||||
webroot := config["webroot"]
|
webroot := config["webroot"]
|
||||||
|
translations := config["translations"]
|
||||||
threads := mapGetInt(config, "regen_threads", 1)
|
threads := mapGetInt(config, "regen_threads", 1)
|
||||||
name := config["name"]
|
name := config["name"]
|
||||||
attachments := mapGetInt(config, "allow_files", 1) == 1
|
attachments := mapGetInt(config, "allow_files", 1) == 1
|
||||||
@ -34,12 +40,12 @@ func NewCache(cache_type, host, port, user, password string, cache_config, confi
|
|||||||
return NewFileCache(prefix, webroot, name, threads, attachments, db, store)
|
return NewFileCache(prefix, webroot, name, threads, attachments, db, store)
|
||||||
}
|
}
|
||||||
if cache_type == "null" {
|
if cache_type == "null" {
|
||||||
return NewNullCache(prefix, webroot, name, attachments, db, store)
|
return NewNullCache(prefix, webroot, name, translations, attachments, db, store)
|
||||||
}
|
}
|
||||||
if cache_type == "varnish" {
|
if cache_type == "varnish" {
|
||||||
url := cache_config["url"]
|
url := cache_config["url"]
|
||||||
bind_addr := cache_config["bind"]
|
bind_addr := cache_config["bind"]
|
||||||
return NewVarnishCache(url, bind_addr, prefix, webroot, name, attachments, db, store)
|
return NewVarnishCache(url, bind_addr, prefix, webroot, name, translations, attachments, db, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Fatalf("invalid cache type: %s", cache_type)
|
log.Fatalf("invalid cache type: %s", cache_type)
|
||||||
|
@ -15,6 +15,8 @@ type FileCache struct {
|
|||||||
database Database
|
database Database
|
||||||
store ArticleStore
|
store ArticleStore
|
||||||
|
|
||||||
|
handler http.Handler
|
||||||
|
|
||||||
webroot_dir string
|
webroot_dir string
|
||||||
name string
|
name string
|
||||||
|
|
||||||
@ -112,7 +114,7 @@ func (self *FileCache) regenLongTerm() {
|
|||||||
log.Println("cannot render history graph", err)
|
log.Println("cannot render history graph", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
template.genGraphs(self.prefix, wr, self.database)
|
template.genGraphs(self.prefix, wr, self.database, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCache) pollLongTerm() {
|
func (self *FileCache) pollLongTerm() {
|
||||||
@ -191,7 +193,7 @@ func (self *FileCache) regenerateThread(root ArticleEntry, json bool) {
|
|||||||
log.Println("did not write", fname, err)
|
log.Println("did not write", fname, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
template.genThread(self.attachments, self.requireCaptcha, root, self.prefix, self.name, wr, self.database, json)
|
template.genThread(self.attachments, self.requireCaptcha, root, self.prefix, self.name, wr, self.database, json, nil)
|
||||||
} else {
|
} else {
|
||||||
log.Println("don't have root post", msgid, "not regenerating thread")
|
log.Println("don't have root post", msgid, "not regenerating thread")
|
||||||
}
|
}
|
||||||
@ -206,7 +208,7 @@ func (self *FileCache) regenerateBoardPage(board string, page int, json bool) {
|
|||||||
log.Println("error generating board page", page, "for", board, err)
|
log.Println("error generating board page", page, "for", board, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
template.genBoardPage(self.attachments, self.requireCaptcha, self.prefix, self.name, board, page, wr, self.database, json)
|
template.genBoardPage(self.attachments, self.requireCaptcha, self.prefix, self.name, board, page, wr, self.database, json, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// regenerate the catalog for a board
|
// regenerate the catalog for a board
|
||||||
@ -218,7 +220,7 @@ func (self *FileCache) regenerateCatalog(board string) {
|
|||||||
log.Println("error generating catalog for", board, err)
|
log.Println("error generating catalog for", board, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
template.genCatalog(self.prefix, self.name, board, wr, self.database)
|
template.genCatalog(self.prefix, self.name, board, wr, self.database, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// regenerate the front page
|
// regenerate the front page
|
||||||
@ -236,7 +238,7 @@ func (self *FileCache) RegenFrontPage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
template.genFrontPage(10, self.prefix, self.name, indexwr, boardswr, self.database)
|
template.genFrontPage(10, self.prefix, self.name, indexwr, boardswr, self.database, nil)
|
||||||
|
|
||||||
j_boardswr, err2 := os.Create(filepath.Join(self.webroot_dir, "boards.json"))
|
j_boardswr, err2 := os.Create(filepath.Join(self.webroot_dir, "boards.json"))
|
||||||
g := self.database.GetAllNewsgroups()
|
g := self.database.GetAllNewsgroups()
|
||||||
@ -258,7 +260,7 @@ func (self *FileCache) regenUkko() {
|
|||||||
log.Println("error generating ukko markup", err)
|
log.Println("error generating ukko markup", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
template.genUkko(self.prefix, self.name, wr, self.database, false)
|
template.genUkko(self.prefix, self.name, wr, self.database, false, nil)
|
||||||
|
|
||||||
// json
|
// json
|
||||||
fname = filepath.Join(self.webroot_dir, "ukko.json")
|
fname = filepath.Join(self.webroot_dir, "ukko.json")
|
||||||
@ -268,7 +270,7 @@ func (self *FileCache) regenUkko() {
|
|||||||
log.Println("error generating ukko json", err)
|
log.Println("error generating ukko json", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
template.genUkko(self.prefix, self.name, wr, self.database, true)
|
template.genUkko(self.prefix, self.name, wr, self.database, true, nil)
|
||||||
i := 0
|
i := 0
|
||||||
for i < 10 {
|
for i < 10 {
|
||||||
fname := fmt.Sprintf("ukko-%d.html", i)
|
fname := fmt.Sprintf("ukko-%d.html", i)
|
||||||
@ -279,14 +281,14 @@ func (self *FileCache) regenUkko() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
template.genUkkoPaginated(self.prefix, self.name, f, self.database, i, false)
|
template.genUkkoPaginated(self.prefix, self.name, f, self.database, i, false, nil)
|
||||||
j, err := os.Create(jname)
|
j, err := os.Create(jname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to create json ukko", i, err)
|
log.Printf("failed to create json ukko", i, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer j.Close()
|
defer j.Close()
|
||||||
template.genUkkoPaginated(self.prefix, self.name, j, self.database, i, true)
|
template.genUkkoPaginated(self.prefix, self.name, j, self.database, i, true, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,8 +336,16 @@ func (self *FileCache) GetGroupChan() chan groupRegenRequest {
|
|||||||
return self.regenGroupChan
|
return self.regenGroupChan
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCache) GetHandler() http.Handler {
|
func (self *FileCache) GetI18N(r *http.Request) *I18N {
|
||||||
return http.FileServer(http.Dir(self.webroot_dir))
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileCache) GetHandler() CacheHandler {
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *FileCache) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
self.handler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FileCache) Close() {
|
func (self *FileCache) Close() {
|
||||||
@ -348,7 +358,7 @@ func (self *FileCache) SetRequireCaptcha(require bool) {
|
|||||||
|
|
||||||
func NewFileCache(prefix, webroot, name string, threads int, attachments bool, db Database, store ArticleStore) CacheInterface {
|
func NewFileCache(prefix, webroot, name string, threads int, attachments bool, db Database, store ArticleStore) CacheInterface {
|
||||||
cache := new(FileCache)
|
cache := new(FileCache)
|
||||||
|
cache.handler = http.FileServer(http.Dir(webroot))
|
||||||
cache.regenBoardTicker = time.NewTicker(time.Second * 10)
|
cache.regenBoardTicker = time.NewTicker(time.Second * 10)
|
||||||
cache.longTermTicker = time.NewTicker(time.Hour)
|
cache.longTermTicker = time.NewTicker(time.Hour)
|
||||||
cache.ukkoTicker = time.NewTicker(time.Second * 30)
|
cache.ukkoTicker = time.NewTicker(time.Second * 30)
|
||||||
|
@ -39,4 +39,6 @@ type Frontend interface {
|
|||||||
|
|
||||||
// regenerate on mod event
|
// regenerate on mod event
|
||||||
RegenOnModEvent(newsgroup, msgid, root string, page int)
|
RegenOnModEvent(newsgroup, msgid, root string, page int)
|
||||||
|
|
||||||
|
GetCacheHandler() CacheHandler
|
||||||
}
|
}
|
||||||
|
@ -440,7 +440,7 @@ func (self *httpFrontend) new_captcha_json(wr http.ResponseWriter, r *http.Reque
|
|||||||
func (self *httpFrontend) handle_newboard(wr http.ResponseWriter, r *http.Request) {
|
func (self *httpFrontend) handle_newboard(wr http.ResponseWriter, r *http.Request) {
|
||||||
param := make(map[string]interface{})
|
param := make(map[string]interface{})
|
||||||
param["prefix"] = self.prefix
|
param["prefix"] = self.prefix
|
||||||
io.WriteString(wr, template.renderTemplate("newboard.mustache", param))
|
io.WriteString(wr, template.renderTemplate("newboard.mustache", param, self.cache.GetHandler().GetI18N(r)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle new post via http request for a board
|
// handle new post via http request for a board
|
||||||
@ -616,7 +616,7 @@ func (self *httpFrontend) handle_postform(wr http.ResponseWriter, r *http.Reques
|
|||||||
resp_map["prefix"] = self.prefix
|
resp_map["prefix"] = self.prefix
|
||||||
resp_map["redirect_url"] = url
|
resp_map["redirect_url"] = url
|
||||||
resp_map["reason"] = "captcha incorrect"
|
resp_map["reason"] = "captcha incorrect"
|
||||||
io.WriteString(wr, template.renderTemplate("post_fail.mustache", resp_map))
|
io.WriteString(wr, template.renderTemplate("post_fail.mustache", resp_map, self.cache.GetHandler().GetI18N(r)))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -650,7 +650,7 @@ func (self *httpFrontend) handle_postform(wr http.ResponseWriter, r *http.Reques
|
|||||||
resp_map["reason"] = err.Error()
|
resp_map["reason"] = err.Error()
|
||||||
resp_map["prefix"] = self.prefix
|
resp_map["prefix"] = self.prefix
|
||||||
resp_map["redirect_url"] = url
|
resp_map["redirect_url"] = url
|
||||||
io.WriteString(wr, template.renderTemplate("post_fail.mustache", resp_map))
|
io.WriteString(wr, template.renderTemplate("post_fail.mustache", resp_map, self.cache.GetHandler().GetI18N(r)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,7 +664,7 @@ func (self *httpFrontend) handle_postform(wr http.ResponseWriter, r *http.Reques
|
|||||||
if sendJson {
|
if sendJson {
|
||||||
json.NewEncoder(wr).Encode(map[string]interface{}{"message_id": nntp.MessageID(), "url": url, "error": nil})
|
json.NewEncoder(wr).Encode(map[string]interface{}{"message_id": nntp.MessageID(), "url": url, "error": nil})
|
||||||
} else {
|
} else {
|
||||||
io.WriteString(wr, template.renderTemplate("post_success.mustache", map[string]interface{}{"prefix": self.prefix, "message_id": nntp.MessageID(), "redirect_url": url}))
|
template.writeTemplate("post_success.mustache", map[string]interface{}{"prefix": self.prefix, "message_id": nntp.MessageID(), "redirect_url": url}, wr, self.cache.GetHandler().GetI18N(r))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.handle_postRequest(pr, b, e, s, self.enableBoardCreation)
|
self.handle_postRequest(pr, b, e, s, self.enableBoardCreation)
|
||||||
@ -1473,7 +1473,7 @@ func (self *httpFrontend) Mainloop() {
|
|||||||
m.Path("/live").HandlerFunc(self.handle_liveui).Methods("GET")
|
m.Path("/live").HandlerFunc(self.handle_liveui).Methods("GET")
|
||||||
// live ui page
|
// live ui page
|
||||||
m.Path("/livechan/").HandlerFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
m.Path("/livechan/").HandlerFunc(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
template.writeTemplate("live.mustache", map[string]interface{}{"prefix": self.prefix}, w)
|
template.writeTemplate("live.mustache", map[string]interface{}{"prefix": self.prefix}, w, self.cache.GetHandler().GetI18N(r))
|
||||||
})).Methods("GET", "HEAD")
|
})).Methods("GET", "HEAD")
|
||||||
// live ui api endpoint
|
// live ui api endpoint
|
||||||
m.Path("/livechan/api/{meth}").HandlerFunc(self.handle_liveapi).Methods("GET", "POST")
|
m.Path("/livechan/api/{meth}").HandlerFunc(self.handle_liveapi).Methods("GET", "POST")
|
||||||
@ -1521,6 +1521,10 @@ func (self *httpFrontend) RegenOnModEvent(newsgroup, msgid, root string, page in
|
|||||||
self.cache.RegenOnModEvent(newsgroup, msgid, root, page)
|
self.cache.RegenOnModEvent(newsgroup, msgid, root, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *httpFrontend) GetCacheHandler() CacheHandler {
|
||||||
|
return self.cache.GetHandler()
|
||||||
|
}
|
||||||
|
|
||||||
// create a new http based frontend
|
// create a new http based frontend
|
||||||
func NewHTTPFrontend(daemon *NNTPDaemon, cache CacheInterface, config map[string]string, url string) Frontend {
|
func NewHTTPFrontend(daemon *NNTPDaemon, cache CacheInterface, config map[string]string, url string) Frontend {
|
||||||
template.Minimize = config["minimize_html"] == "1"
|
template.Minimize = config["minimize_html"] == "1"
|
||||||
|
@ -10,6 +10,11 @@ type multiFrontend struct {
|
|||||||
frontends []Frontend
|
frontends []Frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self multiFrontend) GetCacheHandler() CacheHandler {
|
||||||
|
// TODO: fixme :^)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (self multiFrontend) AllowNewsgroup(newsgroup string) bool {
|
func (self multiFrontend) AllowNewsgroup(newsgroup string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -9,27 +9,37 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type i18n struct {
|
type I18N struct {
|
||||||
locale language.Tag
|
locale language.Tag
|
||||||
// loaded translations
|
// loaded translations
|
||||||
translations map[string]string
|
Translations map[string]string
|
||||||
// loaded formats
|
// loaded formats
|
||||||
formats map[string]string
|
Formats map[string]string
|
||||||
// root directory for translations
|
// root directory for translations
|
||||||
translation_dir string
|
translation_dir string
|
||||||
|
// name of locale
|
||||||
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
var i18nProvider *i18n = nil
|
var I18nProvider *I18N = nil
|
||||||
|
|
||||||
//Read all .ini files in dir, where the filenames are BCP 47 tags
|
//Read all .ini files in dir, where the filenames are BCP 47 tags
|
||||||
//Use the language matcher to get the best match for the locale preference
|
//Use the language matcher to get the best match for the locale preference
|
||||||
func InitI18n(locale, dir string) {
|
func InitI18n(locale, dir string) {
|
||||||
pref := language.Make(locale) // falls back to en-US on parse error
|
var err error
|
||||||
log.Println("using locale", pref)
|
I18nProvider, err = NewI18n(locale, dir)
|
||||||
files, err := ioutil.ReadDir(dir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewI18n(locale, dir string) (*I18N, error) {
|
||||||
|
log.Println("get locale", locale)
|
||||||
|
pref := language.Make(locale) // falls back to en-US on parse error
|
||||||
|
files, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
serverLangs := make([]language.Tag, 1)
|
serverLangs := make([]language.Tag, 1)
|
||||||
serverLangs[0] = language.AmericanEnglish // en-US fallback
|
serverLangs[0] = language.AmericanEnglish // en-US fallback
|
||||||
@ -48,39 +58,40 @@ func InitI18n(locale, dir string) {
|
|||||||
fname := filepath.Join(dir, tag.String()+".ini")
|
fname := filepath.Join(dir, tag.String()+".ini")
|
||||||
conf, err := configparser.Read(fname)
|
conf, err := configparser.Read(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("cannot read translation file for", tag.String(), err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
formats, err := conf.Section("formats")
|
formats, err := conf.Section("formats")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Cannot read formats sections in translations for", tag.String(), err)
|
return nil, err
|
||||||
}
|
}
|
||||||
translations, err := conf.Section("strings")
|
translations, err := conf.Section("strings")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Cannot read strings sections in translations for", tag.String(), err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
i18nProvider = &i18n{
|
return &I18N{
|
||||||
|
name: locale,
|
||||||
translation_dir: dir,
|
translation_dir: dir,
|
||||||
formats: formats.Options(),
|
Formats: formats.Options(),
|
||||||
translations: translations.Options(),
|
Translations: translations.Options(),
|
||||||
locale: tag,
|
locale: tag,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *i18n) Translate(key string) string {
|
func (self *I18N) Translate(key string) string {
|
||||||
return self.translations[key]
|
return self.Translations[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *i18n) Format(key string) string {
|
func (self *I18N) Format(key string) string {
|
||||||
return self.formats[key]
|
return self.Formats[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
//this signature seems to be expected by mustache
|
//this signature seems to be expected by mustache
|
||||||
func (self *i18n) Translations() (map[string]string, error) {
|
//func (self *I18N) Translations() (map[string]string, error) {
|
||||||
return self.translations, nil
|
// return self._translations, nil
|
||||||
}
|
//}
|
||||||
|
|
||||||
func (self *i18n) Formats() (map[string]string, error) {
|
//func (self *I18N) Formats() (map[string]string, error) {
|
||||||
return self.formats, nil
|
// return self.formats, nil
|
||||||
}
|
//}
|
||||||
|
@ -316,7 +316,7 @@ func (self *Installer) HandleInstallerGet(wr http.ResponseWriter, r *http.Reques
|
|||||||
wr.WriteHeader(404)
|
wr.WriteHeader(404)
|
||||||
} else {
|
} else {
|
||||||
m := self.currentNode.model(self.currentNode, self.currentErr, self.config)
|
m := self.currentNode.model(self.currentNode, self.currentErr, self.config)
|
||||||
template.writeTemplate(self.currentNode.templateName, m, wr)
|
template.writeTemplate(self.currentNode.templateName, m, wr, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,10 +32,11 @@ type httpModUI struct {
|
|||||||
store *sessions.CookieStore
|
store *sessions.CookieStore
|
||||||
prefix string
|
prefix string
|
||||||
mod_prefix string
|
mod_prefix string
|
||||||
|
cache CacheHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHttpModUI(frontend *httpFrontend) httpModUI {
|
func createHttpModUI(frontend *httpFrontend) httpModUI {
|
||||||
return httpModUI{frontend.regenAll, frontend.Regen, frontend.RegenerateBoard, frontend.deleteThreadMarkup, frontend.deleteBoardMarkup, make(chan NNTPMessage), frontend.daemon, frontend.daemon.store, frontend.store, frontend.prefix, frontend.prefix + "mod/"}
|
return httpModUI{frontend.regenAll, frontend.Regen, frontend.RegenerateBoard, frontend.deleteThreadMarkup, frontend.deleteBoardMarkup, make(chan NNTPMessage), frontend.daemon, frontend.daemon.store, frontend.store, frontend.prefix, frontend.prefix + "mod/", frontend.GetCacheHandler()}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,7 +475,8 @@ func (self httpModUI) writeTemplateParam(wr http.ResponseWriter, r *http.Request
|
|||||||
param[csrf.TemplateTag] = csrf.TemplateField(r)
|
param[csrf.TemplateTag] = csrf.TemplateField(r)
|
||||||
param["prefix"] = self.prefix
|
param["prefix"] = self.prefix
|
||||||
param["mod_prefix"] = self.mod_prefix
|
param["mod_prefix"] = self.mod_prefix
|
||||||
io.WriteString(wr, template.renderTemplate(name, param))
|
i18n := self.cache.GetI18N(r)
|
||||||
|
io.WriteString(wr, template.renderTemplate(name, param, i18n))
|
||||||
}
|
}
|
||||||
|
|
||||||
// do a function as authenticated
|
// do a function as authenticated
|
||||||
|
@ -19,6 +19,9 @@ type BaseModel interface {
|
|||||||
|
|
||||||
// to json string
|
// to json string
|
||||||
JSON() string
|
JSON() string
|
||||||
|
|
||||||
|
// inject I18N
|
||||||
|
I18N(i *I18N)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ThumbInfo struct {
|
type ThumbInfo struct {
|
||||||
@ -253,11 +256,11 @@ func (p *postsGraphRow) GraphRune(r string) (s string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p postsGraphRow) Date() (s string) {
|
func (p postsGraphRow) Date() (s string) {
|
||||||
return p.day.Format(i18nProvider.Format("month_date_format"))
|
return p.day.Format(I18nProvider.Format("month_date_format"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p postsGraphRow) Day() (s string) {
|
func (p postsGraphRow) Day() (s string) {
|
||||||
return p.day.Format(i18nProvider.Format("day_date_format"))
|
return p.day.Format(I18nProvider.Format("day_date_format"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p postsGraphRow) RegularGraph() (s string) {
|
func (p postsGraphRow) RegularGraph() (s string) {
|
||||||
|
@ -19,6 +19,7 @@ type catalogModel struct {
|
|||||||
prefix string
|
prefix string
|
||||||
board string
|
board string
|
||||||
threads []CatalogItemModel
|
threads []CatalogItemModel
|
||||||
|
_i18n *I18N
|
||||||
}
|
}
|
||||||
|
|
||||||
type catalogItemModel struct {
|
type catalogItemModel struct {
|
||||||
@ -27,6 +28,35 @@ type catalogItemModel struct {
|
|||||||
op PostModel
|
op PostModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *catalogModel) I18N(i *I18N) {
|
||||||
|
self._i18n = i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *post) I18N(i *I18N) {
|
||||||
|
self._i18n = i
|
||||||
|
for idx := range self.Files {
|
||||||
|
self.Files[idx].I18N(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *thread) I18N(i *I18N) {
|
||||||
|
self._i18n = i
|
||||||
|
for idx := range self.Posts {
|
||||||
|
self.Posts[idx].I18N(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *boardModel) I18N(i *I18N) {
|
||||||
|
self._i18n = i
|
||||||
|
for idx := range self.threads {
|
||||||
|
self.threads[idx].I18N(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *attachment) I18N(i *I18N) {
|
||||||
|
self._i18n = i
|
||||||
|
}
|
||||||
|
|
||||||
func (self *catalogModel) Navbar() string {
|
func (self *catalogModel) Navbar() string {
|
||||||
param := make(map[string]interface{})
|
param := make(map[string]interface{})
|
||||||
param["name"] = fmt.Sprintf("Catalog for %s", self.board)
|
param["name"] = fmt.Sprintf("Catalog for %s", self.board)
|
||||||
@ -38,7 +68,7 @@ func (self *catalogModel) Navbar() string {
|
|||||||
})
|
})
|
||||||
param["prefix"] = self.prefix
|
param["prefix"] = self.prefix
|
||||||
param["links"] = links
|
param["links"] = links
|
||||||
return template.renderTemplate("navbar.mustache", param)
|
return template.renderTemplate("navbar.mustache", param, self._i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *catalogModel) MarshalJSON() (b []byte, err error) {
|
func (self *catalogModel) MarshalJSON() (b []byte, err error) {
|
||||||
@ -78,6 +108,7 @@ func (self *catalogItemModel) ReplyCount() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type boardModel struct {
|
type boardModel struct {
|
||||||
|
_i18n *I18N
|
||||||
allowFiles bool
|
allowFiles bool
|
||||||
frontend string
|
frontend string
|
||||||
prefix string
|
prefix string
|
||||||
@ -131,7 +162,7 @@ func (self *boardModel) Navbar() string {
|
|||||||
param["frontend"] = self.frontend
|
param["frontend"] = self.frontend
|
||||||
param["prefix"] = self.prefix
|
param["prefix"] = self.prefix
|
||||||
param["links"] = self.PageList()
|
param["links"] = self.PageList()
|
||||||
return template.renderTemplate("navbar.mustache", param)
|
return template.renderTemplate("navbar.mustache", param, self._i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *boardModel) Board() string {
|
func (self *boardModel) Board() string {
|
||||||
@ -207,6 +238,7 @@ func (self *boardModel) Update(db Database) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type post struct {
|
type post struct {
|
||||||
|
_i18n *I18N
|
||||||
truncated bool
|
truncated bool
|
||||||
prefix string
|
prefix string
|
||||||
board string
|
board string
|
||||||
@ -286,6 +318,7 @@ func (self *post) JSON() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type attachment struct {
|
type attachment struct {
|
||||||
|
_i18n *I18N
|
||||||
prefix string
|
prefix string
|
||||||
Path string
|
Path string
|
||||||
Name string
|
Name string
|
||||||
@ -405,7 +438,11 @@ func (self *post) OP() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *post) Date() string {
|
func (self *post) Date() string {
|
||||||
return time.Unix(self.Posted, 0).Format(i18nProvider.Format("full_date_format"))
|
i18n := self._i18n
|
||||||
|
if i18n == nil {
|
||||||
|
i18n = I18nProvider
|
||||||
|
}
|
||||||
|
return time.Unix(self.Posted, 0).Format(i18n.Format("full_date_format"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *post) DateRFC() string {
|
func (self *post) DateRFC() string {
|
||||||
@ -479,7 +516,7 @@ func (self *post) SetIndex(idx int) {
|
|||||||
func (self *post) RenderPost() string {
|
func (self *post) RenderPost() string {
|
||||||
param := make(map[string]interface{})
|
param := make(map[string]interface{})
|
||||||
param["post"] = self
|
param["post"] = self
|
||||||
return template.renderTemplate("post.mustache", param)
|
return template.renderTemplate("post.mustache", param, self._i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *post) RenderTruncatedPost() string {
|
func (self *post) RenderTruncatedPost() string {
|
||||||
@ -505,6 +542,7 @@ func (self *post) Truncate() PostModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &post{
|
return &post{
|
||||||
|
_i18n: self._i18n,
|
||||||
truncated: true,
|
truncated: true,
|
||||||
prefix: self.prefix,
|
prefix: self.prefix,
|
||||||
board: self.board,
|
board: self.board,
|
||||||
@ -541,6 +579,7 @@ func (self *post) RenderBody() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type thread struct {
|
type thread struct {
|
||||||
|
_i18n *I18N
|
||||||
allowFiles bool
|
allowFiles bool
|
||||||
prefix string
|
prefix string
|
||||||
links []LinkModel
|
links []LinkModel
|
||||||
@ -583,7 +622,7 @@ func (self *thread) Navbar() string {
|
|||||||
param["frontend"] = self.Board()
|
param["frontend"] = self.Board()
|
||||||
param["links"] = self.links
|
param["links"] = self.links
|
||||||
param["prefix"] = self.prefix
|
param["prefix"] = self.prefix
|
||||||
return template.renderTemplate("navbar.mustache", param)
|
return template.renderTemplate("navbar.mustache", param, self._i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *thread) Board() string {
|
func (self *thread) Board() string {
|
||||||
@ -658,6 +697,7 @@ func (self *thread) Truncate() ThreadModel {
|
|||||||
trunc := 5
|
trunc := 5
|
||||||
if len(self.Posts) > trunc {
|
if len(self.Posts) > trunc {
|
||||||
t := &thread{
|
t := &thread{
|
||||||
|
_i18n: self._i18n,
|
||||||
allowFiles: self.allowFiles,
|
allowFiles: self.allowFiles,
|
||||||
links: self.links,
|
links: self.links,
|
||||||
Posts: append([]PostModel{self.Posts[0]}, self.Posts[len(self.Posts)-trunc:]...),
|
Posts: append([]PostModel{self.Posts[0]}, self.Posts[len(self.Posts)-trunc:]...),
|
||||||
|
@ -3,10 +3,12 @@ package srnd
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NullCache struct {
|
type NullCache struct {
|
||||||
@ -19,9 +21,36 @@ type nullHandler struct {
|
|||||||
requireCaptcha bool
|
requireCaptcha bool
|
||||||
name string
|
name string
|
||||||
prefix string
|
prefix string
|
||||||
|
translations string
|
||||||
|
i18n map[string]*I18N
|
||||||
|
access sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *nullHandler) GetI18N(r *http.Request) *I18N {
|
||||||
|
lang := r.URL.Query().Get("lang")
|
||||||
|
if lang == "" {
|
||||||
|
lang = I18nProvider.name
|
||||||
|
}
|
||||||
|
self.access.Lock()
|
||||||
|
i, ok := self.i18n[lang]
|
||||||
|
if !ok {
|
||||||
|
var err error
|
||||||
|
i, err = NewI18n(lang, self.translations)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
if i != nil {
|
||||||
|
self.i18n[lang] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.access.Unlock()
|
||||||
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
i18n := self.GetI18N(r)
|
||||||
|
|
||||||
path := r.URL.Path
|
path := r.URL.Path
|
||||||
_, file := filepath.Split(path)
|
_, file := filepath.Split(path)
|
||||||
|
|
||||||
@ -38,7 +67,7 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
|
|
||||||
template.genThread(self.attachments, self.requireCaptcha, msg, self.prefix, self.name, w, self.database, isjson)
|
template.genThread(self.attachments, self.requireCaptcha, msg, self.prefix, self.name, w, self.database, isjson, i18n)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
goto notfound
|
goto notfound
|
||||||
@ -46,7 +75,7 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
if strings.Trim(path, "/") == "overboard" {
|
if strings.Trim(path, "/") == "overboard" {
|
||||||
// generate ukko aka overboard
|
// generate ukko aka overboard
|
||||||
template.genUkko(self.prefix, self.name, w, self.database, isjson)
|
template.genUkko(self.prefix, self.name, w, self.database, isjson, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +105,7 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
if page >= int(pages) {
|
if page >= int(pages) {
|
||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
template.genBoardPage(self.attachments, self.requireCaptcha, self.prefix, self.name, group, page, w, self.database, isjson)
|
template.genBoardPage(self.attachments, self.requireCaptcha, self.prefix, self.name, group, page, w, self.database, isjson, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,12 +119,12 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template.genUkkoPaginated(self.prefix, self.name, w, self.database, page, isjson)
|
template.genUkkoPaginated(self.prefix, self.name, w, self.database, page, isjson, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(file) == 0 || file == "index.html" {
|
if len(file) == 0 || file == "index.html" {
|
||||||
template.genFrontPage(10, self.prefix, self.name, w, ioutil.Discard, self.database)
|
template.genFrontPage(10, self.prefix, self.name, w, ioutil.Discard, self.database, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,11 +133,11 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(file, "history.html") {
|
if strings.HasPrefix(file, "history.html") {
|
||||||
template.genGraphs(self.prefix, w, self.database)
|
template.genGraphs(self.prefix, w, self.database, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(file, "boards.html") {
|
if strings.HasPrefix(file, "boards.html") {
|
||||||
template.genBoardList(self.prefix, self.name, w, self.database)
|
template.genBoardList(self.prefix, self.name, w, self.database, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,17 +148,17 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(file, "ukko.html") {
|
if strings.HasPrefix(file, "ukko.html") {
|
||||||
template.genUkko(self.prefix, self.name, w, self.database, false)
|
template.genUkko(self.prefix, self.name, w, self.database, false, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(file, "ukko.json") {
|
if strings.HasPrefix(file, "ukko.json") {
|
||||||
template.genUkko(self.prefix, self.name, w, self.database, true)
|
template.genUkko(self.prefix, self.name, w, self.database, true, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(file, "ukko-") {
|
if strings.HasPrefix(file, "ukko-") {
|
||||||
page := getUkkoPage(file)
|
page := getUkkoPage(file)
|
||||||
template.genUkkoPaginated(self.prefix, self.name, w, self.database, page, isjson)
|
template.genUkkoPaginated(self.prefix, self.name, w, self.database, page, isjson, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(file, "thread-") {
|
if strings.HasPrefix(file, "thread-") {
|
||||||
@ -147,7 +176,7 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
|
|
||||||
template.genThread(self.attachments, self.requireCaptcha, msg, self.prefix, self.name, w, self.database, isjson)
|
template.genThread(self.attachments, self.requireCaptcha, msg, self.prefix, self.name, w, self.database, isjson, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(file, "catalog-") {
|
if strings.HasPrefix(file, "catalog-") {
|
||||||
@ -159,7 +188,7 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
if !hasgroup {
|
if !hasgroup {
|
||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
template.genCatalog(self.prefix, self.name, group, w, self.database)
|
template.genCatalog(self.prefix, self.name, group, w, self.database, i18n)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
group, page := getGroupAndPage(file)
|
group, page := getGroupAndPage(file)
|
||||||
@ -174,12 +203,12 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
if page >= int(pages) {
|
if page >= int(pages) {
|
||||||
goto notfound
|
goto notfound
|
||||||
}
|
}
|
||||||
template.genBoardPage(self.attachments, self.requireCaptcha, self.prefix, self.name, group, page, w, self.database, isjson)
|
template.genBoardPage(self.attachments, self.requireCaptcha, self.prefix, self.name, group, page, w, self.database, isjson, i18n)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
notfound:
|
notfound:
|
||||||
template.renderNotFound(w, r, self.prefix, self.name)
|
template.renderNotFound(w, r, self.prefix, self.name, i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NullCache) DeleteBoardMarkup(group string) {
|
func (self *NullCache) DeleteBoardMarkup(group string) {
|
||||||
@ -214,7 +243,7 @@ func (self *NullCache) Start() {
|
|||||||
func (self *NullCache) Regen(msg ArticleEntry) {
|
func (self *NullCache) Regen(msg ArticleEntry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *NullCache) GetHandler() http.Handler {
|
func (self *NullCache) GetHandler() CacheHandler {
|
||||||
return self.handler
|
return self.handler
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +251,7 @@ func (self *NullCache) Close() {
|
|||||||
//nothig to do
|
//nothig to do
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNullCache(prefix, webroot, name string, attachments bool, db Database, store ArticleStore) CacheInterface {
|
func NewNullCache(prefix, webroot, name, translations string, attachments bool, db Database, store ArticleStore) CacheInterface {
|
||||||
cache := new(NullCache)
|
cache := new(NullCache)
|
||||||
cache.handler = &nullHandler{
|
cache.handler = &nullHandler{
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
@ -230,6 +259,8 @@ func NewNullCache(prefix, webroot, name string, attachments bool, db Database, s
|
|||||||
attachments: attachments,
|
attachments: attachments,
|
||||||
requireCaptcha: true,
|
requireCaptcha: true,
|
||||||
database: db,
|
database: db,
|
||||||
|
i18n: make(map[string]*I18N),
|
||||||
|
translations: translations,
|
||||||
}
|
}
|
||||||
|
|
||||||
return cache
|
return cache
|
||||||
|
@ -173,9 +173,12 @@ func (self *templateEngine) getTemplate(name string) (t string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// render a template, self explanitory
|
// render a template, self explanitory
|
||||||
func (self *templateEngine) renderTemplate(name string, obj map[string]interface{}) string {
|
func (self *templateEngine) renderTemplate(name string, obj map[string]interface{}, i18n *I18N) string {
|
||||||
t := self.getTemplate(name)
|
t := self.getTemplate(name)
|
||||||
obj["i18n"] = i18nProvider
|
if i18n == nil {
|
||||||
|
i18n = I18nProvider
|
||||||
|
}
|
||||||
|
obj["i18n"] = i18n
|
||||||
s, err := mustache.Render(t, obj)
|
s, err := mustache.Render(t, obj)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return s
|
return s
|
||||||
@ -185,8 +188,8 @@ func (self *templateEngine) renderTemplate(name string, obj map[string]interface
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write a template to an io.Writer
|
// write a template to an io.Writer
|
||||||
func (self *templateEngine) writeTemplate(name string, obj map[string]interface{}, wr io.Writer) (err error) {
|
func (self *templateEngine) writeTemplate(name string, obj map[string]interface{}, wr io.Writer, i18n *I18N) (err error) {
|
||||||
str := self.renderTemplate(name, obj)
|
str := self.renderTemplate(name, obj, i18n)
|
||||||
var r io.Reader
|
var r io.Reader
|
||||||
r = bytes.NewBufferString(str)
|
r = bytes.NewBufferString(str)
|
||||||
if self.Minimize {
|
if self.Minimize {
|
||||||
@ -222,47 +225,49 @@ func (self *templateEngine) obtainBoard(prefix, frontend, group string, db Datab
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templateEngine) genCatalog(prefix, frontend, group string, wr io.Writer, db Database) {
|
func (self *templateEngine) genCatalog(prefix, frontend, group string, wr io.Writer, db Database, i18n *I18N) {
|
||||||
board := self.obtainBoard(prefix, frontend, group, db)
|
board := self.obtainBoard(prefix, frontend, group, db)
|
||||||
catalog := new(catalogModel)
|
catalog := new(catalogModel)
|
||||||
catalog.prefix = prefix
|
catalog.prefix = prefix
|
||||||
catalog.frontend = frontend
|
catalog.frontend = frontend
|
||||||
catalog.board = group
|
catalog.board = group
|
||||||
|
catalog.I18N(i18n)
|
||||||
for page, bm := range board {
|
for page, bm := range board {
|
||||||
for _, th := range bm.Threads() {
|
for _, th := range bm.Threads() {
|
||||||
th.Update(db)
|
th.Update(db)
|
||||||
catalog.threads = append(catalog.threads, &catalogItemModel{op: th.OP(), page: page, replycount: len(th.Replies())})
|
catalog.threads = append(catalog.threads, &catalogItemModel{op: th.OP(), page: page, replycount: len(th.Replies())})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.writeTemplate("catalog.mustache", map[string]interface{}{"board": catalog}, wr)
|
self.writeTemplate("catalog.mustache", map[string]interface{}{"board": catalog}, wr, i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate a board page
|
// generate a board page
|
||||||
func (self *templateEngine) genBoardPage(allowFiles, requireCaptcha bool, prefix, frontend, newsgroup string, page int, wr io.Writer, db Database, json bool) {
|
func (self *templateEngine) genBoardPage(allowFiles, requireCaptcha bool, prefix, frontend, newsgroup string, page int, wr io.Writer, db Database, json bool, i18n *I18N) {
|
||||||
// get the board page model
|
// get the board page model
|
||||||
perpage, _ := db.GetThreadsPerPage(newsgroup)
|
perpage, _ := db.GetThreadsPerPage(newsgroup)
|
||||||
boardPage := db.GetGroupForPage(prefix, frontend, newsgroup, page, int(perpage))
|
boardPage := db.GetGroupForPage(prefix, frontend, newsgroup, page, int(perpage))
|
||||||
boardPage.Update(db)
|
boardPage.Update(db)
|
||||||
|
boardPage.I18N(i18n)
|
||||||
// render it
|
// render it
|
||||||
if json {
|
if json {
|
||||||
self.renderJSON(wr, boardPage)
|
self.renderJSON(wr, boardPage)
|
||||||
} else {
|
} else {
|
||||||
form := renderPostForm(prefix, newsgroup, "", allowFiles, requireCaptcha)
|
form := renderPostForm(prefix, newsgroup, "", allowFiles, requireCaptcha, i18n)
|
||||||
self.writeTemplate("board.mustache", map[string]interface{}{"board": boardPage, "page": page, "form": form}, wr)
|
self.writeTemplate("board.mustache", map[string]interface{}{"board": boardPage, "page": page, "form": form}, wr, i18n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templateEngine) genUkko(prefix, frontend string, wr io.Writer, database Database, json bool) {
|
func (self *templateEngine) genUkko(prefix, frontend string, wr io.Writer, database Database, json bool, i18n *I18N) {
|
||||||
self.genUkkoPaginated(prefix, frontend, wr, database, 0, json)
|
self.genUkkoPaginated(prefix, frontend, wr, database, 0, json, i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templateEngine) genUkkoPaginated(prefix, frontend string, wr io.Writer, database Database, page int, json bool) {
|
func (self *templateEngine) genUkkoPaginated(prefix, frontend string, wr io.Writer, database Database, page int, json bool, i18n *I18N) {
|
||||||
var threads []ThreadModel
|
var threads []ThreadModel
|
||||||
for _, article := range database.GetLastBumpedThreadsPaginated("", 10, page*10) {
|
for _, article := range database.GetLastBumpedThreadsPaginated("", 10, page*10) {
|
||||||
root := article[0]
|
root := article[0]
|
||||||
thread, err := database.GetThreadModel(prefix, root)
|
thread, err := database.GetThreadModel(prefix, root)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
thread.I18N(i18n)
|
||||||
threads = append(threads, thread)
|
threads = append(threads, thread)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,13 +287,13 @@ func (self *templateEngine) genUkkoPaginated(prefix, frontend string, wr io.Writ
|
|||||||
navbar["frontend"] = frontend
|
navbar["frontend"] = frontend
|
||||||
navbar["prefix"] = prefix
|
navbar["prefix"] = prefix
|
||||||
// inject navbar
|
// inject navbar
|
||||||
obj["navbar"] = self.renderTemplate("navbar.mustache", navbar)
|
obj["navbar"] = self.renderTemplate("navbar.mustache", navbar, i18n)
|
||||||
// render
|
// render
|
||||||
self.writeTemplate("ukko.mustache", obj, wr)
|
self.writeTemplate("ukko.mustache", obj, wr, i18n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templateEngine) genThread(allowFiles, requireCaptcha bool, root ArticleEntry, prefix, frontend string, wr io.Writer, db Database, json bool) {
|
func (self *templateEngine) genThread(allowFiles, requireCaptcha bool, root ArticleEntry, prefix, frontend string, wr io.Writer, db Database, json bool, i18n *I18N) {
|
||||||
newsgroup := root.Newsgroup()
|
newsgroup := root.Newsgroup()
|
||||||
msgid := root.MessageID()
|
msgid := root.MessageID()
|
||||||
|
|
||||||
@ -303,8 +308,9 @@ func (self *templateEngine) genThread(allowFiles, requireCaptcha bool, root Arti
|
|||||||
if json {
|
if json {
|
||||||
self.renderJSON(wr, t)
|
self.renderJSON(wr, t)
|
||||||
} else {
|
} else {
|
||||||
form := renderPostForm(prefix, newsgroup, msgid, allowFiles, requireCaptcha)
|
t.I18N(i18n)
|
||||||
self.writeTemplate("thread.mustache", map[string]interface{}{"thread": t, "board": map[string]interface{}{"Name": newsgroup, "Frontend": frontend, "AllowFiles": allowFiles}, "form": form, "prefix": prefix}, wr)
|
form := renderPostForm(prefix, newsgroup, msgid, allowFiles, requireCaptcha, i18n)
|
||||||
|
self.writeTemplate("thread.mustache", map[string]interface{}{"thread": t, "board": map[string]interface{}{"Name": newsgroup, "Frontend": frontend, "AllowFiles": allowFiles}, "form": form, "prefix": prefix}, wr, i18n)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Println("templates: error getting thread for ", msgid, err.Error())
|
log.Println("templates: error getting thread for ", msgid, err.Error())
|
||||||
@ -368,18 +374,18 @@ func (self *templateEngine) changeTemplateDir(dirname string) {
|
|||||||
|
|
||||||
func (self *templateEngine) createNotFoundHandler(prefix, frontend string) (h http.Handler) {
|
func (self *templateEngine) createNotFoundHandler(prefix, frontend string) (h http.Handler) {
|
||||||
h = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
h = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
self.renderNotFound(w, r, prefix, frontend)
|
self.renderNotFound(w, r, prefix, frontend, nil)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// default renderer of 404 pages
|
// default renderer of 404 pages
|
||||||
func (self *templateEngine) renderNotFound(wr http.ResponseWriter, r *http.Request, prefix, frontend string) {
|
func (self *templateEngine) renderNotFound(wr http.ResponseWriter, r *http.Request, prefix, frontend string, i18n *I18N) {
|
||||||
wr.WriteHeader(404)
|
wr.WriteHeader(404)
|
||||||
opts := make(map[string]interface{})
|
opts := make(map[string]interface{})
|
||||||
opts["prefix"] = prefix
|
opts["prefix"] = prefix
|
||||||
opts["frontend"] = frontend
|
opts["frontend"] = frontend
|
||||||
self.writeTemplate("404.mustache", opts, wr)
|
self.writeTemplate("404.mustache", opts, wr, i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTemplateEngine(dir string) *templateEngine {
|
func newTemplateEngine(dir string) *templateEngine {
|
||||||
@ -399,17 +405,17 @@ func (self *templateEngine) findLink(prefix, hash string) (url string) {
|
|||||||
|
|
||||||
var template = newTemplateEngine(defaultTemplateDir())
|
var template = newTemplateEngine(defaultTemplateDir())
|
||||||
|
|
||||||
func renderPostForm(prefix, board, op_msg_id string, files, captcha bool) string {
|
func renderPostForm(prefix, board, op_msg_id string, files, captcha bool, i18n *I18N) string {
|
||||||
url := prefix + "post/" + board
|
url := prefix + "post/" + board
|
||||||
button := "New Thread"
|
button := "New Thread"
|
||||||
if op_msg_id != "" {
|
if op_msg_id != "" {
|
||||||
button = "Reply"
|
button = "Reply"
|
||||||
}
|
}
|
||||||
return template.renderTemplate("postform.mustache", map[string]interface{}{"post_url": url, "reference": op_msg_id, "button": button, "files": files, "prefix": prefix, "DisableCaptcha": !captcha})
|
return template.renderTemplate("postform.mustache", map[string]interface{}{"post_url": url, "reference": op_msg_id, "button": button, "files": files, "prefix": prefix, "DisableCaptcha": !captcha}, i18n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate misc graphs
|
// generate misc graphs
|
||||||
func (self *templateEngine) genGraphs(prefix string, wr io.Writer, db Database) {
|
func (self *templateEngine) genGraphs(prefix string, wr io.Writer, db Database, i18n *I18N) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// begin gen history.html
|
// begin gen history.html
|
||||||
@ -433,7 +439,7 @@ func (self *templateEngine) genGraphs(prefix string, wr io.Writer, db Database)
|
|||||||
}
|
}
|
||||||
sort.Sort(all_posts)
|
sort.Sort(all_posts)
|
||||||
|
|
||||||
_, err := io.WriteString(wr, self.renderTemplate("graph_history.mustache", map[string]interface{}{"history": all_posts}))
|
_, err := io.WriteString(wr, self.renderTemplate("graph_history.mustache", map[string]interface{}{"history": all_posts}, i18n))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error writing history graph", err)
|
log.Println("error writing history graph", err)
|
||||||
}
|
}
|
||||||
@ -444,7 +450,7 @@ func (self *templateEngine) genGraphs(prefix string, wr io.Writer, db Database)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templateEngine) genBoardList(prefix, name string, wr io.Writer, db Database) {
|
func (self *templateEngine) genBoardList(prefix, name string, wr io.Writer, db Database, i18n *I18N) {
|
||||||
// the graph for the front page
|
// the graph for the front page
|
||||||
var frontpage_graph boardPageRows
|
var frontpage_graph boardPageRows
|
||||||
|
|
||||||
@ -470,22 +476,26 @@ func (self *templateEngine) genBoardList(prefix, name string, wr io.Writer, db D
|
|||||||
}
|
}
|
||||||
sort.Sort(frontpage_graph)
|
sort.Sort(frontpage_graph)
|
||||||
param["graph"] = frontpage_graph
|
param["graph"] = frontpage_graph
|
||||||
_, err := io.WriteString(wr, self.renderTemplate("boardlist.mustache", param))
|
_, err := io.WriteString(wr, self.renderTemplate("boardlist.mustache", param, i18n))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error writing board list page", err)
|
log.Println("error writing board list page", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate front page
|
// generate front page
|
||||||
func (self *templateEngine) genFrontPage(top_count int, prefix, frontend_name string, indexwr, boardswr io.Writer, db Database) {
|
func (self *templateEngine) genFrontPage(top_count int, prefix, frontend_name string, indexwr, boardswr io.Writer, db Database, i18n *I18N) {
|
||||||
|
|
||||||
models := db.GetLastPostedPostModels(prefix, 20)
|
models := db.GetLastPostedPostModels(prefix, 20)
|
||||||
|
|
||||||
|
for idx := range models {
|
||||||
|
models[idx].I18N(i18n)
|
||||||
|
}
|
||||||
|
|
||||||
wr := indexwr
|
wr := indexwr
|
||||||
|
|
||||||
param := make(map[string]interface{})
|
param := make(map[string]interface{})
|
||||||
|
|
||||||
param["overview"] = self.renderTemplate("overview.mustache", map[string]interface{}{"overview": overviewModel(models)})
|
param["overview"] = self.renderTemplate("overview.mustache", map[string]interface{}{"overview": overviewModel(models)}, i18n)
|
||||||
/*
|
/*
|
||||||
sort.Sort(posts_graph)
|
sort.Sort(posts_graph)
|
||||||
param["postsgraph"] = self.renderTemplate("posts_graph.mustache", map[string]interface{}{"graph": posts_graph})
|
param["postsgraph"] = self.renderTemplate("posts_graph.mustache", map[string]interface{}{"graph": posts_graph})
|
||||||
@ -500,9 +510,9 @@ func (self *templateEngine) genFrontPage(top_count int, prefix, frontend_name st
|
|||||||
param["totalposts"] = db.ArticleCount()
|
param["totalposts"] = db.ArticleCount()
|
||||||
param["prefix"] = prefix
|
param["prefix"] = prefix
|
||||||
// render and inject navbar
|
// render and inject navbar
|
||||||
param["navbar"] = self.renderTemplate("navbar.mustache", map[string]interface{}{"name": "Front Page", "frontend": frontend_name, "prefix": prefix})
|
param["navbar"] = self.renderTemplate("navbar.mustache", map[string]interface{}{"name": "Front Page", "frontend": frontend_name, "prefix": prefix}, i18n)
|
||||||
|
|
||||||
_, err := io.WriteString(wr, self.renderTemplate("frontpage.mustache", param))
|
_, err := io.WriteString(wr, self.renderTemplate("frontpage.mustache", param, i18n))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error writing front page", err)
|
log.Println("error writing front page", err)
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ func BenchmarkRenderBoardPage(b *testing.B) {
|
|||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
wr, err := os.Create("boardpage.html")
|
wr, err := os.Create("boardpage.html")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
template.genBoardPage(true, true, "prefix", "test", "overchan.random", 0, wr, db, false)
|
template.genBoardPage(true, true, "prefix", "test", "overchan.random", 0, wr, db, false, nil)
|
||||||
} else {
|
} else {
|
||||||
log.Println("did not write", "boardpage.html", err)
|
log.Println("did not write", "boardpage.html", err)
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@ func BenchmarkRenderThread(b *testing.B) {
|
|||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
wr, err := os.Create("thread.html")
|
wr, err := os.Create("thread.html")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
template.genThread(true, true, ArticleEntry{"<c49be1451427261@nntp.nsfl.tk>", "overchan.random"}, "prefix", "frontend", wr, db, false)
|
template.genThread(true, true, ArticleEntry{"<c49be1451427261@nntp.nsfl.tk>", "overchan.random"}, "prefix", "frontend", wr, db, false, nil)
|
||||||
} else {
|
} else {
|
||||||
log.Println("did not write", "thread.html", err)
|
log.Println("did not write", "thread.html", err)
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ func (self *VarnishCache) Regen(msg ArticleEntry) {
|
|||||||
self.DeleteThreadMarkup(msg.MessageID())
|
self.DeleteThreadMarkup(msg.MessageID())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VarnishCache) GetHandler() http.Handler {
|
func (self *VarnishCache) GetHandler() CacheHandler {
|
||||||
return self.handler
|
return self.handler
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ func (self *VarnishCache) SetRequireCaptcha(required bool) {
|
|||||||
self.handler.requireCaptcha = required
|
self.handler.requireCaptcha = required
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVarnishCache(varnish_url, bind_addr, prefix, webroot, name string, attachments bool, db Database, store ArticleStore) CacheInterface {
|
func NewVarnishCache(varnish_url, bind_addr, prefix, webroot, name, translations string, attachments bool, db Database, store ArticleStore) CacheInterface {
|
||||||
cache := new(VarnishCache)
|
cache := new(VarnishCache)
|
||||||
cache.threadsRegenChan = make(chan ArticleEntry)
|
cache.threadsRegenChan = make(chan ArticleEntry)
|
||||||
local_addr, err := net.ResolveTCPAddr("tcp", bind_addr)
|
local_addr, err := net.ResolveTCPAddr("tcp", bind_addr)
|
||||||
@ -150,6 +150,8 @@ func NewVarnishCache(varnish_url, bind_addr, prefix, webroot, name string, attac
|
|||||||
attachments: attachments,
|
attachments: attachments,
|
||||||
database: db,
|
database: db,
|
||||||
requireCaptcha: true,
|
requireCaptcha: true,
|
||||||
|
i18n: make(map[string]*I18N),
|
||||||
|
translations: translations,
|
||||||
}
|
}
|
||||||
cache.varnish_url = varnish_url
|
cache.varnish_url = varnish_url
|
||||||
return cache
|
return cache
|
||||||
|
Reference in New Issue
Block a user