// Example for use of GNU gettext.
// This file is in the public domain.

// Source code of a Go web server showing the use of a multi-locale API.


package main

import (
	// Documentation: https://pkg.go.dev/fmt
	"fmt"
	// Documentation: https://pkg.go.dev/github.com/leonelquinteros/gotext
	"github.com/leonelquinteros/gotext"
	// Other Go packages
	"context"
	"log"
	"net/http"
	"strings"
)

var localizer_table map[string]*gotext.Locale

// key under which to store the language in the context
const langKey string = "userLanguage"

// Middleware to extract language from request and store in context
func languageMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		acceptLang := r.Header.Get("Accept-Language") // Extract language from header
		// Spec: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language
		lang := "en" // Default to English
		if acceptLang != "" {
			for _, l := range strings.Split(acceptLang, ",") {
				l = strings.TrimSpace(strings.Split(l, ";")[0]) // Remove quality values
				if _, exists := localizer_table[l]; exists {
					lang = l
					break
				}
			}
		}

		// Store language in the context
		ctx := context.WithValue(r.Context(), langKey, lang)

		// Pass request with new context to the next handler
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// Handler that retrieves the per-goroutine language from the context
func handler(w http.ResponseWriter, r *http.Request) {
	// Retrieve language from the context
	lang, _ := r.Context().Value(langKey).(string)

	fmt.Fprintf(w, "Detected language: %s\n", lang)

	localizer := localizer_table[lang]

	fmt.Fprintln(w, localizer.Get("Hello, world!"))
	fmt.Fprintln(w, localizer.Get("Hello %s", "Dolly"))
}

func main() {
	// Preload all the existing translations into the localizer_table.
	// This leads to faster response times than allocating the localizer
	// lazily, for each HTTP request.
	localizer_table = make(map[string]*gotext.Locale)
	for _, language := range []string {
			"en_US",
			"ast_ES",
			"bg_BG",
			"ca_ES",
			"cs_CZ",
			"da_DK",
			"de_DE",
			"el_GR",
			"eo",
			"es_ES",
			"fi_FI",
			"fr_FR",
			"ga_IE",
			"gl_ES",
			"hr_HR",
			"hu_HU",
			"id_ID",
			"it_IT",
			"ja_JP",
			"ka_GE",
			"ky_KG",
			"lv_LV",
			"ms_MY",
			"mt_MT",
			"nb_NO",
			"nl_NL",
			"nn_NO",
			"pl_PL",
			"pt_PT",
			"pt_BR",
			"ro_RO",
			"ru_RU",
			"sk_SK",
			"sl_SI",
			"sq_AL",
			"sr_RS",
			"sv_SE",
			"ta_IN",
			"tr_TR",
			"uk_UA",
			"vi_VN",
			"zh_CN",
			"zh_HK",
			"zh_TW",
		} {
		// Specify localedir, locale.
		localizer := gotext.NewLocale("@localedir@", language)
		// Specify domain.
		localizer.AddDomain("hello-go-http")
		localizer_table[strings.Split(language, "_")[0]] = localizer
	}

	mux := http.NewServeMux()
	mux.Handle("/", languageMiddleware(http.HandlerFunc(handler)))

	port := 8080
	fmt.Printf("Server listening on port %d\n", port)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), mux))
}
