-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2059 from tf/href-lang
Entry translations/hreflang alternate links
- Loading branch information
Showing
40 changed files
with
1,421 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
ruby: | ||
config_file: .rubocop.yml | ||
enabled: false | ||
javascript: | ||
config_file: .jshintrc | ||
ignore_file: .jshintignore | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
module Pageflow | ||
ActiveAdmin.register Entry, as: 'Translations' do | ||
menu false | ||
belongs_to :entry | ||
|
||
actions :new, :create, :destroy | ||
|
||
searchable_select_options(name: :potential_entry_translations, | ||
scope: lambda do |_params| | ||
authorize!(:manage_translations, parent) | ||
PotentialEntryTranslations.for(parent).resolve | ||
end, | ||
text_attribute: :title, | ||
display_text: lambda do |entry| | ||
if entry.translation_group | ||
entry.translation_group | ||
.entries | ||
.order('title ASC') | ||
.map(&:title) | ||
.join(' / ') | ||
.presence | ||
else | ||
entry.title | ||
end | ||
end) | ||
|
||
form partial: 'form' | ||
|
||
member_action :default, method: :put do | ||
entry = Entry.find(params[:id]) | ||
|
||
authorize!(:manage_translations, entry) | ||
entry.mark_as_default_translation | ||
|
||
redirect_to(admin_entry_path(parent, tab: 'translations')) | ||
end | ||
|
||
controller do | ||
helper Pageflow::Admin::FormHelper | ||
|
||
def index | ||
redirect_to admin_entry_path(parent, tab: 'translations') | ||
end | ||
|
||
def create | ||
entry = Entry.find(params.require(:entry)[:id]) | ||
|
||
authorize!(:manage_translations, parent) | ||
authorize!(:manage_translations, entry) | ||
parent.mark_as_translation_of(entry) | ||
|
||
redirect_to(admin_entry_path(parent, tab: 'translations')) | ||
end | ||
|
||
def destroy | ||
entry = Entry.find(params[:id]) | ||
|
||
authorize!(:manage_translations, entry) | ||
entry.remove_from_translation_group | ||
|
||
redirect_to(admin_entry_path(parent, tab: 'translations')) | ||
end | ||
|
||
protected | ||
|
||
def authorized?(action, subject = nil) | ||
if subject.is_a?(Entry) && subject.new_record? | ||
super(:manage_translations, parent) | ||
else | ||
super | ||
end | ||
end | ||
end | ||
end | ||
end |
3 changes: 2 additions & 1 deletion
3
app/assets/stylesheets/pageflow/admin/entries/index_table.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
.index_table { | ||
.index_table, | ||
.embedded_index_table { | ||
.publication_state { | ||
width: 16px; | ||
padding: 5px; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
module Pageflow | ||
module Admin | ||
# @api private | ||
module EntryTranslationsHelper | ||
def entry_translation_display_locale(entry) | ||
display_locale = t( | ||
'pageflow.public._language', | ||
locale: (entry.published_revision || entry.draft).locale | ||
) | ||
|
||
if entry.default_translation? | ||
t('pageflow.admin.entry_translations.default_translation', display_locale:) | ||
else | ||
display_locale | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module Pageflow | ||
# Helpers to render alternate links to translations of an entry. | ||
# | ||
# @since edge | ||
module HreflangLinksHelper | ||
include SocialShareHelper | ||
|
||
# Render alternate links to all published entries that have been | ||
# marked as translations of the given entry. | ||
def hreflang_link_tags_for_entry(entry) | ||
translations = | ||
entry.translations(-> { preload(:site, :translation_group, permalink: :directory) }) | ||
|
||
safe_join( | ||
translations.each_with_object([]) do |translation, links| | ||
links << hreflang_link_tag(translation) | ||
|
||
if translation.default_translation? | ||
links << hreflang_link_tag(translation, hreflang: 'x-default') | ||
end | ||
end | ||
) | ||
end | ||
|
||
private | ||
|
||
def hreflang_link_tag(entry, hreflang: entry.locale) | ||
tag('link', | ||
rel: 'alternate', | ||
hreflang:, | ||
href: social_share_entry_url(entry)) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
module Pageflow | ||
# @api private | ||
module Translatable | ||
extend ActiveSupport::Concern | ||
|
||
included do | ||
belongs_to(:translation_group, | ||
optional: true, | ||
class_name: 'EntryTranslationGroup') | ||
|
||
has_many(:translations, | ||
through: :translation_group, | ||
source: :entries) | ||
|
||
after_destroy do | ||
if translation_group&.single_item_or_empty? | ||
translation_group.destroy | ||
elsif default_translation? | ||
translation_group.update(default_translation: nil) | ||
end | ||
end | ||
end | ||
|
||
def mark_as_translation_of(entry) | ||
transaction do | ||
ensure_translation_group(entry) | ||
|
||
if !entry.translation_group | ||
entry.update!(translation_group:) | ||
elsif entry.translation_group != translation_group | ||
entry.translation_group.merge_into(translation_group) | ||
end | ||
end | ||
end | ||
|
||
def remove_from_translation_group | ||
if translation_group.entries.count <= 2 | ||
translation_group.destroy | ||
else | ||
translation_group.update(default_translation: nil) if default_translation? | ||
update!(translation_group: nil) | ||
end | ||
end | ||
|
||
def mark_as_default_translation | ||
translation_group.update!(default_translation: self) | ||
end | ||
|
||
def default_translation? | ||
translation_group&.default_translation == self | ||
end | ||
|
||
private | ||
|
||
def ensure_translation_group(other_entry) | ||
return if translation_group | ||
|
||
update!(translation_group: other_entry.translation_group || | ||
build_translation_group(default_translation: self)) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
module Pageflow | ||
# @api private | ||
class EntryTranslationGroup < ApplicationRecord | ||
has_many :entries, | ||
-> { order(title: :asc) }, | ||
foreign_key: 'translation_group_id', | ||
dependent: :nullify | ||
|
||
has_many :publicly_visible_entries, | ||
-> { published_without_password_protection.published_without_noindex }, | ||
foreign_key: 'translation_group_id', | ||
class_name: 'Entry' | ||
|
||
belongs_to :default_translation, | ||
class_name: 'Entry', | ||
optional: true | ||
|
||
def merge_into(translation_group) | ||
entries.update_all(translation_group_id: translation_group.id) | ||
destroy | ||
end | ||
|
||
def single_item_or_empty? | ||
!entries.many? | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
module Pageflow | ||
# @api private | ||
class PotentialEntryTranslations | ||
def initialize(entry) | ||
@entry = entry | ||
end | ||
|
||
def self.for(entry) | ||
new(entry) | ||
end | ||
|
||
def resolve | ||
preload( | ||
group_by_translation_group( | ||
exclude_translations( | ||
other_entries_of_account | ||
) | ||
) | ||
) | ||
end | ||
|
||
private | ||
|
||
def other_entries_of_account | ||
@entry.account.entries.where.not(id: @entry.id) | ||
end | ||
|
||
def exclude_translations(scope) | ||
return scope unless @entry.translation_group | ||
|
||
scope | ||
.where.not(translation_group_id: @entry.translation_group) | ||
.or(scope.where(translation_group: nil)) | ||
end | ||
|
||
def group_by_translation_group(scope) | ||
scope | ||
# Use MIN(id) to choose an arbitrary entry to represent its | ||
# translation group. MIN(translation_group_id) is needed since | ||
# technically translation_group_id is not part of the GROUP BY | ||
# clause. | ||
.select(<<-SQL) | ||
MIN(id) as id, | ||
GROUP_CONCAT(title) as title, | ||
MIN(translation_group_id) as translation_group_id | ||
SQL | ||
.group('IFNULL(translation_group_id, id)') | ||
.order('title ASC') | ||
end | ||
|
||
def preload(scope) | ||
scope.includes(translation_group: :entries) | ||
end | ||
end | ||
end |
Oops, something went wrong.