package models import ( "gorm.io/gorm" "time" ) // Translation represents a polymorphic translation for any entity type Translation struct { BaseModel Title string `gorm:"size:255;not null"` Content string `gorm:"type:text"` // Markdown formatted content Description string `gorm:"type:text"` Language string `gorm:"size:50;not null"` Status TranslationStatus `gorm:"size:50;default:'draft'"` PublishedAt *time.Time // Polymorphic relationship TranslatableID uint `gorm:"not null"` TranslatableType string `gorm:"size:50;not null"` // "Work", "Author", "Book", "Country", etc. // Translator information TranslatorID *uint Translator *User `gorm:"foreignKey:TranslatorID"` // Additional metadata IsOriginalLanguage bool `gorm:"default:false"` AudioURL string `gorm:"size:512"` DateTranslated *time.Time } // TranslationField represents a specific translatable field type TranslationField struct { BaseModel TranslationID uint Translation *Translation `gorm:"foreignKey:TranslationID"` FieldName string `gorm:"size:100;not null"` // e.g., "title", "description", "biography" FieldValue string `gorm:"type:text;not null"` Language string `gorm:"size:50;not null"` } // TranslatableEntity interface for entities that can have translations type TranslatableEntity interface { GetID() uint GetType() string GetDefaultLanguage() string } // Persistence is owned by repositories; models remain persistence-agnostic // GetTranslatableFields returns the fields that can be translated for an entity type func GetTranslatableFields(entityType string) []string { fieldMappings := map[string][]string{ "Work": {"title", "content", "description"}, "Author": {"name", "biography"}, "Book": {"title", "description"}, "Country": {"name"}, "Publisher": {"name", "description"}, "Source": {"name", "description"}, } if fields, exists := fieldMappings[entityType]; exists { return fields } return []string{} } // BeforeSave hook for Translation to ensure title is set func (t *Translation) BeforeSave(tx *gorm.DB) error { if t.Title == "" { t.Title = "Untitled Translation" } return nil } // Interface implementations for existing models // Work implements TranslatableEntity func (w *Work) GetID() uint { return w.ID } func (w *Work) GetType() string { return "Work" } func (w *Work) GetDefaultLanguage() string { return w.Language } // Author implements TranslatableEntity func (a *Author) GetID() uint { return a.ID } func (a *Author) GetType() string { return "Author" } func (a *Author) GetDefaultLanguage() string { return a.Language } // Book implements TranslatableEntity func (b *Book) GetID() uint { return b.ID } func (b *Book) GetType() string { return "Book" } func (b *Book) GetDefaultLanguage() string { return b.Language } // Country implements TranslatableEntity func (c *Country) GetID() uint { return c.ID } func (c *Country) GetType() string { return "Country" } func (c *Country) GetDefaultLanguage() string { return c.Language } // Publisher implements TranslatableEntity func (p *Publisher) GetID() uint { return p.ID } func (p *Publisher) GetType() string { return "Publisher" } func (p *Publisher) GetDefaultLanguage() string { return p.Language } // Source implements TranslatableEntity func (s *Source) GetID() uint { return s.ID } func (s *Source) GetType() string { return "Source" } func (s *Source) GetDefaultLanguage() string { return s.Language }