Skip to content

Commit 2400139

Browse files
committed
fix: unable to translate (switch to DeepL iOS)
1 parent 26a9003 commit 2400139

File tree

2 files changed

+91
-123
lines changed

2 files changed

+91
-123
lines changed

translate/translate.go

+63-89
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
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-03-01 04:23:49
66
* @FilePath: /DeepLX/translate/translate.go
77
* @Telegram: https://t.me/missuo
88
* @GitHub: https://github.com/missuo
@@ -14,6 +14,8 @@ package translate
1414

1515
import (
1616
"bytes"
17+
"compress/flate"
18+
"compress/gzip"
1719
"fmt"
1820
"io"
1921
"net/http"
@@ -27,35 +29,28 @@ import (
2729
"github.com/tidwall/gjson"
2830
)
2931

30-
const baseURL = "https://www2.deepl.com/jsonrpc"
31-
3232
// makeRequest makes an HTTP request to DeepL API
33-
34-
func makeRequest(postData *PostData, urlMethod string, proxyURL string, dlSession string) (gjson.Result, error) {
35-
urlFull := fmt.Sprintf("%s?client=chrome-extension,1.28.0&method=%s", baseURL, urlMethod)
36-
33+
func makeRequest(postData *PostData, proxyURL string, dlSession string) (gjson.Result, error) {
34+
urlFull := "https://www2.deepl.com/jsonrpc"
3735
postStr := formatPostString(postData)
3836

3937
// Create a new req client
4038
client := req.C().SetTLSFingerprintRandomized()
4139

4240
// Set headers
4341
headers := http.Header{
44-
"Accept": []string{"*/*"},
45-
"Accept-Language": []string{"en-US,en;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh-HK;q=0.6,zh;q=0.5"},
46-
"Authorization": []string{"None"},
47-
"Cache-Control": []string{"no-cache"},
48-
"Content-Type": []string{"application/json"},
49-
"DNT": []string{"1"},
50-
"Origin": []string{"chrome-extension://cofdbpoegempjloogbagkncekinflcnj"},
51-
"Pragma": []string{"no-cache"},
52-
"Priority": []string{"u=1, i"},
53-
"Referer": []string{"https://www.deepl.com/"},
54-
"Sec-Fetch-Dest": []string{"empty"},
55-
"Sec-Fetch-Mode": []string{"cors"},
56-
"Sec-Fetch-Site": []string{"none"},
57-
"Sec-GPC": []string{"1"},
58-
"User-Agent": []string{"DeepLBrowserExtension/1.28.0 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"},
42+
"Content-Type": []string{"application/json"},
43+
"User-Agent": []string{"DeepL/1627620 CFNetwork/3826.500.62.2.1 Darwin/24.4.0"},
44+
"Accept": []string{"*/*"},
45+
"X-App-Os-Name": []string{"iOS"},
46+
"X-App-Os-Version": []string{"18.4.0"},
47+
"Accept-Language": []string{"en-US,en;q=0.9"},
48+
"Accept-Encoding": []string{"gzip, deflate, br"}, // Keep this!
49+
"X-App-Device": []string{"iPhone16,2"},
50+
"Referer": []string{"https://www.deepl.com/"},
51+
"X-Product": []string{"translator"},
52+
"X-App-Build": []string{"1627620"},
53+
"X-App-Version": []string{"25.1"},
5954
}
6055

6156
if dlSession != "" {
@@ -83,40 +78,28 @@ func makeRequest(postData *PostData, urlMethod string, proxyURL string, dlSessio
8378
}
8479

8580
var bodyReader io.Reader
86-
if resp.Header.Get("Content-Encoding") == "br" {
81+
contentEncoding := resp.Header.Get("Content-Encoding")
82+
switch contentEncoding {
83+
case "br":
8784
bodyReader = brotli.NewReader(resp.Body)
88-
} else {
85+
case "gzip":
86+
bodyReader, err = gzip.NewReader(resp.Body) // Use gzip.NewReader
87+
if err != nil {
88+
return gjson.Result{}, fmt.Errorf("failed to create gzip reader: %w", err)
89+
}
90+
case "deflate": // Less common, but good to handle
91+
bodyReader = flate.NewReader(resp.Body)
92+
default:
8993
bodyReader = resp.Body
9094
}
9195

9296
body, err := io.ReadAll(bodyReader)
9397
if err != nil {
94-
return gjson.Result{}, err
98+
return gjson.Result{}, fmt.Errorf("failed to read response body: %w", err)
9599
}
96100
return gjson.ParseBytes(body), nil
97101
}
98102

99-
// splitText splits the input text for translation
100-
func splitText(text string, tagHandling bool, proxyURL string, dlSession string) (gjson.Result, error) {
101-
postData := &PostData{
102-
Jsonrpc: "2.0",
103-
Method: "LMT_split_text",
104-
ID: getRandomNumber(),
105-
Params: Params{
106-
CommonJobParams: CommonJobParams{
107-
Mode: "translate",
108-
},
109-
Lang: Lang{
110-
LangUserSelected: "auto",
111-
},
112-
Texts: []string{text},
113-
TextType: map[bool]string{true: "richtext", false: "plaintext"}[tagHandling || isRichText(text)],
114-
},
115-
}
116-
117-
return makeRequest(postData, "LMT_split_text", proxyURL, dlSession)
118-
}
119-
120103
// TranslateByDeepLX performs translation using DeepL API
121104
func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string, proxyURL string, dlSession string) (DeepLXTranslationResult, error) {
122105
if text == "" {
@@ -126,6 +109,10 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
126109
}, nil
127110
}
128111

112+
if tagHandling == "" {
113+
tagHandling = "plaintext"
114+
}
115+
129116
// Split text by newlines and store them for later reconstruction
130117
textParts := strings.Split(text, "\n")
131118
var translatedParts []string
@@ -138,48 +125,25 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
138125
continue
139126
}
140127

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-
150128
// Get detected language if source language is auto
151129
if sourceLang == "auto" || sourceLang == "" {
152130
sourceLang = strings.ToUpper(whatlanggo.DetectLang(part).Iso6391())
153131
}
154132

155133
// Prepare jobs from split result
156134
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()}
166-
}
167-
if idx < len(chunks)-1 {
168-
contextAfter = []string{chunks[idx+1].Get("sentences.0.text").String()}
169-
}
170135

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-
}
136+
jobs = append(jobs, Job{
137+
Kind: "default",
138+
PreferredNumBeams: 4,
139+
RawEnContextBefore: []string{},
140+
RawEnContextAfter: []string{},
141+
Sentences: []Sentence{{
142+
Prefix: "",
143+
Text: text,
144+
ID: 0,
145+
}},
146+
})
183147

184148
hasRegionalVariant := false
185149
targetLangCode := targetLang
@@ -198,14 +162,19 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
198162
ID: id,
199163
Params: Params{
200164
CommonJobParams: CommonJobParams{
201-
Mode: "translate",
165+
Mode: "translate",
166+
Formality: "undefined",
167+
TranscribeAs: "romanize",
168+
AdvancedMode: false,
169+
TextType: tagHandling,
170+
WasSpoken: false,
202171
},
203172
Lang: Lang{
204-
SourceLangComputed: strings.ToUpper(sourceLang),
205-
TargetLang: strings.ToUpper(targetLangCode),
173+
SourceLangUserSelected: "auto",
174+
TargetLang: strings.ToUpper(targetLangCode),
175+
SourceLangComputed: strings.ToUpper(sourceLang),
206176
},
207177
Jobs: jobs,
208-
Priority: 1,
209178
Timestamp: getTimeStamp(getICount(part)),
210179
},
211180
}
@@ -218,21 +187,26 @@ func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string,
218187
Params: Params{
219188
CommonJobParams: CommonJobParams{
220189
Mode: "translate",
221-
RegionalVariant: map[bool]string{true: targetLang, false: ""}[hasRegionalVariant],
190+
Formality: "undefined",
191+
TranscribeAs: "romanize",
192+
AdvancedMode: false,
193+
TextType: tagHandling,
194+
WasSpoken: false,
195+
RegionalVariant: targetLang,
222196
},
223197
Lang: Lang{
224-
SourceLangComputed: strings.ToUpper(sourceLang),
225-
TargetLang: strings.ToUpper(targetLangCode),
198+
SourceLangUserSelected: "auto",
199+
TargetLang: strings.ToUpper(targetLangCode),
200+
SourceLangComputed: strings.ToUpper(sourceLang),
226201
},
227202
Jobs: jobs,
228-
Priority: 1,
229203
Timestamp: getTimeStamp(getICount(part)),
230204
},
231205
}
232206
}
233207

234208
// Make translation request
235-
result, err := makeRequest(postData, "LMT_handle_jobs", proxyURL, dlSession)
209+
result, err := makeRequest(postData, proxyURL, dlSession)
236210
if err != nil {
237211
return DeepLXTranslationResult{
238212
Code: http.StatusServiceUnavailable,

translate/types.go

+28-34
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: Vincent Young
33
* @Date: 2024-09-16 11:59:24
44
* @LastEditors: Vincent Yang
5-
* @LastEditTime: 2024-11-01 23:18:56
5+
* @LastEditTime: 2025-03-01 04:16:07
66
* @FilePath: /DeepLX/translate/types.go
77
* @Telegram: https://t.me/missuo
88
* @GitHub: https://github.com/missuo
@@ -14,14 +14,19 @@ package translate
1414

1515
// Lang represents the language settings for translation
1616
type Lang struct {
17-
SourceLangComputed string `json:"source_lang_computed,omitempty"`
18-
TargetLang string `json:"target_lang"`
19-
LangUserSelected string `json:"lang_user_selected,omitempty"`
17+
SourceLangUserSelected string `json:"source_lang_user_selected"` // Can be "auto"
18+
TargetLang string `json:"target_lang"`
19+
SourceLangComputed string `json:"source_lang_computed,omitempty"`
2020
}
2121

2222
// CommonJobParams represents common parameters for translation jobs
2323
type CommonJobParams struct {
24+
Formality string `json:"formality"` // Can be "undefined"
25+
TranscribeAs string `json:"transcribe_as"`
2426
Mode string `json:"mode"`
27+
WasSpoken bool `json:"wasSpoken"`
28+
AdvancedMode bool `json:"advancedMode"`
29+
TextType string `json:"textType"`
2530
RegionalVariant string `json:"regionalVariant,omitempty"`
2631
}
2732

@@ -45,10 +50,7 @@ type Job struct {
4550
type Params struct {
4651
CommonJobParams CommonJobParams `json:"commonJobParams"`
4752
Lang Lang `json:"lang"`
48-
Texts []string `json:"texts,omitempty"`
49-
TextType string `json:"textType,omitempty"`
50-
Jobs []Job `json:"jobs,omitempty"`
51-
Priority int `json:"priority,omitempty"`
53+
Jobs []Job `json:"jobs"`
5254
Timestamp int64 `json:"timestamp"`
5355
}
5456

@@ -60,49 +62,41 @@ type PostData struct {
6062
Params Params `json:"params"`
6163
}
6264

63-
// SplitTextResponse represents the response from text splitting
64-
type SplitTextResponse struct {
65-
Jsonrpc string `json:"jsonrpc"`
66-
ID int64 `json:"id"`
67-
Result struct {
68-
Lang struct {
69-
Detected string `json:"detected"`
70-
} `json:"lang"`
71-
Texts []struct {
72-
Chunks []struct {
73-
Sentences []struct {
74-
Prefix string `json:"prefix"`
75-
Text string `json:"text"`
76-
} `json:"sentences"`
77-
} `json:"chunks"`
78-
} `json:"texts"`
79-
} `json:"result"`
80-
}
81-
8265
// TranslationResponse represents the response from translation
8366
type TranslationResponse struct {
8467
Jsonrpc string `json:"jsonrpc"`
8568
ID int64 `json:"id"`
8669
Result struct {
8770
Translations []struct {
8871
Beams []struct {
89-
Sentences []struct {
90-
Text string `json:"text"`
91-
} `json:"sentences"`
72+
Sentences []SentenceResponse `json:"sentences"`
73+
NumSymbols int `json:"num_symbols"`
74+
RephraseVariant struct { // Added rephrase_variant
75+
Name string `json:"name"`
76+
} `json:"rephrase_variant"`
9277
} `json:"beams"`
78+
Quality string `json:"quality"` // Added quality
9379
} `json:"translations"`
94-
SourceLang string `json:"source_lang"`
95-
TargetLang string `json:"target_lang"`
80+
TargetLang string `json:"target_lang"`
81+
SourceLang string `json:"source_lang"`
82+
SourceLangIsConfident bool `json:"source_lang_is_confident"`
83+
DetectedLanguages map[string]interface{} `json:"detectedLanguages"` // Use interface{} for now
9684
} `json:"result"`
9785
}
9886

87+
// SentenceResponse is a helper struct for the response sentences
88+
type SentenceResponse struct {
89+
Text string `json:"text"`
90+
IDS []int `json:"ids"` // Added IDS
91+
}
92+
9993
// DeepLXTranslationResult represents the final translation result
10094
type DeepLXTranslationResult struct {
10195
Code int `json:"code"`
10296
ID int64 `json:"id"`
10397
Message string `json:"message,omitempty"`
104-
Data string `json:"data"`
105-
Alternatives []string `json:"alternatives"`
98+
Data string `json:"data"` // The primary translated text
99+
Alternatives []string `json:"alternatives"` // Other possible translations
106100
SourceLang string `json:"source_lang"`
107101
TargetLang string `json:"target_lang"`
108102
Method string `json:"method"`

0 commit comments

Comments
 (0)