FEATURE: Add a onebox_locale site setting. (#30655)

Following on from f369db5ae9, this change adds the ability to choose a custom locale to send to onebox providers.

If this setting is left blank, it will fall back to using default_locale.
This commit is contained in:
Gary Pendergast 2025-01-09 14:11:37 +11:00 committed by GitHub
parent 590b3e11fb
commit f53c734ba6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 66 additions and 17 deletions

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
# onebox_locale is just like any other locale setting, except it allows for an empty value,
# which is used to indicate that the default_locale should be used for onebox_locale.
class OneboxLocaleSiteSetting < LocaleSiteSetting
def self.valid_value?(val)
supported_locales.include?(val) || val == ""
end
@lock = Mutex.new
end

View File

@ -1803,6 +1803,7 @@ en:
block_onebox_on_redirect: "Prevent oneboxing for URLs that lead to a redirecting page. This configuration stops the creation of a visual card (onebox) for any URL that redirects to a different destination, ensuring that direct, non-redirecting URLs are prioritized for oneboxing."
allowed_inline_onebox_domains: "A list of domains that will be oneboxed in miniature form if linked without a title"
enable_inline_onebox_on_all_domains: "Ignore allowed_inline_onebox_domains site setting and allow inline onebox on all domains."
onebox_locale: "The locale sent to onebox providers. If left blank, the default locale will be used."
force_custom_user_agent_hosts: "Hosts for which to use the custom onebox user agent on all requests. (Especially useful for hosts that limit access by user agent)."
max_oneboxes_per_post: "Set the maximum number of oneboxes that can be included in a single post. Oneboxes provide a preview of linked content within the post."
facebook_app_access_token: "A token generated from your Facebook app ID and secret. Used to generate Instagram oneboxes."
@ -3021,7 +3022,6 @@ en:
delete_user_max_post_age: ""
delete_user_self_max_post_count: ""
desktop_category_page_style: ""
mobile_category_page_style: ""
detailed_404: ""
detect_custom_avatars: ""
digest_logo: ""
@ -3214,11 +3214,11 @@ en:
here_mention_allowed_groups: ""
hidden_post_visible_groups: ""
hide_email_address_taken: ""
hide_new_user_profiles: ""
hide_post_sensitivity: ""
hide_suspension_reasons: ""
hide_user_activity_tab: ""
hide_user_profiles_from_public: ""
hide_new_user_profiles: ""
high_trust_flaggers_auto_hide_posts: ""
highlighted_languages: ""
history_hours_high: ""
@ -3356,6 +3356,7 @@ en:
min_trust_to_send_messages: ""
min_username_length: ""
minimum_topics_similar: ""
mobile_category_page_style: ""
mobile_logo: ""
mobile_logo_dark: ""
moderators_change_post_ownership: ""
@ -3387,6 +3388,7 @@ en:
num_tl3_users_to_silence_new_user: ""
num_users_to_silence_new_user: ""
old_post_notice_days: ""
onebox_locale: ""
opengraph_image: ""
page_loading_indicator: ""
password_unique_characters: ""

View File

@ -2284,6 +2284,10 @@ onebox:
onebox_user_agent:
default: ""
hidden: true
onebox_locale:
default: ""
type: enum
enum: "OneboxLocaleSiteSetting"
force_custom_user_agent_hosts:
default: "http://codepen.io"
type: list

View File

@ -41,10 +41,11 @@ module Onebox
canonical_uri = Addressable::URI.parse(canonical_link)
if canonical_link && canonical_uri &&
"#{canonical_uri.host}#{canonical_uri.path}" != "#{uri.host}#{uri.path}"
canonical_options = Oneboxer.get_final_destination_options(canonical_link)
canonical_options["extra_headers"] = { "Accept-Language" => accept_language }
uri = FinalDestination.new(canonical_link, canonical_options).resolve
uri =
FinalDestination.new(
canonical_link,
Oneboxer.get_final_destination_options(canonical_link),
).resolve
if uri.present?
response =
(
@ -104,7 +105,7 @@ module Onebox
headers ||= {}
headers["User-Agent"] ||= user_agent if user_agent
headers["Accept-Language"] ||= accept_language if accept_language
headers["Accept-Language"] ||= Oneboxer.accept_language
request = Net::HTTP::Get.new(uri.request_uri, headers)
start_time = Time.now
@ -236,14 +237,6 @@ module Onebox
user_agent
end
def self.accept_language
if SiteSetting.default_locale == "en"
"en;q=0.9, *;q=0.5"
else
"#{SiteSetting.default_locale.gsub(/_/, "-")};q=0.9, en;q=0.8, *;q=0.5"
end
end
# Percent-encodes a URI string per RFC3986 - https://tools.ietf.org/html/rfc3986
def self.uri_encode(url)
return "" unless url

View File

@ -152,7 +152,7 @@ module Oneboxer
end
def self.redis_cached_response_body_key(uri)
"CACHED_RESPONSE_#{SiteSetting.default_locale}_#{uri}"
"CACHED_RESPONSE_#{onebox_locale}_#{uri}"
end
# Parse URLs out of HTML, returning the document when finished.
@ -677,6 +677,9 @@ module Oneboxer
force_custom_user_agent_hosts: force_custom_user_agent_hosts,
preserve_fragment_url_hosts: preserve_fragment_url_hosts,
timeout: 5,
headers: {
"Accept-Language" => accept_language,
},
}
uri = URI(url)
@ -705,4 +708,16 @@ module Oneboxer
fd_options
end
def self.onebox_locale
SiteSetting.onebox_locale.presence || SiteSetting.default_locale
end
def self.accept_language
if onebox_locale == "en"
"en;q=0.9, *;q=0.5"
else
"#{onebox_locale.gsub(/_/, "-")};q=0.9, en;q=0.8, *;q=0.5"
end
end
end

View File

@ -957,11 +957,18 @@ RSpec.describe Oneboxer do
end
it "separates cache by default_locale" do
preview = Oneboxer.preview(url, invalidate_oneboxes: true)
Oneboxer.preview(url, invalidate_oneboxes: true)
expect(Oneboxer.cached_response_body_exists?(url)).to eq(true)
SiteSetting.default_locale = "fr"
expect(Oneboxer.cached_response_body_exists?(url)).to eq(false)
end
it "separates cache by onebox_locale, when set" do
Oneboxer.preview(url, invalidate_oneboxes: true)
expect(Oneboxer.cached_response_body_exists?(url)).to eq(true)
SiteSetting.onebox_locale = "fr"
expect(Oneboxer.cached_response_body_exists?(url)).to eq(false)
end
end
describe "register_local_handler" do

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
RSpec.describe OneboxLocaleSiteSetting do
describe ".valid_value?" do
it "returns true for a locale that we have translations for" do
expect(OneboxLocaleSiteSetting.valid_value?("en")).to eq(true)
end
it "returns true for an empty value" do
expect(OneboxLocaleSiteSetting.valid_value?("")).to eq(true)
end
it "returns false for a locale that we do not have translations for" do
expect(OneboxLocaleSiteSetting.valid_value?("swedish-chef")).to eq(false)
end
end
end