2
2
* @Author: Vincent Young
3
3
* @Date: 2024-09-16 11:59:24
4
4
* @LastEditors: Vincent Yang
5
- * @LastEditTime: 2025-01-20 17:09:59
5
+ * @LastEditTime: 2025-02-01 03:21:41
6
6
* @FilePath: /DeepLX/translate/translate.go
7
7
* @Telegram: https://t.me/missuo
8
8
* @GitHub: https://github.com/missuo
@@ -19,6 +19,7 @@ import (
19
19
"net/http"
20
20
"net/url"
21
21
"strings"
22
+ "sync"
22
23
23
24
"github.com/abadojack/whatlanggo"
24
25
"github.com/imroc/req/v3"
@@ -126,92 +127,89 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
126
127
}, nil
127
128
}
128
129
129
- // Split text by newlines and store them for later reconstruction
130
+ // Split text by newlines
130
131
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
- }
140
132
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
166
158
}
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
169
165
}
170
166
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
+ }
183
172
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
+ }
191
188
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
+ }
194
201
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
+ }
212
209
213
- if hasRegionalVariant {
214
- postData = & PostData {
210
+ // Prepare translation request
211
+ id := getRandomNumber ()
212
+ postData := & PostData {
215
213
Jsonrpc : "2.0" ,
216
214
Method : "LMT_handle_jobs" ,
217
215
ID : id ,
@@ -221,62 +219,82 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
221
219
RegionalVariant : map [bool ]string {true : targetLang , false : "" }[hasRegionalVariant ],
222
220
},
223
221
Lang : Lang {
224
- SourceLangComputed : strings .ToUpper (sourceLang ),
222
+ SourceLangComputed : strings .ToUpper (currentSourceLang ),
225
223
TargetLang : strings .ToUpper (targetLangCode ),
226
224
},
227
225
Jobs : jobs ,
228
226
Priority : 1 ,
229
- Timestamp : getTimeStamp (getICount (part )),
227
+ Timestamp : getTimeStamp (getICount (text )),
230
228
},
231
229
}
232
- }
233
230
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
252
236
}
253
- partTranslation = strings .TrimSpace (partTranslation )
254
237
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
259
245
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 () + " "
264
247
}
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
+ }
267
263
}
268
264
}
269
- }
270
265
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 {
272
291
return DeepLXTranslationResult {
273
292
Code : http .StatusServiceUnavailable ,
274
- Message : "Translation failed" ,
293
+ Message : result . err . Error () ,
275
294
}, nil
276
295
}
277
-
278
- translatedParts = append (translatedParts , partTranslation )
279
- allAlternatives = append (allAlternatives , partAlternatives )
296
+ translatedParts [result .index ] = result .translation
297
+ allAlternatives [result .index ] = result .alternatives
280
298
}
281
299
282
300
// Join all translated parts with newlines
@@ -298,17 +316,17 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
298
316
if i < len (alts ) {
299
317
altParts = append (altParts , alts [i ])
300
318
} else if len (translatedParts [j ]) == 0 {
301
- altParts = append (altParts , "" ) // Keep empty lines
319
+ altParts = append (altParts , "" )
302
320
} else {
303
- altParts = append (altParts , translatedParts [j ]) // Use main translation if no alternative
321
+ altParts = append (altParts , translatedParts [j ])
304
322
}
305
323
}
306
324
combinedAlternatives = append (combinedAlternatives , strings .Join (altParts , "\n " ))
307
325
}
308
326
309
327
return DeepLXTranslationResult {
310
328
Code : http .StatusOK ,
311
- ID : getRandomNumber (), // Using new ID for the complete translation
329
+ ID : getRandomNumber (),
312
330
Data : translatedText ,
313
331
Alternatives : combinedAlternatives ,
314
332
SourceLang : sourceLang ,
0 commit comments