{{ define "translator" }}
package {{ .Locale }}

import (
	"math"
	"strconv"
	"time"

	"github.com/go-playground/locales"
	"github.com/go-playground/locales/currency"
)

type {{ .Locale }} struct {
	locale     			   string
	pluralsCardinal 	   []locales.PluralRule
	pluralsOrdinal  	   []locales.PluralRule
	pluralsRange		   []locales.PluralRule
	decimal    			   string
	group      			   string
	minus      			   string
	percent    			   string
	{{- if gt (len .FmtPercentPrefix) 0}}
	percentPrefix   	   string
	{{- end }}
	{{- if gt (len .FmtPercentSuffix) 0}}
	percentSuffix   	   string
	{{- end }}
	perMille   			   string
	timeSeparator		   string
	inifinity			   string
	currencies 			   []string // idx = enum of currency code
	{{- if gt (len .FmtCurrencyPrefix) 0}}
	currencyPositivePrefix string
	{{- end }}
	{{- if gt (len .FmtCurrencySuffix) 0}}
	currencyPositiveSuffix string
	{{- end }}
	{{- if gt (len .FmtCurrencyNegativePrefix) 0}}
	currencyNegativePrefix string
	{{- end }}
	{{- if gt (len .FmtCurrencyNegativeSuffix) 0}}
	currencyNegativeSuffix string
	{{- end }}
	monthsAbbreviated      []string
	monthsNarrow      	   []string
	monthsWide      	   []string
	daysAbbreviated        []string
	daysNarrow      	   []string
	daysShort      	   	   []string
	daysWide      	   	   []string
	periodsAbbreviated     []string
	periodsNarrow      	   []string
	periodsShort      	   []string
	periodsWide      	   []string
	erasAbbreviated        []string
	erasNarrow      	   []string
	erasWide      	   	   []string
	timezones 			   map[string]string
}

// New returns a new instance of translator for the '{{ .Locale }}' locale
func New() locales.Translator {
	return &{{ .Locale }}{
		locale:   		 "{{ .Locale }}",
		pluralsCardinal: {{ .Plurals }},
		pluralsOrdinal:  {{ .PluralsOrdinal }},
		pluralsRange:    {{ .PluralsRange }},
		{{- if gt (len .Decimal) 0}}
		decimal:  		 "{{ .Decimal }}",
		{{- end}}
		{{- if gt (len .Group) 0}}
		group:    		 "{{ .Group }}",
		{{- end}}
		{{- if gt (len .Minus) 0}}
		minus:    		 "{{ .Minus }}",
		{{- end}}
		{{- if gt (len .Percent) 0}}
		percent:  		 "{{ .Percent }}",
		{{- end}}
		{{- if gt (len .PerMille) 0}}
		perMille:        "{{ .PerMille }}",
		{{- end}}
		{{- if gt (len .TimeSeparator) 0}}
		timeSeparator:	 "{{ .TimeSeparator }}",
		{{- end}}
		{{- if gt (len .Infinity) 0}}
		inifinity:		 "{{ .Infinity }}",
		{{- end}}
		currencies:      {{ .Currencies }},
		{{- if gt (len .FmtPercentPrefix) 0}}
		percentPrefix:   "{{ .FmtPercentPrefix }}",
		{{- end -}}
		{{- if gt (len .FmtPercentSuffix) 0}}
		percentSuffix:   "{{ .FmtPercentSuffix }}",
		{{- end -}}
		{{- if gt (len .FmtCurrencyPrefix) 0}}
		currencyPositivePrefix:   "{{ .FmtCurrencyPrefix }}",
		{{- end -}}
		{{- if gt (len .FmtCurrencySuffix) 0}}
		currencyPositiveSuffix:   "{{ .FmtCurrencySuffix }}",
		{{- end -}}
		{{- if gt (len .FmtCurrencyNegativePrefix) 0}}
		currencyNegativePrefix:   "{{ .FmtCurrencyNegativePrefix }}",
		{{- end -}}
		{{- if gt (len .FmtCurrencyNegativeSuffix) 0}}
		currencyNegativeSuffix:   "{{ .FmtCurrencyNegativeSuffix }}",
		{{- end -}}
		{{- if gt (len .FmtMonthsAbbreviated) 0 }}
		monthsAbbreviated:   {{ .FmtMonthsAbbreviated }},
		{{- end -}}
		{{- if gt (len .FmtMonthsNarrow) 0 }}
		monthsNarrow:   {{ .FmtMonthsNarrow }},
		{{- end -}}
		{{- if gt (len .FmtMonthsWide) 0 }}
		monthsWide:   {{ .FmtMonthsWide }},
		{{- end -}}
		{{- if gt (len .FmtDaysAbbreviated) 0 }}
		daysAbbreviated:   {{ .FmtDaysAbbreviated }},
		{{- end -}}
		{{- if gt (len .FmtDaysNarrow) 0 }}
		daysNarrow:   {{ .FmtDaysNarrow }},
		{{- end -}}
		{{- if gt (len .FmtDaysShort) 0 }}
		daysShort:   {{ .FmtDaysShort }},
		{{- end -}}
		{{- if gt (len .FmtDaysWide) 0 }}
		daysWide:   {{ .FmtDaysWide }},
		{{- end -}}
		{{- if gt (len .FmtPeriodsAbbreviated) 0 }}
		periodsAbbreviated:   {{ .FmtPeriodsAbbreviated }},
		{{- end -}}
		{{- if gt (len .FmtPeriodsNarrow) 0 }}
		periodsNarrow:   {{ .FmtPeriodsNarrow }},
		{{- end -}}
		{{- if gt (len .FmtPeriodsShort) 0 }}
		periodsShort:   {{ .FmtPeriodsShort }},
		{{- end -}}
		{{- if gt (len .FmtPeriodsWide) 0 }}
		periodsWide:   {{ .FmtPeriodsWide }},
		{{- end -}}
		{{- if gt (len .FmtErasAbbreviated) 0 }}
		erasAbbreviated:   {{ .FmtErasAbbreviated }},
		{{- end -}}
		{{- if gt (len .FmtErasNarrow) 0 }}
		erasNarrow:   {{ .FmtErasNarrow }},
		{{- end -}}
		{{- if gt (len .FmtErasWide) 0 }}
		erasWide:   {{ .FmtErasWide }},
		{{- end }}
		timezones: {{ .FmtTimezones }},
	}
}

// Locale returns the current translators string locale
func({{ .BaseLocale }} *{{ .Locale }}) Locale() string {
	return {{ .BaseLocale }}.locale
}

// PluralsCardinal returns the list of cardinal plural rules associated with '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) PluralsCardinal() []locales.PluralRule {
	return {{ .BaseLocale }}.pluralsCardinal
}

// PluralsOrdinal returns the list of ordinal plural rules associated with '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) PluralsOrdinal() []locales.PluralRule {
	return {{ .BaseLocale }}.pluralsOrdinal
}

// PluralsRange returns the list of range plural rules associated with '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) PluralsRange() []locales.PluralRule {
	return {{ .BaseLocale }}.pluralsRange
}

// CardinalPluralRule returns the cardinal PluralRule given 'num' and digits/precision of 'v' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) CardinalPluralRule(num float64, v uint64) locales.PluralRule {
	{{ .CardinalFunc }}
}

// OrdinalPluralRule returns the ordinal PluralRule given 'num' and digits/precision of 'v' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) OrdinalPluralRule(num float64, v uint64) locales.PluralRule {
	{{ .OrdinalFunc }}
}

// RangePluralRule returns the ordinal PluralRule given 'num1', 'num2' and digits/precision of 'v1' and 'v2' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) RangePluralRule(num1 float64, v1 uint64,num2 float64, v2 uint64) locales.PluralRule {
	{{ .RangeFunc }}
}

// MonthAbbreviated returns the locales abbreviated month given the 'month' provided
func({{ .BaseLocale }} *{{ .Locale }}) MonthAbbreviated(month time.Month) string {
	return {{ .BaseLocale }}.monthsAbbreviated[month]
}

// MonthsAbbreviated returns the locales abbreviated months
func({{ .BaseLocale }} *{{ .Locale }}) MonthsAbbreviated() []string {
	{{- if gt (len .FmtMonthsAbbreviated) 0 }}
	return {{ .BaseLocale }}.monthsAbbreviated[1:]
	{{ else }}
	return nil
	{{- end -}}
}

// MonthNarrow returns the locales narrow month given the 'month' provided
func({{ .BaseLocale }} *{{ .Locale }}) MonthNarrow(month time.Month) string {
	return {{ .BaseLocale }}.monthsNarrow[month]
}

// MonthsNarrow returns the locales narrow months
func({{ .BaseLocale }} *{{ .Locale }}) MonthsNarrow() []string {
	{{- if gt (len .FmtMonthsNarrow) 0 }}
	return {{ .BaseLocale }}.monthsNarrow[1:]
	{{ else }}
	return nil
	{{- end -}}
}

// MonthWide returns the locales wide month given the 'month' provided
func({{ .BaseLocale }} *{{ .Locale }}) MonthWide(month time.Month) string {
	return {{ .BaseLocale }}.monthsWide[month]
}

// MonthsWide returns the locales wide months
func({{ .BaseLocale }} *{{ .Locale }}) MonthsWide() []string {
	{{- if gt (len .FmtMonthsWide) 0 }}
	return {{ .BaseLocale }}.monthsWide[1:]
	{{ else }}
	return nil
	{{- end -}}
}

// WeekdayAbbreviated returns the locales abbreviated weekday given the 'weekday' provided
func({{ .BaseLocale }} *{{ .Locale }}) WeekdayAbbreviated(weekday time.Weekday) string {
	return {{ .BaseLocale }}.daysAbbreviated[weekday]
}

// WeekdaysAbbreviated returns the locales abbreviated weekdays
func({{ .BaseLocale }} *{{ .Locale }}) WeekdaysAbbreviated() []string {
	return {{ .BaseLocale }}.daysAbbreviated
}

// WeekdayNarrow returns the locales narrow weekday given the 'weekday' provided
func({{ .BaseLocale }} *{{ .Locale }}) WeekdayNarrow(weekday time.Weekday) string {
	return {{ .BaseLocale }}.daysNarrow[weekday]
}

// WeekdaysNarrow returns the locales narrow weekdays
func({{ .BaseLocale }} *{{ .Locale }}) WeekdaysNarrow() []string {
	return {{ .BaseLocale }}.daysNarrow
}

// WeekdayShort returns the locales short weekday given the 'weekday' provided
func({{ .BaseLocale }} *{{ .Locale }}) WeekdayShort(weekday time.Weekday) string {
	return {{ .BaseLocale }}.daysShort[weekday]
}

// WeekdaysShort returns the locales short weekdays
func({{ .BaseLocale }} *{{ .Locale }}) WeekdaysShort() []string {
	return {{ .BaseLocale }}.daysShort
}

// WeekdayWide returns the locales wide weekday given the 'weekday' provided
func({{ .BaseLocale }} *{{ .Locale }}) WeekdayWide(weekday time.Weekday) string {
	return {{ .BaseLocale }}.daysWide[weekday]
}

// WeekdaysWide returns the locales wide weekdays
func({{ .BaseLocale }} *{{ .Locale }}) WeekdaysWide() []string {
	return {{ .BaseLocale }}.daysWide
}

// Decimal returns the decimal point of number
func({{ .BaseLocale }} *{{ .Locale }}) Decimal() string {
	return {{ .BaseLocale }}.decimal
}

// Group returns the group of number
func({{ .BaseLocale }} *{{ .Locale }}) Group() string {
	return {{ .BaseLocale }}.group
}

// Group returns the minus sign of number
func({{ .BaseLocale }} *{{ .Locale }}) Minus() string {
	return {{ .BaseLocale }}.minus
}

// FmtNumber returns 'num' with digits/precision of 'v' for '{{ .Locale }}' and handles both Whole and Real numbers based on 'v'
func({{ .BaseLocale }} *{{ .Locale }}) FmtNumber(num float64, v uint64) string {

	{{ if eq .FmtNumberExists true }}
	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
	{{- if gt .FmtNumberGroupLen 0 }}
	{{- $byteCountGroup := byte_count .Group -}}
	{{ if ne $byteCountGroup "0" }}
	l := len(s) + {{ byte_count .Decimal .Minus }} + {{ $byteCountGroup }} * len(s[:len(s)-int(v)-1]) / {{ .FmtNumberGroupLen }}
	{{ else }}
	l := len(s) + {{ byte_count .Decimal .Minus }}
	{{ end -}}
	count := 0
	inWhole := v == 0
	{{- if gt .FmtNumberSecondaryGroupLen 0}}
	inSecondary := false
	groupThreshold := {{ .FmtNumberGroupLen }}
	{{ end -}}
	{{ else }}
	l := len(s) + {{ byte_count .Decimal .Minus }}
	{{ end }}
	b := make([]byte, 0, l)

	for i := len(s) - 1; i >= 0; i-- {

		if s[i] == '.' {

			{{- if is_multibyte .Decimal }}
			for j := len({{ .BaseLocale }}.decimal) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.decimal[j])
			}
			{{- else }}
			b = append(b, {{ .BaseLocale }}.decimal[0])
			{{- end -}}
			{{- if gt .FmtNumberGroupLen 0 }}
			inWhole = true
			{{- end }}
			continue
		}

		{{ if gt .FmtNumberGroupLen 0 }}
		if inWhole {

			{{- if gt .FmtNumberSecondaryGroupLen 0}}
			
			if count == groupThreshold {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1

				if !inSecondary {
					inSecondary = true
					groupThreshold = {{ .FmtNumberSecondaryGroupLen }}
				}
			{{ else }}
			if count == {{ .FmtNumberGroupLen }} {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1
			{{ end -}}
			} else {
				count++
			}
		}

		{{ end }}

		b = append(b, s[i])
	}

	if num < 0 {
		{{- if is_multibyte .Minus }}
		for j := len({{ .BaseLocale }}.minus) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.minus[j])
		}
		{{ else }}
		b = append(b, {{ .BaseLocale }}.minus[0])
		{{ end -}}
	}

	// reverse
	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
		b[i], b[j] = b[j], b[i]
	}

	{{ if gt .FmtNumberMinDecimalLen 0 }}
	if int(v) < {{ .FmtNumberMinDecimalLen }} {

		if v == 0 {
			b = append(b, {{ .BaseLocale }}.decimal...)
		}

		for i := 0; i < {{ .FmtNumberMinDecimalLen }}-int(v); i++ {
			b = append(b, '0')
		}
	}
	{{ end }}

	return string(b)
	{{ else }}
	return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
	{{ end -}}
}

// FmtPercent returns 'num' with digits/precision of 'v' for '{{ .Locale }}' and handles both Whole and Real numbers based on 'v'
// NOTE: 'num' passed into FmtPercent is assumed to be in percent already
func({{ .BaseLocale }} *{{ .Locale }}) FmtPercent(num float64, v uint64) string {

	{{- if eq .FmtPercentExists true }}
	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
	{{- if gt .FmtPercentGroupLen 0 }}
	{{- $byteCountGroup := byte_count .Group -}}
	{{ if ne $byteCountGroup "0" }}
	l := len(s) + {{ byte_count .Decimal .Minus .Percent .FmtPercentPrefix .FmtPercentSuffix }} + {{ $byteCountGroup }} * len(s[:len(s)-int(v)-1]) / {{ .FmtPercentGroupLen }}
	{{ else }}
	l := len(s) + {{ byte_count .Decimal .Minus .Percent .FmtPercentPrefix .FmtPercentSuffix }}
	{{ end -}}
	count := 0
	inWhole := v == 0
	{{- if gt .FmtPercentSecondaryGroupLen 0}}
	inSecondary := false
	groupThreshold := {{ .FmtPercentGroupLen }}
	{{ end -}}
	{{ else }}
	l := len(s) + {{ byte_count .Decimal .Minus .Percent .FmtPercentPrefix .FmtPercentSuffix }}
	{{- end }}
	b := make([]byte, 0, l)

	for i := len(s) - 1; i >= 0; i-- {

		if s[i] == '.' {

			{{- if is_multibyte .Decimal }}
			for j := len({{ .BaseLocale }}.decimal) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.decimal[j])
			}
			{{- else }}
			b = append(b, {{ .BaseLocale }}.decimal[0])
			{{- end -}}
			{{- if gt .FmtPercentGroupLen 0 }}
			inWhole = true
			{{ end }}
			continue
		}

		{{ if gt .FmtPercentGroupLen 0 }}
		if inWhole {

			{{- if gt .FmtPercentSecondaryGroupLen 0}}
			
			if count == groupThreshold {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1

				if !inSecondary {
					inSecondary = true
					groupThreshold = {{ .FmtPercentSecondaryGroupLen }}
				}
			{{ else }}
			if count == {{ .FmtPercentGroupLen }} {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1
			{{ end -}}
			} else {
				count++
			}
		}

		{{ end }}

		b = append(b, s[i])
	}

	if num < 0 {
		{{- if is_multibyte .Minus }}
		for j := len({{ .BaseLocale }}.minus) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.minus[j])
		}
		{{ else }}
		b = append(b, {{ .BaseLocale }}.minus[0])
		{{ end -}}
	}

	{{ if and .FmtPercentInPrefix (not .FmtPercentLeft) }}
		{{- if is_multibyte .Percent }}
		for j := len({{ .BaseLocale }}.percent) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.percent[j])
		}
		{{ else }}
		b = append(b, {{ .BaseLocale }}.percent[0])
		{{ end }}
	{{ end }}

	{{ if gt (len .FmtPercentPrefix) 0}}
		{{- if is_multibyte .FmtPercentPrefix }}
		for j := len({{ .BaseLocale }}.percentPrefix) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.percentPrefix[j])
		}
		{{ else }}
		b = append(b, {{ .BaseLocale }}.percentPrefix[0])
		{{ end }}
	{{ end }}

	{{ if and .FmtPercentInPrefix .FmtPercentLeft }}
		{{- if is_multibyte .Percent }}
		for j := len({{ .BaseLocale }}.percent) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.percent[j])
		}
		{{ else }}
		b = append(b, {{ .BaseLocale }}.percent[0])
		{{ end }}
	{{ end }}

	// reverse
	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
		b[i], b[j] = b[j], b[i]
	}

	{{ if gt .FmtPercentMinDecimalLen 0 }}
	if int(v) < {{ .FmtPercentMinDecimalLen }} {

		if v == 0 {
			b = append(b, {{ .BaseLocale }}.decimal...)
		}

		for i := 0; i < {{ .FmtPercentMinDecimalLen }}-int(v); i++ {
			b = append(b, '0')
		}
	}
	{{ end }}

	{{ if and (not .FmtPercentInPrefix) .FmtPercentLeft }}
		b = append(b, {{ .BaseLocale }}.percent...)
	{{ end }}

	{{ if gt (len .FmtPercentSuffix) 0}}
		b = append(b, {{ .BaseLocale }}.percentSuffix...)
	{{ end }}

	{{ if and (not .FmtPercentInPrefix) (not .FmtPercentLeft) }}
		b = append(b, {{ .BaseLocale }}.percent...)
	{{ end }}

	return string(b)
	{{ else }}
	return strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
	{{ end -}}
}

// FmtCurrency returns the currency representation of 'num' with digits/precision of 'v' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtCurrency(num float64, v uint64, currency currency.Type) string {

	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
	symbol := {{ .BaseLocale }}.currencies[currency]
	{{- if eq .FmtCurrencyExists true }}
	{{- if gt .FmtCurrencyGroupLen 0 }}
	{{- $byteCountGroup := byte_count .Group -}}
	{{ if ne $byteCountGroup "0" }}
	l := len(s) + len(symbol) + {{ byte_count .Decimal .Minus .FmtCurrencyPrefix .FmtCurrencySuffix }} + {{ $byteCountGroup }} * len(s[:len(s)-int(v)-1]) / {{ .FmtCurrencyGroupLen }}
	{{ else }}
	l := len(s) + len(symbol) + {{ byte_count .Decimal .Minus .FmtCurrencyPrefix .FmtCurrencySuffix }}
	{{ end -}}
	count := 0
	inWhole := v == 0
	{{- if gt .FmtCurrencySecondaryGroupLen 0}}
	inSecondary := false
	groupThreshold := {{ .FmtCurrencyGroupLen }}
	{{ end -}}
	{{ else }}
	l := len(s) + len(symbol) + {{ byte_count .Decimal .Minus .FmtCurrencyPrefix .FmtCurrencySuffix }}
	{{ end }}
	b := make([]byte, 0, l)

	for i := len(s) - 1; i >= 0; i-- {

		if s[i] == '.' {

			{{- if is_multibyte .Decimal }}
			for j := len({{ .BaseLocale }}.decimal) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.decimal[j])
			}
			{{- else }}
			b = append(b, {{ .BaseLocale }}.decimal[0])
			{{- end -}}
			{{- if gt .FmtCurrencyGroupLen 0 }}
			inWhole = true
			{{- end }}
			continue
		}

		{{ if gt .FmtCurrencyGroupLen 0 }}
		if inWhole {

			{{- if gt .FmtCurrencySecondaryGroupLen 0}}
			
			if count == groupThreshold {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1

				if !inSecondary {
					inSecondary = true
					groupThreshold = {{ .FmtCurrencySecondaryGroupLen }}
				}
			{{ else }}
			if count == {{ .FmtCurrencyGroupLen }} {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1
			{{ end -}}
			} else {
				count++
			}
		}

		{{ end }}

		b = append(b, s[i])
	}

	{{ if and .FmtCurrencyInPrefix (not .FmtCurrencyLeft) }}
		for j := len(symbol) - 1; j >= 0; j-- {
			b = append(b, symbol[j])
		}
	{{ end }}

	{{ if gt (len .FmtCurrencyPrefix) 0}}
		{{- if is_multibyte .FmtCurrencyPrefix }}
		for j := len({{ .BaseLocale }}.currencyPositivePrefix) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.currencyPositivePrefix[j])
		}
		{{ else }}
		b = append(b, {{ .BaseLocale }}.currencyPositivePrefix[0])
		{{ end }}
	{{ end }}

	{{ if and .FmtCurrencyInPrefix .FmtCurrencyLeft }}
		for j := len(symbol) - 1; j >= 0; j-- {
			b = append(b, symbol[j])
		}
	{{ end }}

	if num < 0 {
		{{- if is_multibyte .Minus }}
		for j := len({{ .BaseLocale }}.minus) - 1; j >= 0; j-- {
			b = append(b, {{ .BaseLocale }}.minus[j])
		}
		{{ else -}}
		b = append(b, {{ .BaseLocale }}.minus[0])
		{{ end -}}
	}

	// reverse
	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
		b[i], b[j] = b[j], b[i]
	}

	{{ if gt .FmtCurrencyMinDecimalLen 0 }}
	if int(v) < {{ .FmtCurrencyMinDecimalLen }} {

		if v == 0 {
			b = append(b, {{ .BaseLocale }}.decimal...)
		}

		for i := 0; i < {{ .FmtCurrencyMinDecimalLen }}-int(v); i++ {
			b = append(b, '0')
		}
	}
	{{ end }}

	{{ if and (not .FmtCurrencyInPrefix) .FmtCurrencyLeft }}
		b = append(b, symbol...)
	{{ end }}

	{{ if gt (len .FmtCurrencySuffix) 0}}
		b = append(b, {{ .BaseLocale }}.currencyPositiveSuffix...)
	{{ end }}

	{{ if and (not .FmtCurrencyInPrefix) (not .FmtCurrencyLeft) }}
		b = append(b, symbol...)
	{{ end }}

	return string(b)
	{{ else }}
	return string(append(append([]byte{}, symbol...), s...))
	{{ end -}}
}

// FmtAccounting returns the currency representation of 'num' with digits/precision of 'v' for '{{ .Locale }}'
// in accounting notation.
func({{ .BaseLocale }} *{{ .Locale }}) FmtAccounting(num float64, v uint64, currency currency.Type) string {

	s := strconv.FormatFloat(math.Abs(num), 'f', int(v), 64)
	symbol := {{ .BaseLocale }}.currencies[currency]
	{{- if eq .FmtCurrencyExists true }}
	{{- if gt .FmtCurrencyGroupLen 0 }}
	{{- $byteCountGroup := byte_count .Group -}}
	{{ if ne $byteCountGroup "0" }}
	l := len(s) + len(symbol) + {{ byte_count .Decimal .Minus .FmtCurrencyNegativePrefix .FmtCurrencyNegativeSuffix }} + {{ $byteCountGroup }} * len(s[:len(s)-int(v)-1]) / {{ .FmtCurrencyGroupLen }}
	{{ else }}
	l := len(s) + len(symbol) + {{ byte_count .Decimal .Minus .FmtCurrencyNegativePrefix .FmtCurrencyNegativeSuffix }}
	{{ end -}}
	count := 0
	inWhole := v == 0
	{{- if gt .FmtCurrencySecondaryGroupLen 0}}
	inSecondary := false
	groupThreshold := {{ .FmtCurrencyGroupLen }}
	{{ end -}}
	{{ else }}
	l := len(s) + len(symbol) + {{ byte_count .Decimal .Minus .FmtCurrencyNegativePrefix .FmtCurrencyNegativeSuffix }}
	{{ end }}
	b := make([]byte, 0, l)

	for i := len(s) - 1; i >= 0; i-- {

		if s[i] == '.' {

			{{- if is_multibyte .Decimal }}
			for j := len({{ .BaseLocale }}.decimal) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.decimal[j])
			}
			{{- else }}
			b = append(b, {{ .BaseLocale }}.decimal[0])
			{{- end -}}
			{{- if gt .FmtCurrencyGroupLen 0 }}
			inWhole = true
			{{- end }}
			continue
		}

		{{ if gt .FmtCurrencyGroupLen 0 }}
		if inWhole {

			{{- if gt .FmtCurrencySecondaryGroupLen 0}}
			
			if count == groupThreshold {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1

				if !inSecondary {
					inSecondary = true
					groupThreshold = {{ .FmtCurrencySecondaryGroupLen }}
				}
			{{ else }}
			if count == {{ .FmtCurrencyGroupLen }} {
				{{- if is_multibyte .Group }}
				for j := len({{ .BaseLocale }}.group) - 1; j >= 0; j-- {
					b = append(b, {{ .BaseLocale }}.group[j])
				}
				{{- else }}
				b = append(b, {{ .BaseLocale }}.group[0])
				{{- end }}
				count = 1
			{{ end -}}
			} else {
				count++
			}
		}

		{{ end }}

		b = append(b, s[i])
	}

	if num < 0 {

		{{ if and .FmtCurrencyNegativeInPrefix (not .FmtCurrencyNegativeLeft) }}
		for j := len(symbol) - 1; j >= 0; j-- {
			b = append(b, symbol[j])
		}
		{{ end }}

		{{ if gt (len .FmtCurrencyNegativePrefix) 0}}
			{{- if is_multibyte .FmtCurrencyNegativePrefix }}
			for j := len({{ .BaseLocale }}.currencyNegativePrefix) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.currencyNegativePrefix[j])
			}
			{{ else }}
			b = append(b, {{ .BaseLocale }}.currencyNegativePrefix[0])
			{{ end }}
		{{ end }}

		{{ if and .FmtCurrencyNegativeInPrefix .FmtCurrencyNegativeLeft }}
			for j := len(symbol) - 1; j >= 0; j-- {
				b = append(b, symbol[j])
			}
		{{ end }}

		{{ if eq (not .FmtCurrencyNegativeExists) true}}
			{{- if is_multibyte .Minus }}
			for j := len({{ .BaseLocale }}.minus) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.minus[j])
			}
			{{ else -}}
			b = append(b, {{ .BaseLocale }}.minus[0])
			{{ end -}}
		{{ end }}

	{{ if or .FmtCurrencyInPrefix (gt (len .FmtCurrencyPrefix) 0) }}
	} else {
	{{ end }}
		
		{{ if and .FmtCurrencyInPrefix (not .FmtCurrencyLeft) }}
		for j := len(symbol) - 1; j >= 0; j-- {
			b = append(b, symbol[j])
		}
		{{ end }}

		{{ if gt (len .FmtCurrencyPrefix) 0}}
			{{- if is_multibyte .FmtCurrencyPrefix }}
			for j := len({{ .BaseLocale }}.currencyPositivePrefix) - 1; j >= 0; j-- {
				b = append(b, {{ .BaseLocale }}.currencyPositivePrefix[j])
			}
			{{ else }}
			b = append(b, {{ .BaseLocale }}.currencyPositivePrefix[0])
			{{ end }}
		{{ end }}

		{{ if and .FmtCurrencyInPrefix .FmtCurrencyLeft }}
			for j := len(symbol) - 1; j >= 0; j-- {
				b = append(b, symbol[j])
			}
		{{- end }}
	}

	// reverse
	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
		b[i], b[j] = b[j], b[i]
	}

	{{ if gt .FmtCurrencyMinDecimalLen 0 }}
	if int(v) < {{ .FmtCurrencyMinDecimalLen }} {

		if v == 0 {
			b = append(b, {{ .BaseLocale }}.decimal...)
		}

		for i := 0; i < {{ .FmtCurrencyMinDecimalLen }}-int(v); i++ {
			b = append(b, '0')
		}
	}
	{{- end }}

	{{ if or (not .FmtCurrencyNegativeInPrefix) (gt (len .FmtCurrencyNegativeSuffix) 0)}}
	if num < 0 {
	{{- end }}
		{{- if and (not .FmtCurrencyNegativeInPrefix) .FmtCurrencyNegativeLeft }}
			b = append(b, symbol...)
		{{- end -}}

		{{- if gt (len .FmtCurrencyNegativeSuffix) 0}}
			b = append(b, {{ .BaseLocale }}.currencyNegativeSuffix...)
		{{- end -}}

		{{- if and (not .FmtCurrencyNegativeInPrefix) (not .FmtCurrencyNegativeLeft) }}
			b = append(b, symbol...)
		{{- end -}}
	{{ if or (not .FmtCurrencyInPrefix) (gt (len .FmtCurrencySuffix) 0)}}
	} else {
	{{ end }}
		{{- if and (not .FmtCurrencyInPrefix) .FmtCurrencyLeft }}
			b = append(b, symbol...)
		{{- end -}}

		{{- if gt (len .FmtCurrencySuffix) 0}}
			b = append(b, {{ .BaseLocale }}.currencyPositiveSuffix...)
		{{- end -}}

		{{- if and (not .FmtCurrencyInPrefix) (not .FmtCurrencyLeft) }}
			b = append(b, symbol...)
		{{- end -}}
	{{- if or (not .FmtCurrencyNegativeInPrefix) (gt (len .FmtCurrencyNegativeSuffix) 0)}}
	}
	{{- end }}

	return string(b)
	{{ else }}
	return string(append(append([]byte{}, symbol...), s...))
	{{ end -}}
}

// FmtDateShort returns the short date representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtDateShort(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtDateShort }}

	return string(b)
}

// FmtDateMedium returns the medium date representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtDateMedium(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtDateMedium }}

	return string(b)
}

// FmtDateLong returns the long date representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtDateLong(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtDateLong }}

	return string(b)
}

// FmtDateFull returns the full date representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtDateFull(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtDateFull }}

	return string(b)
}

// FmtTimeShort returns the short time representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtTimeShort(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtTimeShort }}

	return string(b)
}

// FmtTimeMedium returns the medium time representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtTimeMedium(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtTimeMedium }}

	return string(b)
}

// FmtTimeLong returns the long time representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtTimeLong(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtTimeLong }}

	return string(b)
}

// FmtTimeFull returns the full time representation of 't' for '{{ .Locale }}'
func({{ .BaseLocale }} *{{ .Locale }}) FmtTimeFull(t time.Time) string {
	
	b := make([]byte, 0, 32)

	{{ .FmtTimeFull }}

	return string(b)
}

{{ end }}
