func (do *Domain) SetNC(id, plural, ctx string, n int, str string) {
	pluralForm := do.pluralForm(n)
	do.trMutex.Lock()
	do.pluralMutex.Lock()
	defer do.trMutex.Unlock()
	defer do.pluralMutex.Unlock()
	if context, ok := do.contexts[ctx]; ok {
		if trans, hasTrans := context[id]; hasTrans {
			trans.SetN(pluralForm, str)
		} else {
			trans = NewTranslation()
			trans.ID = id
			trans.SetN(pluralForm, str)
			context[id] = trans
		}
	} else {
		trans := NewTranslation()
		trans.ID = id
		trans.SetN(pluralForm, str)
		do.contexts[ctx] = map[string]*Translation{
			id: trans,
		}
	}
}
Set the (N)th plural form for the given string in the given context
package gotext
import (
	"bytes"
	"encoding/gob"
	"sort"
	"strconv"
	"strings"
	"sync"
	"golang.org/x/text/language"
	"github.com/leonelquinteros/gotext/plurals"
)
type Domain struct {
	Headers HeaderMap
	Language string
	tag      language.Tag
	PluralForms string
	headerComments []string
	nplurals    int
	plural      string
	pluralforms plurals.Expression
	translations       map[string]*Translation
	contexts           map[string]map[string]*Translation
	pluralTranslations map[string]*Translation
	trMutex     sync.RWMutex
	pluralMutex sync.RWMutex
	trBuffer  *Translation
	ctxBuffer string
	refBuffer string
}
type HeaderMap map[string][]string
func (m HeaderMap) Add(key, value string) {
	m[key] = append(m[key], value)
}
func (m HeaderMap) Del(key string) {
	delete(m, key)
}
func (m HeaderMap) Get(key string) string {
	if m == nil {
		return ""
	}
	v := m[key]
	if len(v) == 0 {
		return ""
	}
	return v[0]
}
func (m HeaderMap) Set(key, value string) {
	m[key] = []string{value}
}
func (m HeaderMap) Values(key string) []string {
	if m == nil {
		return nil
	}
	return m[key]
}
func NewDomain() *Domain {
	domain := new(Domain)
	domain.Headers = make(HeaderMap)
	domain.headerComments = make([]string, 0)
	domain.translations = make(map[string]*Translation)
	domain.contexts = make(map[string]map[string]*Translation)
	domain.pluralTranslations = make(map[string]*Translation)
	return domain
}
func (do *Domain) pluralForm(n int) int {
	do.pluralMutex.RLock()
	defer do.pluralMutex.RUnlock()
	if do.pluralforms == nil {
		if n == 1 {
			return 0
		}
		return 1
	}
	return do.pluralforms.Eval(uint32(n))
}
func (do *Domain) parseHeaders() {
	raw := ""
	if _, ok := do.translations[raw]; ok {
		raw = do.translations[raw].Get()
	}
	languageKey := "Language"
	pluralFormsKey := "Plural-Forms"
	rawLines := strings.Split(raw, "\n")
	for _, line := range rawLines {
		if len(line) == 0 {
			continue
		}
		colonIdx := strings.Index(line, ":")
		if colonIdx < 0 {
			continue
		}
		key := line[:colonIdx]
		lowerKey := strings.ToLower(key)
		if lowerKey == strings.ToLower(languageKey) {
			languageKey = key
		} else if lowerKey == strings.ToLower(pluralFormsKey) {
			pluralFormsKey = key
		}
		value := strings.TrimSpace(line[colonIdx+1:])
		do.Headers.Add(key, value)
	}
	do.Language = do.Headers.Get(languageKey)
	do.tag = language.Make(do.Language)
	do.PluralForms = do.Headers.Get(pluralFormsKey)
	if do.PluralForms == "" {
		return
	}
	pfs := strings.Split(do.PluralForms, ";")
	for _, i := range pfs {
		vs := strings.SplitN(i, "=", 2)
		if len(vs) != 2 {
			continue
		}
		switch strings.TrimSpace(vs[0]) {
		case "nplurals":
			do.nplurals, _ = strconv.Atoi(vs[1])
		case "plural":
			do.plural = vs[1]
			if expr, err := plurals.Compile(do.plural); err == nil {
				do.pluralforms = expr
			}
		}
	}
}
func (do *Domain) DropStaleTranslations() {
	do.trMutex.Lock()
	do.pluralMutex.Lock()
	defer do.trMutex.Unlock()
	defer do.pluralMutex.Unlock()
	for name, ctx := range do.contexts {
		for id, trans := range ctx {
			if trans.IsStale() {
				delete(ctx, id)
			}
		}
		if len(ctx) == 0 {
			delete(do.contexts, name)
		}
	}
	for id, trans := range do.translations {
		if trans.IsStale() {
			delete(do.translations, id)
		}
	}
}
func (do *Domain) SetRefs(str string, refs []string) {
	do.trMutex.Lock()
	do.pluralMutex.Lock()
	defer do.trMutex.Unlock()
	defer do.pluralMutex.Unlock()
	if trans, ok := do.translations[str]; ok {
		trans.Refs = refs
	} else {
		trans = NewTranslation()
		trans.ID = str
		trans.SetRefs(refs)
		do.translations[str] = trans
	}
}
func (do *Domain) GetRefs(str string) []string {
	do.trMutex.RLock()
	defer do.trMutex.RUnlock()
	if do.translations != nil {
		if trans, ok := do.translations[str]; ok {
			return trans.Refs
		}
	}
	return nil
}
func (do *Domain) Set(id, str string) {
	do.trMutex.Lock()
	do.pluralMutex.Lock()
	defer do.trMutex.Unlock()
	defer do.pluralMutex.Unlock()
	if trans, ok := do.translations[id]; ok {
		trans.Set(str)
	} else {
		trans = NewTranslation()
		trans.ID = id
		trans.Set(str)
		do.translations[str] = trans
	}
}
func (do *Domain) Get(str string, vars ...interface{}) string {
	do.trMutex.RLock()
	defer do.trMutex.RUnlock()
	if do.translations != nil {
		if _, ok := do.translations[str]; ok {
			return Printf(do.translations[str].Get(), vars...)
		}
	}
	return Printf(str, vars...)
}
func (do *Domain) SetN(id, plural string, n int, str string) {
	pluralForm := do.pluralForm(n)
	do.trMutex.Lock()
	do.pluralMutex.Lock()
	defer do.trMutex.Unlock()
	defer do.pluralMutex.Unlock()
	if trans, ok := do.translations[id]; ok {
		trans.SetN(pluralForm, str)
	} else {
		trans = NewTranslation()
		trans.ID = id
		trans.PluralID = plural
		trans.SetN(pluralForm, str)
		do.translations[str] = trans
	}
}
func (do *Domain) GetN(str, plural string, n int, vars ...interface{}) string {
	do.trMutex.RLock()
	defer do.trMutex.RUnlock()
	if do.translations != nil {
		if _, ok := do.translations[str]; ok {
			return Printf(do.translations[str].GetN(do.pluralForm(n)), vars...)
		}
	}
	if do.pluralForm(n) == 0 {
		return Printf(str, vars...)
	}
	return Printf(plural, vars...)
}
func (do *Domain) SetC(id, ctx, str string) {
	do.trMutex.Lock()
	do.pluralMutex.Lock()
	defer do.trMutex.Unlock()
	defer do.pluralMutex.Unlock()
	if context, ok := do.contexts[ctx]; ok {
		if trans, hasTrans := context[id]; hasTrans {
			trans.Set(str)
		} else {
			trans = NewTranslation()
			trans.ID = id
			trans.Set(str)
			context[id] = trans
		}
	} else {
		trans := NewTranslation()
		trans.ID = id
		trans.Set(str)
		do.contexts[ctx] = map[string]*Translation{
			id: trans,
		}
	}
}
func (do *Domain) GetC(str, ctx string, vars ...interface{}) string {
	do.trMutex.RLock()
	defer do.trMutex.RUnlock()
	if do.contexts != nil {
		if _, ok := do.contexts[ctx]; ok {
			if do.contexts[ctx] != nil {
				if _, ok := do.contexts[ctx][str]; ok {
					return Printf(do.contexts[ctx][str].Get(), vars...)
				}
			}
		}
	}
	return Printf(str, vars...)
}