feat: translator
This commit is contained in:
1
tag.bat
1
tag.bat
@@ -2,6 +2,7 @@ git tag v1.1.21
|
||||
|
||||
git tag bank_card/v1.1.5
|
||||
git tag geoip/v1.1.5
|
||||
git tag translator/v1.1.1
|
||||
|
||||
git tag entgo/v1.1.27
|
||||
git tag gorm/v1.1.5
|
||||
|
||||
113
translator/README.md
Normal file
113
translator/README.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# 翻译器
|
||||
|
||||
## 目标语言
|
||||
|
||||
1. 阿尔巴尼亚语: `sq`
|
||||
2. 阿拉伯语: `ar`
|
||||
3. 阿姆哈拉语: `am`
|
||||
4. 阿塞拜疆语: `az`
|
||||
5. 爱尔兰语: `ga`
|
||||
6. 爱沙尼亚语: `et`
|
||||
7. 奥利亚语: `or`
|
||||
8. 巴斯克语: `eu`
|
||||
9. 白俄罗斯语: `be`
|
||||
10. 保加利亚语: `bg`
|
||||
11. 冰岛语: `is`
|
||||
12. 波兰语: `pl`
|
||||
13. 波斯尼亚语: `bs`
|
||||
14. 波斯语: `fa`
|
||||
15. 布尔语(南非荷兰语): `af`
|
||||
16. 鞑靼语: `tt`
|
||||
17. 丹麦语: `da`
|
||||
18. 德语: `de`
|
||||
19. 俄语: `ru`
|
||||
20. 法语: `fr`
|
||||
21. 菲律宾语: `tl`
|
||||
22. 芬兰语: `fi`
|
||||
23. 弗里西语: `fy`
|
||||
24. 高棉语: `km`
|
||||
25. 格鲁吉亚语: `ka`
|
||||
26. 古吉拉特语: `gu`
|
||||
27. 哈萨克语: `kk`
|
||||
28. 海地克里奥尔语: `ht`
|
||||
29. 韩语: `ko`
|
||||
30. 豪萨语: `ha`
|
||||
31. 荷兰语: `nl`
|
||||
32. 吉尔吉斯语: `ky`
|
||||
33. 加利西亚语: `gl`
|
||||
34. 加泰罗尼亚语: `ca`
|
||||
35. 捷克语: `cs`
|
||||
36. 卡纳达语: `kn`
|
||||
37. 科西嘉语: `co`
|
||||
38. 克罗地亚语: `hr`
|
||||
39. 库尔德语: `ku`
|
||||
40. 拉丁语: `la`
|
||||
41. 拉脱维亚语: `lv`
|
||||
42. 老挝语: `lo`
|
||||
43. 立陶宛语: `lt`
|
||||
44. 卢森堡语: `lb`
|
||||
45. 卢旺达语: `rw`
|
||||
46. 罗马尼亚语: `ro`
|
||||
47. 马尔加什语: `mg`
|
||||
48. 马耳他语: `mt`
|
||||
49. 马拉地语: `mr`
|
||||
50. 马拉雅拉姆语: `ml`
|
||||
51. 马来语: `ms`
|
||||
52. 马其顿语: `mk`
|
||||
53. 毛利语: `mi`
|
||||
54. 蒙古语: `mn`
|
||||
55. 孟加拉语: `bn`
|
||||
56. 缅甸语: `my`
|
||||
57. 苗语: `hmn`
|
||||
58. 南非科萨语: `xh`
|
||||
59. 南非祖鲁语: `zu`
|
||||
60. 尼泊尔语: `ne`
|
||||
61. 挪威语: `no`
|
||||
62. 旁遮普语: `pa`
|
||||
63. 葡萄牙语: `pt`
|
||||
64. 普什图语: `ps`
|
||||
65. 齐切瓦语: `ny`
|
||||
66. 日语: `ja`
|
||||
67. 瑞典语: `sv`
|
||||
68. 萨摩亚语: `sm`
|
||||
69. 塞尔维亚语: `sr`
|
||||
70. 塞索托语: `st`
|
||||
71. 僧伽罗语: `si`
|
||||
72. 世界语: `eo`
|
||||
73. 斯洛伐克语: `sk`
|
||||
74. 斯洛文尼亚语: `sl`
|
||||
75. 斯瓦希里语: `sw`
|
||||
76. 苏格兰盖尔语: `gd`
|
||||
77. 宿务语: `ceb`
|
||||
78. 索马里语: `so`
|
||||
79. 塔吉克语: `tg`
|
||||
80. 泰卢固语: `te`
|
||||
81. 泰米尔语: `ta`
|
||||
82. 泰语: `th`
|
||||
83. 土耳其语: `tr`
|
||||
84. 土库曼语: `tk`
|
||||
85. 威尔士语: `cy`
|
||||
86. 维吾尔语: `ug`
|
||||
87. 乌尔都语: `ur`
|
||||
88. 乌克兰语: `uk`
|
||||
89. 乌兹别克语: `uz`
|
||||
90. 西班牙语: `es`
|
||||
91. 希伯来语: `iw`
|
||||
92. 希腊语: `el`
|
||||
93. 夏威夷语: `haw`
|
||||
94. 信德语: `sd`
|
||||
95. 匈牙利语: `hu`
|
||||
96. 修纳语: `sn`
|
||||
97. 亚美尼亚语: `hy`
|
||||
98. 伊博语: `ig`
|
||||
99. 意大利语: `it`
|
||||
100. 意第绪语: `yi`
|
||||
101. 印地语: `hi`
|
||||
102. 印尼巽他语: `su`
|
||||
103. 印尼语: `id`
|
||||
104. 印尼爪哇语: `jw`
|
||||
105. 英语: `en`
|
||||
106. 约鲁巴语: `yo`
|
||||
107. 越南语: `vi`
|
||||
108. 中文(繁体): `zh-TW`
|
||||
109. 中文(简体): `zh-CN`
|
||||
49
translator/go.mod
Normal file
49
translator/go.mod
Normal file
@@ -0,0 +1,49 @@
|
||||
module github.com/tx7do/go-utils/translator
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.3
|
||||
|
||||
require (
|
||||
cloud.google.com/go/translate v1.12.5
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/text v0.25.0
|
||||
google.golang.org/api v0.233.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.120.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
golang.org/x/crypto v0.38.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 // indirect
|
||||
google.golang.org/grpc v1.72.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/tx7do/go-utils => ../
|
||||
90
translator/go.sum
Normal file
90
translator/go.sum
Normal file
@@ -0,0 +1,90 @@
|
||||
cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
|
||||
cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
|
||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw=
|
||||
cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw=
|
||||
cloud.google.com/go/translate v1.12.5 h1:QPMNi4WCtHwc2PPfxbyUMwdN/0+cyCGLaKi2tig41J8=
|
||||
cloud.google.com/go/translate v1.12.5/go.mod h1:o/v+QG/bdtBV1d1edmtau0PwTfActvxPk/gtqdSDBi4=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
google.golang.org/api v0.233.0 h1:iGZfjXAJiUFSSaekVB7LzXl6tRfEKhUN7FkZN++07tI=
|
||||
google.golang.org/api v0.233.0/go.mod h1:TCIVLLlcwunlMpZIhIp7Ltk77W+vUSdUKAAIlbxY44c=
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e h1:UdXH7Kzbj+Vzastr5nVfccbmFsmYNygVLSPk1pEfDoY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2 h1:IqsN8hx+lWLqlN+Sc3DoMy/watjofWiU8sRFgQ8fhKM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
20
translator/google/options.go
Normal file
20
translator/google/options.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package google
|
||||
|
||||
type Option func(*options)
|
||||
|
||||
type options struct {
|
||||
version string
|
||||
apiKey string
|
||||
}
|
||||
|
||||
func WithVersion(version string) Option {
|
||||
return func(o *options) {
|
||||
o.version = version
|
||||
}
|
||||
}
|
||||
|
||||
func WithApiKey(key string) Option {
|
||||
return func(o *options) {
|
||||
o.apiKey = key
|
||||
}
|
||||
}
|
||||
40
translator/google/translator.go
Normal file
40
translator/google/translator.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
translateV2 "cloud.google.com/go/translate"
|
||||
translateV3 "cloud.google.com/go/translate/apiv3"
|
||||
)
|
||||
|
||||
type Translator struct {
|
||||
options *options
|
||||
|
||||
clientV2 *translateV2.Client
|
||||
clientV3 *translateV3.TranslationClient
|
||||
}
|
||||
|
||||
func NewTranslator(opts ...Option) *Translator {
|
||||
op := options{}
|
||||
for _, o := range opts {
|
||||
o(&op)
|
||||
}
|
||||
|
||||
return &Translator{
|
||||
options: &op,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Translator) Translate(source, sourceLang, targetLang string) (string, error) {
|
||||
switch t.options.version {
|
||||
default:
|
||||
fallthrough
|
||||
case "v1":
|
||||
return t.TranslateV1(source, sourceLang, targetLang)
|
||||
|
||||
case "v2":
|
||||
text, _, err := t.TranslateV2(source, sourceLang, targetLang)
|
||||
return text, err
|
||||
|
||||
case "v3":
|
||||
return t.TranslateV3(source, sourceLang, targetLang)
|
||||
}
|
||||
}
|
||||
98
translator/google/translator_test.go
Normal file
98
translator/google/translator_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestTranslateV1(t *testing.T) {
|
||||
translator := NewTranslator(
|
||||
WithVersion("v1"),
|
||||
)
|
||||
assert.NotNil(t, translator)
|
||||
|
||||
const text string = `Hello, World!`
|
||||
// you can use "auto" for source language
|
||||
// so, translator will detect language
|
||||
result, err := translator.TranslateV1(text, "en", "es")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
// Output: "Hola, Mundo!"
|
||||
|
||||
result, err = translator.TranslateV1(text, "en", "zh-CN")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
|
||||
result, err = translator.TranslateV1(text, "en", "lo")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
|
||||
result, err = translator.TranslateV1(text, "en", "my")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func TestTranslateV2(t *testing.T) {
|
||||
translator := NewTranslator(
|
||||
WithVersion("v2"),
|
||||
WithApiKey("apikey"),
|
||||
)
|
||||
assert.NotNil(t, translator)
|
||||
|
||||
const text string = `Hello, World!`
|
||||
|
||||
result, _, err := translator.TranslateV2(text, "en", "es")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
// Output: "Hola, Mundo!"
|
||||
|
||||
result, _, err = translator.TranslateV2(text, "en", "zh-CN")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
|
||||
result, _, err = translator.TranslateV2(text, "en", "lo")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
|
||||
result, _, err = translator.TranslateV2(text, "en", "my")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func TestTranslateV3(t *testing.T) {
|
||||
translator := NewTranslator(
|
||||
WithVersion("v3"),
|
||||
WithApiKey("apikey"),
|
||||
)
|
||||
assert.NotNil(t, translator)
|
||||
|
||||
const text string = `Hello, World!`
|
||||
// you can use "auto" for source language
|
||||
// so, translator will detect language
|
||||
result, err := translator.TranslateV3(text, "en", "es")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
// Output: "Hola, Mundo!"
|
||||
|
||||
result, err = translator.TranslateV3(text, "en", "zh-CN")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
|
||||
result, err = translator.TranslateV3(text, "en", "lo")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
|
||||
result, err = translator.TranslateV3(text, "en", "my")
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
func TestLanguageParse(t *testing.T) {
|
||||
lang, _ := language.Parse("en")
|
||||
assert.Equal(t, lang, language.English)
|
||||
fmt.Println(lang)
|
||||
fmt.Println(language.English.String())
|
||||
}
|
||||
9
translator/google/utils.go
Normal file
9
translator/google/utils.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package google
|
||||
|
||||
import "net/url"
|
||||
|
||||
// javascript "encodeURI()"
|
||||
// so we embed js to our golang program
|
||||
func encodeURI(s string) string {
|
||||
return url.QueryEscape(s)
|
||||
}
|
||||
55
translator/google/v1.go
Normal file
55
translator/google/v1.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (t *Translator) TranslateV1(source, sourceLang, targetLang string) (string, error) {
|
||||
var text []string
|
||||
var result []interface{}
|
||||
|
||||
encodedSource := encodeURI(source)
|
||||
uri := "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" +
|
||||
sourceLang + "&tl=" + targetLang + "&dt=t&q=" + encodedSource
|
||||
|
||||
r, err := http.Get(uri)
|
||||
if err != nil {
|
||||
return "err", errors.New("error getting translate.googleapis.com")
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return "err", errors.New("error reading response body")
|
||||
}
|
||||
|
||||
bReq := strings.Contains(string(body), `<title>Error 400 (Bad Request)`)
|
||||
if bReq {
|
||||
return "err", errors.New("error 400 (Bad Request)")
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &result)
|
||||
if err != nil {
|
||||
return "err", errors.New("error unmarshalling data")
|
||||
}
|
||||
|
||||
if len(result) > 0 {
|
||||
inner := result[0]
|
||||
for _, slice := range inner.([]interface{}) {
|
||||
for _, translatedText := range slice.([]interface{}) {
|
||||
text = append(text, fmt.Sprintf("%v", translatedText))
|
||||
break
|
||||
}
|
||||
}
|
||||
cText := strings.Join(text, "")
|
||||
|
||||
return cText, nil
|
||||
} else {
|
||||
return "err", errors.New("no translated data in response")
|
||||
}
|
||||
}
|
||||
33
translator/google/v2.go
Normal file
33
translator/google/v2.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
translateV2 "cloud.google.com/go/translate"
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
func (t *Translator) TranslateV2(source, _, targetLanguage string) (string, language.Tag, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
lang, err := language.Parse(targetLanguage)
|
||||
if err != nil {
|
||||
return "", language.English, err
|
||||
}
|
||||
|
||||
if t.clientV2 == nil {
|
||||
client, err := translateV2.NewClient(ctx, option.WithAPIKey(t.options.apiKey))
|
||||
if err != nil {
|
||||
return "", language.English, err
|
||||
}
|
||||
t.clientV2 = client
|
||||
}
|
||||
|
||||
resp, err := t.clientV2.Translate(ctx, []string{source}, lang, nil)
|
||||
if err != nil {
|
||||
return "", language.English, err
|
||||
}
|
||||
|
||||
return resp[0].Text, resp[0].Source, nil
|
||||
}
|
||||
40
translator/google/v3.go
Normal file
40
translator/google/v3.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
translateV3 "cloud.google.com/go/translate/apiv3"
|
||||
"cloud.google.com/go/translate/apiv3/translatepb"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
func (t *Translator) TranslateV3(source, sourceLang, targetLang string) (string, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
if t.clientV3 == nil {
|
||||
client, err := translateV3.NewTranslationClient(ctx, option.WithAPIKey(t.options.apiKey))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("NewTranslationClient: %w", err)
|
||||
}
|
||||
t.clientV3 = client
|
||||
}
|
||||
|
||||
req := &translatepb.TranslateTextRequest{
|
||||
SourceLanguageCode: sourceLang,
|
||||
TargetLanguageCode: targetLang,
|
||||
MimeType: "text/plain", // Mime types: "text/plain", "text/html"
|
||||
Contents: []string{source},
|
||||
}
|
||||
|
||||
resp, err := t.clientV3.TranslateText(ctx, req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("TranslateText: %w", err)
|
||||
}
|
||||
|
||||
if len(resp.GetTranslations()) != 1 {
|
||||
return "", fmt.Errorf("TranslateText: %w", err)
|
||||
}
|
||||
|
||||
return resp.GetTranslations()[0].GetTranslatedText(), nil
|
||||
}
|
||||
7
translator/translator.go
Normal file
7
translator/translator.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package translator
|
||||
|
||||
// Translator 翻译器
|
||||
type Translator interface {
|
||||
// Translate 翻译
|
||||
Translate(source, sourceLang, targetLang string) (string, error)
|
||||
}
|
||||
9
translator/translator_test.go
Normal file
9
translator/translator_test.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package translator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTranslator(t *testing.T) {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user