-
Notifications
You must be signed in to change notification settings - Fork 50
/
plugin.rb
176 lines (146 loc) · 6.17 KB
/
plugin.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# frozen_string_literal: true
# name: discourse-translator
# about: Translates posts on Discourse using Microsoft, Google, Yandex or LibreTranslate translation APIs.
# meta_topic_id: 32630
# version: 0.3.0
# authors: Alan Tan
# url: https://github.com/discourse/discourse-translator
gem "aws-sdk-translate", "1.35.0", require: false
enabled_site_setting :translator_enabled
register_asset "stylesheets/common/post.scss"
after_initialize do
module ::DiscourseTranslator
PLUGIN_NAME = "discourse_translator".freeze
DETECTED_LANG_CUSTOM_FIELD = "post_detected_lang".freeze
TRANSLATED_CUSTOM_FIELD = "translated_text".freeze
autoload :Microsoft,
"#{Rails.root}/plugins/discourse-translator/services/discourse_translator/microsoft"
autoload :Google,
"#{Rails.root}/plugins/discourse-translator/services/discourse_translator/google"
autoload :Amazon,
"#{Rails.root}/plugins/discourse-translator/services/discourse_translator/amazon"
autoload :Yandex,
"#{Rails.root}/plugins/discourse-translator/services/discourse_translator/yandex"
autoload :LibreTranslate,
"#{Rails.root}/plugins/discourse-translator/services/discourse_translator/libretranslate"
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace DiscourseTranslator
end
end
require_relative "app/services/problem_check/missing_translator_api_key"
require_relative "app/services/problem_check/translator_error"
register_problem_check ProblemCheck::MissingTranslatorApiKey
register_problem_check ProblemCheck::TranslatorError
class DiscourseTranslator::TranslatorController < ::ApplicationController
before_action :ensure_logged_in
def translate
raise PluginDisabled if !SiteSetting.translator_enabled
if !current_user.staff?
RateLimiter.new(
current_user,
"translate_post",
SiteSetting.max_translations_per_minute,
1.minute,
).performed!
end
params.require(:post_id)
post = Post.find_by(id: params[:post_id])
raise Discourse::InvalidParameters.new(:post_id) if post.blank?
guardian.ensure_can_see!(post)
if !guardian.user_group_allow_translate?
raise Discourse::InvalidAccess.new(
"not_in_group",
SiteSetting.restrict_translation_by_group,
custom_message: "not_in_group.user_not_in_group",
group: current_user.groups.pluck(:id),
)
end
if !guardian.poster_group_allow_translate?(post)
raise Discourse::InvalidAccess.new(
"not_in_group",
SiteSetting.restrict_translation_by_poster_group,
custom_message: "not_in_group.poster_not_in_group",
)
end
begin
title_json = {}
detected_lang, translation =
"DiscourseTranslator::#{SiteSetting.translator}".constantize.translate(post)
if post.is_first_post?
_, title_translation =
"DiscourseTranslator::#{SiteSetting.translator}".constantize.translate(post.topic)
title_json = { title_translation: title_translation }
end
render json: { translation: translation, detected_lang: detected_lang }.merge(title_json),
status: 200
rescue ::DiscourseTranslator::TranslatorError => e
render_json_error e.message, status: 422
end
end
end
Post.register_custom_field_type(::DiscourseTranslator::TRANSLATED_CUSTOM_FIELD, :json)
Topic.register_custom_field_type(::DiscourseTranslator::TRANSLATED_CUSTOM_FIELD, :json)
module ::Jobs
class TranslatorMigrateToAzurePortal < ::Jobs::Onceoff
def execute_onceoff(args)
%w[translator_client_id translator_client_secret].each { |name| DB.exec <<~SQL }
DELETE FROM site_settings WHERE name = '#{name}'
SQL
DB.exec <<~SQL
UPDATE site_settings
SET name = 'translator_azure_subscription_key'
WHERE name = 'azure_subscription_key'
SQL
end
end
class DetectTranslation < ::Jobs::Base
sidekiq_options retry: false
def execute(args)
return if !SiteSetting.translator_enabled
post = Post.find_by(id: args[:post_id])
return unless post
DistributedMutex.synchronize("detect_translation_#{post.id}") do
begin
"DiscourseTranslator::#{SiteSetting.translator}".constantize.detect(post)
if !post.custom_fields_clean?
post.save_custom_fields
post.publish_change_to_clients! :revised
end
rescue ::DiscourseTranslator::ProblemCheckedTranslationError
# The error was handled by ProblemCheck., no need to log errors here
end
end
end
end
end
on(:post_process) { |post| Jobs.enqueue(:detect_translation, post_id: post.id) }
topic_view_post_custom_fields_allowlister { [::DiscourseTranslator::DETECTED_LANG_CUSTOM_FIELD] }
require_relative "lib/discourse_translator/guardian_extension"
require_relative "lib/discourse_translator/post_extension"
require_relative "lib/discourse_translator/topic_extension"
reloadable_patch do |plugin|
Guardian.prepend(DiscourseTranslator::GuardianExtension)
Post.prepend(DiscourseTranslator::PostExtension)
Topic.prepend(DiscourseTranslator::TopicExtension)
end
add_to_serializer :post, :can_translate do
return false if !SiteSetting.translator_enabled
if !scope.user_group_allow_translate? || !scope.poster_group_allow_translate?(object)
return false
end
return false if raw.blank? || post_type == Post.types[:small_action]
detected_lang = post_custom_fields[::DiscourseTranslator::DETECTED_LANG_CUSTOM_FIELD]
if !detected_lang
Jobs.enqueue(:detect_translation, post_id: object.id)
false
else
detected_lang !=
"DiscourseTranslator::#{SiteSetting.translator}::SUPPORTED_LANG_MAPPING".constantize[
I18n.locale
]
end
end
DiscourseTranslator::Engine.routes.draw { post "translate" => "translator#translate" }
Discourse::Application.routes.append { mount ::DiscourseTranslator::Engine, at: "translator" }
end