Inserted command line option to translate config strings during database setup. Fixed #460.

This commit is contained in:
Norman Jäckel 2014-01-31 01:54:41 +01:00
parent d49d087f4e
commit ce8274fb53
9 changed files with 58 additions and 6 deletions

View File

@ -20,6 +20,7 @@ Other:
- Changed api for plugins. Used entry points to detect them automaticly. - Changed api for plugins. Used entry points to detect them automaticly.
- Renamed config api classes. - Renamed config api classes.
- Renamed some classes of the poll api. - Renamed some classes of the poll api.
- Inserted command line option to translate config strings during database setup.
- Inserted api for the personal info widget. - Inserted api for the personal info widget.
- Changed api for main menu entries. - Changed api for main menu entries.
- Enhanced http error pages. - Enhanced http error pages.

View File

@ -21,6 +21,7 @@ from openslides.utils.main import (
get_port, get_port,
setup_django_settings_module, setup_django_settings_module,
start_browser, start_browser,
translate_customizable_strings,
write_settings) write_settings)
@ -87,7 +88,7 @@ def parse_args():
'start', 'start',
help='Setup settings and database, start tornado webserver, launch the ' help='Setup settings and database, start tornado webserver, launch the '
'default web browser and open the webinterface.') 'default web browser and open the webinterface.')
add_general_arguments(subcommand_start, ('settings', 'user_data_path', 'address', 'port')) add_general_arguments(subcommand_start, ('settings', 'user_data_path', 'language', 'address', 'port'))
subcommand_start.add_argument( subcommand_start.add_argument(
'--no-browser', '--no-browser',
action='store_true', action='store_true',
@ -113,7 +114,7 @@ def parse_args():
subcommand_syncdb = subparsers.add_parser( subcommand_syncdb = subparsers.add_parser(
'syncdb', 'syncdb',
help='Create or update database tables.') help='Create or update database tables.')
add_general_arguments(subcommand_syncdb, ('settings', 'user_data_path')) add_general_arguments(subcommand_syncdb, ('settings', 'user_data_path', 'language'))
subcommand_syncdb.set_defaults(callback=syncdb) subcommand_syncdb.set_defaults(callback=syncdb)
# Subcommand createsuperuser # Subcommand createsuperuser
@ -191,6 +192,11 @@ def add_general_arguments(subcommand, arguments):
'when a new settings file is created. The given path is only ' 'when a new settings file is created. The given path is only '
'written into the new settings file. Default according to the ' 'written into the new settings file. Default according to the '
'OpenSlides is at the moment %s' % get_default_user_data_path(openslides_type))) 'OpenSlides is at the moment %s' % get_default_user_data_path(openslides_type)))
general_arguments['language'] = (
('-l', '--language'),
dict(help='Language code. All customizable strings will be translated '
'during database setup. See https://www.transifex.com/projects/p/openslides/ '
'for supported languages.'))
general_arguments['address'] = ( general_arguments['address'] = (
('-a', '--address',), ('-a', '--address',),
dict(default='0.0.0.0', help='IP address to listen on. Default is %(default)s.')) dict(default='0.0.0.0', help='IP address to listen on. Default is %(default)s.'))
@ -250,6 +256,8 @@ def syncdb(settings, args):
print('Clearing old search index...') print('Clearing old search index...')
execute_from_command_line(["", "clear_index", "--noinput"]) execute_from_command_line(["", "clear_index", "--noinput"])
execute_from_command_line(["", "syncdb", "--noinput"]) execute_from_command_line(["", "syncdb", "--noinput"])
if args.language:
translate_customizable_strings(args.language)
return 0 return 0

View File

@ -43,6 +43,7 @@ def setup_assignment_config(sender, **kwargs):
assignment_pdf_title = ConfigVariable( assignment_pdf_title = ConfigVariable(
name='assignment_pdf_title', name='assignment_pdf_title',
default_value=_('Elections'), default_value=_('Elections'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
required=False, required=False,

View File

@ -53,8 +53,8 @@ class ConfigHandler(object):
def setup_cache(self): def setup_cache(self):
""" """
Loads all config variables from the database and by sending a Loads all config variables from the database by sending a signal to
signal to get the default into the cache. save the default to the cache.
""" """
self._cache = {} self._cache = {}
for receiver, config_collection in config_signal.send(sender='setup_cache'): for receiver, config_collection in config_signal.send(sender='setup_cache'):
@ -73,6 +73,15 @@ class ConfigHandler(object):
else: else:
return True return True
def get_all_translatable(self):
"""
Generator to get all config variables as strings when their values are
intended to be translated.
"""
for receiver, config_collection in config_signal.send(sender='get_all_translatable'):
for config_variable in config_collection.variables:
if config_variable.translatable:
yield config_variable.name
config = ConfigHandler() config = ConfigHandler()
""" """
@ -162,10 +171,13 @@ class ConfigVariable(object):
arguments 'name' and 'default_value' are required. The keyword arguments 'name' and 'default_value' are required. The keyword
argument 'form_field' has to be set if the variable should appear argument 'form_field' has to be set if the variable should appear
on the ConfigView. The argument 'on_change' can get a callback on the ConfigView. The argument 'on_change' can get a callback
which is called every time, the variable is changed. which is called every time, the variable is changed. If the argument
'translatable' is set, OpenSlides is able to translate the value during
setup of the database if the admin uses the respective command line option.
""" """
def __init__(self, name, default_value, form_field=None, on_change=None): def __init__(self, name, default_value, form_field=None, on_change=None, translatable=False):
self.name = name self.name = name
self.default_value = default_value self.default_value = default_value
self.form_field = form_field self.form_field = form_field
self.on_change = on_change self.on_change = on_change
self.translatable = translatable

View File

@ -29,6 +29,7 @@ def setup_general_config(sender, **kwargs):
event_description = ConfigVariable( event_description = ConfigVariable(
name='event_description', name='event_description',
default_value=_('Presentation and assembly system'), default_value=_('Presentation and assembly system'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
label=ugettext_lazy('Short description of event'), label=ugettext_lazy('Short description of event'),
@ -104,6 +105,7 @@ def setup_general_config(sender, **kwargs):
welcome_title = ConfigVariable( welcome_title = ConfigVariable(
name='welcome_title', name='welcome_title',
default_value=_('Welcome to OpenSlides'), default_value=_('Welcome to OpenSlides'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
label=ugettext_lazy('Title'), label=ugettext_lazy('Title'),
@ -113,6 +115,7 @@ def setup_general_config(sender, **kwargs):
welcome_text = ConfigVariable( welcome_text = ConfigVariable(
name='welcome_text', name='welcome_text',
default_value=_('[Place for your welcome text.]'), default_value=_('[Place for your welcome text.]'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.Textarea(), widget=forms.Textarea(),
label=ugettext_lazy('Welcome text'), label=ugettext_lazy('Welcome text'),

View File

@ -40,6 +40,7 @@ def setup_motion_config(sender, **kwargs):
motion_preamble = ConfigVariable( motion_preamble = ConfigVariable(
name='motion_preamble', name='motion_preamble',
default_value=_('The assembly may decide,'), default_value=_('The assembly may decide,'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
required=False, required=False,
@ -66,6 +67,7 @@ def setup_motion_config(sender, **kwargs):
motion_pdf_title = ConfigVariable( motion_pdf_title = ConfigVariable(
name='motion_pdf_title', name='motion_pdf_title',
default_value=_('Motions'), default_value=_('Motions'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.TextInput(), widget=forms.TextInput(),
required=False, required=False,

View File

@ -23,6 +23,7 @@ def setup_participant_config(sender, **kwargs):
participant_pdf_welcometitle = ConfigVariable( participant_pdf_welcometitle = ConfigVariable(
name='participant_pdf_welcometitle', name='participant_pdf_welcometitle',
default_value=_('Welcome to OpenSlides!'), default_value=_('Welcome to OpenSlides!'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.Textarea(), widget=forms.Textarea(),
required=False, required=False,
@ -31,6 +32,7 @@ def setup_participant_config(sender, **kwargs):
participant_pdf_welcometext = ConfigVariable( participant_pdf_welcometext = ConfigVariable(
name='participant_pdf_welcometext', name='participant_pdf_welcometext',
default_value=_('[Place for your welcome and help text.]'), default_value=_('[Place for your welcome and help text.]'),
translatable=True,
form_field=forms.CharField( form_field=forms.CharField(
widget=forms.Textarea(), widget=forms.Textarea(),
required=False, required=False,

View File

@ -12,6 +12,8 @@ import webbrowser
from base64 import b64encode from base64 import b64encode
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.conf import ENVIRONMENT_VARIABLE from django.conf import ENVIRONMENT_VARIABLE
from django.utils.translation import activate, check_for_language, get_language
from django.utils.translation import ugettext as _
UNIX_VERSION = 'Unix Version' UNIX_VERSION = 'Unix Version'
WINDOWS_VERSION = 'Windows Version' WINDOWS_VERSION = 'Windows Version'
@ -301,3 +303,16 @@ def get_database_path_from_settings():
if default.get('ENGINE') != 'django.db.backends.sqlite3': if default.get('ENGINE') != 'django.db.backends.sqlite3':
database_path = None database_path = None
return database_path return database_path
def translate_customizable_strings(language_code):
"""
Translates all translatable config values and saves them into database.
"""
if check_for_language(language_code):
from openslides.config.api import config
current_language = get_language()
activate(language_code)
for name in config.get_all_translatable():
config[name] = _(config[name])
activate(current_language)

View File

@ -12,6 +12,7 @@ from openslides.__main__ import (
runserver, runserver,
start, start,
syncdb) syncdb)
from openslides.config.api import config
from openslides.utils.main import ( from openslides.utils.main import (
get_browser_url, get_browser_url,
get_database_path_from_settings, get_database_path_from_settings,
@ -22,6 +23,7 @@ from openslides.utils.main import (
PortIsBlockedError, PortIsBlockedError,
setup_django_settings_module, setup_django_settings_module,
start_browser, start_browser,
translate_customizable_strings,
UNIX_VERSION, UNIX_VERSION,
WINDOWS_PORTABLE_VERSION) WINDOWS_PORTABLE_VERSION)
from openslides.utils.test import TestCase from openslides.utils.test import TestCase
@ -91,6 +93,11 @@ class TestFunctions(TestCase):
def test_get_database_path_from_settings_memory(self): def test_get_database_path_from_settings_memory(self):
self.assertEqual(get_database_path_from_settings(), ':memory:') self.assertEqual(get_database_path_from_settings(), ':memory:')
def test_translate_customizable_strings(self):
self.assertEqual(config['event_description'], 'Presentation and assembly system')
translate_customizable_strings('de')
self.assertEqual(config['event_description'], u'Präsentations- und Versammlungssystem')
class TestOtherFunctions(TestCase): class TestOtherFunctions(TestCase):
""" """
@ -127,6 +134,7 @@ class TestOtherFunctions(TestCase):
def test_syncdb(self, mock_execute_from_command_line, mock_os, mock_exists): def test_syncdb(self, mock_execute_from_command_line, mock_os, mock_exists):
mock_exists.return_value = True mock_exists.return_value = True
mock_args = MagicMock() mock_args = MagicMock()
mock_args.language = None
syncdb(settings=None, args=mock_args) syncdb(settings=None, args=mock_args)
self.assertTrue(mock_execute_from_command_line.called) self.assertTrue(mock_execute_from_command_line.called)