diff --git a/peachjam/migrations/0088_model_translations.py b/peachjam/migrations/0088_model_translations.py new file mode 100644 index 000000000..eafda62da --- /dev/null +++ b/peachjam/migrations/0088_model_translations.py @@ -0,0 +1,245 @@ +# Generated by Django 3.2.19 on 2023-06-30 13:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("peachjam", "0087_article_attachments"), + ] + + operations = [ + migrations.AddField( + model_name="attachedfilenature", + name="name_en", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="attachedfilenature", + name="name_fr", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="attachedfilenature", + name="name_pt", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="attachedfilenature", + name="name_sw", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="court", + name="name_en", + field=models.CharField( + max_length=255, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="court", + name="name_fr", + field=models.CharField( + max_length=255, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="court", + name="name_pt", + field=models.CharField( + max_length=255, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="court", + name="name_sw", + field=models.CharField( + max_length=255, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="courtclass", + name="name_en", + field=models.CharField( + max_length=100, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="courtclass", + name="name_fr", + field=models.CharField( + max_length=100, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="courtclass", + name="name_pt", + field=models.CharField( + max_length=100, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="courtclass", + name="name_sw", + field=models.CharField( + max_length=100, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="courtregistry", + name="name_en", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="courtregistry", + name="name_fr", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="courtregistry", + name="name_pt", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="courtregistry", + name="name_sw", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="documentnature", + name="name_en", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="documentnature", + name="name_fr", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="documentnature", + name="name_pt", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="documentnature", + name="name_sw", + field=models.CharField( + max_length=1024, null=True, unique=True, verbose_name="name" + ), + ), + migrations.AddField( + model_name="orderoutcome", + name="name_en", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="orderoutcome", + name="name_fr", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="orderoutcome", + name="name_pt", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="orderoutcome", + name="name_sw", + field=models.CharField(max_length=1024, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="predicate", + name="reverse_verb_en", + field=models.CharField( + help_text="Reversed verbal form of the relationship", + max_length=100, + null=True, + verbose_name="reverse verb", + ), + ), + migrations.AddField( + model_name="predicate", + name="reverse_verb_fr", + field=models.CharField( + help_text="Reversed verbal form of the relationship", + max_length=100, + null=True, + verbose_name="reverse verb", + ), + ), + migrations.AddField( + model_name="predicate", + name="reverse_verb_pt", + field=models.CharField( + help_text="Reversed verbal form of the relationship", + max_length=100, + null=True, + verbose_name="reverse verb", + ), + ), + migrations.AddField( + model_name="predicate", + name="reverse_verb_sw", + field=models.CharField( + help_text="Reversed verbal form of the relationship", + max_length=100, + null=True, + verbose_name="reverse verb", + ), + ), + migrations.AddField( + model_name="predicate", + name="verb_en", + field=models.CharField(max_length=100, null=True, verbose_name="verb"), + ), + migrations.AddField( + model_name="predicate", + name="verb_fr", + field=models.CharField(max_length=100, null=True, verbose_name="verb"), + ), + migrations.AddField( + model_name="predicate", + name="verb_pt", + field=models.CharField(max_length=100, null=True, verbose_name="verb"), + ), + migrations.AddField( + model_name="predicate", + name="verb_sw", + field=models.CharField(max_length=100, null=True, verbose_name="verb"), + ), + migrations.AddField( + model_name="taxonomy", + name="name_en", + field=models.CharField(max_length=255, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="taxonomy", + name="name_fr", + field=models.CharField(max_length=255, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="taxonomy", + name="name_pt", + field=models.CharField(max_length=255, null=True, verbose_name="name"), + ), + migrations.AddField( + model_name="taxonomy", + name="name_sw", + field=models.CharField(max_length=255, null=True, verbose_name="name"), + ), + ] diff --git a/peachjam/settings.py b/peachjam/settings.py index 64b4935d8..5ba93418f 100644 --- a/peachjam/settings.py +++ b/peachjam/settings.py @@ -58,6 +58,7 @@ "django_elasticsearch_dsl", "django_elasticsearch_dsl_drf", "jazzmin", + "modeltranslation", "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", diff --git a/peachjam/translation.py b/peachjam/translation.py new file mode 100644 index 000000000..e5399d5c7 --- /dev/null +++ b/peachjam/translation.py @@ -0,0 +1,52 @@ +from modeltranslation.translator import TranslationOptions, register + +from peachjam.models import ( + AttachedFileNature, + Court, + CourtClass, + CourtRegistry, + DocumentNature, + OrderOutcome, + Predicate, + Taxonomy, +) + + +@register(AttachedFileNature) +class AttachedFileNatureTranslationOptions(TranslationOptions): + fields = ("name",) + + +@register(Court) +class CourtTranslationOptions(TranslationOptions): + fields = ("name",) + + +@register(CourtClass) +class CourtClassTranslationOptions(TranslationOptions): + fields = ("name",) + + +@register(CourtRegistry) +class CourtRegistryTranslationOptions(TranslationOptions): + fields = ("name",) + + +@register(DocumentNature) +class DocumentNatureTranslationOptions(TranslationOptions): + fields = ("name",) + + +@register(OrderOutcome) +class OrderOutcomeTranslationOptions(TranslationOptions): + fields = ("name",) + + +@register(Predicate) +class PredicateTranslationOptions(TranslationOptions): + fields = ("verb", "reverse_verb") + + +@register(Taxonomy) +class TaxonomyTranslationOptions(TranslationOptions): + fields = ("name",) diff --git a/peachjam_search/documents.py b/peachjam_search/documents.py index 07936641c..9675e630b 100644 --- a/peachjam_search/documents.py +++ b/peachjam_search/documents.py @@ -54,21 +54,41 @@ class SearchableDocument(Document): taxonomies = fields.KeywordField() # Judgment + court = fields.KeywordField(attr="court.name") + court_en = fields.KeywordField(attr="court.name_en") + court_sw = fields.KeywordField(attr="court.name_sw") + court_fr = fields.KeywordField(attr="court.name_fr") + court_pt = fields.KeywordField(attr="court.name_pt") + matter_type = fields.KeywordField(attr="matter_type.name") case_number = fields.TextField() # this case party names etc. and so the standard analyzer is better than a language-based one case_name = fields.TextField(analyzer="standard") - court = fields.KeywordField(attr="court.name") headnote_holding = fields.TextField() flynote = fields.TextField() judges = fields.KeywordField(attr="judge.name") - registry = fields.KeywordField(attr="registry.name") attorneys = fields.KeywordField(attr="attorney.name") + + registry = fields.KeywordField(attr="registry.name") + registry_en = fields.KeywordField(attr="registry.name_en") + registry_sw = fields.KeywordField(attr="registry.name_sw") + registry_fr = fields.KeywordField(attr="registry.name_fr") + registry_pt = fields.KeywordField(attr="registry.name_pt") + order_outcome = fields.KeywordField(attr="order_outcome.name") + order_outcome_en = fields.KeywordField(attr="order_outcome.name_en") + order_outcome_sw = fields.KeywordField(attr="order_outcome.name_sw") + order_outcome_fr = fields.KeywordField(attr="order_outcome.name_fr") + order_outcome_pt = fields.KeywordField(attr="order_outcome.name_pt") # GenericDocument, LegalInstrument authors = fields.KeywordField() + nature = fields.KeywordField(attr="nature.name") + nature_en = fields.KeywordField(attr="nature.name_en") + nature_sw = fields.KeywordField(attr="nature.name_sw") + nature_fr = fields.KeywordField(attr="nature.name_fr") + nature_pt = fields.KeywordField(attr="nature.name_pt") ranking = RankField(attr="work.ranking") @@ -195,6 +215,86 @@ def prepare_ranking(self, instance): return instance.work.ranking return 0.00000001 + def prepare_court(self, instance): + if hasattr(instance, "court") and instance.court: + return instance.court.name + + def prepare_court_en(self, instance): + if hasattr(instance, "court") and instance.court: + return instance.court.name_en or instance.court.name + + def prepare_court_sw(self, instance): + if hasattr(instance, "court") and instance.court: + return instance.court.name_sw or instance.court.name + + def prepare_court_pt(self, instance): + if hasattr(instance, "court") and instance.court: + return instance.court.name_pt or instance.court.name + + def prepare_court_fr(self, instance): + if hasattr(instance, "court") and instance.court: + return instance.court.name_fr or instance.court.name + + def prepare_registry(self, instance): + if hasattr(instance, "registry") and instance.registry: + return instance.registry.name + + def prepare_registry_en(self, instance): + if hasattr(instance, "registry") and instance.registry: + return instance.registry.name_en or instance.registry.name + + def prepare_registry_sw(self, instance): + if hasattr(instance, "registry") and instance.registry: + return instance.registry.name_sw or instance.registry.name + + def prepare_registry_pt(self, instance): + if hasattr(instance, "registry") and instance.registry: + return instance.registry.name_pt or instance.registry.name + + def prepare_registry_fr(self, instance): + if hasattr(instance, "registry") and instance.registry: + return instance.registry.name_fr or instance.registry.name + + def prepare_nature(self, instance): + if hasattr(instance, "nature") and instance.nature: + return instance.nature.name + + def prepare_nature_en(self, instance): + if hasattr(instance, "nature") and instance.nature: + return instance.nature.name_en or instance.nature.name + + def prepare_nature_sw(self, instance): + if hasattr(instance, "nature") and instance.nature: + return instance.nature.name_sw or instance.nature.name + + def prepare_nature_pt(self, instance): + if hasattr(instance, "nature") and instance.nature: + return instance.nature.name_pt or instance.nature.name + + def prepare_nature_fr(self, instance): + if hasattr(instance, "nature") and instance.nature: + return instance.nature.name_fr or instance.nature.name + + def prepare_order_outcome(self, instance): + if hasattr(instance, "order_outcome") and instance.order_outcome: + return instance.order_outcome.name + + def prepare_order_outcome_en(self, instance): + if hasattr(instance, "order_outcome") and instance.order_outcome: + return instance.order_outcome.name_en or instance.order_outcome.name + + def prepare_order_outcome_sw(self, instance): + if hasattr(instance, "order_outcome") and instance.order_outcome: + return instance.order_outcome.name_sw or instance.order_outcome.name + + def prepare_order_outcome_pt(self, instance): + if hasattr(instance, "order_outcome") and instance.order_outcome: + return instance.order_outcome.name_pt or instance.order_outcome.name + + def prepare_order_outcome_fr(self, instance): + if hasattr(instance, "order_outcome") and instance.order_outcome: + return instance.order_outcome.name_fr or instance.order_outcome.name + def prepare_pages(self, instance): """Text content of pages extracted from PDF.""" if not instance.content_html: diff --git a/peachjam_search/serializers.py b/peachjam_search/serializers.py index dc6610e73..21b062e11 100644 --- a/peachjam_search/serializers.py +++ b/peachjam_search/serializers.py @@ -1,3 +1,4 @@ +# from django.utils.translation import get_language_from_request from django_elasticsearch_dsl_drf.serializers import DocumentSerializer from rest_framework.serializers import SerializerMethodField @@ -7,6 +8,16 @@ class SearchableDocumentSerializer(DocumentSerializer): highlight = SerializerMethodField() pages = SerializerMethodField() + court = SerializerMethodField() + nature = SerializerMethodField() + order_outcome = SerializerMethodField() + registry = SerializerMethodField() + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # TODO: uncomment this when we have reindexed + # self.language_suffix = "_" + get_language_from_request(self.context["request"]) + self.language_suffix = "" class Meta: document = SearchableDocument @@ -48,3 +59,15 @@ def get_pages(self, obj): ) pages.append(info) return pages + + def get_court(self, obj): + return obj["court" + self.language_suffix] + + def get_nature(self, obj): + return obj["nature" + self.language_suffix] + + def get_order_outcome(self, obj): + return obj["order_outcome" + self.language_suffix] + + def get_registry(self, obj): + return obj["registry" + self.language_suffix] diff --git a/peachjam_search/views.py b/peachjam_search/views.py index 3d51d68ab..38e19bdac 100644 --- a/peachjam_search/views.py +++ b/peachjam_search/views.py @@ -1,5 +1,8 @@ +import copy + from django.conf import settings from django.utils.decorators import method_decorator +from django.utils.translation import get_language_from_request from django.utils.translation import gettext_lazy as _ from django.views.decorators.cache import cache_page from django.views.generic import TemplateView @@ -322,6 +325,32 @@ def __init__(self, *args, **kwargs): self.index = get_search_indexes(self.document._index._name) self.search = self.search.index(self.index) + def get_translatable_fields(self, request): + # get language from request to use as suffix for translatable fields + current_language_code = get_language_from_request(request) + suffix = "_" + current_language_code + + self.filter_fields = copy.deepcopy(self.filter_fields) + self.faceted_search_fields = copy.deepcopy(self.faceted_search_fields) + + translatable_fields = [ + "court", + "nature", + "registry", + "order_outcome", + ] + + for field in translatable_fields: + self.filter_fields[field] = self.filter_fields[field] + suffix + self.faceted_search_fields[field]["field"] = ( + self.faceted_search_fields[field]["field"] + suffix + ) + + def list(self, request, *args, **kwargs): + # TODO: uncomment when we have reindexd the data + # self.get_translatable_fields(request) + return super().list(request, *args, **kwargs) + @method_decorator(cache_page(CACHE_SECS)) def dispatch(self, request, *args, **kwargs): return super().dispatch(request, *args, **kwargs) diff --git a/pyproject.toml b/pyproject.toml index 697c88ff4..a6e108fc0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,7 @@ dependencies = [ "django-jazzmin>=2.5.0", "django-languages-plus>=1.1.1", "django-log-request-id>=2.0.0", + "django-modeltranslation>=0.18.10", "django-polymorphic==3.1.0", "django-sass-processor>=1.1", "django-sass-processor-dart-sass>=0.1.0",