From 737e323fcb32ed3a95203c92e3d4de0e57eceda8 Mon Sep 17 00:00:00 2001 From: logikonline Date: Tue, 17 Mar 2026 21:24:05 -0400 Subject: [PATCH] perf(pages): parallelize bulk AI translation Run AI translations for multiple languages concurrently using goroutines and sync.WaitGroup. Protects shared counters with mutex. Significantly reduces total translation time when translating many languages. For example, translating 10 languages now takes ~10 seconds instead of ~100 seconds (assuming 10s per language). --- routers/web/repo/setting/pages.go | 79 +++++++++++++++++++------------ 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/routers/web/repo/setting/pages.go b/routers/web/repo/setting/pages.go index c0b72c819e..e91ea5d187 100644 --- a/routers/web/repo/setting/pages.go +++ b/routers/web/repo/setting/pages.go @@ -10,6 +10,7 @@ import ( "net/http" "slices" "strings" + "sync" pages_model "code.gitcaddy.com/server/v3/models/pages" repo_model "code.gitcaddy.com/server/v3/models/repo" @@ -1311,46 +1312,62 @@ func PagesLanguagesPost(ctx *context.Context) { if defaultLang == "" { defaultLang = "en" } - var successCount, failCount int + var ( + mu sync.Mutex + successCount int + failCount int + wg sync.WaitGroup + ) + repoID := ctx.Repo.Repository.ID + repo := ctx.Repo.Repository for _, lang := range config.I18n.Languages { if lang == defaultLang { continue } - translated, err := pages_service.TranslateLandingPageContent(ctx, ctx.Repo.Repository, config, lang) - if err != nil { - log.Error("AI translation failed for %s: %v", lang, err) - failCount++ - continue - } - existing, err := pages_model.GetTranslation(ctx, ctx.Repo.Repository.ID, lang) - if err != nil { - log.Error("GetTranslation failed for %s: %v", lang, err) - failCount++ - continue - } - if existing != nil { - existing.ConfigJSON = translated - existing.AutoGenerated = true - if err := pages_model.UpdateTranslation(ctx, existing); err != nil { - log.Error("UpdateTranslation failed for %s: %v", lang, err) + wg.Add(1) + go func(lang string) { + defer wg.Done() + translated, err := pages_service.TranslateLandingPageContent(ctx, repo, config, lang) + if err != nil { + log.Error("AI translation failed for %s: %v", lang, err) + mu.Lock() failCount++ - continue + mu.Unlock() + return } - } else { - t := &pages_model.Translation{ - RepoID: ctx.Repo.Repository.ID, - Lang: lang, - ConfigJSON: translated, - AutoGenerated: true, - } - if err := pages_model.CreateTranslation(ctx, t); err != nil { - log.Error("CreateTranslation failed for %s: %v", lang, err) + mu.Lock() + defer mu.Unlock() + existing, err := pages_model.GetTranslation(ctx, repoID, lang) + if err != nil { + log.Error("GetTranslation failed for %s: %v", lang, err) failCount++ - continue + return } - } - successCount++ + if existing != nil { + existing.ConfigJSON = translated + existing.AutoGenerated = true + if err := pages_model.UpdateTranslation(ctx, existing); err != nil { + log.Error("UpdateTranslation failed for %s: %v", lang, err) + failCount++ + return + } + } else { + t := &pages_model.Translation{ + RepoID: repoID, + Lang: lang, + ConfigJSON: translated, + AutoGenerated: true, + } + if err := pages_model.CreateTranslation(ctx, t); err != nil { + log.Error("CreateTranslation failed for %s: %v", lang, err) + failCount++ + return + } + } + successCount++ + }(lang) } + wg.Wait() if failCount == 0 { ctx.Flash.Success(ctx.Tr("repo.settings.pages.ai_translate_all_success", successCount)) } else {