Skip to content

Commit

Permalink
Merge 66683c3 into 57821db
Browse files Browse the repository at this point in the history
  • Loading branch information
koenedaele committed Jul 20, 2020
2 parents 57821db + 66683c3 commit daf0839
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 34 deletions.
Expand Up @@ -126,7 +126,8 @@ def create_registry(request):
'created': [date(2011,5,23)],
'language': ['nl-BE', 'la'],
'license': LICENSES
}
},
'atramhasis.force_display_label_language': 'la'
},
request.db,
uri_generator=UriPatternGenerator('https://id.erfgoed.net/thesauri/soorten/%s')
Expand Down
3 changes: 2 additions & 1 deletion atramhasis/skos/__init__.py
Expand Up @@ -137,7 +137,8 @@ def create_registry(request):
'created': [date(2011, 5, 23)],
'language': ['nl-BE', 'la'],
'license': LICENSES
}
},
'atramhasis.force_display_label_language': 'la'
},
request.db,
uri_generator=UriPatternGenerator('https://id.erfgoed.net/thesauri/soorten/%s')
Expand Down
18 changes: 9 additions & 9 deletions atramhasis/templates/concept.jinja2
Expand Up @@ -37,7 +37,7 @@
</div>
{% if concept %}
<div class="large-12 columns panel">
<h1 class="panel-header left word-wrap-element">{{ concept.label(request.locale_name).label|title }}</h1>
<h1 class="panel-header left word-wrap-element">{{ concept.label(locale).label|title }}</h1>
<h2 class="id-header right">[ ID : {{ concept.concept_id }} ]</h2>
<hr>
<dl class="infolist clearfix">
Expand Down Expand Up @@ -105,10 +105,10 @@
<div class="clearfix">
<h4 class="relations-subtitle">{% trans %}broader{% endtrans %}</h4>
{% if concept.broader_concepts|length > 0 %}
{{ render_relaties_lijst(request, concept.broader_concepts, scheme_id) }}
{{ render_relaties_lijst(request, concept.broader_concepts, scheme_id, locale) }}
{% endif %}
{% if concept.member_of|length > 0 %}
{{ render_relaties_lijst(request, concept.member_of, scheme_id) }}
{{ render_relaties_lijst(request, concept.member_of, scheme_id, locale) }}
{% endif %}
</div>
{% endif %}
Expand All @@ -118,10 +118,10 @@
<div class="clearfix">
<h4 class="relations-subtitle">{% trans %}narrower{% endtrans %}</h4>
{% if concept.narrower_concepts|length > 0 %}
{{ render_relaties_lijst(request, concept.narrower_concepts, scheme_id) }}
{{ render_relaties_lijst(request, concept.narrower_concepts, scheme_id, locale) }}
{% endif %}
{% if concept.narrower_collections|length > 0 %}
{{ render_relaties_lijst(request, concept.narrower_collections, scheme_id) }}
{{ render_relaties_lijst(request, concept.narrower_collections, scheme_id, locale) }}
{% endif %}
</div>
{% endif %}
Expand All @@ -130,7 +130,7 @@
{% if concept.related_concepts|length > 0 %}
<div class="clearfix">
<h4 class="relations-subtitle">{% trans %}related{% endtrans %}</h4>
{{ render_relaties_lijst(request, concept.related_concepts, scheme_id) }}
{{ render_relaties_lijst(request, concept.related_concepts, scheme_id, locale) }}
</div>
{% endif %}
{% endif %}
Expand All @@ -141,18 +141,18 @@
<div class="clearfix">
<h4 class="relations-subtitle">{% trans %}broader{% endtrans %}</h4>
{% if concept.broader_concepts|length > 0 %}
{{ render_relaties_lijst(request, concept.broader_concepts, scheme_id) }}
{{ render_relaties_lijst(request, concept.broader_concepts, scheme_id, locale) }}
{% endif %}
{% if concept.member_of|length > 0 %}
{{ render_relaties_lijst(request, concept.member_of, scheme_id) }}
{{ render_relaties_lijst(request, concept.member_of, scheme_id, locale) }}
{% endif %}
</div>
{% endif %}
{# // narrower#}
{% if concept.members|length > 0 %}
<div class="clearfix">
<h4 class="relations-subtitle">{% trans %}narrower{% endtrans %}</h4>
{{ render_relaties_lijst(request, concept.members, scheme_id) }}
{{ render_relaties_lijst(request, concept.members, scheme_id, locale) }}
</div>
{% endif %}
{% endif %}
Expand Down
6 changes: 3 additions & 3 deletions atramhasis/templates/macros.jinja2
@@ -1,11 +1,11 @@
{% macro render_relaties_lijst(request, relaties, scheme_id) %}
{% macro render_relaties_lijst(request, relaties, scheme_id, locale) %}
{% if relaties|length > 0 %}
{%- set counter = 0 %}
<div class="large-12 columns">
{%- for c in relaties|label_sort(language=request.locale_name) %}
{%- for c in relaties|label_sort(language=locale) %}
{%- set counter = counter + 1 %}
<div class="large-3 large-3-pad columns result-grid" {% if counter == relaties|length %}style="float: left;"{% endif %}>
<a href="{{ request.route_path('concept', scheme_id = scheme_id, c_id = c.concept_id) }}"><h5>{{ c.label(request.locale_name).label }}</h5> <span> [ ID : {{ c.concept_id }} ]</span><br><small>{{ c.type }}</small></a>
<a href="{{ request.route_path('concept', scheme_id = scheme_id, c_id = c.concept_id) }}"><h5>{{ c.label(locale).label }}</h5> <span> [ ID : {{ c.concept_id }} ]</span><br><small>{{ c.type }}</small></a>
</div>
{%- endfor %}
</div>
Expand Down
6 changes: 3 additions & 3 deletions atramhasis/templates/tree.jinja2
Expand Up @@ -51,16 +51,16 @@
{% endif %}
{% if concept %}
var scheme_label = '{{ get_conceptscheme_label(concept.conceptscheme, request.locale_name)|trim }}';
var scheme_label = '{{ get_conceptscheme_label(concept.conceptscheme, locale)|trim }}';
var scheme_id = '{{ scheme_id }}';
var current = '{{ concept.concept_id }}';
{% else %}
var scheme_label = '{{ conceptscheme.title|trim }}';
var scheme_id = '{{ conceptscheme.scheme_id }}';
var current = '{{ conceptscheme.scheme_id }}';
{% endif %}
d3.json('{{ request.route_path("scheme_tree", scheme_id = scheme_id ) }}', function(error, tree) {
d3.json('{{ request.route_path("scheme_tree", scheme_id = scheme_id, _query={'language':locale}) }}',
function(error, tree) {
if (error) throw error;
var treeData = { 'label': scheme_label, 'scheme_id': scheme_id, children: tree }
Expand Down
27 changes: 18 additions & 9 deletions atramhasis/views/views.py
Expand Up @@ -116,19 +116,24 @@ def conceptscheme_view(self):
scheme_id = self.request.matchdict['scheme_id']
provider = self.request.skos_registry.get_provider(scheme_id)
conceptscheme = provider.concept_scheme
title = conceptscheme.label(self.request.locale_name).label if (conceptscheme.label()) \
else scheme_id
if 'atramhasis.force_display_label_language' in provider.metadata:
locale = provider.metadata['atramhasis.force_display_label_language']
else:
locale = self.request.locale_name
title = (conceptscheme.label(locale).label if (conceptscheme.label())
else scheme_id)

scheme = {
'scheme_id': scheme_id,
'title': title,
'uri': conceptscheme.uri,
'labels': conceptscheme.labels,
'notes': conceptscheme.notes,
'top_concepts': provider.get_top_concepts()
'top_concepts': provider.get_top_concepts(),
}

return {'conceptscheme': scheme, 'conceptschemes': conceptschemes}
return {'conceptscheme': scheme, 'conceptschemes': conceptschemes,
'locale': locale}

@audit
@view_config(route_name='concept', renderer='atramhasis:templates/concept.jinja2')
Expand All @@ -146,9 +151,12 @@ def concept_view(self):
scheme_id = self.request.matchdict['scheme_id']
c_id = self.request.matchdict['c_id']
provider = self.request.skos_registry.get_provider(scheme_id)

if not provider:
raise ConceptSchemeNotFoundException(scheme_id)
if 'atramhasis.force_display_label_language' in provider.metadata:
locale = provider.metadata['atramhasis.force_display_label_language']
else:
locale = self.request.locale_name
try:
c = self.skos_manager.get_thing(c_id, provider.conceptscheme_id)
if isinstance(c, Concept):
Expand All @@ -160,7 +168,8 @@ def concept_view(self):
url = self.request.route_url('concept', scheme_id=scheme_id, c_id=c_id)
update_last_visited_concepts(self.request, {'label': c.label(self.request.locale_name).label, 'url': url})
return {'concept': c, 'conceptType': concept_type, 'scheme_id': scheme_id,
'conceptschemes': conceptschemes, 'provider': provider}
'conceptschemes': conceptschemes, 'provider': provider,
'locale': locale}
except NoResultFound:
raise ConceptNotFoundException(c_id)

Expand Down Expand Up @@ -256,8 +265,8 @@ def results_csv(self):
@view_config(route_name='scheme_tree', renderer='json', accept='application/json')
def results_tree_json(self):
scheme_id = self.request.matchdict['scheme_id']
locale = self.request.locale_name
dicts = self.get_results_tree(scheme_id, locale)
language = self.request.params.get('language') or self.request.locale_name
dicts = self.get_results_tree(scheme_id, language)
if dicts:
if 'text/html' not in self.request.accept:
return dicts
Expand Down Expand Up @@ -286,7 +295,7 @@ def get_scheme(self, scheme, locale):

def parse_thing(self, thing, parent_tree_id):
tree_id = self.create_treeid(parent_tree_id, thing.concept_id)
locale = self.request.locale_name
locale = self.request.params.get('language', self.request.locale_name)

if thing.type and thing.type == 'collection':
cs = [member for member in thing.members] if hasattr(thing, 'members') else []
Expand Down
61 changes: 61 additions & 0 deletions docs/source/customisation.rst
Expand Up @@ -294,6 +294,67 @@ calls to this conceptscheme will function as normal and you will be able to
maintain it from the admin interface.


.. _force_display_label_language:

Force a display language for a vocabulary
=========================================

Under normal circumstances, Atramhasis tries to provide the most
appropriate label for a certain concept or collection, based on some default
configuration and the preferences of the end-user. Every provider can be marked
as having a certain `default language` (English if not set), but Atramhasis
also tries to read what the user wants. It does this through the user's
browser's locale. This information can be read from the browser's HTTP headers
or cookies. Generally, Atramhasis just knows in what language a user is
browsing the site and tries to return labels appropriate for that language. So,
the same thesaurus visited from the US will return English labels, while it
will return Dutch when visited from Gent (Belgium).

You might have a vocabulary with a strongly preferential relation to a certain
language. We ran into this situation with a vocabulary of species: names for
plants and trees commonly found in Flanders. Some of them have one or more
local, Dutch, names. Most or all of them have an official name in Latin. The
normal language handling mechanism created a weird situation. It led to a tree
of names that was mostly in Latin, with the odd Dutch word thrown in for good
measure. This was not as desired by our users. To that end, a special mechanism
was created to force rendering labels of concepts and collections in a certain
language, no matter what the end-user's browser is requesting.

To set this, please edit the :file:`my_thesaurus/skos/__init__.py`. Look for the
thesaurus you want to override and add a setting `atramhasis.force_display_label_language`
to the provider's metadata. Set it to a language supported by the provider
(there's little sense to setting it to a language that isn't present in the
vocabulary). Now Atramhasis will try serving concepts from this provider with
this language. All labels will still be shown, but the page title or current
label will be set to the selected language as much as possible. The normal
language determination mechanisms will keep on working, so if the concept has
no label in the requested language, Atramhasis will fall back on other labels
present.

Your provider should end up similar to this:

.. code-block:: python
STUFF = SQLAlchemyProvider(
{
'id': 'STUFF',
'conceptscheme_id': 1,
'atramhasis.force_display_label_language': 'la'
},
request.db,
uri_generator=UriPatternGenerator(
'http://id.mydata.org/thesauri/stuff/%s'
)
)
Beware that this will only affect the Atramhasis UI, not the Atramhasis REST
services. We looked into some solutions for our problem that would have also
changed the underlying service, but decided against that because it would have
prevented you from making your own choices when interacting with Atramhasis. If
you want to render the tree of concepts using a preferred language different
from what a browser would advocate for, you can pass the language parameter in
a url, eg. `http://my.thesaurus.org/conceptschemes/STUFF/tree?language=la`.

.. _i18n:

Internationalisation
Expand Down
16 changes: 16 additions & 0 deletions tests/test_functional.py
Expand Up @@ -520,6 +520,22 @@ def test_missing_labels(self):
self.assertEqual('label', response.json[0]['label'])
self.assertEqual(None, response.json[1]['label'])

def test_tree_language(self):
response = self.testapp.get('/conceptschemes/TREES/tree?language=nl',
headers=self._get_default_headers())
self.assertEqual(200, response.status_code)
self.assertEqual(
['De Lariks', 'De Paardekastanje'],
[child['label'] for child in response.json[0]['children']]
)
response = self.testapp.get('/conceptschemes/TREES/tree?language=en',
headers=self._get_default_headers())
self.assertEqual(200, response.status_code)
self.assertEqual(
['The Chestnut', 'The Larch'],
[child['label'] for child in response.json[0]['children']]
)

def test_no_tree(self):
response = self.testapp.get('/conceptschemes/FOO/tree?_LOCALE_=nl', headers=self._get_default_headers(),
status=404, expect_errors=True)
Expand Down
52 changes: 44 additions & 8 deletions tests/test_views.py
Expand Up @@ -2,18 +2,30 @@
import os
import unittest

from skosprovider.registry import Registry
from paste.deploy.loadwsgi import appconfig
from pyramid import testing
from skosprovider_sqlalchemy.models import Concept, Collection, Thing, Label, Note, LabelType, ConceptScheme
from skosprovider.registry import Registry
from skosprovider_sqlalchemy.models import Collection
from skosprovider_sqlalchemy.models import Concept
from skosprovider_sqlalchemy.models import ConceptScheme
from skosprovider_sqlalchemy.models import Label
from skosprovider_sqlalchemy.models import LabelType
from skosprovider_sqlalchemy.models import Note
from skosprovider_sqlalchemy.models import Thing
from sqlalchemy.orm.exc import NoResultFound
from webob.multidict import MultiDict
from paste.deploy.loadwsgi import appconfig

from atramhasis.cache import list_region
from atramhasis.data.datamanagers import SkosManager, ConceptSchemeManager, AuditManager
from atramhasis.errors import SkosRegistryNotFoundException, ConceptSchemeNotFoundException, ConceptNotFoundException
from atramhasis.views.views import AtramhasisView, AtramhasisAdminView, AtramhasisListView, \
labels_to_string, get_definition
from atramhasis.data.datamanagers import AuditManager
from atramhasis.data.datamanagers import ConceptSchemeManager
from atramhasis.data.datamanagers import SkosManager
from atramhasis.errors import ConceptNotFoundException
from atramhasis.errors import ConceptSchemeNotFoundException
from atramhasis.errors import SkosRegistryNotFoundException
from atramhasis.views.views import AtramhasisAdminView
from atramhasis.views.views import AtramhasisListView
from atramhasis.views.views import AtramhasisView
from atramhasis.views.views import get_definition
from atramhasis.views.views import labels_to_string
from fixtures.data import trees

try:
Expand All @@ -32,6 +44,7 @@ def provider(some_id):
provider_mock.get_metadata = Mock(return_value={'id': some_id, 'subject': []})
provider_mock.allowed_instance_scopes = ['single', 'threaded_thread']
provider_mock.conceptscheme_id = Mock(return_value=some_id)
provider_mock.metadata={}
return provider_mock


Expand Down Expand Up @@ -259,6 +272,16 @@ def test_conceptscheme_view(self):
self.assertIsNotNone(res['conceptscheme']['notes'])
self.assertIsNotNone(res['conceptscheme']['top_concepts'])

def test_conceptscheme_view_language(self):
self.request.matchdict['scheme_id'] = 'TREES'
self.request.skos_registry.providers['TREES'].metadata[
'atramhasis.force_display_label_language'] = 'nl'

atramhasisview = AtramhasisView(self.request)
res = atramhasisview.conceptscheme_view()
self.assertIsNotNone(res)
self.assertEqual(res['locale'], 'nl')


class TestConceptView(unittest.TestCase):
def setUp(self):
Expand All @@ -285,6 +308,19 @@ def test_passing_view(self):
self.assertEqual(info['conceptType'], 'Concept')
self.assertEqual(info['scheme_id'], 'TREES')

def test_passing_view_with_languague(self):
request = self.request
request.matchdict['scheme_id'] = 'TREES'
request.matchdict['c_id'] = '1'
request.skos_registry = self.regis
request.skos_registry.providers['TREES'].metadata = {
'atramhasis.force_display_label_language': 'nl'
}
atramhasisview = AtramhasisView(request)
info = atramhasisview.concept_view()
self.assertIsNotNone(info['concept'])
self.assertEqual(info['locale'], 'nl')

def test_passing_collection_view(self):
request = self.request
request.matchdict['scheme_id'] = 'TREES'
Expand Down

0 comments on commit daf0839

Please sign in to comment.