docs: layout

pull/341/head
Demian 4 years ago
parent 684692e890
commit cde97c26cf

@ -8,18 +8,23 @@ import (
tele "gopkg.in/tucnak/telebot.v3"
)
// Config represents typed map interface related to the "config" section in layout.
type Config struct {
v map[string]interface{}
}
// Unmarshal parses the config into the out value. It's useful when you want to
// describe and to pre-define the fields in your custom configuration struct.
func (c *Config) Unmarshal(v interface{}) error {
data, err := yaml.Marshal(c.v)
if err != nil {
return err
}
return yaml.Unmarshal(data, c.v)
return yaml.Unmarshal(data, v)
}
// Get returns child map field wrapped into Config.
// If the field isn't map, returns nil.
func (c *Config) Get(k string) *Config {
v, ok := c.v[k].(map[string]interface{})
if !ok {
@ -28,30 +33,39 @@ func (c *Config) Get(k string) *Config {
return &Config{v: v}
}
// String returns a field casted to the string.
func (c *Config) String(k string) string {
return cast.ToString(c.v[k])
}
// Int returns a field casted to the int.
func (c *Config) Int(k string) int {
return cast.ToInt(c.v[k])
}
// Int64 returns a field casted to the int64.
func (c *Config) Int64(k string) int64 {
return cast.ToInt64(c.v[k])
}
// Float returns a field casted to the float64.
func (c *Config) Float(k string) float64 {
return cast.ToFloat64(c.v[k])
}
// Float returns a field casted to the bool.
func (c *Config) Bool(k string) bool {
return cast.ToBool(c.v[k])
}
// Duration returns a field casted to the time.Duration.
// Accepts number-represented duration or a string in 0nsuµmh format.
func (c *Config) Duration(k string) time.Duration {
return cast.ToDuration(c.v[k])
}
// ChatID returns a field casted to the ChatID.
// The value must be an integer.
func (c *Config) ChatID(k string) tele.ChatID {
return tele.ChatID(c.Int64(k))
}

@ -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
}

@ -4,8 +4,19 @@ import (
tele "gopkg.in/tucnak/telebot.v3"
)
// LocaleFunc is the function used to fetch the locale of the recipient.
// Returned locale will be remembered and linked to the corresponding context.
type LocaleFunc func(tele.Recipient) string
// Middleware builds a global middleware to make internationalisation work.
//
// Usage:
//
// b.Use(lt.Middleware("en", func(r tele.Recipient) string {
// loc, _ := db.UserLocale(r.Recipient())
// return loc
// }))
//
func (lt *Layout) Middleware(defaultLocale string, localeFunc ...LocaleFunc) tele.MiddlewareFunc {
var f LocaleFunc
if len(localeFunc) > 0 {

Loading…
Cancel
Save