Custom Translations

This commit is contained in:
FinnStutzenstein 2017-08-30 12:17:07 +02:00
parent 97a1431c32
commit b30919eada
7 changed files with 137 additions and 1 deletions

View File

@ -73,6 +73,7 @@ Core:
- Added config for disabling header and footer in the projector [#3357].
- Updated CKEditor to 4.7 [#3375].
- Reduced ckeditor toolbar for inline editing [#3368].
- Added custom translations in config [#3383].
Mediafiles:
- Fixed reloading of PDF on page change [#3274].

View File

@ -29,6 +29,7 @@ INPUT_TYPE_MAPPING = {
'datetimepicker': int,
'majorityMethod': str,
'logo': dict,
'translations': list,
}
@ -134,6 +135,22 @@ class ConfigHandler:
if not isinstance(value[required_entry], str):
raise ConfigError(_('{} has to be a string.'.format(required_entry)))
if config_variable.input_type == 'translations':
if not isinstance(value, list):
raise ConfigError(_('Translations has to be a list.'))
for entry in value:
if not isinstance(entry, dict):
raise ConfigError(_('Every value has to be a dict, not {}.'.format(type(entry))))
whitelist = (
'original',
'translation',
)
for required_entry in whitelist:
if required_entry not in entry:
raise ConfigError(_('{} has to be given.'.format(required_entry)))
if not isinstance(entry[required_entry], str):
raise ConfigError(_('{} has to be a string.'.format(required_entry)))
# Save the new value to the database.
db_value = ConfigStore.objects.get(key=key)
db_value.value = value

View File

@ -322,3 +322,12 @@ def get_config_variables():
weight=312,
group='Logo',
hidden=True)
# Custom translations
yield ConfigVariable(
name='translations',
label='Custom translations',
default_value=[],
input_type='translations',
weight=1000,
group='Custom translations')

View File

@ -1095,11 +1095,24 @@ img {
/** Config **/
.input-comments > div {
margin-bottom: 5px
margin-bottom: 5px;
}
.config-checkbox {
padding: 6px 12px;
}
.config-translations > div {
margin-bottom: 5px;
padding-right: 15px;
width: 100%;
}
.config-translations .inputs input {
width: 47%;
}
.config-translations .inputs .arrow {
width: 6%;
float: left;
text-align: center;
}
/** Pojector sidebar **/
.col2 .projectorSelector {

View File

@ -254,6 +254,52 @@ angular.module('OpenSlidesApp.core', [
}
])
// Hook into gettextCatalog to include custom translations by wrapping
// the getString method. The translations are stored in the config.
.decorator('gettextCatalog', [
'$delegate',
'$rootScope',
function ($delegate, $rootScope) {
var oldGetString = $delegate.getString;
var customTranslations = {};
$delegate.getString = function () {
var translated = oldGetString.apply($delegate, arguments);
if (customTranslations[translated]) {
translated = customTranslations[translated];
}
return translated;
};
$delegate.setCustomTranslations = function (translations) {
customTranslations = translations;
$rootScope.$broadcast('gettextLanguageChanged');
};
return $delegate;
}
])
.run([
'$rootScope',
'Config',
'gettextCatalog',
function ($rootScope, Config, gettextCatalog) {
$rootScope.$watch(function () {
return Config.lastModified('translations');
}, function () {
var translations = Config.get('translations');
if (translations) {
var customTranslations = {};
_.forEach(translations.value, function (entry) {
customTranslations[entry.original] = entry.translation;
});
// Update all translate directives
gettextCatalog.setCustomTranslations(customTranslations);
}
});
}
])
// set browser language as default language for OpenSlides
.run([
'gettextCatalog',

View File

@ -825,6 +825,7 @@ angular.module('OpenSlidesApp.core.site', [
colorpicker: 'colorpicker',
datetimepicker: 'datetimepicker',
majorityMethod: 'choice',
translations: 'translations',
}[type];
};
@ -1134,6 +1135,19 @@ angular.module('OpenSlidesApp.core.site', [
$scope.save(configOption, parent.value);
};
// For custom translations input
$scope.addTranslation = function (configOption, parent) {
parent.value.push({
original: gettextCatalog.getString('New'),
translation: gettextCatalog.getString('New'),
});
$scope.save(configOption, parent.value);
};
$scope.removeTranslation = function (configOption, parent, index) {
parent.value.splice(index, 1);
$scope.save(configOption, parent.value);
};
// For majority method
angular.forEach(
_.filter($scope.configGroups, function (configGroup) {
@ -1912,6 +1926,7 @@ angular.module('OpenSlidesApp.core.site', [
gettext('PDF footer logo');
gettext('Web interface header logo');
gettext('PDF ballot paper logo');
gettext('Custom translations');
// Mark the string 'Default projector' here, because it does not appear in the templates.
gettext('Default projector');

View File

@ -95,6 +95,41 @@
ng-options="option.value as option.display_name | translate for option in choices">
</select>
<!-- custom trnaslations -->
<div class="config-translations" ng-if="type === 'translations'">
<div ng-repeat="entry in $parent.value" class="input-group">
<div class="inputs">
<input ng-model="entry.original"
ng-model-options="{debounce: 1000}"
ng-change="save(configOption, $parent.value)"
class="form-control"
id="{{ key }}_original"
type="text">
<span class="arrow form-control"><i class="fa fa-arrow-right"></i></span>
<input ng-model="entry.translation"
ng-model-options="{debounce: 1000}"
ng-change="save(configOption, $parent.value)"
class="form-control"
id="{{ key }}_translated"
type="text">
</div>
<span class="input-group-btn">
<button type="button" class="btn btn-default"
ng-click="removeTranslation(configOption, $parent, $index)">
<i class="fa fa-minus"></i>
<translate>Remove</translate>
</button>
</span>
</div>
<div>
<button type="button" ng-click="addTranslation(configOption, $parent)"
class="btn btn-default btn-sm">
<i class="fa fa-plus"></i>
<translate>Add new custom translation</translate>
</button>
</div>
</div>
<span id="success-{{ key }}" class="input-group-addon" ng-if="configOption.success !== undefined">
<i class="fa fa-lg fa-check-circle text-success"
ng-if="configOption.success === true"></i>