Documentation
¶
Overview ¶
Package i18n provides minimal locale-keyed string lookup for the Kite MCP user-facing surfaces (landing page, briefing templates, RiskGuard rejection messages, OAuth login screen).
Design constraints (per the internal-100 sprint Item 2 brief):
- Leaf package — zero internal repo deps, so any package can import.
- JSON-file translation source under locales/ — version-controlled, auditable, no external CMS dependency.
- English fallback for missing keys (T(LocaleHI, k) returns en[k] when hi[k] is absent). Keeps the UI from rendering blank when a translator hasn't covered a string yet.
- Unknown-key passthrough — T(loc, k) returns the literal key when neither locale has it, surfacing missing translations during dev and not crashing in prod.
Locale resolution at runtime:
- Explicit query / cookie / user-pref (set via WithLocale on ctx)
- Accept-Language header (ParseAcceptLanguage)
- Default LocaleEN
Initial Hindi coverage: 30 strings across landing/briefing/RiskGuard/ OAuth — the most-visible surfaces for an Indian retail trader.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsSupported ¶
IsSupported reports whether the given locale string maps to a shipping translation set. Used by ParseAcceptLanguage and any cookie/ query-parameter validation.
func LoadError ¶
func LoadError() error
LoadError returns any error encountered while loading translation files at init. Callers (test helpers, startup health checks) should treat a non-nil return as a hard failure.
func T ¶
T returns the translated string for the given (locale, key) pair. Resolution order:
- translations[loc][key] if present and non-empty
- translations[en][key] (English fallback) if present and non-empty
- key itself (passthrough) so missing translations are visible
Args support is intentionally minimal: callers wanting interpolation should use the {placeholder} convention in the JSON value and strings.Replace at the call site, e.g.:
msg := i18n.T(loc, "briefing.morning.alerts_active")
msg = strings.Replace(msg, "{n}", strconv.Itoa(count), 1)
Avoiding fmt-style format-string interpolation here prevents the classic CWE-134 footgun and keeps translator-side templates free of Go-specific verbs.
func TFromContext ¶
TFromContext is sugar for T(LocaleFromContext(ctx), key).
Types ¶
type Locale ¶
type Locale string
Locale identifies a translation set. The string value must match the JSON filename under locales/ and the standard IETF BCP-47 language tag for client header / cookie negotiation.
func LocaleFromContext ¶
LocaleFromContext extracts the request-scoped locale, defaulting to LocaleEN when ctx has no locale value (e.g., default Go context, non-HTTP code paths).
func ParseAcceptLanguage ¶
ParseAcceptLanguage extracts the highest-q-value supported locale from a browser-style Accept-Language header. Returns LocaleEN for an empty header or a header containing only unsupported locales.
Spec compliance is partial — we honor q-values and exact / language tag matches but skip the long tail of fallback chains. For our 2-locale ship-set this is sufficient; expand later if we add a 3rd / 4th locale.
Examples:
"hi-IN,hi;q=0.9,en;q=0.8" -> hi (hi has higher implicit q=1) "en-US,en;q=0.9" -> en "fr-FR,fr;q=0.9" -> en (no fr translation; en fallback) "en-IN,hi;q=0.5" -> en (en has higher q) "" -> en (empty header; default)
func SupportedLocales ¶
func SupportedLocales() []Locale
SupportedLocales returns a copy of the supported-locale list. Callers (Accept-Language parser, Locale picker UI) should iterate this rather than hard-coding the set.