From 5cb3bcb0642cd2cbe111f1800b47736907e2766c Mon Sep 17 00:00:00 2001 From: Sean Hammond Date: Thu, 23 Feb 2012 12:26:37 +0100 Subject: [PATCH] [#1808] Handle fallback language in dataset view translations term_translation_show() logic action function now accepts a list of lang codes instead of just one lang code. MultilingualDataset.before_view() looks for translations in the fallback language if they are not found in the desired language. test_multilingual_plugin.py: Add some fallback language stuff into the test. --- ckan/logic/action/get.py | 4 +- ckanext/multilingual/plugin.py | 30 +++++++++--- .../tests/test_multilingual_plugin.py | 47 ++++++++++++++++++- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index d465277fca5..be0bb4242bf 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -891,8 +891,8 @@ def term_translation_show(context, data_dict): q = q.where(trans_table.c.term.in_(data_dict['terms'])) - if 'lang_code' in data_dict: - q = q.where(trans_table.c.lang_code == data_dict['lang_code']) + if 'lang_codes' in data_dict: + q = q.where(trans_table.c.lang_code.in_(data_dict['lang_codes'])) conn = model.Session.connection() cursor = conn.execute(q) diff --git a/ckanext/multilingual/plugin.py b/ckanext/multilingual/plugin.py index fed6dd3caaa..798b18cc123 100644 --- a/ckanext/multilingual/plugin.py +++ b/ckanext/multilingual/plugin.py @@ -14,7 +14,8 @@ def before_search(self, search_params): # FIXME: Look for translation in fallback language when none found in # desired language. def before_view(self, data_dict): - lang_code = pylons.request.environ['CKAN_LANG'] + desired_lang_code = pylons.request.environ['CKAN_LANG'] + fallback_lang_code = pylons.config.get('ckan.locale_default', 'en') # Get a flattened copy of data_dict to do the translation on. flattened = ckan.lib.navl.dictization_functions.flatten_dict( @@ -36,13 +37,20 @@ def before_view(self, data_dict): # Get the translations of all the terms (as a list of dictionaries). translations = ckan.logic.action.get.term_translation_show( {'model': ckan.model}, - {'terms': terms, 'lang_code': lang_code}) + {'terms': terms, + 'lang_codes': (desired_lang_code, fallback_lang_code)}) # Transform the translations into a more convenient structure. - translations_dict = {} + desired_translations = {} + fallback_translations = {} for translation in translations: - translations_dict[translation['term']] = ( - translation['term_translation']) + if translation['lang_code'] == desired_lang_code: + desired_translations[translation['term']] = ( + translation['term_translation']) + else: + assert translation['lang_code'] == fallback_lang_code + fallback_translations[translation['term']] = ( + translation['term_translation']) # Make a copy of the flattened data dict with all the terms replaced by # their translations, where available. @@ -51,11 +59,19 @@ def before_view(self, data_dict): if value in (None, True, False): translated_flattened[key] = value elif isinstance(value, basestring): - translated_flattened[key] = translations_dict.get(value, value) + if desired_translations.has_key(value): + translated_flattened[key] = desired_translations[value] + else: + translated_flattened[key] = fallback_translations.get( + value, value) else: translated_value = [] for item in value: - translated_value.append(translations_dict.get(item, item)) + if desired_translations.has_key(value): + translated_flattened[key] = desired_translations[value] + else: + translated_flattened[key] = fallback_translations.get( + value, value) translated_flattened[key] = translated_value # Finally unflatten and return the translated data dict. diff --git a/ckanext/multilingual/tests/test_multilingual_plugin.py b/ckanext/multilingual/tests/test_multilingual_plugin.py index bbf1f9ff65b..d93e2d94a48 100644 --- a/ckanext/multilingual/tests/test_multilingual_plugin.py +++ b/ckanext/multilingual/tests/test_multilingual_plugin.py @@ -1,10 +1,12 @@ import ckan.plugins import ckan.lib.helpers +import ckan.logic.action.update import ckan.tests.html_check import routes import paste.fixture import pylons.test + class TestDatasetTermTranslation(ckan.tests.html_check.HtmlCheckMethods): '''Test the translation of datasets by the multilingual_dataset plugin. @@ -12,6 +14,7 @@ class TestDatasetTermTranslation(ckan.tests.html_check.HtmlCheckMethods): @classmethod def setup(cls): ckan.tests.CreateTestData.create() + cls.normal_user = ckan.model.User.get('annafan') cls.sysadmin_user = ckan.model.User.get('testsysadmin') cls.app = paste.fixture.TestApp(pylons.test.pylonsapp) ckan.plugins.load('multilingual_dataset') @@ -25,6 +28,31 @@ def test_dataset_view_translation(self): multilingual_dataset plugin. ''' + # Get a package. + context = { + 'model': ckan.model, + 'session': ckan.model.Session, + 'user': self.normal_user.name, + 'allow_partial_update': True + } + package = ckan.logic.action.get.package_show(context, + {'id': "annakarenina"}) + + # Add some new tags to the package. + # These tags are codes that are meant to be always translated before + # display, if not into the user's current language then into the + # fallback language. + new_tag_list = package['tags'] + [ + {'name': '123'}, + {'name': '456'}, + {'name': '789'}, + ] + data_dict = { + 'id': package['id'], + 'tags': new_tag_list + } + package = ckan.logic.action.update.package_update(context, data_dict) + # Test translations for some of the package's fields. terms = ('A Novel By Tolstoy', 'Index of the novel', @@ -34,7 +62,16 @@ def test_dataset_view_translation(self): "Roger's books", 'Other (Open)', 'romantic novel', - 'book',) + 'book', + '123', + '456', + '789', + ) + english_translations = { + '123': 'jealousy', + '456': 'realism', + '789': 'hypocrisy', + } german_translations = { 'A Novel By Tolstoy': 'Roman von Tolstoi', 'Index of the novel': 'Index des Romans', @@ -45,6 +82,8 @@ def test_dataset_view_translation(self): 'Other (Open)': 'Andere (Open)', 'romantic novel': 'Liebesroman', 'book': 'Buch', + '456': 'Realismus', + '789': 'Heuchelei', } french_translations = { 'A Novel By Tolstoy': 'A Novel par Tolstoi', @@ -52,12 +91,14 @@ def test_dataset_view_translation(self): 'russian': 'russe', 'romantic novel': 'roman romantique', 'book': 'livre', + '123': 'jalousie', + '789': 'hypocrisie', } # Use the term_translation_update API to add the above translations to # CKAN. for (lang_code, translations) in (('de', german_translations), - ('fr', french_translations)): + ('fr', french_translations), ('en', english_translations)): for term in terms: if term in translations: paramd = { @@ -86,5 +127,7 @@ def test_dataset_view_translation(self): for term in terms: if term in translations: response.mustcontain(translations[term]) + elif term in english_translations: + response.mustcontain(english_translations[term]) else: response.mustcontain(term)