diff options
59 files changed, 785 insertions, 136 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index cb2bb5673..0f8e64bb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Releases * Unreleased + - New features: + - Body and category names can now be translated in the admin. #1244 - Front end improvements: - Always show pagination figures even if only one page. - Admin improvements: diff --git a/bin/fixmystreet.com/fixture b/bin/fixmystreet.com/fixture index d3b0a8349..912d34aab 100755 --- a/bin/fixmystreet.com/fixture +++ b/bin/fixmystreet.com/fixture @@ -31,7 +31,7 @@ my ($opt, $usage) = describe_options( ); print($usage->text), exit if $opt->help; -my $db = FixMyStreet::DB->storage; +my $db = FixMyStreet::DB->schema->storage; $db->txn_begin; END { if ($db) { diff --git a/bin/oxfordshire/send-rdi-emails b/bin/oxfordshire/send-rdi-emails index 11e7a6fe9..9eff02715 100755 --- a/bin/oxfordshire/send-rdi-emails +++ b/bin/oxfordshire/send-rdi-emails @@ -55,7 +55,7 @@ foreach my $inspector (@inspectors) { }; my $result = FixMyStreet::Email::send_cron( - FixMyStreet::DB->storage->schema, + FixMyStreet::DB->schema, "rdi.txt", $params, $hdrs, undef, 0, $cobrand, ); diff --git a/bin/zurich/overdue-alert b/bin/zurich/overdue-alert index 90e31df1c..f4fd0f4b7 100755 --- a/bin/zurich/overdue-alert +++ b/bin/zurich/overdue-alert @@ -38,7 +38,7 @@ loop_through( 'alert-overdue.txt', 0, 6, ['confirmed', 'planned'] ); sub loop_through { my ( $template, $include_parent, $days, $states ) = @_; - my $dtf = FixMyStreet::DB->storage->datetime_parser; + my $dtf = FixMyStreet::DB->schema->storage->datetime_parser; my $date_threshold = $dtf->format_datetime(FixMyStreet::Cobrand::Zurich::sub_days( $now, $days )); my $reports = FixMyStreet::DB->resultset("Problem")->search( { @@ -78,7 +78,7 @@ sub send_alert { } FixMyStreet::Email::send_cron( - FixMyStreet::DB->storage->schema, + FixMyStreet::DB->schema, $template, $h, { diff --git a/db/downgrade_0052---0051.sql b/db/downgrade_0052---0051.sql new file mode 100644 index 000000000..715b4549f --- /dev/null +++ b/db/downgrade_0052---0051.sql @@ -0,0 +1,5 @@ +BEGIN; + +DROP TABLE translation; + +COMMIT; diff --git a/db/rerun_dbic_loader.pl b/db/rerun_dbic_loader.pl index 958b28241..cf6e89ab2 100755 --- a/db/rerun_dbic_loader.pl +++ b/db/rerun_dbic_loader.pl @@ -3,6 +3,13 @@ use strict; use warnings; +BEGIN { + use File::Basename qw(dirname); + use File::Spec; + my $d = dirname(File::Spec->rel2abs($0)); + require "$d/../setenv.pl"; +} + # This script inspects the current state of the database and then amends the # FixMyStreet::DB::Result::* files to suit. After running the changes should be # inspected before the code is commited. @@ -20,13 +27,15 @@ my @tables_to_ignore = ( my $exclude = '^(?:' . join( '|', @tables_to_ignore ) . ')$'; make_schema_at( - 'FixMyStreet::DB', + 'FixMyStreet::DB::Schema', { debug => 0, # switch on to be chatty dump_directory => './perllib', # edit files in place exclude => qr{$exclude}, # ignore some tables generate_pod => 0, # no need for pod overwrite_modifications => 1, # don't worry that the md5 is wrong + result_namespace => '+FixMyStreet::DB::Result', + resultset_namespace => '+FixMyStreet::DB::ResultSet', # add in some extra components components => [ 'FilterColumn', 'InflateColumn::DateTime', 'EncodedColumn' ], diff --git a/db/schema.sql b/db/schema.sql index d35071c0f..af6570b7a 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -528,3 +528,13 @@ CREATE TABLE contact_defect_types ( ALTER TABLE problem ADD COLUMN defect_type_id int REFERENCES defect_types(id); + +CREATE TABLE translation ( + id serial not null primary key, + tbl text not null, + object_id integer not null, + col text not null, + lang text not null, + msgstr text not null, + unique(tbl, object_id, col, lang) +); diff --git a/db/schema_0052-translation-table.sql b/db/schema_0052-translation-table.sql new file mode 100644 index 000000000..95df499cc --- /dev/null +++ b/db/schema_0052-translation-table.sql @@ -0,0 +1,13 @@ +BEGIN; + +CREATE TABLE translation ( + id serial not null primary key, + tbl text not null, + object_id integer not null, + col text not null, + lang text not null, + msgstr text not null, + unique(tbl, object_id, col, lang) +); + +COMMIT; diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm index c1628d010..2365118ea 100644 --- a/perllib/FixMyStreet/App.pm +++ b/perllib/FixMyStreet/App.pm @@ -168,6 +168,9 @@ template paths, maps, languages etc, etc. sub setup_request { my $c = shift; + # Set the Catalyst model schema to the same as the DB schema + $c->model("DB")->schema( FixMyStreet::DB->schema ); + $c->setup_dev_overrides(); my $cobrand = $c->cobrand; diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index d1ac5e76b..0fa58eb9d 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -244,6 +244,9 @@ sub bodies : Path('bodies') : Args(0) { $c->stash->{edit_activity} = $edit_activity; + $c->forward( 'fetch_languages' ); + $c->forward( 'fetch_translations' ); + my $posted = $c->get_param('posted') || ''; if ( $posted eq 'body' ) { $c->forward('check_for_super_user'); @@ -257,6 +260,9 @@ sub bodies : Path('bodies') : Args(0) { $c->model('DB::BodyArea')->create( { body => $body, area_id => $_ } ); } + $c->stash->{object} = $body; + $c->stash->{translation_col} = 'name'; + $c->forward('update_translations'); $c->stash->{updated} = _('New body added'); } } @@ -300,30 +306,6 @@ sub body_form_dropdowns : Private { $c->stash->{send_methods} = \@methods; } -sub body : Path('body') : Args(1) { - my ( $self, $c, $body_id ) = @_; - - $c->stash->{body_id} = $body_id; - - unless ($c->user->has_permission_to('category_edit', $body_id)) { - $c->forward('check_for_super_user'); - } - - $c->forward( '/auth/get_csrf_token' ); - $c->forward( 'lookup_body' ); - $c->forward( 'fetch_all_bodies' ); - $c->forward( 'body_form_dropdowns' ); - - if ( $c->get_param('posted') ) { - $c->log->debug( 'posted' ); - $c->forward('update_contacts'); - } - - $c->forward('fetch_contacts'); - - return 1; -} - sub check_for_super_user : Private { my ( $self, $c ) = @_; @@ -407,6 +389,12 @@ sub update_contacts : Private { $contact->insert; } + unless ( %errors ) { + $c->stash->{translation_col} = 'category'; + $c->stash->{object} = $contact; + $c->forward('update_translations'); + } + } elsif ( $posted eq 'update' ) { $c->forward('/auth/check_csrf_token'); @@ -446,11 +434,45 @@ sub update_contacts : Private { # Remove any others $c->stash->{body}->body_areas->search( { area_id => [ keys %current ] } )->delete; + $c->stash->{translation_col} = 'name'; + $c->stash->{object} = $c->stash->{body}; + $c->forward('update_translations'); + $c->stash->{updated} = _('Values updated'); } } } +sub update_translations : Private { + my ( $self, $c ) = @_; + + foreach my $lang (keys(%{$c->stash->{languages}})) { + my $id = $c->get_param('translation_id_' . $lang); + my $text = $c->get_param('translation_' . $lang); + if ($id) { + my $translation = $c->model('DB::Translation')->find( + { + id => $id, + } + ); + + if ($text) { + $translation->msgstr($text); + $translation->update; + } else { + $translation->delete; + } + } elsif ($text) { + my $col = $c->stash->{translation_col}; + $c->stash->{object}->add_translation_for( + $col, $lang, $text + ); + } + } + + $c->stash->{updated} = _('Translations updated'); +} + sub body_params : Private { my ( $self, $c ) = @_; @@ -497,6 +519,44 @@ sub fetch_contacts : Private { return 1; } +sub fetch_languages : Private { + my ( $self, $c ) = @_; + + my $lang_map = {}; + foreach my $lang (sort @{$c->cobrand->languages}) { + my ($id, $name, $code) = split(',', $lang); + $lang_map->{$id} = { name => $name, code => $code }; + } + + $c->stash->{languages} = $lang_map; + + return 1; +} + +sub fetch_translations : Private { + my ( $self, $c ) = @_; + + my $translations = {}; + if ($c->get_param('posted')) { + foreach my $lang (keys %{$c->stash->{languages}}) { + if (my $msgstr = $c->get_param('translation_' . $lang)) { + $translations->{$lang} = { msgstr => $msgstr }; + } + if (my $id = $c->get_param('translation_id_' . $lang)) { + $translations->{$lang}->{id} = $id; + } + } + } elsif ($c->stash->{object}) { + my @translations = $c->stash->{object}->translation_for($c->stash->{translation_col})->all; + + foreach my $tx (@translations) { + $translations->{$tx->lang} = { id => $tx->id, msgstr => $tx->msgstr }; + } + } + + $c->stash->{translations} = $translations; +} + sub lookup_body : Private { my ( $self, $c ) = @_; @@ -516,35 +576,94 @@ sub lookup_body : Private { return 1; } +sub body_base : Chained('/') : PathPart('admin/body') : CaptureArgs(0) { } + # This is for if the category name contains a '/' -sub category_edit_all : Path('body') { +sub category_edit_all : Chained('body_base') : PathPart('') { my ( $self, $c, $body_id, @category ) = @_; my $category = join( '/', @category ); - $c->go( 'category_edit', [ $body_id, $category ] ); -} -sub category_edit : Path('body') : Args(2) { - my ( $self, $c, $body_id, $category ) = @_; + $c->stash->{body_id} = $body_id; + $c->forward( 'lookup_body' ); + my $contact = $c->stash->{body}->contacts->search( { category => $category } )->first; + $c->stash->{contact} = $contact; + + $c->stash->{template} = 'admin/category_edit.html'; + $c->forward( 'category_edit' ); +} + +sub body : Chained('body_base') : PathPart('') : CaptureArgs(1) { + my ( $self, $c, $body_id ) = @_; $c->stash->{body_id} = $body_id; +} + +sub edit_body : Chained('body') : PathPart('') : Args(0) { + my ( $self, $c ) = @_; + + unless ($c->user->has_permission_to('category_edit', $c->stash->{body_id})) { + $c->forward('check_for_super_user'); + } + + $c->forward( '/auth/get_csrf_token' ); + $c->forward( 'lookup_body' ); + $c->forward( 'fetch_all_bodies' ); + $c->forward( 'body_form_dropdowns' ); + $c->forward('fetch_languages'); + + if ( $c->get_param('posted') ) { + $c->forward('update_contacts'); + } + + $c->stash->{object} = $c->stash->{body}; + $c->stash->{translation_col} = 'name'; + + # if there's a contact then it's because we're displaying error + # messages about adding a contact so grabbing translations will + # fetch the contact submitted translations. So grab them, stash + # them and then clear posted so we can fetch the body translations + if ($c->stash->{contact}) { + $c->forward('fetch_translations'); + $c->stash->{contact_translations} = $c->stash->{translations}; + } + $c->set_param('posted', ''); + + $c->forward('fetch_translations'); + $c->forward('fetch_contacts'); + + $c->stash->{template} = 'admin/body.html'; + return 1; +} + +sub category : Chained('body') : PathPart('') : CaptureArgs(1) { + my ( $self, $c, $category ) = @_; $c->forward( '/auth/get_csrf_token' ); $c->forward( 'lookup_body' ); my $contact = $c->stash->{body}->contacts->search( { category => $category } )->first; $c->stash->{contact} = $contact; +} + +sub category_edit : Chained('category') : PathPart('') : Args(0) { + my ( $self, $c ) = @_; + + $c->stash->{translation_col} = 'category'; + $c->stash->{object} = $c->stash->{contact}; + + $c->forward('fetch_languages'); + $c->forward('fetch_translations'); my $history = $c->model('DB::ContactsHistory')->search( { - body_id => $body_id, - category => $category + body_id => $c->stash->{body_id}, + category => $c->stash->{contact}->category }, { order_by => ['contacts_history_id'] }, ); $c->stash->{history} = $history; - my @methods = map { $_ =~ s/FixMyStreet::SendReport:://; $_ } keys %{ FixMyStreet::SendReport->get_senders }; $c->stash->{send_methods} = \@methods; @@ -925,8 +1044,8 @@ sub categories_for_point : Private { # Remove the "Pick a category" option shift @{$c->stash->{category_options}} if @{$c->stash->{category_options}}; - $c->stash->{categories} = $c->stash->{category_options}; - $c->stash->{categories_hash} = { map { $_ => 1 } @{$c->stash->{category_options}} }; + $c->stash->{category_options_copy} = $c->stash->{category_options}; + $c->stash->{categories_hash} = { map { $_->{name} => 1 } @{$c->stash->{category_options}} }; } sub templates : Path('templates') : Args(0) { diff --git a/perllib/FixMyStreet/App/Controller/Around.pm b/perllib/FixMyStreet/App/Controller/Around.pm index bd9e80dc7..a8782eba2 100644 --- a/perllib/FixMyStreet/App/Controller/Around.pm +++ b/perllib/FixMyStreet/App/Controller/Around.pm @@ -196,8 +196,8 @@ sub display_location : Private { my @pins; unless ($c->get_param('no_pins')) { @pins = map { - # Here we might have a DB::Problem or a DB::Nearby, we always want the problem. - my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_; + # Here we might have a DB::Problem or a DB::Result::Nearby, we always want the problem. + my $p = (ref $_ eq 'FixMyStreet::DB::Result::Nearby') ? $_->problem : $_; $p->pin_data($c, 'around'); } @$on_map_all, @$nearby; } @@ -259,7 +259,7 @@ sub check_and_stash_category : Private { distinct => 1 } )->all; - my @categories = map { $_->category } @contacts; + my @categories = map { { name => $_->category, value => $_->category_display } } @contacts; $c->stash->{filter_categories} = \@categories; my %categories_mapped = map { $_ => 1 } @categories; @@ -311,8 +311,8 @@ sub ajax : Path('/ajax') { # create a list of all the pins my @pins = map { - # Here we might have a DB::Problem or a DB::Nearby, we always want the problem. - my $p = (ref $_ eq 'FixMyStreet::App::Model::DB::Nearby') ? $_->problem : $_; + # Here we might have a DB::Problem or a DB::Result::Nearby, we always want the problem. + my $p = (ref $_ eq 'FixMyStreet::DB::Result::Nearby') ? $_->problem : $_; my $colour = $c->cobrand->pin_colour( $p, 'around' ); my $title = $c->cobrand->call_hook(pin_hover_title => $p, $p->title_safe) || $p->title_safe; [ $p->latitude, $p->longitude, diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm index 6fee25ec5..ea7aee016 100644 --- a/perllib/FixMyStreet/App/Controller/My.pm +++ b/perllib/FixMyStreet/App/Controller/My.pm @@ -162,7 +162,7 @@ sub setup_page_data : Private { distinct => 1, order_by => [ 'category' ], } )->all; - @categories = map { $_->category } @categories; + @categories = map { { name => $_->category, value => $_->category_display } } @categories; $c->stash->{filter_categories} = \@categories; $c->stash->{page} = 'my'; diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm index 3acb385bd..ab4c616fb 100644 --- a/perllib/FixMyStreet/App/Controller/Report/New.pm +++ b/perllib/FixMyStreet/App/Controller/Report/New.pm @@ -201,7 +201,7 @@ sub report_form_ajax : Path('ajax') : Args(0) { if ($c->user_exists) { my @bodies = keys %{$c->stash->{bodies}}; my $ca_another_user = $c->user->has_permission_to('contribute_as_another_user', \@bodies); - my $ca_body = $c->user->has_permission_to('contribute_as_body', \@bodies); + my $ca_body = $c->user->from_body && $c->user->has_permission_to('contribute_as_body', \@bodies); $contribute_as->{another_user} = $ca_another_user if $ca_another_user; $contribute_as->{body} = $ca_body if $ca_body; } @@ -213,7 +213,6 @@ sub report_form_ajax : Path('ajax') : Args(0) { category => $category, extra_name_info => $extra_name_info, titles_list => $extra_titles_list, - categories => $c->stash->{category_options}, %$contribute_as ? (contribute_as => $contribute_as) : (), $top_message ? (top_message => $top_message) : (), } @@ -645,7 +644,7 @@ sub setup_categories_and_bodies : Private { $bodies_to_list{ $contact->body_id } = $contact->body; unless ( $seen{$contact->category} ) { - push @category_options, $contact->category; + push @category_options, { name => $contact->category, value => $contact->category_display }; my $metas = $contact->get_metadata_for_input; $category_extras{$contact->category} = $metas if @$metas; @@ -657,13 +656,15 @@ sub setup_categories_and_bodies : Private { $non_public_categories{ $contact->category } = 1 if $contact->non_public; } - $seen{$contact->category} = 1; + $seen{$contact->category} = $contact->category_display; } if (@category_options) { # If there's an Other category present, put it at the bottom - @category_options = ( _('-- Pick a category --'), grep { $_ ne _('Other') } @category_options ); - push @category_options, _('Other') if $seen{_('Other')}; + @category_options = ( + { name => _('-- Pick a category --'), value => _('-- Pick a category --') }, + grep { $_->{name} ne _('Other') } @category_options ); + push @category_options, { name => _('Other'), value => $seen{_('Other')} } if $seen{_('Other')}; } $c->cobrand->call_hook(munge_category_list => \@category_options, \@contacts, \%category_extras); diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm index 8f068f0ec..33a1ac5b9 100644 --- a/perllib/FixMyStreet/App/Controller/Reports.pm +++ b/perllib/FixMyStreet/App/Controller/Reports.pm @@ -150,7 +150,7 @@ sub ward : Path : Args(2) { distinct => 1, order_by => [ 'category' ], } )->all; - @categories = map { $_->category } @categories; + @categories = map { { name => $_->category, value => $_->category_display } } @categories; $c->stash->{filter_categories} = \@categories; $c->stash->{filter_category} = { map { $_ => 1 } $c->get_param_list('filter_category', 1) }; @@ -318,6 +318,19 @@ sub body_check : Private { } } + my @translations = $c->model('DB::Translation')->search( { + tbl => 'body', + col => 'name', + msgstr => $q_body + } )->all; + + if (@translations == 1) { + if ( my $body = $c->model('DB::Body')->find( { id => $translations[0]->object_id } ) ) { + $c->stash->{body} = $body; + return; + } + } + # No result, bad body name. $c->detach( 'redirect_index' ); } diff --git a/perllib/FixMyStreet/App/Model/DB.pm b/perllib/FixMyStreet/App/Model/DB.pm index ac1f98dc9..9d09186b8 100644 --- a/perllib/FixMyStreet/App/Model/DB.pm +++ b/perllib/FixMyStreet/App/Model/DB.pm @@ -7,8 +7,8 @@ use warnings; use FixMyStreet; __PACKAGE__->config( - schema_class => 'FixMyStreet::DB', - connect_info => sub { FixMyStreet::DB->storage->dbh }, + schema_class => 'FixMyStreet::DB::Schema', + connect_info => sub { FixMyStreet::DB->schema->storage->dbh }, ); =head1 NAME diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm index 4a886204c..1a0bbb0c8 100644 --- a/perllib/FixMyStreet/Cobrand/Default.pm +++ b/perllib/FixMyStreet/Cobrand/Default.pm @@ -269,6 +269,8 @@ sub set_lang_and_domain { DateTime->DefaultLocale( 'en_US' ); } + FixMyStreet::DB->schema->lang($set_lang); + return $set_lang; } sub languages { FixMyStreet->config('LANGUAGES') || [] } diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 776350b25..c56f595ca 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -519,7 +519,7 @@ sub admin_report_edit { # Can change category to any other my @categories = $c->model('DB::Contact')->not_deleted->all; - $c->stash->{categories} = [ map { $_->category } @categories ]; + $c->stash->{category_options} = [ map { { name => $_->category, value => $_->category } } @categories ]; } elsif ($type eq 'dm') { @@ -534,7 +534,7 @@ sub admin_report_edit { # Can change category to any other my @categories = $c->model('DB::Contact')->not_deleted->all; - $c->stash->{categories} = [ map { $_->category } @categories ]; + $c->stash->{category_options} = [ map { { name => $_->category, value => $_->category } } @categories ]; } diff --git a/perllib/FixMyStreet/DB.pm b/perllib/FixMyStreet/DB.pm index d920c809f..cee66b434 100644 --- a/perllib/FixMyStreet/DB.pm +++ b/perllib/FixMyStreet/DB.pm @@ -1,22 +1,13 @@ -use utf8; package FixMyStreet::DB; -# Created by DBIx::Class::Schema::Loader -# DO NOT MODIFY THE FIRST PART OF THIS FILE - use strict; use warnings; +use FixMyStreet::DB::Schema; -use base 'DBIx::Class::Schema'; - -__PACKAGE__->load_namespaces; - - -# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:CjFpUvon7KggFM7OF7VK/w +my $schema; -use FixMyStreet; +sub schema { $schema ||= FixMyStreet::DB::Schema->clone } -__PACKAGE__->connection(FixMyStreet->dbic_connect_info); +sub resultset { shift->schema->resultset(@_) } 1; diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm index 9a64d1608..db7777053 100644 --- a/perllib/FixMyStreet/DB/Result/Body.pm +++ b/perllib/FixMyStreet/DB/Result/Body.pm @@ -121,12 +121,19 @@ __PACKAGE__->has_many( # Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-02-13 15:11:11 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BOJANVwg3kR/1VjDq0LykA +use Moo; +use namespace::clean; + +with 'FixMyStreet::Roles::Translatable'; + sub url { my ( $self, $c, $args ) = @_; # XXX $areas_info was used here for Norway parent - needs body parents, I guess return $c->uri_for( '/reports/' . $c->cobrand->short_name( $self ), $args || {} ); } +around name => \&translate_around; + sub areas { my $self = shift; my %ids = map { $_->area_id => 1 } $self->body_areas->all; diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm index 3454c5806..fb731b9a3 100644 --- a/perllib/FixMyStreet/DB/Result/Contact.pm +++ b/perllib/FixMyStreet/DB/Result/Contact.pm @@ -82,12 +82,18 @@ __PACKAGE__->rabx_column('extra'); use Moo; use namespace::clean -except => [ 'meta' ]; -with 'FixMyStreet::Roles::Extra'; +with 'FixMyStreet::Roles::Extra', + 'FixMyStreet::Roles::Translatable'; __PACKAGE__->many_to_many( response_templates => 'contact_response_templates', 'response_template' ); __PACKAGE__->many_to_many( response_priorities => 'contact_response_priorities', 'response_priority' ); __PACKAGE__->many_to_many( defect_types => 'contact_defect_types', 'defect_type' ); +sub category_display { + my $self = shift; + $self->translate('category'); +} + sub get_metadata_for_input { my $self = shift; my $id_field = $self->id_field; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index f353c02ee..afa117e4c 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -206,6 +206,7 @@ my $IM = eval { with 'FixMyStreet::Roles::Abuser', 'FixMyStreet::Roles::Extra', + 'FixMyStreet::Roles::Translatable', 'FixMyStreet::Roles::PhotoSet'; =head2 @@ -456,12 +457,6 @@ sub check_for_errors { $errors{category} = _('Please choose a category'); $self->category(undef); } - elsif ($self->category - && $self->category eq _('-- Pick a property type --') ) - { - $errors{category} = _('Please choose a property type'); - $self->category(undef); - } return \%errors; } @@ -489,6 +484,11 @@ sub confirm { return 1; } +sub category_display { + my $self = shift; + $self->translate('category'); +} + sub bodies_str_ids { my $self = shift; return [] unless $self->bodies_str; @@ -635,7 +635,7 @@ sub meta_line { my $date_time = Utils::prettify_dt( $problem->confirmed ); my $meta = ''; - my $category = $problem->category; + my $category = $problem->category_display; $category = $c->cobrand->call_hook(change_category_text => $category) || $category; if ( $problem->anonymous ) { diff --git a/perllib/FixMyStreet/DB/Result/Translation.pm b/perllib/FixMyStreet/DB/Result/Translation.pm new file mode 100644 index 000000000..fafc7ccf1 --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/Translation.pm @@ -0,0 +1,44 @@ +use utf8; +package FixMyStreet::DB::Result::Translation; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; +__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime", "EncodedColumn"); +__PACKAGE__->table("translation"); +__PACKAGE__->add_columns( + "id", + { + data_type => "integer", + is_auto_increment => 1, + is_nullable => 0, + sequence => "translation_id_seq", + }, + "tbl", + { data_type => "text", is_nullable => 0 }, + "object_id", + { data_type => "integer", is_nullable => 0 }, + "col", + { data_type => "text", is_nullable => 0 }, + "lang", + { data_type => "text", is_nullable => 0 }, + "msgstr", + { data_type => "text", is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("id"); +__PACKAGE__->add_unique_constraint( + "translation_tbl_object_id_col_lang_key", + ["tbl", "object_id", "col", "lang"], +); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-07-14 23:24:32 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:///VNqg4BOuO29xKhnY8vw + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/perllib/FixMyStreet/DB/Schema.pm b/perllib/FixMyStreet/DB/Schema.pm new file mode 100644 index 000000000..45d731c33 --- /dev/null +++ b/perllib/FixMyStreet/DB/Schema.pm @@ -0,0 +1,28 @@ +use utf8; +package FixMyStreet::DB::Schema; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Schema'; + +__PACKAGE__->load_namespaces( + result_namespace => "+FixMyStreet::DB::Result", + resultset_namespace => "+FixMyStreet::DB::ResultSet", +); + + +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-07-13 14:15:09 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:UpH30RXb6SbCqRv2FPmpkg + +use Moo; +use FixMyStreet; + +__PACKAGE__->connection(FixMyStreet->dbic_connect_info); + +has lang => ( is => 'rw' ); + +1; diff --git a/perllib/FixMyStreet/Roles/Translatable.pm b/perllib/FixMyStreet/Roles/Translatable.pm new file mode 100644 index 000000000..49f10d51a --- /dev/null +++ b/perllib/FixMyStreet/Roles/Translatable.pm @@ -0,0 +1,97 @@ +package FixMyStreet::Roles::Translatable; + +use Moo::Role; + +sub translate_around { + my ($orig, $self) = (shift, shift); + my $fallback = $self->$orig(@_); + (my $col = (caller(2))[3]) =~ s/.*:://; + $self->_translate($col, $fallback); +} + +sub translate { + my ($self, $col) = (shift, shift); + my $fallback = $self->$col(@_); + $self->_translate($col, $fallback); +} + +sub _translate { + my ($self, $col, $fallback) = @_; + + my $schema = $self->result_source->schema; + my $table = lc $self->result_source->source_name; + my $id = $self->id; + + # Deal with the fact problem table has denormalized copy of category string + if ($table eq 'problem' && $col eq 'category') { + my $body_id = $self->bodies_str_ids->[0]; + return $fallback unless $body_id && $body_id =~ /^[0-9]+$/; + my $contact = $schema->resultset("Contact")->find( { + body_id => $body_id, + category => $fallback, + } ); + return $fallback unless $contact; # Shouldn't happen, but some tests + $table = 'contact'; + $id = $contact->id; + } + + if (ref $schema) { + my $translation = $schema->resultset('Translation')->find({ + lang => $schema->lang, + tbl => $table, + object_id => $id, + col => $col + }); + return $translation->msgstr if $translation; + } else { + warn "Can't use translation on this call to $table.$col"; + } + return $fallback; +}; + +# These next two functions (translation_for and and_translation_for) are +# convenience methods for use in the translation interface in the admin. +# They shouldn't be used else where as they don't take account of things +# like denormalised strings (e.g report category) +sub translation_for { + my ($self, $col, $lang) = @_; + + my $schema = $self->result_source->schema; + + my $props = { + tbl => lc $self->result_source->source_name, + object_id => $self->id, + col => $col + }; + + if ($lang) { + $props->{lang} = $lang; + } + + my $translations = $schema->resultset('Translation')->search($props); + + return $lang ? $translations->first : $translations; +} + +sub add_translation_for { + my ($self, $col, $lang, $msgstr) = @_; + + my $schema = $self->result_source->schema; + + my $props = { + tbl => lc $self->result_source->source_name, + object_id => $self->id, + col => $col, + lang => $lang, + msgstr => $msgstr, + }; + + my $translation = $schema->resultset('Translation')->update_or_create( + $props, + { key => 'translation_tbl_object_id_col_lang_key' } + ); + + return $translation; +} + +1; diff --git a/perllib/FixMyStreet/Script/Alerts.pm b/perllib/FixMyStreet/Script/Alerts.pm index ef1bdb08b..aefe13318 100644 --- a/perllib/FixMyStreet/Script/Alerts.pm +++ b/perllib/FixMyStreet/Script/Alerts.pm @@ -62,7 +62,7 @@ sub send() { $query =~ s/\?/alert.parameter/ if ($query =~ /\?/); $query =~ s/\?/alert.parameter2/ if ($query =~ /\?/); - $query = FixMyStreet::DB->storage->dbh->prepare($query); + $query = FixMyStreet::DB->schema->storage->dbh->prepare($query); $query->execute(); my $last_alert_id; my %data = ( template => $alert_type->template, data => [], schema => $schema ); @@ -225,7 +225,7 @@ sub send() { and (select whenqueued from alert_sent where alert_sent.alert_id = ? and alert_sent.parameter::integer = problem.id) is null and users.email <> ? order by confirmed desc"; - $q = FixMyStreet::DB->storage->dbh->prepare($q); + $q = FixMyStreet::DB->schema->storage->dbh->prepare($q); $q->execute($latitude, $longitude, $d, $alert->whensubscribed, $alert->id, $alert->user->email); while (my $row = $q->fetchrow_hashref) { $schema->resultset('AlertSent')->create( { diff --git a/perllib/FixMyStreet/Script/UpdateAllReports.pm b/perllib/FixMyStreet/Script/UpdateAllReports.pm index 51cb7b856..1bd069ee8 100755 --- a/perllib/FixMyStreet/Script/UpdateAllReports.pm +++ b/perllib/FixMyStreet/Script/UpdateAllReports.pm @@ -158,7 +158,7 @@ sub generate_dashboard { ); $data{last_seven_days} = \%last_seven_days; - my $dtf = FixMyStreet::DB->storage->datetime_parser; + my $dtf = FixMyStreet::DB->schema->storage->datetime_parser; my $eight_ago = $dtf->format_datetime(DateTime->now->subtract(days => 8)); %problems_reported_by_period = stuff_by_day_or_year('day', 'Problem', diff --git a/perllib/FixMyStreet/Test.pm b/perllib/FixMyStreet/Test.pm index add67dfd9..6b6bc02bc 100644 --- a/perllib/FixMyStreet/Test.pm +++ b/perllib/FixMyStreet/Test.pm @@ -8,7 +8,7 @@ use utf8; use Test::More; use FixMyStreet::DB; -my $db = FixMyStreet::DB->storage; +my $db = FixMyStreet::DB->schema->storage; sub import { strict->import; diff --git a/perllib/Open311/GetServiceRequestUpdates.pm b/perllib/Open311/GetServiceRequestUpdates.pm index 30db24164..6ba53b7af 100644 --- a/perllib/Open311/GetServiceRequestUpdates.pm +++ b/perllib/Open311/GetServiceRequestUpdates.pm @@ -11,7 +11,7 @@ has start_date => ( is => 'ro', default => sub { undef } ); has end_date => ( is => 'ro', default => sub { undef } ); has suppress_alerts => ( is => 'rw', default => 0 ); has verbose => ( is => 'ro', default => 0 ); -has schema => ( is =>'ro', lazy => 1, default => sub { FixMyStreet::DB->connect } ); +has schema => ( is =>'ro', lazy => 1, default => sub { FixMyStreet::DB->schema->connect } ); Readonly::Scalar my $AREA_ID_BROMLEY => 2482; Readonly::Scalar my $AREA_ID_OXFORDSHIRE => 2237; diff --git a/perllib/Open311/PopulateServiceList.pm b/perllib/Open311/PopulateServiceList.pm index 540425bf1..764207626 100644 --- a/perllib/Open311/PopulateServiceList.pm +++ b/perllib/Open311/PopulateServiceList.pm @@ -6,7 +6,7 @@ use Open311; has bodies => ( is => 'ro' ); has found_contacts => ( is => 'rw', default => sub { [] } ); has verbose => ( is => 'ro', default => 0 ); -has schema => ( is => 'ro', lazy => 1, default => sub { FixMyStreet::DB->connect } ); +has schema => ( is => 'ro', lazy => 1, default => sub { FixMyStreet::DB->schema->connect } ); has _current_body => ( is => 'rw' ); has _current_open311 => ( is => 'rw' ); diff --git a/t/app/controller/admin.t b/t/app/controller/admin.t index db7f9fc3c..069e00b5e 100644 --- a/t/app/controller/admin.t +++ b/t/app/controller/admin.t @@ -182,7 +182,7 @@ subtest 'check contact creation' => sub { non_public => 'on', } } ); $mech->get_ok('/admin/body/' . $body->id . '/test/category'); - + $mech->content_contains('<h1>test/category</h1>'); }; subtest 'check contact editing' => sub { diff --git a/t/app/controller/admin_translations.t b/t/app/controller/admin_translations.t new file mode 100644 index 000000000..f5c32baa6 --- /dev/null +++ b/t/app/controller/admin_translations.t @@ -0,0 +1,191 @@ +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; + +my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); + +$mech->log_in_ok( $superuser->email ); + +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + MAPIT_TYPES => [ 'UTA' ], +}, sub { + +my $body = $mech->create_body_ok(2650, 'Aberdeen City Council'); +$mech->create_contact_ok( body_id => $body->id, category => 'Traffic lights', email => 'lights@example.com' ); + +subtest 'check no translations if one language' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_lacks( 'Translations' ); + +}; + +}; + +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + MAPIT_TYPES => [ 'UTA' ], + LANGUAGES => [ + 'en-gb,English,en_GB', + 'de,German,de_DE' + ] +}, sub { + +my $body = $mech->create_body_ok(2650, 'Aberdeen City Council'); +$mech->create_contact_ok( body_id => $body->id, category => 'Traffic lights', email => 'lights@example.com' ); + +my $body2 = $mech->create_body_ok(2643, 'Arun District Council'); + +FixMyStreet::DB->resultset("Translation")->create({ + lang => "de", + tbl => "body", + object_id => $body2->id, + col => "name", + msgstr => "DE Arun", +}); + +subtest 'check translations if multiple languages' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_contains( 'Translations' ); +}; + +subtest 'check add category with translation' => sub { + $mech->get_ok('/admin/body/' . $body2->id); + + $mech->content_contains('DE Arun'); + + $mech->submit_form_ok( { with_fields => { + category => 'Potholes', + translation_de => 'DE potholes', + email => 'potholes@example.org', + } } ); + + # check that error page includes translations + $mech->content_lacks('DE Arun'); + $mech->content_contains('DE potholes'); + + $mech->submit_form_ok( { with_fields => { + category => 'Potholes', + translation_de => 'DE potholes', + email => 'potholes@example.org', + note => 'adding category with translation', + } } ); + + $mech->content_contains('DE Arun'); + $mech->content_lacks('DE potholes'); + + $mech->get_ok('/admin/body/' . $body2->id . '/Potholes'); + + $mech->content_contains( 'DE potholes' ); +}; + +subtest 'check add category translation' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_lacks( 'DE Traffic lights' ); + + $mech->submit_form_ok( { with_fields => { + translation_de => 'DE Traffic lights', + note => 'updating translation', + } } ); + + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_contains( 'DE Traffic lights' ); +}; + +subtest 'check replace category translation' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_contains( 'DE Traffic lights' ); + + $mech->submit_form_ok( { with_fields => { + translation_de => 'German Traffic lights', + note => 'updating translation', + } } ); + + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_lacks( 'DE Traffic lights' ); + $mech->content_contains( 'German Traffic lights' ); +}; + +subtest 'delete category translation' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + $mech->content_contains( 'German Traffic lights' ); + + $mech->submit_form_ok( { with_fields => { + translation_de => '', + note => 'updating translation', + } } ); + + $mech->get_ok('/admin/body/' . $body->id . '/Traffic%20lights'); + + $mech->content_lacks( 'DE German Traffic lights' ); +}; + +subtest 'check add body translation' => sub { + $mech->get_ok('/admin/body/' . $body->id); + + $mech->content_lacks( 'DE Aberdeen' ); + + $mech->submit_form_ok( { with_fields => { + send_method => 'email', + translation_de => 'DE Aberdeen', + } } ); + + $mech->content_contains( 'DE Aberdeen' ); +}; + +subtest 'check replace body translation' => sub { + $mech->get_ok('/admin/body/' . $body->id); + + $mech->content_contains( 'DE Aberdeen' ); + + $mech->submit_form_ok( { with_fields => { + send_method => 'email', + translation_de => 'German Aberdeen', + } } ); + + $mech->content_lacks( 'DE Aberdeen' ); + $mech->content_contains( 'German Aberdeen' ); +}; + +subtest 'delete body translation' => sub { + $mech->get_ok('/admin/body/' . $body->id); + $mech->content_contains( 'German Aberdeen' ); + + $mech->submit_form_ok( { with_fields => { + send_method => 'email', + translation_de => '', + } } ); + + $mech->content_lacks( 'DE German Aberdeen' ); +}; + +subtest 'check add body with translation' => sub { + $mech->get_ok('/admin/bodies/'); + $mech->submit_form_ok( { with_fields => { + area_ids => 2643, + send_method => 'email', + translation_de => 'DE A Body', + } } ); + + # check that error page includes translations + $mech->content_contains( 'DE A Body' ); + + $mech->submit_form_ok( { with_fields => { + name => 'A body', + area_ids => 2643, + send_method => 'email', + translation_de => 'DE A Body', + } } ); + + $mech->follow_link_ok({ text => 'A body' }); + $mech->content_contains( 'DE A Body' ); +} +}; + +done_testing(); diff --git a/t/app/controller/reports.t b/t/app/controller/reports.t index dd84d3d2e..9f28a6c89 100644 --- a/t/app/controller/reports.t +++ b/t/app/controller/reports.t @@ -25,6 +25,16 @@ my @edinburgh_problems = $mech->create_problems_for_body(3, $body_edin_id, 'All my @westminster_problems = $mech->create_problems_for_body(5, $body_west_id, 'All reports', { category => 'Graffiti' }); my @fife_problems = $mech->create_problems_for_body(15, $body_fife_id, 'All reports', { category => 'Flytipping' }); +my $west_trans = FixMyStreet::DB->resultset('Translation')->find_or_create({ + tbl => 'body', + object_id => $body_west_id, + col => 'name', + lang => 'de', + msgstr => 'De Westminster' +}); + +ok $west_trans, 'created westminster translation'; + is scalar @westminster_problems, 5, 'correct number of westminster problems created'; is scalar @edinburgh_problems, 3, 'correct number of edinburgh problems created'; is scalar @fife_problems, 15, 'correct number of fife problems created'; @@ -267,4 +277,13 @@ subtest "it lists shortlisted reports" => sub { }; }; +subtest "can use translated body name" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->get_ok('/reports/De Westminster'); + $mech->title_like(qr/Westminster City Council/); + }; +}; + done_testing(); diff --git a/t/app/model/extra.t b/t/app/model/extra.t index 4e2a8ed37..17f34c6c1 100644 --- a/t/app/model/extra.t +++ b/t/app/model/extra.t @@ -2,7 +2,7 @@ use FixMyStreet::Test; use DateTime; -my $db = FixMyStreet::DB->storage->schema; +my $db = FixMyStreet::DB->schema; my $body = $db->resultset('Body')->create({ name => 'ExtraTestingBody' }); diff --git a/t/app/model/photoset.t b/t/app/model/photoset.t index 3651a188a..4aa5c8992 100644 --- a/t/app/model/photoset.t +++ b/t/app/model/photoset.t @@ -10,7 +10,7 @@ my $dt = DateTime->now; my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); -my $db = FixMyStreet::DB->storage->schema; +my $db = FixMyStreet::DB->schema; my $user = $db->resultset('User')->find_or_create({ name => 'Bob', email => 'bob@example.com', diff --git a/t/app/model/problem.t b/t/app/model/problem.t index 76b7c476a..718b980b0 100644 --- a/t/app/model/problem.t +++ b/t/app/model/problem.t @@ -117,15 +117,6 @@ for my $test ( } }, { - desc => 'bad category', - changed => { - category => '-- Pick a property type --', - }, - errors => { - category => 'Please choose a property type', - } - }, - { desc => 'correct category', changed => { category => 'Horse!', diff --git a/t/app/sendreport/open311.t b/t/app/sendreport/open311.t index 8f933065c..32564dbd8 100644 --- a/t/app/sendreport/open311.t +++ b/t/app/sendreport/open311.t @@ -157,7 +157,7 @@ sub test_overrides { FixMyStreet::override_config { ALLOWED_COBRANDS => ['fixmystreet', 'oxfordshire', 'bromley', 'westberkshire', 'greenwich'], }, sub { - my $db = FixMyStreet::DB->storage->schema; + my $db = FixMyStreet::DB->schema; #$db->txn_begin; my $params = { id => $input->{body_id}, name => $input->{body_name} }; diff --git a/t/roles/translatable.t b/t/roles/translatable.t new file mode 100644 index 000000000..71e39c360 --- /dev/null +++ b/t/roles/translatable.t @@ -0,0 +1,71 @@ +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +my $body = FixMyStreet::DB->resultset("Body")->create({ name => 'Dunkirk' }); +my $contact = $mech->create_contact_ok( + body => $body, + email => 'potholes@dunkirk', + category => 'Potholes' +); + +FixMyStreet::DB->resultset("Translation")->create({ + lang => "fr", + tbl => "body", + object_id => $body->id, + col => "name", + msgstr => "Dunkerque", +}); + +FixMyStreet::DB->resultset("Translation")->create({ + lang => "de", + tbl => "contact", + object_id => $contact->id, + col => "category", + msgstr => "Schlaglöcher", +}); + +FixMyStreet::DB->resultset("Translation")->create({ + lang => "nb", + tbl => "contact", + object_id => $contact->id, + col => "category", + msgstr => "Hull i veien", +}); + +my ($problem) = $mech->create_problems_for_body(1, $body->id, "Title", { + whensent => \'current_timestamp', + category => 'Potholes', +}); + +is $body->name, "Dunkirk"; +is $contact->category_display, "Potholes"; +is $problem->category_display, "Potholes"; + +FixMyStreet::DB->schema->lang("fr"); +is $body->name, "Dunkerque"; +is $contact->category_display, "Potholes"; +is $problem->category_display, "Potholes"; + +FixMyStreet::DB->schema->lang("de"); +is $body->name, "Dunkirk"; +is $contact->category_display, "Schlaglöcher"; +is $problem->category_display, "Schlaglöcher"; + +is $contact->translation_for('category', 'de')->msgstr, "Schlaglöcher"; +is $body->translation_for('name', 'fr')->msgstr, "Dunkerque"; + +ok $body->add_translation_for('name', 'es', 'Dunkerque'); + +FixMyStreet::DB->schema->lang("es"); +is $body->name, "Dunkerque"; + +is $body->translation_for('name')->count, 2; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fiksgatami' ], +}, sub { + $mech->get_ok($problem->url); + $mech->content_contains('Hull i veien'); +}; + +done_testing; diff --git a/templates/web/base/admin/_translations.html b/templates/web/base/admin/_translations.html new file mode 100644 index 000000000..d2e0ba322 --- /dev/null +++ b/templates/web/base/admin/_translations.html @@ -0,0 +1,19 @@ +[% IF languages.size > 1 %] +<h2>[% loc('Translations') %]</h2> + <input type="hidden" name="token" value="[% csrf_token %]" > +<table> + <tr> + <th>[% loc('Language') %]</th> + <th>[% loc('Translation') %]</th> + </tr> + [% FOREACH language IN languages.keys %] + <tr> + <td> + <label for="translation_[% language %]">[% languages.$language.name %] ([% language %])</label> + <input type="hidden" name="translation_id_[% language %]" value="[% translations.$language.id %]"> + </td> + <td><input type="text" name="translation_[% language %]" id="translation_[% language %]" value="[% translations.$language.msgstr %]"></td> + </tr> + [% END %] +</table> +[% END %] diff --git a/templates/web/base/admin/body-form.html b/templates/web/base/admin/body-form.html index 6c750bcaf..55d0e500c 100644 --- a/templates/web/base/admin/body-form.html +++ b/templates/web/base/admin/body-form.html @@ -25,6 +25,8 @@ <input type="text" class="form-control" name="name" id="name" value="[% body.name | html %]" size="50"> </p> + [% INCLUDE 'admin/_translations.html' %] + <div class="admin-hint"> <p> [% loc( diff --git a/templates/web/base/admin/body.html b/templates/web/base/admin/body.html index 82032c0c3..7fa446f44 100644 --- a/templates/web/base/admin/body.html +++ b/templates/web/base/admin/body.html @@ -79,7 +79,7 @@ </tr> [% WHILE ( cat = contacts.next ) %] <tr [% IF cat.state == 'deleted' %]class="is-deleted"[% END %]> - <td class="contact-category"><a href="[% c.uri_for( 'body', body_id, cat.category ) %]">[% cat.category | html %]</a> + <td class="contact-category"><a href="[% c.uri_for( 'body', body_id, cat.category ) %]">[% cat.category_display | html %]</a> <br>[% cat.email | html %]</td> <td> [% cat.state %] @@ -130,9 +130,10 @@ <div class="fms-admin-warning"> [% errors.values.join('<br>') %] </div> + [% INCLUDE 'admin/contact-form.html' translations=contact_translations %] + [% ELSE %] + [% INCLUDE 'admin/contact-form.html' translations={} %] [% END %] - - [% INCLUDE 'admin/contact-form.html' %] </div> [% IF NOT errors and c.user.is_superuser %] diff --git a/templates/web/base/admin/category-checkboxes.html b/templates/web/base/admin/category-checkboxes.html index 63acd4112..9d5ab17ea 100644 --- a/templates/web/base/admin/category-checkboxes.html +++ b/templates/web/base/admin/category-checkboxes.html @@ -11,7 +11,7 @@ <li> <label> <input type="checkbox" name="contacts[[% contact.id %]]" [% 'checked' IF contact.active %]/> - [% contact.category %] + [% contact.category_display %] </label> </li> [% END %] diff --git a/templates/web/base/admin/category-multiselect.html b/templates/web/base/admin/category-multiselect.html index 98416204f..4e4eceeed 100644 --- a/templates/web/base/admin/category-multiselect.html +++ b/templates/web/base/admin/category-multiselect.html @@ -4,7 +4,7 @@ <p> <select class="form-control js-multiple" name="categories" id="categories" multiple data-all="[% loc('All categories') %]"> [% FOR contact IN contacts %] - <option value="[% contact.id %]" [% 'selected' IF contact.active %]>[% contact.category | html %]</option> + <option value="[% contact.id %]" [% 'selected' IF contact.active %]>[% contact.category_display | html %]</option> [% END %] </select> </p> diff --git a/templates/web/base/admin/contact-form.html b/templates/web/base/admin/contact-form.html index 0694459cb..375b3eb99 100644 --- a/templates/web/base/admin/contact-form.html +++ b/templates/web/base/admin/contact-form.html @@ -2,7 +2,7 @@ [% IF contact.in_storage %] <p> - <h1>[% contact.category | html %]</h2> + <h1>[% contact.category_display | html %]</h1> <input type="hidden" name="category" value="[% contact.category | html %]" > </p> [% ELSE %] @@ -20,6 +20,8 @@ </p> [% END %] + [% INCLUDE 'admin/_translations.html' %] + <div class="admin-hint"> <p> [% loc("The <strong>email address</strong> is the destination to which reports about this category will be sent. diff --git a/templates/web/base/admin/council_contacts.txt b/templates/web/base/admin/council_contacts.txt index ffab83ab6..f11615789 100644 --- a/templates/web/base/admin/council_contacts.txt +++ b/templates/web/base/admin/council_contacts.txt @@ -1,4 +1,4 @@ [% WHILE ( contact = contacts.next ) -%] [%- NEXT IF contact.state != 'confirmed' %] -[% contact.category %] [% contact.email %] +[% contact.category_display %] [% contact.email %] [%- END %] diff --git a/templates/web/base/admin/defecttypes/list.html b/templates/web/base/admin/defecttypes/list.html index 783bd085c..ffff89eff 100644 --- a/templates/web/base/admin/defecttypes/list.html +++ b/templates/web/base/admin/defecttypes/list.html @@ -20,7 +20,7 @@ <em>[% ('All categories') %]</em> [% ELSE %] [% FOR contact IN d.contacts %] - [% contact.category %][% ',' UNLESS loop.last %] + [% contact.category_display %][% ',' UNLESS loop.last %] [% END %] [% END %] </td> diff --git a/templates/web/base/admin/problem_row.html b/templates/web/base/admin/problem_row.html index e7e18dee9..def6ce60f 100644 --- a/templates/web/base/admin/problem_row.html +++ b/templates/web/base/admin/problem_row.html @@ -20,7 +20,7 @@ <br>[% loc('Anonymous') %]: [% IF problem.anonymous %][% loc('Yes') %][% ELSE %][% loc('No') %][% END %] </td> <td> - [% PROCESS value_or_nbsp value=problem.category %] + [% PROCESS value_or_nbsp value=problem.category_display %] <br>[%- IF edit_body_contacts -%] [% FOR body IN problem.bodies.values %] <a href="[% c.uri_for('body', body.id ) %]">[% PROCESS value_or_nbsp value=body.name %]</a> diff --git a/templates/web/base/admin/report-category.html b/templates/web/base/admin/report-category.html index 1e39236d7..a2290089b 100644 --- a/templates/web/base/admin/report-category.html +++ b/templates/web/base/admin/report-category.html @@ -1,13 +1,13 @@ <select class="form-control" name="category" id="category"> [% IF NOT problem.category OR NOT categories_hash.${problem.category} %] <optgroup label="[% loc('Existing category') %]"> - <option selected value="[% problem.category | html %]">[% (problem.category OR '-') | html %]</option> + <option selected value="[% problem.category | html %]">[% (problem.category_display OR '-') | html %]</option> </optgroup> [% END %] - [% IF categories.size %] + [% IF category_options_copy.size %] <optgroup label="[% loc('Available categories') %]"> - [% FOREACH cat IN categories %] - <option[% ' selected' IF problem.category == cat %]>[% cat | html %]</option> + [% FOREACH cat IN category_options_copy %] + <option value="[% cat.name | html %]"[% ' selected' IF problem.category == cat.name %]>[% cat.value | html %]</option> [% END %] </optgroup> [% END %] diff --git a/templates/web/base/admin/responsepriorities/list.html b/templates/web/base/admin/responsepriorities/list.html index 4c05ca14d..80d4e2cee 100644 --- a/templates/web/base/admin/responsepriorities/list.html +++ b/templates/web/base/admin/responsepriorities/list.html @@ -19,7 +19,7 @@ <em>[% loc('All categories') %]</em> [% ELSE %] [% FOR contact IN p.contacts %] - [% contact.category %][% ',' UNLESS loop.last %] + [% contact.category_display %][% ',' UNLESS loop.last %] [% END %] [% END %] </td> diff --git a/templates/web/base/dashboard/index.html b/templates/web/base/dashboard/index.html index 2a9a2ef42..6033ef36b 100644 --- a/templates/web/base/dashboard/index.html +++ b/templates/web/base/dashboard/index.html @@ -29,7 +29,7 @@ <label for="category">[% loc('Category:') %]</label> <select class="form-control" name="category"><option value=''>[% loc('All') %]</option> [% FOR cat_op IN category_options %] - <option value='[% cat_op | html %]'[% ' selected' IF category == cat_op %]>[% cat_op | html %]</option> + <option value='[% cat_op.name | html %]'[% ' selected' IF category == cat_op.name %]>[% cat_op.value | html %]</option> [% END %] </select> </p> diff --git a/templates/web/base/report/_inspect.html b/templates/web/base/report/_inspect.html index bf57cb858..922cc480b 100644 --- a/templates/web/base/report/_inspect.html +++ b/templates/web/base/report/_inspect.html @@ -50,18 +50,21 @@ [% INCLUDE 'admin/report-category.html' %] </p> - [% FOREACH category IN categories %] - [% cat_prefix = category | lower | replace('[^a-z]', '') %] - [% cat_prefix = "category_" _ cat_prefix _ "_" %] - [% IF category == problem.category %] - <p data-category="[% category | html %]" data-priorities='[% priorities_by_category.$category %]' data-defect-types='[% category_defect_types.$category %]' data-templates='[% templates_by_category.$category %]'> - [% INCLUDE 'report/new/category_extras_fields.html' %] - </p> - [% ELSE %] - <p data-category="[% category | html %]" class="hidden" data-priorities='[% priorities_by_category.$category %]' data-defect-types='[% category_defect_types.$category %]' data-templates='[% templates_by_category.$category %]'> - [% INCLUDE 'report/new/category_extras_fields.html' report_meta='' %] + [% FOREACH category IN category_options_copy %] + [% cat_name = category.name; + cat_prefix = cat_name | lower | replace('[^a-z]', ''); + cat_prefix = "category_" _ cat_prefix _ "_" %] + <p data-category="[% cat_name | html %]" + [%~ IF cat_name != problem.category %] class="hidden"[% END %] + data-priorities='[% priorities_by_category.$cat_name %]' + data-defect-types='[% category_defect_types.$cat_name %]' + ata-templates='[% templates_by_category.$cat_name %]'> + [% IF cat_name == problem.category %] + [% INCLUDE 'report/new/category_extras_fields.html' %] + [% ELSE %] + [% INCLUDE 'report/new/category_extras_fields.html' report_meta='' %] + [% END %] </p> - [% END %] [% END %] [% IF permissions.report_inspect %] diff --git a/templates/web/base/report/_item.html b/templates/web/base/report/_item.html index 7a3530b1f..a892086ca 100644 --- a/templates/web/base/report/_item.html +++ b/templates/web/base/report/_item.html @@ -90,7 +90,7 @@ </div> <div> <h4>[% loc('Category') %]</h4> - <p>[% (problem.category OR '-') | html %]</p> + <p>[% (problem.category_display OR '-') | html %]</p> </div> <div> <h4>[% loc('State') %]</h4> diff --git a/templates/web/base/report/new/category.html b/templates/web/base/report/new/category.html index 4c66f00fb..b8ebf1653 100644 --- a/templates/web/base/report/new/category.html +++ b/templates/web/base/report/new/category.html @@ -7,9 +7,9 @@ </label>[% =%] <select class="form-control" name='category' id='form_category' data-role='[% c.user.has_body_permission_to('planned_reports') ? 'inspector' : 'user' %]' data-body='[% c.user.from_body.name %]'> [%~ FOREACH cat_op IN category_options ~%] - [% cat_op_lc = cat_op | lower =%] - <option value='[% cat_op | html %]'[% ' selected' IF report.category == cat_op || category_lc == cat_op_lc || (category_options.size == 2 AND loop.last) ~%] - >[% IF loop.first %][% cat_op %][% ELSE %][% cat_op | html %][% END %]</option> + [% cat_op_lc = cat_op.name | lower =%] + <option value='[% cat_op.name | html %]'[% ' selected' IF report.category == cat_op.name || category_lc == cat_op_lc || (category_options.size == 2 AND loop.last) ~%] + >[% IF loop.first %][% cat_op.value %][% ELSE %][% cat_op.value | html %][% END %]</option> [%~ END =%] </select> [%~ END ~%] diff --git a/templates/web/base/reports/_list-filters.html b/templates/web/base/reports/_list-filters.html index efb917c16..73afe64f4 100644 --- a/templates/web/base/reports/_list-filters.html +++ b/templates/web/base/reports/_list-filters.html @@ -19,8 +19,8 @@ [% IF filter_categories.size %] <select class="form-control js-multiple" name="filter_category" id="filter_categories" multiple data-all="[% loc('Everything') %]"> [% FOR cat IN filter_categories %] - <option value="[% cat | html %]"[% ' selected' IF filter_category.$cat %]> - [% cat | html %] + <option value="[% cat.name | html %]"[% ' selected' IF filter_category.${cat.name} %]> + [% cat.value | html %] </option> [% END %] </select> diff --git a/templates/web/zurich/admin/body.html b/templates/web/zurich/admin/body.html index cf860990d..468f7adff 100644 --- a/templates/web/zurich/admin/body.html +++ b/templates/web/zurich/admin/body.html @@ -19,7 +19,7 @@ </tr> [% WHILE ( cat = contacts.next ) %] <tr[% IF cat.deleted %] class="is-deleted"[% END %]> - <td><a href="[% c.uri_for( 'body', body_id, cat.category ) %]">[% cat.category %]</a></td> + <td><a href="[% c.uri_for( 'body', body_id, cat.category ) %]">[% cat.category_display %]</a></td> <td>[% cat.email | html %]</td> <td>[% cat.editor %]</td> <td>[% cat.note | html %]</td> diff --git a/templates/web/zurich/admin/contact-form.html b/templates/web/zurich/admin/contact-form.html index aaf7a1797..236b169d0 100644 --- a/templates/web/zurich/admin/contact-form.html +++ b/templates/web/zurich/admin/contact-form.html @@ -1,5 +1,5 @@ <form method="post" action="[% c.uri_for('body', body_id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8" id="category_edit"> - <p><strong>[% loc('Category:') %] </strong>[% contact.category | html %] + <p><strong>[% loc('Category:') %] </strong>[% contact.category_display | html %] <input type="hidden" name="category" value="[% contact.category | html %]" > <input type="hidden" name="token" value="[% csrf_token %]" > diff --git a/templates/web/zurich/admin/problem_row.html b/templates/web/zurich/admin/problem_row.html index acbf17017..a83e22b27 100644 --- a/templates/web/zurich/admin/problem_row.html +++ b/templates/web/zurich/admin/problem_row.html @@ -15,7 +15,7 @@ [% END %] </td> <td>[% PROCESS value_or_nbsp value=problem.title %]</td> - <td>[% PROCESS value_or_nbsp value=problem.category %]</td> + <td>[% PROCESS value_or_nbsp value=problem.category_display %]</td> <td>[% PROCESS format_date this_date=problem.created %]</td> <td>[% PROCESS format_date this_date=problem.lastupdate %]</td> <td> [% states.${problem.state} %][% IF problem.state == 'planned'; diff --git a/templates/web/zurich/admin/report_edit-sdm.html b/templates/web/zurich/admin/report_edit-sdm.html index 3df9459f9..07f0332d5 100644 --- a/templates/web/zurich/admin/report_edit-sdm.html +++ b/templates/web/zurich/admin/report_edit-sdm.html @@ -70,7 +70,7 @@ </dd> <dt>[% loc('Category:') %] <!-- Kategorie --></dt> - <dd>[% problem.category | html %]</dd> + <dd>[% problem.category_display | html %]</dd> <dt class="print-only">[% loc('State:') %] <!-- Status --></dt> <dd class="print-only">[% states.${problem.state} %]</dd> diff --git a/templates/web/zurich/admin/report_edit.html b/templates/web/zurich/admin/report_edit.html index f87dcb5cf..35075a9f0 100644 --- a/templates/web/zurich/admin/report_edit.html +++ b/templates/web/zurich/admin/report_edit.html @@ -98,7 +98,7 @@ </dd> <dt>[% loc('Category:') %] <!-- Kategorie --></dt> - <dd>[% problem.category | html %]</dd> + <dd>[% problem.category_display | html %]</dd> <dt class="print-only">[% loc('State:') %] <!-- Status --></dt> <dd class="print-only">[% states_trans.${problem.state} %]</dd> @@ -169,8 +169,8 @@ <label for="category">[% loc('Assign to different category:') %]</label> <select class="form-control" name="category" id="category"> <option value="">--</option> - [% FOREACH cat IN categories %] - <option value="[% cat %]">[% cat %]</option> + [% FOREACH cat IN category_options %] + <option value="[% cat.name %]">[% cat.value %]</option> [% END %] </select> </div> diff --git a/templates/web/zurich/report/_main.html b/templates/web/zurich/report/_main.html index c1e4d15e6..b868c03e2 100644 --- a/templates/web/zurich/report/_main.html +++ b/templates/web/zurich/report/_main.html @@ -1,5 +1,5 @@ <div class="problem-header clearfix"> - <h1>[% tprintf( loc('Reported in the %s category'), problem.category ) %]</h1> + <h1>[% tprintf( loc('Reported in the %s category'), problem.category_display ) %]</h1> <p class="sub"> [% prettify_dt( problem.created, 'zurich' ) %] [%- IF !problem.used_map %]<br>[% loc('there is no pin shown as the user did not use the map') %][% END %] |