diff --git a/lib_static/redmine/i18n.rb b/lib_static/redmine/i18n.rb index e93a9de16c5..c844ec1cc6b 100644 --- a/lib_static/redmine/i18n.rb +++ b/lib_static/redmine/i18n.rb @@ -116,13 +116,20 @@ module Redmine # @param links [Hash] Link names mapped to URLs. # @param external [Boolean] Whether the links should be opened as external links, i.e. in a new tab (default: true) # @param underline [Boolean] Whether to underline links inserted into the text (default: true) - def link_translate(i18n_key, i18n_args: {}, links: {}, external: true, underline: true, **) + def link_translate(i18n_key, i18n_args: {}, links: {}, external: true, underline: true, **) # rubocop:disable Metrics/AbcSize + translation = ApplicationController.helpers.t(i18n_key.to_s, **i18n_args) output = ActiveSupport::SafeBuffer.new - output << ApplicationController.helpers.t(i18n_key.to_s, **i18n_args) + last_end = 0 - output.html_safe_gsub(link_regex) do - create_link_content($3, $2, external:, links:, underline:, **) + translation.scan(link_regex) do + match = Regexp.last_match + output << translation[last_end...match.begin(0)] + output << create_link_content(match[3], match[2], external:, links:, underline:, **) + last_end = match.end(0) end + output << translation[last_end..] + + output end ## diff --git a/spec/lib/redmine/i18n_spec.rb b/spec/lib/redmine/i18n_spec.rb index ac7ade0d0ce..db8157fb9a8 100644 --- a/spec/lib/redmine/i18n_spec.rb +++ b/spec/lib/redmine/i18n_spec.rb @@ -211,6 +211,25 @@ module OpenProject expect(links[1][:href]).to eq("/baz") end + context "when the link text contains an apostrophe" do + before do + allow(::I18n) + .to receive(:translate) + .with("translation_with_apostrophe", *any_args) + .and_return("Here's [what's new](url) to see.") + end + + it "does not double-escape the apostrophe in the link text" do + translated = link_translate :translation_with_apostrophe, + links: { url: "https://example.com" }, + external: false + fragment = Capybara.string(translated) + + link = fragment.find("a") + expect(link.text).to eq("what's new") + end + end + context "when passing URLs as a list of symbols" do let(:urls) do { url_1: [:a, :b], url_2: [:a, :c] }