package handlers import ( "net/http" "regexp" "strings" ) const postI18nColsSQL = ` COALESCE(p.text_zh,''), COALESCE(p.text_en,''), COALESCE(p.text_ja,''), COALESCE(p.text_ko,''), COALESCE(p.text_vi,''), COALESCE(p.text_id,''), COALESCE(p.text_ms,'')` const maxPostTextLen = 32768 const maxPostAttachments = 20 var postLinkRe = regexp.MustCompile(`https?://`) type postTextI18n struct { TextZh, TextEn, TextJa, TextKo, TextVi, TextId, TextMs string } type postLocalePayload struct { Text string `json:"text"` } // requestLangCode is the normalized locale from ?lang= or Accept-Language (zh, en, ja, …). func requestLangCode(r *http.Request) string { raw := strings.TrimSpace(r.URL.Query().Get("lang")) if raw == "" { raw = r.Header.Get("Accept-Language") } raw = strings.TrimSpace(strings.Split(raw, ",")[0]) if raw == "" { return "zh" } return translateNormalizePostLang(raw) } func (t postTextI18n) pick(r *http.Request) string { return pickLangField(r, t.TextZh, t.TextEn, t.TextJa, t.TextKo, t.TextVi, t.TextId, t.TextMs) } func (t postTextI18n) anyNonEmpty() bool { return strings.TrimSpace(t.TextZh) != "" || strings.TrimSpace(t.TextEn) != "" || strings.TrimSpace(t.TextJa) != "" || strings.TrimSpace(t.TextKo) != "" || strings.TrimSpace(t.TextVi) != "" || strings.TrimSpace(t.TextId) != "" || strings.TrimSpace(t.TextMs) != "" } func (t postTextI18n) legacyPrimary() string { if strings.TrimSpace(t.TextZh) != "" { return strings.TrimSpace(t.TextZh) } if strings.TrimSpace(t.TextEn) != "" { return strings.TrimSpace(t.TextEn) } return "" } func scanPostTextI18n(zh, en, ja, ko, vi, id, ms string) postTextI18n { return postTextI18n{TextZh: zh, TextEn: en, TextJa: ja, TextKo: ko, TextVi: vi, TextId: id, TextMs: ms} } func (t postTextI18n) toLocalizations() map[string]postLocalePayload { return map[string]postLocalePayload{ "zh": {Text: t.TextZh}, "en": {Text: t.TextEn}, "ja": {Text: t.TextJa}, "ko": {Text: t.TextKo}, "vi": {Text: t.TextVi}, "id": {Text: t.TextId}, "ms": {Text: t.TextMs}, } } func postTextHasLink(text string) bool { return postLinkRe.MatchString(text) } func truncatePostTexts(t postTextI18n) postTextI18n { tr := func(s string) string { s = strings.TrimSpace(s) if len(s) > maxPostTextLen { return s[:maxPostTextLen] } return s } t.TextZh = tr(t.TextZh) t.TextEn = tr(t.TextEn) t.TextJa = tr(t.TextJa) t.TextKo = tr(t.TextKo) t.TextVi = tr(t.TextVi) t.TextId = tr(t.TextId) t.TextMs = tr(t.TextMs) return t }