diff --git a/ckan/lib/i18n.py b/ckan/lib/i18n.py index 0d2d8e49499..eadf8d0a793 100644 --- a/ckan/lib/i18n.py +++ b/ckan/lib/i18n.py @@ -2,10 +2,14 @@ from babel import Locale, localedata from babel.core import LOCALE_ALIASES +from babel.support import Translations from pylons import config from pylons import i18n +import pylons import ckan.i18n +from ckan.plugins import PluginImplementations +from ckan.plugins.interfaces import ITranslations LOCALE_ALIASES['pt'] = 'pt_BR' # Default Portuguese language to # Brazilian territory, since @@ -121,9 +125,17 @@ def _set_lang(lang): if config.get('ckan.i18n_directory'): fake_config = {'pylons.paths': {'root': config['ckan.i18n_directory']}, 'pylons.package': config['pylons.package']} - i18n.set_lang(lang, pylons_config=fake_config) + i18n.set_lang(lang, pylons_config=fake_config, class_=Translations) else: - i18n.set_lang(lang) + i18n.set_lang(lang, class_=Translations) + + for plugin in PluginImplementations(ITranslations): + pylons.translator.merge(Translations.load( + dirname=plugin.directory(), + locales=plugin.locales(), + domain=plugin.domain() + )) + def handle_request(request, tmpl_context): ''' Set the language for the request ''' diff --git a/ckan/lib/plugins.py b/ckan/lib/plugins.py index abb7ffbeb4c..4939426685a 100644 --- a/ckan/lib/plugins.py +++ b/ckan/lib/plugins.py @@ -524,3 +524,31 @@ def activity_template(self): return 'organization/activity_stream.html' _default_organization_plugin = DefaultOrganizationForm() + + +class DefaultTranslation(object): + def directory(self): + '''Change the directory of the *.mo translation files + + The default implementation assumes the plugin is + ckanext/myplugin/plugin.py and the translations are stored in + i18n/ + ''' + import os + return os.path.abspath(os.path.join(os.path.dirname(__file__), + '../../', 'i18n')) + def locales(self): + '''Change the list of locales that this plugin handles + + By default the will assume any directory in subdirectory returned + by self.directory() is a locale handled by this plugin + ''' + import os + directory = self.directory() + return [ d for + d in os.listdir(directory) + if os.path.isdir(os.path.join(directory, d)) + ] + + def domain(self): + return 'ckanext-{name}'.format(name=self.name) diff --git a/ckan/plugins/interfaces.py b/ckan/plugins/interfaces.py index bd151dbb279..5de911496f2 100644 --- a/ckan/plugins/interfaces.py +++ b/ckan/plugins/interfaces.py @@ -22,6 +22,7 @@ 'ITemplateHelpers', 'IFacets', 'IAuthenticator', + 'ITranslations', ] from inspect import isclass @@ -1432,3 +1433,22 @@ def abort(self, status_code, detail, headers, comment): '''called on abort. This allows aborts due to authorization issues to be overriden''' return (status_code, detail, headers, comment) + + +class ITranslations(Interface): + def directory(self): + '''Change the directory of the *.mo translation files + + The default implementation assumes the plugin is + ckanext/myplugin/plugin.py and the translations are stored in + i18n/ + ''' + def locales(self): + '''Change the list of locales that this plugin handles + + By default the will assume any directory in subdirectory returned + by self.directory() is a locale handled by this plugin + ''' + + def domain(self): + '''Change the gettext domain handled by this plugin'''