···22222323// TrHTML implements Locale.
2424func (k *KeyLocale) TrHTML(trKey string, trArgs ...any) template.HTML {
2525- args := slices.Clone(trArgs)
2626- for i, v := range args {
2727- switch v := v.(type) {
2828- case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML:
2929- // for most basic types (including template.HTML which is safe), just do nothing and use it
3030- case string:
3131- args[i] = template.HTMLEscapeString(v)
3232- case fmt.Stringer:
3333- args[i] = template.HTMLEscapeString(v.String())
3434- default:
3535- args[i] = template.HTMLEscapeString(fmt.Sprint(v))
3636- }
3737- }
3838- return template.HTML(k.TrString(trKey, args...))
2525+ return template.HTML(k.TrString(trKey, PrepareArgsForHTML(trArgs...)...))
3926}
40274128// TrString implements Locale.
4229func (k *KeyLocale) TrString(trKey string, trArgs ...any) string {
4330 return FormatDummy(trKey, trArgs...)
3131+}
3232+3333+// TrPluralString implements Locale.
3434+func (k *KeyLocale) TrPluralString(count any, trKey string, trArgs ...any) template.HTML {
3535+ return template.HTML(FormatDummy(trKey, PrepareArgsForHTML(trArgs...)...))
4436}
45374638func FormatDummy(trKey string, args ...any) string {
+4-2
modules/translation/i18n/errors.go
···88)
991010var (
1111- ErrLocaleAlreadyExist = util.SilentWrap{Message: "lang already exists", Err: util.ErrAlreadyExist}
1212- ErrUncertainArguments = util.SilentWrap{Message: "arguments to i18n should not contain uncertain slices", Err: util.ErrInvalidArgument}
1111+ ErrLocaleAlreadyExist = util.SilentWrap{Message: "lang already exists", Err: util.ErrAlreadyExist}
1212+ ErrLocaleDoesNotExist = util.SilentWrap{Message: "lang does not exist", Err: util.ErrNotExist}
1313+ ErrTranslationDoesNotExist = util.SilentWrap{Message: "translation does not exist", Err: util.ErrNotExist}
1414+ ErrUncertainArguments = util.SilentWrap{Message: "arguments to i18n should not contain uncertain slices", Err: util.ErrInvalidArgument}
1315)
+21-2
modules/translation/i18n/i18n.go
···88 "io"
99)
10101111+type (
1212+ PluralFormIndex uint8
1313+ PluralFormRule func(int64) PluralFormIndex
1414+)
1515+1616+const (
1717+ PluralFormZero PluralFormIndex = iota
1818+ PluralFormOne
1919+ PluralFormTwo
2020+ PluralFormFew
2121+ PluralFormMany
2222+ PluralFormOther
2323+)
2424+1125var DefaultLocales = NewLocaleStore()
12261327type Locale interface {
1428 // TrString translates a given key and arguments for a language
1529 TrString(trKey string, trArgs ...any) string
3030+ // TrPluralString translates a given pluralized key and arguments for a language.
3131+ // This function returns an error if new-style support for the given key is not available.
3232+ TrPluralString(count any, trKey string, trArgs ...any) template.HTML
1633 // TrHTML translates a given key and arguments for a language, string arguments are escaped to HTML
1734 TrHTML(trKey string, trArgs ...any) template.HTML
1835 // HasKey reports if a locale has a translation for a given key
···3148 Locale(langName string) (Locale, bool)
3249 // HasLang returns whether a given language is present in the store
3350 HasLang(langName string) bool
3434- // AddLocaleByIni adds a new language to the store
3535- AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error
5151+ // AddLocaleByIni adds a new old-style language to the store
5252+ AddLocaleByIni(langName, langDesc string, pluralRule PluralFormRule, source, moreSource []byte) error
5353+ // AddLocaleByJSON adds new-style content to an existing language to the store
5454+ AddToLocaleFromJSON(langName string, source []byte) error
3655}
37563857// ResetDefaultLocales resets the current default locales
···190190runner_kind = Search runners...
191191no_results = No matching results found.
192192issue_kind = Search issues...
193193-milestone_kind = Search milestones...
194193pull_kind = Search pulls...
195194keyword_search_unavailable = Searching by keyword is currently not available. Please contact the site administrator.
196195···18871886pulls.nothing_to_compare_and_allow_empty_pr = These branches are equal. This PR will be empty.
18881887pulls.has_pull_request = `A pull request between these branches already exists: <a href="%[1]s">%[2]s#%[3]d</a>`
18891888pulls.create = Create pull request
18901890-pulls.title_desc_one = wants to merge %[1]d commit from <code>%[2]s</code> into <code id="%[4]s">%[3]s</code>
18911891-pulls.title_desc_few = wants to merge %[1]d commits from <code>%[2]s</code> into <code id="%[4]s">%[3]s</code>
18921892-pulls.merged_title_desc_one = merged %[1]d commit from <code>%[2]s</code> into <code>%[3]s</code> %[4]s
18931893-pulls.merged_title_desc_few = merged %[1]d commits from <code>%[2]s</code> into <code>%[3]s</code> %[4]s
18941889pulls.change_target_branch_at = `changed target branch from <b>%s</b> to <b>%s</b> %s`
18951890pulls.tab_conversation = Conversation
18961891pulls.tab_commits = Commits