Ctrl K
ComunidadGuías…

internal/server/i18n.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// SPDX-License-Identifier: Apache-2.0

package server

import (
	"log"
	"net/http"
	"sync"

	"github.com/X4Applegate/caddyui/internal/i18n"
	"github.com/X4Applegate/caddyui/internal/models"
	"github.com/X4Applegate/caddyui/web"
)

// v2.62.0 (issue #128): localization plumbing. See internal/i18n for the catalog
// format; this file picks each request's language and exposes the translate
// helper to the templates.

// settingDefaultLocale is the site-wide fallback language ("" = none).
const settingDefaultLocale = "default_locale"

var (
	i18nOnce   sync.Once
	i18nBundle *i18n.Bundle
)

// translations returns the catalogs embedded in the binary. A broken catalog is
// a build mistake (the tests load every one), so it is logged and the app keeps
// running in English rather than refusing to start.
func translations() *i18n.Bundle {
	i18nOnce.Do(func() {
		b, err := i18n.Load(web.FS, "i18n")
		if err != nil {
			log.Printf("i18n: %v — falling back to built-in English keys", err)
			b, _ = i18n.LoadFallback()
		}
		i18nBundle = b
	})
	return i18nBundle
}

// tFunc is the template helper: {{t $ "nav.proxy_hosts"}} — or with
// placeholders, {{t $ "x.count" "count" 3}}. The first argument is the page's
// root data (which carries "Lang") or a locale code; anything else means English.
func tFunc(ctx any, key string, args ...any) string {
	lang := i18n.Default
	switch v := ctx.(type) {
	case map[string]any:
		if l, ok := v["Lang"].(string); ok && l != "" {
			lang = l
		}
	case string:
		if v != "" {
			lang = v
		}
	}
	return translations().T(lang, key, args...)
}

// requestLocale picks the language for a request: the signed-in user's own
// choice, then the site default an administrator set, then the browser's
// Accept-Language, then English. Only languages with a catalog are returned.
//
// v2.62.2: the site default used to come AFTER the browser, so for anyone whose
// browser asks for English (which always exists) it never applied — choosing a
// default language in Settings visibly did nothing. An explicit default now
// wins over the browser; leaving it on "follow each browser" keeps the browser.
func (s *Server) requestLocale(r *http.Request, u *models.User) string {
	b := translations()
	if u != nil && u.Locale != "" && b.Has(u.Locale) {
		return u.Locale
	}
	if s != nil && s.DB != nil {
		if d := mustGetSetting(s.DB, settingDefaultLocale); d != "" && b.Has(d) {
			return d
		}
	}
	if r != nil {
		if l := b.Match(i18n.ParseAcceptLanguage(r.Header.Get("Accept-Language"))...); l != "" {
			return l
		}
	}
	return i18n.Default
}

// tr translates key for the request's language — for messages built in Go,
// such as the flash and error texts handed to a page through a redirect.
func (s *Server) tr(r *http.Request, key string, args ...any) string {
	return translations().T(s.requestLocale(r, s.currentUser(r)), key, args...)
}