New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MBS-7646: Show localized artist aliases in more places #3191
Changes from all commits
77548e4
9aeebd1
df20e34
acbdd15
67e05c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -146,9 +146,9 @@ after 'load' => sub | |
} | ||
} | ||
|
||
$c->model('ArtistType')->load($artist, map { $_->target } @{ $artist->relationships_by_type('artist') }); | ||
$c->model('Gender')->load($artist); | ||
$c->model('Area')->load($artist); | ||
my $lang = $c->stash->{current_language} // 'en'; | ||
$c->model('Artist')->load_related_info([$artist], $lang); | ||
$c->model('ArtistType')->load(map { $_->target } @{ $artist->relationships_by_type('artist') }); | ||
$c->model('Area')->load_containment($artist->area, $artist->begin_area, $artist->end_area); | ||
}; | ||
|
||
|
@@ -286,26 +286,22 @@ sub show : PathPart('') Chained('load') | |
if (defined $base_name) { | ||
$c->model('Relationship')->load_subset(['artist'], $base_name); | ||
$c->stash( legal_name => $base_name ); | ||
my $aliases = $c->model('Artist')->alias->find_by_entity_id($base_name->id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it safe to assume that It seems to work to the extent that I still see legal names when I view artist pages, at least. (Those weren't being shown with this change until I added the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It looks safe to me since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this isn't the case. https://beta.musicbrainz.org/artist/869cf6cc-07bb-470a-aa30-7e7e6000ffcf currently fails to load:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It works locally running the beta code, which suggests to me that the product of a prod load without aliases is being cached and causing the beta crash. If that's the case, we could either amend prod to save the info to the artist even if it doesn't use it, or amend beta temporarily to just show nothing rather than ISE if the data is missing. My preference would be the first, if we think it's safe (we're supposed to hotfix prod soon anyway for unrelated reasons) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mwiencek and @reosarevok, just to make sure I understand this properly, will the caching also cause issues with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That shouldn't be an issue as entities are cached immediately before any additional data is loaded onto them. So no There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whew, thanks! |
||
$c->model('Artist')->alias_type->load(@$aliases); | ||
my @aliases = uniq map { $_->name } | ||
sort_by { $coll->getSortKey($_->name) } | ||
# An alias equal to the artist name already shown isn't useful | ||
grep { ($_->name) ne $base_name->name } | ||
# A legal name alias marked ended isn't a current legal name | ||
grep { !($_->ended) } | ||
grep { ($_->type_name // '') eq 'Legal name' } @$aliases; | ||
grep { ($_->type_name // '') eq 'Legal name' } @{ $base_name->aliases }; | ||
$c->stash( legal_name_artist_aliases => \@aliases ); | ||
$base_name_legal_name_aliases = \@aliases; | ||
push(@identities, $base_name); | ||
} else { | ||
my $aliases = $c->model('Artist')->alias->find_by_entity_id($artist->id); | ||
$c->model('Artist')->alias_type->load(@$aliases); | ||
my @aliases = uniq map { $_->name } | ||
sort_by { $coll->getSortKey($_->name) } | ||
# A legal name alias marked ended isn't a current legal name | ||
grep { !($_->ended) } | ||
grep { ($_->type_name // '') eq 'Legal name' } @$aliases; | ||
grep { ($_->type_name // '') eq 'Legal name' } @{ $artist->aliases }; | ||
$c->stash( legal_name_aliases => \@aliases ); | ||
$legal_name_aliases = \@aliases; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ use Data::Dumper; | |
use Data::Page; | ||
use URI::Escape qw( uri_escape_utf8 ); | ||
use List::AllUtils qw( any partition_by ); | ||
use MusicBrainz::Server::Entity::Alias; | ||
use MusicBrainz::Server::Entity::Annotation; | ||
use MusicBrainz::Server::Entity::Area; | ||
use MusicBrainz::Server::Entity::AreaType; | ||
|
@@ -58,7 +59,11 @@ use MusicBrainz::Server::Data::Release; | |
use MusicBrainz::Server::Data::ReleaseGroup; | ||
use MusicBrainz::Server::Data::Series; | ||
use MusicBrainz::Server::Data::Tag; | ||
use MusicBrainz::Server::Data::Utils qw( contains_string ref_to_type ); | ||
use MusicBrainz::Server::Data::Utils qw( | ||
contains_string | ||
find_best_primary_alias | ||
ref_to_type | ||
); | ||
use MusicBrainz::Server::Data::Work; | ||
use MusicBrainz::Server::Constants qw( entities_with $DARTIST_ID $DLABEL_ID ); | ||
use MusicBrainz::Server::Data::Utils qw( type_to_model ); | ||
|
@@ -419,7 +424,7 @@ sub schema_fixup_type { | |
# matches up with the data returned from the DB for easy object creation | ||
sub schema_fixup | ||
{ | ||
my ($self, $data, $type) = @_; | ||
my ($self, $data, $type, $user_lang) = @_; | ||
|
||
return unless (ref($data) eq 'HASH'); | ||
|
||
|
@@ -685,7 +690,7 @@ sub schema_fixup | |
|
||
my %entity = %{ $rel->{$entity_type} }; | ||
|
||
$self->schema_fixup(\%entity, $entity_type); | ||
$self->schema_fixup(\%entity, $entity_type, $user_lang); | ||
|
||
# The search server returns the MBID in the 'id' attribute, so we | ||
# need to delete that. (`schema_fixup` copies it to gid.) | ||
|
@@ -716,13 +721,13 @@ sub schema_fixup | |
next if $k eq '_extra'; | ||
if (ref($data->{$k}) eq 'HASH') | ||
{ | ||
$self->schema_fixup($data->{$k}, $type); | ||
$self->schema_fixup($data->{$k}, $type, $user_lang); | ||
} | ||
if (ref($data->{$k}) eq 'ARRAY') | ||
{ | ||
foreach my $item (@{$data->{$k}}) | ||
{ | ||
$self->schema_fixup($item, $type); | ||
$self->schema_fixup($item, $type, $user_lang); | ||
} | ||
} | ||
} | ||
|
@@ -740,6 +745,24 @@ sub schema_fixup | |
$data->{'artist_credit'} = MusicBrainz::Server::Entity::ArtistCredit->new( { names => \@credits } ); | ||
} | ||
|
||
if (defined $data->{aliases}) { | ||
my @aliases = map { | ||
MusicBrainz::Server::Entity::Alias->new( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to work, but please let me know if I should be doing something else to create these objects. |
||
name => $_->{name} // '', | ||
sort_name => $_->{sort_name} // '', | ||
locale => $_->{locale} // '', | ||
primary_for_locale => $_->{primary}, | ||
) | ||
} @{ $data->{aliases} }; | ||
my $best_alias = find_best_primary_alias(\@aliases, $user_lang); | ||
$data->{primary_alias} = $best_alias->{name} if defined $best_alias; | ||
|
||
# Save the new objects so validation will pass, but note that the search | ||
# API doesn't include all attributes that are present in Entity::Alias, | ||
# e.g. no IDs. | ||
$data->{aliases} = \@aliases; | ||
} | ||
|
||
if ($type eq 'work') { | ||
if (defined $data->{relationships}) { | ||
my %relationship_map = partition_by { $_->entity1->gid } | ||
|
@@ -822,7 +845,7 @@ sub escape_query | |
|
||
sub external_search | ||
{ | ||
my ($self, $type, $query, $limit, $page, $adv) = @_; | ||
my ($self, $type, $query, $limit, $page, $adv, $user_lang) = @_; | ||
|
||
my $entity_model = $self->c->model( type_to_model($type) )->_entity_class; | ||
load_class($entity_model); | ||
|
@@ -906,7 +929,7 @@ sub external_search | |
|
||
foreach my $t (@{$data->{$xmltype}}) | ||
{ | ||
$self->schema_fixup($t, $type); | ||
$self->schema_fixup($t, $type, $user_lang); | ||
push @results, MusicBrainz::Server::Entity::SearchResult->new( | ||
position => $pos++, | ||
score => $t->{score}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ our @EXPORT_OK = qw( | |
copy_escape | ||
coordinates_to_hash | ||
datetime_to_iso8601 | ||
find_best_primary_alias | ||
generate_gid | ||
generate_token | ||
get_area_containment_join | ||
|
@@ -770,6 +771,35 @@ sub contains_string { | |
return any { $_ eq $string } @$array_ref; | ||
} | ||
|
||
# Given an array of MusicBrainz::Server::Entity::Alias objects and the UI | ||
# language, try to find a localized primary alias to display to the user. | ||
sub find_best_primary_alias { | ||
my ($aliases_ref, $lang) = @_; | ||
|
||
my $short_lang = substr($lang, 0, 2); | ||
my ($best, $fallback); | ||
foreach my $alias (@$aliases_ref) { | ||
next if !defined $alias->locale || !$alias->primary_for_locale; | ||
|
||
# If we find an exact match for the user's language, use it. | ||
return $alias if $alias->locale eq $lang; | ||
|
||
# Otherwise, favor more-generic aliases (e.g. "en" over "en_US"). | ||
if (substr($alias->locale, 0, 2) eq $short_lang && | ||
(!defined $best || length($alias->locale) == 2)) { | ||
$best = $alias; | ||
} | ||
# If we find an English alias, use it as a fallback. This is likely | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured it'd be worthwhile falling back to English here since it looks like all of the UI languages that are presently listed use the Latin script. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I mentioned it earlier, but a (future?) downside of this is that if e.g. a user selects Japanese as their UI language (I don't think they can at present), then they'll always see English aliases for Japanese artists, since I don't think there's any way to know that the artist entity's name is already in Japanese. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could in theory check if there's a Japanese artist alias that exactly matches the artist name (but you're right, if that data doesn't exist). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, in practice I don't think that many editors add primary aliases that are identical to entity names. https://musicbrainz.org/artist/9ddd7abc-9e1b-471d-8031-583bc6bc8be9/aliases has a zillion aliases, but of the two matching the "Пётр Ильич Чайковский" entity name, one is a non-primary legal name for Russian and the other is a search hint. Oddly, there's a primary artist name Russian alias of "Пётр Чайковский". |
||
# better than nothing in many cases, since English aliases often apply | ||
# to all Latin-script languages. | ||
if (substr($alias->locale, 0, 2) eq 'en' && | ||
(!defined $fallback || length($alias->locale) == 2)) { | ||
$fallback = $alias; | ||
} | ||
} | ||
return $best || $fallback; | ||
} | ||
|
||
1; | ||
|
||
=head1 COPYRIGHT AND LICENSE | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty clueless about how this
c
(context?) stash stuff works. I'm passing the language around sincecurrent_language
didn't seem to be available inload_related_info
and the indexed search code, but please let me know if there's an easier way to get at it there.