|
|
|
@ -12,6 +12,8 @@ import (
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type (
|
|
|
|
|
// Layout provides an interface to interact with the layout,
|
|
|
|
|
// parsed from the config file and locales.
|
|
|
|
|
Layout struct {
|
|
|
|
|
pref *tele.Settings
|
|
|
|
|
mu sync.RWMutex // protects ctxs
|
|
|
|
@ -25,8 +27,10 @@ type (
|
|
|
|
|
*Config
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Button is a shortcut for tele.Btn.
|
|
|
|
|
Button = tele.Btn
|
|
|
|
|
|
|
|
|
|
// Markup represents layout-specific markup to be parsed.
|
|
|
|
|
Markup struct {
|
|
|
|
|
inline *bool
|
|
|
|
|
keyboard *template.Template
|
|
|
|
@ -38,6 +42,7 @@ type (
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// New reads and parses the given layout file.
|
|
|
|
|
func New(path string) (*Layout, error) {
|
|
|
|
|
data, err := ioutil.ReadFile(path)
|
|
|
|
|
if err != nil {
|
|
|
|
@ -63,16 +68,37 @@ var funcs = template.FuncMap{
|
|
|
|
|
"text": func(string) string { return "" },
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddFunc adds the given function to the template FuncMap.
|
|
|
|
|
// Note: to make it come into effect, always add functions before New().
|
|
|
|
|
func AddFunc(key string, fn interface{}) {
|
|
|
|
|
funcs[key] = fn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AddFuncs extends the template FuncMap with the given one.
|
|
|
|
|
// Note: to make it come into effect, always add functions before New().
|
|
|
|
|
func AddFuncs(fm template.FuncMap) {
|
|
|
|
|
for k, v := range fm {
|
|
|
|
|
funcs[k] = v
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Settings returns built telebot Settings required for bot initialising.
|
|
|
|
|
//
|
|
|
|
|
// settings:
|
|
|
|
|
// url: (custom url if needed)
|
|
|
|
|
// token: (not recommended)
|
|
|
|
|
// updates: (chan capacity)
|
|
|
|
|
// locales_dir: (optional)
|
|
|
|
|
// token_env: (token env var name, example: TOKEN)
|
|
|
|
|
// parse_mode: (default parse mode)
|
|
|
|
|
// long_poller: (long poller settings)
|
|
|
|
|
// webhook: (or webhook settings)
|
|
|
|
|
//
|
|
|
|
|
// Usage:
|
|
|
|
|
// lt, err := layout.New("bot.yml")
|
|
|
|
|
// b, err := tele.NewBot(lt.Settings())
|
|
|
|
|
// // That's all!
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Settings() tele.Settings {
|
|
|
|
|
if lt.pref == nil {
|
|
|
|
|
panic("telebot/layout: settings is empty")
|
|
|
|
@ -80,6 +106,32 @@ func (lt *Layout) Settings() tele.Settings {
|
|
|
|
|
return *lt.pref
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Locale returns the context locale.
|
|
|
|
|
func (lt *Layout) Locale(c tele.Context) (string, bool) {
|
|
|
|
|
lt.mu.RLock()
|
|
|
|
|
defer lt.mu.RUnlock()
|
|
|
|
|
locale, ok := lt.ctxs[c]
|
|
|
|
|
return locale, ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetLocale allows you to change a locale for the passed context.
|
|
|
|
|
func (lt *Layout) SetLocale(c tele.Context, locale string) {
|
|
|
|
|
lt.mu.Lock()
|
|
|
|
|
lt.ctxs[c] = locale
|
|
|
|
|
lt.mu.Unlock()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Text returns a text, which locale is dependent on the context.
|
|
|
|
|
// The given optional argument will be passed to the template engine.
|
|
|
|
|
//
|
|
|
|
|
// Example of en.yml:
|
|
|
|
|
// start: Hi, {{.FirstName}}!
|
|
|
|
|
//
|
|
|
|
|
// Usage:
|
|
|
|
|
// func OnStart(c tele.Context) error {
|
|
|
|
|
// return c.Send(lt.Text(c, "start", c.Sender()))
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Text(c tele.Context, k string, args ...interface{}) string {
|
|
|
|
|
locale, ok := lt.Locale(c)
|
|
|
|
|
if !ok {
|
|
|
|
@ -89,6 +141,8 @@ func (lt *Layout) Text(c tele.Context, k string, args ...interface{}) string {
|
|
|
|
|
return lt.TextLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TextLocale returns a localised text processed with standard template engine.
|
|
|
|
|
// See Text for more details.
|
|
|
|
|
func (lt *Layout) TextLocale(locale, k string, args ...interface{}) string {
|
|
|
|
|
tmpl, ok := lt.locales[locale]
|
|
|
|
|
if !ok {
|
|
|
|
@ -108,6 +162,14 @@ func (lt *Layout) TextLocale(locale, k string, args ...interface{}) string {
|
|
|
|
|
return buf.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Callback returns casted to CallbackEndpoint button, which mostly
|
|
|
|
|
// useful for handlers registering.
|
|
|
|
|
//
|
|
|
|
|
// Example:
|
|
|
|
|
//
|
|
|
|
|
// // Handling settings button
|
|
|
|
|
// b.Handle(lt.Callback("settings"), OnSettings)
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Callback(k string) tele.CallbackEndpoint {
|
|
|
|
|
btn, ok := lt.buttons[k]
|
|
|
|
|
if !ok {
|
|
|
|
@ -116,6 +178,31 @@ func (lt *Layout) Callback(k string) tele.CallbackEndpoint {
|
|
|
|
|
return &btn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Button returns a button, which locale is dependent on the context.
|
|
|
|
|
// The given optional argument will be passed to the template engine.
|
|
|
|
|
//
|
|
|
|
|
// buttons:
|
|
|
|
|
// item:
|
|
|
|
|
// unique: item
|
|
|
|
|
// callback_data: {{.ID}}
|
|
|
|
|
// text: Item #{{.Number}}
|
|
|
|
|
//
|
|
|
|
|
// Usage:
|
|
|
|
|
// btns := make([]tele.Btn, len(items))
|
|
|
|
|
// for i, item := range items {
|
|
|
|
|
// btns[i] = lt.Button(c, "item", struct {
|
|
|
|
|
// Number int
|
|
|
|
|
// Item Item
|
|
|
|
|
// }{
|
|
|
|
|
// Number: i,
|
|
|
|
|
// Item: item,
|
|
|
|
|
// })
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// m := b.NewMarkup()
|
|
|
|
|
// m.Inline(m.Row(btns...))
|
|
|
|
|
// // Your generated markup is ready.
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Button(c tele.Context, k string, args ...interface{}) *tele.Btn {
|
|
|
|
|
locale, ok := lt.Locale(c)
|
|
|
|
|
if !ok {
|
|
|
|
@ -125,6 +212,8 @@ func (lt *Layout) Button(c tele.Context, k string, args ...interface{}) *tele.Bt
|
|
|
|
|
return lt.ButtonLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ButtonLocale returns a localised button processed with standard template engine.
|
|
|
|
|
// See Button for more details.
|
|
|
|
|
func (lt *Layout) ButtonLocale(locale, k string, args ...interface{}) *tele.Btn {
|
|
|
|
|
btn, ok := lt.buttons[k]
|
|
|
|
|
if !ok {
|
|
|
|
@ -162,6 +251,22 @@ func (lt *Layout) ButtonLocale(locale, k string, args ...interface{}) *tele.Btn
|
|
|
|
|
return &btn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Markup returns a markup, which locale is dependent on the context.
|
|
|
|
|
// The given optional argument will be passed to the template engine.
|
|
|
|
|
//
|
|
|
|
|
// buttons:
|
|
|
|
|
// settings: 'Settings'
|
|
|
|
|
// markups:
|
|
|
|
|
// menu:
|
|
|
|
|
// - [settings]
|
|
|
|
|
//
|
|
|
|
|
// Usage:
|
|
|
|
|
// func OnStart(c tele.Context) error {
|
|
|
|
|
// return c.Send(
|
|
|
|
|
// lt.Text(c, "start"),
|
|
|
|
|
// lt.Markup(c, "menu"))
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Markup(c tele.Context, k string, args ...interface{}) *tele.ReplyMarkup {
|
|
|
|
|
locale, ok := lt.Locale(c)
|
|
|
|
|
if !ok {
|
|
|
|
@ -171,6 +276,8 @@ func (lt *Layout) Markup(c tele.Context, k string, args ...interface{}) *tele.Re
|
|
|
|
|
return lt.MarkupLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarkupLocale returns a localised markup processed with standard template engine.
|
|
|
|
|
// See Markup for more details.
|
|
|
|
|
func (lt *Layout) MarkupLocale(locale, k string, args ...interface{}) *tele.ReplyMarkup {
|
|
|
|
|
markup, ok := lt.markups[k]
|
|
|
|
|
if !ok {
|
|
|
|
@ -217,16 +324,3 @@ func (lt *Layout) template(tmpl *template.Template, locale string) *template.Tem
|
|
|
|
|
|
|
|
|
|
return tmpl.Funcs(funcs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (lt *Layout) SetLocale(c tele.Context, locale string) {
|
|
|
|
|
lt.mu.Lock()
|
|
|
|
|
lt.ctxs[c] = locale
|
|
|
|
|
lt.mu.Unlock()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (lt *Layout) Locale(c tele.Context) (string, bool) {
|
|
|
|
|
lt.mu.RLock()
|
|
|
|
|
defer lt.mu.RUnlock()
|
|
|
|
|
locale, ok := lt.ctxs[c]
|
|
|
|
|
return locale, ok
|
|
|
|
|
}
|
|
|
|
|