Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TencentService Support #240

Merged
merged 38 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
1809ee7
Add basic support for CaiyunService
Kyle-Ye Nov 6, 2023
da78dee
Add basic support for CaiyunService
Kyle-Ye Nov 6, 2023
3d17eab
feat: initiate Tencent Translate support
Jerry23011 Nov 26, 2023
e65aabf
feat: continue building Tencent Translate
Jerry23011 Nov 26, 2023
9487372
fix: error when detecting unsupported languages in transType
Jerry23011 Nov 26, 2023
2322fd9
style: code formatting
Jerry23011 Nov 26, 2023
79f0b29
feat: proceed to Authentication header
Jerry23011 Nov 26, 2023
4f75dff
fix: re-add TencentAPIKek
Jerry23011 Nov 28, 2023
7ba3b85
Fix header issue
Kyle-Ye Nov 6, 2023
1a49e05
fix: remove duplicated EZTencentAPIKey
tisfeng Nov 28, 2023
e2aa439
perf: optimize logic in TencentTranslateType.swift
Jerry23011 Nov 29, 2023
ae63db4
perf: optimize and localize error handling in unsupported languages
Jerry23011 Nov 29, 2023
a6615e3
perf(UI): add English localization for Tencent Translate
Jerry23011 Nov 29, 2023
1fb0466
perf: optimize MMOrderedDictionary logic
Jerry23011 Nov 29, 2023
9424bda
perf(UI): revert TMT icon
Jerry23011 Nov 29, 2023
f2d07aa
perf: initialize support for secrets customization
Jerry23011 Nov 30, 2023
3e67fe7
perf: implement demo for authentication
Jerry23011 Nov 30, 2023
e105749
fix: proper json decoding
Jerry23011 Nov 30, 2023
e944ac3
feat: implement secrets customization
Jerry23011 Nov 30, 2023
7e224ee
style: format code
Jerry23011 Nov 30, 2023
06e9fb0
perf: add self support language
Jerry23011 Dec 1, 2023
e8baf87
fix: build error
Jerry23011 Dec 1, 2023
f03f9e7
perf(UI): adopt official name of Tencent Translate
Jerry23011 Dec 1, 2023
ec5bc26
perf: create headerAuth func for authorization
Jerry23011 Dec 1, 2023
93a9176
perf(UI): delete Tencent TTS in dropdown
Jerry23011 Dec 2, 2023
d884980
refactor: improve tencent sign
tisfeng Dec 2, 2023
31da701
refractor: improve tencent sign
Jerry23011 Dec 2, 2023
693be50
fix: tencent api endpoint
Jerry23011 Dec 2, 2023
3abdd7c
Revert "perf: add self support language"
Jerry23011 Dec 2, 2023
8989471
perf: update handling of language
Jerry23011 Dec 2, 2023
b53cdb8
fix: correct supportedTypes
tisfeng Dec 3, 2023
751e723
style: format code
Jerry23011 Dec 3, 2023
5ec8182
perf: prepares TencentSigning for other services
Jerry23011 Dec 3, 2023
43016da
perf: enable tencent from == to
tisfeng Dec 3, 2023
4065085
perf: add missing traditional Chinese target language
tisfeng Dec 3, 2023
2848e10
perf: improve tencent error message
tisfeng Dec 3, 2023
2e49e6f
perf: map error response --> Response
tisfeng Dec 3, 2023
2b0a378
Merge branch 'dev' into tencent-translate
tisfeng Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Easydict.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@
03F639952AA6CFBB009B9914 /* EZBingConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 03F639942AA6CFBB009B9914 /* EZBingConfig.m */; };
03FD68BB2B1DC59600FD388E /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 03FD68BA2B1DC59600FD388E /* CryptoSwift */; };
03FD68BE2B1E151A00FD388E /* String+EncryptAES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FD68BD2B1E151A00FD388E /* String+EncryptAES.swift */; };
03FB3EDD2B1B405B004C3238 /* sign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FB3EDC2B1B405B004C3238 /* sign.swift */; };
03FB3EDD2B1B405B004C3238 /* TencentSigning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FB3EDC2B1B405B004C3238 /* TencentSigning.swift */; };
17BCAEF72B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF52B0DFF9000A7D372 /* EZNiuTransTranslateResponse.m */; };
17BCAEF82B0DFF9000A7D372 /* EZNiuTransTranslate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17BCAEF62B0DFF9000A7D372 /* EZNiuTransTranslate.m */; };
2721E4D02AFE920700A059AC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 2721E4CF2AFE920700A059AC /* Alamofire */; };
Expand All @@ -225,6 +227,9 @@
62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 62ED29A12B15F1F500901F51 /* EZWrapView.m */; };
A0B65CA0F31AC8ECFB8347CC /* Pods_EasydictTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 378E73A7EA8FC8FB9C975A63 /* Pods_EasydictTests.framework */; };
B87AC7E36367075BA5D13234 /* Pods_Easydict.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6372B33DFF803C7096A82250 /* Pods_Easydict.framework */; };
C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01E82B12B3C80025EE8E /* TencentService.swift */; };
C4DD01EB2B12BA250025EE8E /* TencentResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01EA2B12BA250025EE8E /* TencentResponse.swift */; };
C4DD01ED2B12BE9B0025EE8E /* TencentTranslateType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4DD01EC2B12BE9B0025EE8E /* TencentTranslateType.swift */; };
C4DE3D6D2AC00EB500C2B85D /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = C4DE3D6C2AC00EB500C2B85D /* Localizable.xcstrings */; };
C98CAE75239F4619005F7DCA /* EasydictHelper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = C90BE309239F38EB00ADE88B /* EasydictHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -641,6 +646,8 @@
03F639932AA6CFBB009B9914 /* EZBingConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EZBingConfig.h; sourceTree = "<group>"; };
03F639942AA6CFBB009B9914 /* EZBingConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EZBingConfig.m; sourceTree = "<group>"; };
03FD68BD2B1E151A00FD388E /* String+EncryptAES.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+EncryptAES.swift"; sourceTree = "<group>"; };
03FB3EDC2B1B405B004C3238 /* sign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = sign.swift; sourceTree = "<group>"; };
03FB3EDC2B1B405B004C3238 /* TencentSigning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentSigning.swift; sourceTree = "<group>"; };
06E15747A7BD34D510ADC6A8 /* Pods-Easydict.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.debug.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.debug.xcconfig"; sourceTree = "<group>"; };
17BCAEF32B0DFF9000A7D372 /* EZNiuTransTranslateResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslateResponse.h; sourceTree = "<group>"; };
17BCAEF42B0DFF9000A7D372 /* EZNiuTransTranslate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZNiuTransTranslate.h; sourceTree = "<group>"; };
Expand All @@ -667,6 +674,9 @@
6372B33DFF803C7096A82250 /* Pods_Easydict.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Easydict.framework; sourceTree = BUILT_PRODUCTS_DIR; };
91E3E579C6DB88658B4BB102 /* Pods-Easydict.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Easydict.release.xcconfig"; path = "Target Support Files/Pods-Easydict/Pods-Easydict.release.xcconfig"; sourceTree = "<group>"; };
A230E9A2358C7FBC7FB26189 /* Pods-EasydictTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EasydictTests.debug.xcconfig"; path = "Target Support Files/Pods-EasydictTests/Pods-EasydictTests.debug.xcconfig"; sourceTree = "<group>"; };
C4DD01E82B12B3C80025EE8E /* TencentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentService.swift; sourceTree = "<group>"; };
C4DD01EA2B12BA250025EE8E /* TencentResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentResponse.swift; sourceTree = "<group>"; };
C4DD01EC2B12BE9B0025EE8E /* TencentTranslateType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentTranslateType.swift; sourceTree = "<group>"; };
C4DE3D6C2AC00EB500C2B85D /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = Localizable.xcstrings; path = Easydict/App/Localizable.xcstrings; sourceTree = SOURCE_ROOT; };
C4DE3D6E2AC00EB500C2B85D /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/Main.xcstrings; sourceTree = "<group>"; };
C90BE309239F38EB00ADE88B /* EasydictHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EasydictHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1172,6 +1182,7 @@
children = (
17BCAEF22B0DFF9000A7D372 /* Niutrans */,
2746AEBF2AF95040005FE0A1 /* Caiyun */,
C4DD01E72B12B3B00025EE8E /* Tencent */,
6220AD582A8280E800BBFB52 /* Bing */,
0399C6A929A8608000B4AFCC /* OpenAI */,
03F14A382956011400CB7379 /* Volcano */,
Expand Down Expand Up @@ -1941,6 +1952,17 @@
name = "Recovered References";
sourceTree = "<group>";
};
C4DD01E72B12B3B00025EE8E /* Tencent */ = {
isa = PBXGroup;
children = (
C4DD01E82B12B3C80025EE8E /* TencentService.swift */,
C4DD01EA2B12BA250025EE8E /* TencentResponse.swift */,
C4DD01EC2B12BE9B0025EE8E /* TencentTranslateType.swift */,
03FB3EDC2B1B405B004C3238 /* TencentSigning.swift */,
);
path = Tencent;
sourceTree = "<group>";
};
C99EEB0F2385796700FEE666 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2250,6 +2272,7 @@
03B0232E29231FA6001C7E63 /* MMCrashSignalExceptionHandler.m in Sources */,
03BDA7C42A26DA280079D04F /* NSDictionary+RubyDescription.m in Sources */,
62ED29A22B15F1F500901F51 /* EZWrapView.m in Sources */,
C4DD01EB2B12BA250025EE8E /* TencentResponse.swift in Sources */,
036A0DB82AD8403A006E6D4F /* NSString+EZHandleInputText.m in Sources */,
03BDA7C12A26DA280079D04F /* XPMArgumentParser.m in Sources */,
03B0231329231FA6001C7E63 /* NSView+HiddenDebug.m in Sources */,
Expand Down Expand Up @@ -2350,6 +2373,7 @@
039B694F2A9D9F370063709D /* EZWebViewManager.m in Sources */,
03D747432A07FB150006CD77 /* EZError.m in Sources */,
03B0231629231FA6001C7E63 /* SnipFocusView.m in Sources */,
03FB3EDD2B1B405B004C3238 /* TencentSigning.swift in Sources */,
03B0230329231FA6001C7E63 /* EZResultView.m in Sources */,
03CAB9552ADBF0FF00DA94A3 /* EZSystemUtility.m in Sources */,
03BDA7C32A26DA280079D04F /* NSArray+XPMArgumentsNormalizer.m in Sources */,
Expand All @@ -2376,13 +2400,15 @@
03B0233129231FA6001C7E63 /* MMCrash.m in Sources */,
03B0232629231FA6001C7E63 /* NSAttributedString+MM.m in Sources */,
03542A402937B3C900C34C33 /* EZOCRResult.m in Sources */,
C4DD01E92B12B3C80025EE8E /* TencentService.swift in Sources */,
036A0DBB2AD941F9006E6D4F /* EZReplaceTextButton.m in Sources */,
03DC7C662A3CA465000BF7C9 /* HWSegmentedControl.m in Sources */,
03B022E929231FA6001C7E63 /* AppDelegate.m in Sources */,
03B0232729231FA6001C7E63 /* NSColor+MM.m in Sources */,
03B0233529231FA6001C7E63 /* MMFileLogFormatter.m in Sources */,
03DC38C1292CC97900922CB2 /* EZServiceInfo.m in Sources */,
03B0232A29231FA6001C7E63 /* NSColor+MyColors.m in Sources */,
C4DD01ED2B12BE9B0025EE8E /* TencentTranslateType.swift in Sources */,
03D043562928940500E7559E /* EZBaseQueryWindow.m in Sources */,
03BDA7B92A26DA280079D04F /* NSProcessInfo+XPMArgumentParser.m in Sources */,
03542A4F2937B64B00C34C33 /* EZYoudaoOCRResponse.m in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions Easydict/App/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,23 @@
}
}
},
"tencent_translate" : {
"comment" : "The name of Tencent Translate",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Tencent Translate"
}
},
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "腾讯翻译君"
}
}
}
},
"toggle_languages" : {
"localizations" : {
"en" : {
Jerry23011 marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
3 changes: 2 additions & 1 deletion Easydict/Feature/Service/Model/EZConstKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ static NSString *const EZDeepLAuthKey = @"EZDeepLAuthKey";
static NSString *const EZBingCookieKey = @"EZBingCookieKey";
static NSString *const EZNiuTransAPIKey = @"EZNiuTransAPIKey";
static NSString *const EZCaiyunToken = @"EZCaiyunToken";

static NSString *const EZTencentSecretId = @"EZTencentSecretId";
static NSString *const EZTencentSecretKey = @"EZTencentSecretKey";

@interface EZConstKey : NSObject

Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZEnumTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ FOUNDATION_EXPORT EZServiceType const EZServiceTypeAppleDictionary;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeBing;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeNiuTrans;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeCaiyun;
FOUNDATION_EXPORT EZServiceType const EZServiceTypeTencent;

FOUNDATION_EXPORT NSString *const EZQueryTextTypeKey;
FOUNDATION_EXPORT NSString *const EZIntelligentQueryTextTypeKey;
Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZEnumTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
NSString *const EZServiceTypeBing = @"Bing";
NSString *const EZServiceTypeNiuTrans = @"NiuTrans";
NSString *const EZServiceTypeCaiyun = @"Caiyun";
NSString *const EZServiceTypeTencent = @"Tencent";

NSString *const EZServiceTypeAppleDictionary = @"AppleDictionary";

Expand Down
1 change: 1 addition & 0 deletions Easydict/Feature/Service/Model/EZServiceTypes.m
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ + (instancetype)allocWithZone:(struct _NSZone *)zone {
EZServiceTypeVolcano, [EZVolcanoTranslate class],
EZServiceTypeNiuTrans, [EZNiuTransTranslate class],
EZServiceTypeCaiyun, [EZCaiyunService class],
EZServiceTypeTencent, [EZTencentService class],
nil];
return allServiceDict;
}
Expand Down
60 changes: 60 additions & 0 deletions Easydict/Feature/Service/Tencent/TencentResponse.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// TencentResponse.swift
// Easydict
//
// Created by Jerry on 2023-11-25.
// Copyright © 2023 izual. All rights reserved.
//

import Foundation

struct TencentResponse: Codable {
struct Response: Codable {
var RequestId: String
var Source: String
var Target: String
var TargetText: String
}

var Response: Response
}

/**
{
"Response": {
"Error": {
"Code": "InvalidParameterValue",
"Message": "不支持的语种:hi_to_zh"
},
"RequestId": "eb6d17f2-6771-4653-af6f-6b2edbf07294"
}
}
*/
struct TencentErrorResponse: Codable {
struct Response: Codable {
var error: Error
var requestId: String

// CodingKeys 枚举用于映射字段名
private enum CodingKeys: String, CodingKey {
case error = "Error" // error --> Error
case requestId = "RequestId" // requestId --> RequestId
}
}

struct Error: Codable {
var code: String
var message: String

private enum CodingKeys: String, CodingKey {
case code = "Code" // code --> Code
case message = "Message" // message --> Message
}
}

var response: Response

private enum CodingKeys: String, CodingKey {
case response = "Response" // response --> Response
}
}
131 changes: 131 additions & 0 deletions Easydict/Feature/Service/Tencent/TencentService.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//
// TencentService.swift
// Easydict
//
// Created by Jerry on 2023-11-25.
// Copyright © 2023 izual. All rights reserved.
//

import Alamofire
import Foundation

@objc(EZTencentService)
public final class TencentService: QueryService {
override public func serviceType() -> ServiceType {
.tencent
}

override public func link() -> String? {
"https://fanyi.qq.com"
}

override public func name() -> String {
NSLocalizedString("tencent_translate", comment: "The name of Tencent Translate")
}

override public func supportLanguagesDictionary() -> MMOrderedDictionary<AnyObject, AnyObject> {
// TODO: Replace MMOrderedDictionary in the API
let orderedDict = MMOrderedDictionary<AnyObject, AnyObject>()
Jerry23011 marked this conversation as resolved.
Show resolved Hide resolved
TencentTranslateType.supportLanguagesDictionary.forEach { key, value in
orderedDict.setObject(value as NSString, forKey: key.rawValue as NSString)
}
return orderedDict
}

override public func ocr(_: EZQueryModel) async throws -> EZOCRResult {
NSLog("Tencent Translate currently does not support OCR")
throw QueryServiceError.notSupported
}

// MARK: API Request
private static let defaultSecretId = ""
private static let defaultSecretKey = ""


// easydict://writeKeyValue?EZTencentSecretId=xxx
private var secretId: String {
let secretId = UserDefaults.standard.string(forKey: EZTencentSecretId)
if let secretId, !secretId.isEmpty {
return secretId
} else {
return TencentService.defaultSecretId
}
}

// easydict://writeKeyValue?EZTencentSecretKey=xxx
private var secretKey: String {
let secretKey = UserDefaults.standard.string(forKey: EZTencentSecretKey)
if let secretKey, !secretKey.isEmpty {
return secretKey
} else {
return TencentService.defaultSecretKey
}
}

public override func translate(_ text: String, from: Language, to: Language, completion: @escaping (EZQueryResult, Error?) -> Void) {
if prehandleQueryTextLanguage(text, from: from, to: to, completion: completion) {
return
}

translateText(text, from: from, to: to, completion: completion)
}

func translateText(_ text: String, from: Language, to: Language, completion: @escaping (EZQueryResult, Error?) -> Void) {
let transType = TencentTranslateType.transType(from: from, to: to)
guard transType != .unsupported else {
result.errorType = .unsupportedLanguage
let unsupportedType = NSLocalizedString("unsupported_translation_type", comment: "")
result.errorMessage = "\(unsupportedType): \(from.rawValue) --> \(to.rawValue)"
completion(result, nil)
return
}

let parameters: [String: Any] = [
"SourceText": text,
"Source": transType.sourceLanguage,
"Target": transType.targetLanguage,
"ProjectId": 0
]

let endpoint = "https://tmt.tencentcloudapi.com"
tisfeng marked this conversation as resolved.
Show resolved Hide resolved

let service = "tmt"
let action = "TextTranslate"
let version = "2018-03-21"

let headers = tencentSignHeader(service: service, action: action, version: version, parameters: parameters, secretId: secretId, secretKey: secretKey)

let request = AF.request(endpoint,
method: .post,
parameters: parameters,
encoding: JSONEncoding.default,
headers: headers)
.validate()
.responseDecodable(of: TencentResponse.self) { [weak self] response in
guard let self else { return }
let result = self.result
switch response.result {
case let .success(value):
result.from = from
result.to = to
result.queryText = text
result.translatedResults = value.Response.TargetText.components(separatedBy: "\n")
completion(result, nil)
case let .failure(error):
NSLog("Tencent lookup error \(error)")
if let data = response.data {
do {
let errorResponse = try JSONDecoder().decode(TencentErrorResponse.self, from: data)
result.errorMessage = errorResponse.response.error.message
} catch {
NSLog("Failed to decode error response: \(error)")
}
}
completion(result, error)
}
}
queryModel.setStop({
request.cancel()
}, serviceType: serviceType().rawValue)
}
}
Loading