Files
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

120 lines
3.2 KiB
Go

package company
import (
"context"
"fmt"
"strings"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
// DefaultLanguage is the content-language fallback when unset.
const DefaultLanguage = "en"
// ContentLanguages is the allowlist for companies.language (AI/product content).
// Keep in sync with apps/web/src/lib/content-languages.ts.
var ContentLanguages = []string{
"en", "fr", "de", "es", "it", "nl", "pt", "pl",
"cs", "sk", "hu", "ro", "bg", "hr", "sl",
"sv", "da", "fi", "el", "et", "lv", "lt", "mt", "ga",
"ja", // CJK plug-in slot (Japanese)
}
// contentLanguageLabels are English display names for AI prompt injection.
// Keep in sync with apps/web/src/lib/content-languages.ts labels.
var contentLanguageLabels = map[string]string{
"en": "English",
"fr": "French",
"de": "German",
"es": "Spanish",
"it": "Italian",
"nl": "Dutch",
"pt": "Portuguese",
"pl": "Polish",
"cs": "Czech",
"sk": "Slovak",
"hu": "Hungarian",
"ro": "Romanian",
"bg": "Bulgarian",
"hr": "Croatian",
"sl": "Slovenian",
"sv": "Swedish",
"da": "Danish",
"fi": "Finnish",
"el": "Greek",
"et": "Estonian",
"lv": "Latvian",
"lt": "Lithuanian",
"mt": "Maltese",
"ga": "Irish",
"ja": "Japanese",
}
var contentLanguageSet map[string]struct{}
func init() {
contentLanguageSet = make(map[string]struct{}, len(ContentLanguages))
for _, code := range ContentLanguages {
contentLanguageSet[code] = struct{}{}
}
}
// NormalizeLanguage trims and lowercases a content-language code.
func NormalizeLanguage(raw string) string {
return strings.ToLower(strings.TrimSpace(raw))
}
// IsAllowedLanguage reports whether code is in ContentLanguages (after normalize).
func IsAllowedLanguage(raw string) bool {
_, ok := contentLanguageSet[NormalizeLanguage(raw)]
return ok
}
// ParseLanguage validates and normalizes a content-language code.
// Empty input returns DefaultLanguage when allowEmptyAsDefault is true;
// otherwise empty is an error (use for explicit PATCH language fields).
func ParseLanguage(raw string, allowEmptyAsDefault bool) (string, error) {
code := NormalizeLanguage(raw)
if code == "" {
if allowEmptyAsDefault {
return DefaultLanguage, nil
}
return "", fmt.Errorf("language is required")
}
if !IsAllowedLanguage(code) {
return "", fmt.Errorf("unsupported language %q", code)
}
return code, nil
}
// LanguageLabel returns the English display name for a content-language code
// (for AI prompt injection). Empty/unknown codes fall back to English.
func LanguageLabel(raw string) string {
code, err := ParseLanguage(raw, true)
if err != nil {
code = DefaultLanguage
}
if label, ok := contentLanguageLabels[code]; ok {
return label
}
return contentLanguageLabels[DefaultLanguage]
}
// LoadLanguage returns companies.language for companyID, or DefaultLanguage.
func LoadLanguage(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) string {
if pool == nil {
return DefaultLanguage
}
var raw string
err := pool.QueryRow(ctx, `SELECT COALESCE(language, '') FROM companies WHERE id = $1`, companyID).Scan(&raw)
if err != nil {
return DefaultLanguage
}
code, err := ParseLanguage(raw, true)
if err != nil {
return DefaultLanguage
}
return code
}