feat: translator

This commit is contained in:
Bobo
2025-05-14 20:43:37 +08:00
parent 982e18a991
commit 3b2678de10
13 changed files with 564 additions and 0 deletions

View File

@@ -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
View 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
View 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
View 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=

View 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
}
}

View 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)
}
}

View 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())
}

View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,7 @@
package translator
// Translator 翻译器
type Translator interface {
// Translate 翻译
Translate(source, sourceLang, targetLang string) (string, error)
}

View File

@@ -0,0 +1,9 @@
package translator
import (
"testing"
)
func TestTranslator(t *testing.T) {
}