22 * @Author: Vincent Young
33 * @Date: 2024-09-16 11:59:24
44 * @LastEditors: Vincent Yang
5- * @LastEditTime: 2025-01-20 17:09:59
5+ * @LastEditTime: 2025-02-01 03:21:41
66 * @FilePath: /DeepLX/translate/translate.go
77 * @Telegram: https://t.me/missuo
88 * @GitHub: https://github.com/missuo
@@ -19,6 +19,7 @@ import (
1919 "net/http"
2020 "net/url"
2121 "strings"
22+ "sync"
2223
2324 "github.com/abadojack/whatlanggo"
2425 "github.com/imroc/req/v3"
@@ -126,92 +127,89 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
126127 }, nil
127128 }
128129
129- // Split text by newlines and store them for later reconstruction
130+ // Split text by newlines
130131 textParts := strings .Split (text , "\n " )
131- var translatedParts []string
132- var allAlternatives [][]string // Store alternatives for each part
133-
134- for _ , part := range textParts {
135- if strings .TrimSpace (part ) == "" {
136- translatedParts = append (translatedParts , "" )
137- allAlternatives = append (allAlternatives , []string {"" })
138- continue
139- }
140132
141- // Split text first
142- splitResult , err := splitText ( part , tagHandling == "html" || tagHandling == "xml" , proxyURL , dlSession )
143- if err != nil {
144- return DeepLXTranslationResult {
145- Code : http . StatusServiceUnavailable ,
146- Message : err . Error (),
147- }, nil
148- }
149-
150- // Get detected language if source language is auto
151- if sourceLang == "auto" || sourceLang == "" {
152- sourceLang = strings . ToUpper ( whatlanggo . DetectLang ( part ). Iso6391 ())
153- }
154-
155- // Prepare jobs from split result
156- var jobs [] Job
157- chunks := splitResult . Get ( "result.texts.0.chunks" ). Array ()
158- for idx , chunk := range chunks {
159- sentence := chunk . Get ( "sentences.0" )
160-
161- // Handle context
162- contextBefore := [] string {}
163- contextAfter := []string {}
164- if idx > 0 {
165- contextBefore = [] string { chunks [ idx - 1 ]. Get ( "sentences.0.text" ). String ()}
133+ // Create channels for results
134+ type translationResult struct {
135+ index int
136+ translation string
137+ alternatives [] string
138+ err error
139+ }
140+ results := make ( chan translationResult , len ( textParts ))
141+
142+ // Create a wait group to track all goroutines
143+ var wg sync. WaitGroup
144+
145+ // Launch goroutines for each text part
146+ for i := range textParts {
147+ wg . Add ( 1 )
148+ go func ( index int , text string ) {
149+ defer wg . Done ()
150+
151+ if strings . TrimSpace ( text ) == "" {
152+ results <- translationResult {
153+ index : index ,
154+ translation : "" ,
155+ alternatives : []string {"" },
156+ }
157+ return
166158 }
167- if idx < len (chunks )- 1 {
168- contextAfter = []string {chunks [idx + 1 ].Get ("sentences.0.text" ).String ()}
159+
160+ // Split text first
161+ splitResult , err := splitText (text , tagHandling == "html" || tagHandling == "xml" , proxyURL , dlSession )
162+ if err != nil {
163+ results <- translationResult {index : index , err : err }
164+ return
169165 }
170166
171- jobs = append (jobs , Job {
172- Kind : "default" ,
173- PreferredNumBeams : 4 ,
174- RawEnContextBefore : contextBefore ,
175- RawEnContextAfter : contextAfter ,
176- Sentences : []Sentence {{
177- Prefix : sentence .Get ("prefix" ).String (),
178- Text : sentence .Get ("text" ).String (),
179- ID : idx + 1 ,
180- }},
181- })
182- }
167+ // Get detected language if source language is auto
168+ currentSourceLang := sourceLang
169+ if currentSourceLang == "auto" || currentSourceLang == "" {
170+ currentSourceLang = strings .ToUpper (whatlanggo .DetectLang (text ).Iso6391 ())
171+ }
183172
184- hasRegionalVariant := false
185- targetLangCode := targetLang
186- targetLangParts := strings .Split (targetLang , "-" )
187- if len (targetLangParts ) > 1 {
188- targetLangCode = targetLangParts [0 ]
189- hasRegionalVariant = true
190- }
173+ // Prepare jobs from split result
174+ var jobs []Job
175+ chunks := splitResult .Get ("result.texts.0.chunks" ).Array ()
176+ for idx , chunk := range chunks {
177+ sentence := chunk .Get ("sentences.0" )
178+
179+ // Handle context
180+ contextBefore := []string {}
181+ contextAfter := []string {}
182+ if idx > 0 {
183+ contextBefore = []string {chunks [idx - 1 ].Get ("sentences.0.text" ).String ()}
184+ }
185+ if idx < len (chunks )- 1 {
186+ contextAfter = []string {chunks [idx + 1 ].Get ("sentences.0.text" ).String ()}
187+ }
191188
192- // Prepare translation request
193- id := getRandomNumber ()
189+ jobs = append (jobs , Job {
190+ Kind : "default" ,
191+ PreferredNumBeams : 4 ,
192+ RawEnContextBefore : contextBefore ,
193+ RawEnContextAfter : contextAfter ,
194+ Sentences : []Sentence {{
195+ Prefix : sentence .Get ("prefix" ).String (),
196+ Text : sentence .Get ("text" ).String (),
197+ ID : idx + 1 ,
198+ }},
199+ })
200+ }
194201
195- postData := & PostData {
196- Jsonrpc : "2.0" ,
197- Method : "LMT_handle_jobs" ,
198- ID : id ,
199- Params : Params {
200- CommonJobParams : CommonJobParams {
201- Mode : "translate" ,
202- },
203- Lang : Lang {
204- SourceLangComputed : strings .ToUpper (sourceLang ),
205- TargetLang : strings .ToUpper (targetLangCode ),
206- },
207- Jobs : jobs ,
208- Priority : 1 ,
209- Timestamp : getTimeStamp (getICount (part )),
210- },
211- }
202+ hasRegionalVariant := false
203+ targetLangCode := targetLang
204+ targetLangParts := strings .Split (targetLang , "-" )
205+ if len (targetLangParts ) > 1 {
206+ targetLangCode = targetLangParts [0 ]
207+ hasRegionalVariant = true
208+ }
212209
213- if hasRegionalVariant {
214- postData = & PostData {
210+ // Prepare translation request
211+ id := getRandomNumber ()
212+ postData := & PostData {
215213 Jsonrpc : "2.0" ,
216214 Method : "LMT_handle_jobs" ,
217215 ID : id ,
@@ -221,62 +219,82 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
221219 RegionalVariant : map [bool ]string {true : targetLang , false : "" }[hasRegionalVariant ],
222220 },
223221 Lang : Lang {
224- SourceLangComputed : strings .ToUpper (sourceLang ),
222+ SourceLangComputed : strings .ToUpper (currentSourceLang ),
225223 TargetLang : strings .ToUpper (targetLangCode ),
226224 },
227225 Jobs : jobs ,
228226 Priority : 1 ,
229- Timestamp : getTimeStamp (getICount (part )),
227+ Timestamp : getTimeStamp (getICount (text )),
230228 },
231229 }
232- }
233230
234- // Make translation request
235- result , err := makeRequest (postData , "LMT_handle_jobs" , proxyURL , dlSession )
236- if err != nil {
237- return DeepLXTranslationResult {
238- Code : http .StatusServiceUnavailable ,
239- Message : err .Error (),
240- }, nil
241- }
242-
243- // Process translation results
244- var partTranslation string
245- var partAlternatives []string
246-
247- translations := result .Get ("result.translations" ).Array ()
248- if len (translations ) > 0 {
249- // Process main translation
250- for _ , translation := range translations {
251- partTranslation += translation .Get ("beams.0.sentences.0.text" ).String () + " "
231+ // Make translation request
232+ result , err := makeRequest (postData , "LMT_handle_jobs" , proxyURL , dlSession )
233+ if err != nil {
234+ results <- translationResult {index : index , err : err }
235+ return
252236 }
253- partTranslation = strings .TrimSpace (partTranslation )
254237
255- // Process alternatives
256- numBeams := len (translations [0 ].Get ("beams" ).Array ())
257- for i := 1 ; i < numBeams ; i ++ { // Start from 1 since 0 is the main translation
258- var altText string
238+ // Process translation results
239+ var partTranslation string
240+ var partAlternatives []string
241+
242+ translations := result .Get ("result.translations" ).Array ()
243+ if len (translations ) > 0 {
244+ // Process main translation
259245 for _ , translation := range translations {
260- beams := translation .Get ("beams" ).Array ()
261- if i < len (beams ) {
262- altText += beams [i ].Get ("sentences.0.text" ).String () + " "
263- }
246+ partTranslation += translation .Get ("beams.0.sentences.0.text" ).String () + " "
264247 }
265- if altText != "" {
266- partAlternatives = append (partAlternatives , strings .TrimSpace (altText ))
248+ partTranslation = strings .TrimSpace (partTranslation )
249+
250+ // Process alternatives
251+ numBeams := len (translations [0 ].Get ("beams" ).Array ())
252+ for i := 1 ; i < numBeams ; i ++ {
253+ var altText string
254+ for _ , translation := range translations {
255+ beams := translation .Get ("beams" ).Array ()
256+ if i < len (beams ) {
257+ altText += beams [i ].Get ("sentences.0.text" ).String () + " "
258+ }
259+ }
260+ if altText != "" {
261+ partAlternatives = append (partAlternatives , strings .TrimSpace (altText ))
262+ }
267263 }
268264 }
269- }
270265
271- if partTranslation == "" {
266+ if partTranslation == "" {
267+ results <- translationResult {index : index , err : fmt .Errorf ("translation failed" )}
268+ return
269+ }
270+
271+ results <- translationResult {
272+ index : index ,
273+ translation : partTranslation ,
274+ alternatives : partAlternatives ,
275+ }
276+ }(i , textParts [i ])
277+ }
278+
279+ // Close results channel when all goroutines are done
280+ go func () {
281+ wg .Wait ()
282+ close (results )
283+ }()
284+
285+ // Collect results maintaining original order
286+ translatedParts := make ([]string , len (textParts ))
287+ allAlternatives := make ([][]string , len (textParts ))
288+
289+ for result := range results {
290+ if result .err != nil {
272291 return DeepLXTranslationResult {
273292 Code : http .StatusServiceUnavailable ,
274- Message : "Translation failed" ,
293+ Message : result . err . Error () ,
275294 }, nil
276295 }
277-
278- translatedParts = append (translatedParts , partTranslation )
279- allAlternatives = append (allAlternatives , partAlternatives )
296+ translatedParts [result .index ] = result .translation
297+ allAlternatives [result .index ] = result .alternatives
280298 }
281299
282300 // Join all translated parts with newlines
@@ -298,17 +316,17 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
298316 if i < len (alts ) {
299317 altParts = append (altParts , alts [i ])
300318 } else if len (translatedParts [j ]) == 0 {
301- altParts = append (altParts , "" ) // Keep empty lines
319+ altParts = append (altParts , "" )
302320 } else {
303- altParts = append (altParts , translatedParts [j ]) // Use main translation if no alternative
321+ altParts = append (altParts , translatedParts [j ])
304322 }
305323 }
306324 combinedAlternatives = append (combinedAlternatives , strings .Join (altParts , "\n " ))
307325 }
308326
309327 return DeepLXTranslationResult {
310328 Code : http .StatusOK ,
311- ID : getRandomNumber (), // Using new ID for the complete translation
329+ ID : getRandomNumber (),
312330 Data : translatedText ,
313331 Alternatives : combinedAlternatives ,
314332 SourceLang : sourceLang ,
0 commit comments