github.com/jasonish/buffalo@v0.8.2-0.20170413145823-bacbdd415f1b/middleware/i18n/i18n.go (about)

     1  package i18n
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/gobuffalo/buffalo"
     7  	"github.com/gobuffalo/packr"
     8  	"github.com/nicksnyder/go-i18n/i18n"
     9  	"github.com/nicksnyder/go-i18n/i18n/language"
    10  	"github.com/nicksnyder/go-i18n/i18n/translation"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  // LanguageFinder can be implemented for custom finding of search
    15  // languages. This can be useful if you want to load a user's langugage
    16  // from something like a database. See Middleware() for more information
    17  // on how the default implementation searches for languages.
    18  type LanguageFinder func(*Translator, buffalo.Context) []string
    19  
    20  // Translator for handling all your i18n needs.
    21  type Translator struct {
    22  	// Box - where are the files?
    23  	Box packr.Box
    24  	// DefaultLanguage - default is "en-US"
    25  	DefaultLanguage string
    26  	// CookieName - name of the cookie to find the desired language.
    27  	// default is "lang"
    28  	CookieName string
    29  	// HelperName - name of the view helper. default is "t"
    30  	HelperName     string
    31  	LanguageFinder LanguageFinder
    32  }
    33  
    34  // Load translations from the t.Box.
    35  func (t *Translator) Load() error {
    36  	return t.Box.Walk(func(path string, f packr.File) error {
    37  		b, err := t.Box.MustBytes(path)
    38  		if err != nil {
    39  			log.Fatal(err)
    40  			return errors.WithStack(err)
    41  		}
    42  		return i18n.ParseTranslationFileBytes(path, b)
    43  	})
    44  }
    45  
    46  // AddTranslation directly, without using a file. This is useful if you wish to load translations
    47  // from a database, instead of disk.
    48  func (t *Translator) AddTranslation(lang *language.Language, translations ...translation.Translation) {
    49  	i18n.AddTranslation(lang, translations...)
    50  }
    51  
    52  // New Translator. Requires a packr.Box that points to the location
    53  // of the translation files, as well as a default language. This will
    54  // also call t.Load() and load the translations from disk.
    55  func New(box packr.Box, language string) (*Translator, error) {
    56  	t := &Translator{
    57  		Box:             box,
    58  		DefaultLanguage: language,
    59  		CookieName:      "lang",
    60  		HelperName:      "t",
    61  		LanguageFinder:  defaultLanguageFinder,
    62  	}
    63  	return t, t.Load()
    64  }
    65  
    66  // Middleware for loading the translations for the language(s)
    67  // selected. By default languages are loaded in the following order:
    68  //
    69  // Cookie - "lang"
    70  // Header - "Accept-Language"
    71  // Default - "en-US"
    72  //
    73  // These values can be changed on the Translator itself. In development
    74  // model the translation files will be reloaded on each request.
    75  func (t *Translator) Middleware() buffalo.MiddlewareFunc {
    76  	return func(next buffalo.Handler) buffalo.Handler {
    77  		return func(c buffalo.Context) error {
    78  
    79  			// in development reload the translations
    80  			if c.Value("env").(string) == "development" {
    81  				err := t.Load()
    82  				if err != nil {
    83  					return err
    84  				}
    85  			}
    86  
    87  			// set up the helper function for the views:
    88  			c.Set(t.HelperName, func(s string) (string, error) {
    89  				return t.Translate(c, s)
    90  			})
    91  			return next(c)
    92  		}
    93  	}
    94  }
    95  
    96  // Translate a string given a Context
    97  func (t *Translator) Translate(c buffalo.Context, s string) (string, error) {
    98  	if langs := c.Value("languages"); langs == nil {
    99  		c.Set("languages", t.LanguageFinder(t, c))
   100  	}
   101  	langs := c.Value("languages").([]string)
   102  	T, err := i18n.Tfunc(langs[0], langs[1:]...)
   103  	if err != nil {
   104  		return "", err
   105  	}
   106  	return T(s, c.Data()), nil
   107  }
   108  
   109  func defaultLanguageFinder(t *Translator, c buffalo.Context) []string {
   110  	langs := []string{}
   111  
   112  	r := c.Request()
   113  
   114  	// try to get the language from a cookie:
   115  	if cookie, err := r.Cookie(t.CookieName); err == nil {
   116  		if cookie.Value != "" {
   117  			langs = append(langs, cookie.Value)
   118  		}
   119  	}
   120  
   121  	// try to get the language from a header:
   122  	acceptLang := r.Header.Get("Accept-Language")
   123  	if acceptLang != "" {
   124  		langs = append(langs, acceptLang)
   125  	}
   126  
   127  	// try to get the language from the session:
   128  	langs = append(langs, t.DefaultLanguage)
   129  	return langs
   130  }