package localization import ( "context" "errors" "tercul/internal/domain" "tercul/internal/platform/log" ) // Service resolves localized attributes using translations type Service interface { GetWorkContent(ctx context.Context, workID uint, preferredLanguage string) (string, error) GetAuthorBiography(ctx context.Context, authorID uint, preferredLanguage string) (string, error) } type service struct { translationRepo domain.TranslationRepository } func NewService(translationRepo domain.TranslationRepository) Service { return &service{translationRepo: translationRepo} } func (s *service) GetWorkContent(ctx context.Context, workID uint, preferredLanguage string) (string, error) { if workID == 0 { return "", errors.New("invalid work ID") } log.LogDebug("fetching translations for work", log.F("work_id", workID)) translations, err := s.translationRepo.ListByWorkID(ctx, workID) if err != nil { log.LogError("failed to fetch translations for work", log.F("work_id", workID), log.F("error", err)) return "", err } return pickContent(ctx, translations, preferredLanguage), nil } func (s *service) GetAuthorBiography(ctx context.Context, authorID uint, preferredLanguage string) (string, error) { if authorID == 0 { return "", errors.New("invalid author ID") } log.LogDebug("fetching translations for author", log.F("author_id", authorID)) translations, err := s.translationRepo.ListByEntity(ctx, "Author", authorID) if err != nil { log.LogError("failed to fetch translations for author", log.F("author_id", authorID), log.F("error", err)) return "", err } // Prefer Description from Translation as biography proxy var byLang *domain.Translation for i := range translations { tr := &translations[i] if tr.IsOriginalLanguage && tr.Description != "" { log.LogDebug("found original language biography for author", log.F("author_id", authorID), log.F("language", tr.Language)) return tr.Description, nil } if tr.Language == preferredLanguage && byLang == nil && tr.Description != "" { byLang = tr } } if byLang != nil { log.LogDebug("found preferred language biography for author", log.F("author_id", authorID), log.F("language", byLang.Language)) return byLang.Description, nil } // fallback to any non-empty description for i := range translations { if translations[i].Description != "" { log.LogDebug("found fallback biography for author", log.F("author_id", authorID), log.F("language", translations[i].Language)) return translations[i].Description, nil } } log.LogDebug("no biography found for author", log.F("author_id", authorID)) return "", nil } func pickContent(ctx context.Context, translations []domain.Translation, preferredLanguage string) string { var byLang *domain.Translation for i := range translations { tr := &translations[i] if tr.IsOriginalLanguage { log.LogDebug("found original language content", log.F("language", tr.Language)) return tr.Content } if tr.Language == preferredLanguage && byLang == nil { byLang = tr } } if byLang != nil { log.LogDebug("found preferred language content", log.F("language", byLang.Language)) return byLang.Content } if len(translations) > 0 { log.LogDebug("found fallback content", log.F("language", translations[0].Language)) return translations[0].Content } log.LogDebug("no content found") return "" }