i18n: add option to mark string as non-translatable (#71791)
This commit is contained in:
parent
5da7ee34d5
commit
8762f72b78
|
@ -312,3 +312,50 @@ def test_i18n_pagination(pub):
|
|||
resp = resp.click('20')
|
||||
resp = resp.click('3')
|
||||
assert 'offset=40' in resp.request.url
|
||||
|
||||
|
||||
def test_i18n_mark_as_non_translatabe(pub):
|
||||
TranslatableMessage.wipe()
|
||||
Workflow.wipe()
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
Category.wipe()
|
||||
CardDef.wipe()
|
||||
MailTemplate.wipe()
|
||||
create_superuser(pub)
|
||||
workflow = Workflow(name='workflow')
|
||||
workflow.add_status('First Status')
|
||||
workflow.add_status('Second Status')
|
||||
workflow.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
# first time goes to scanning
|
||||
resp = app.get('/backoffice/i18n/', status=302)
|
||||
resp = resp.follow()
|
||||
resp = resp.click('Go to multilinguism page')
|
||||
# second time, the page stays on
|
||||
resp = app.get('/backoffice/i18n/', status=200)
|
||||
|
||||
assert TranslatableMessage.count() == 2 # First Status / Second Status
|
||||
assert resp.pyquery('tr').length == 2
|
||||
|
||||
# check form filter
|
||||
assert resp.form['lang'].value == 'fr'
|
||||
resp.form['q'] = 'First'
|
||||
resp = resp.form.submit()
|
||||
assert resp.pyquery('tr').length == 1
|
||||
|
||||
# mark a message as non translatable
|
||||
resp = resp.click('edit', index=0)
|
||||
resp.form['non_translatable'].checked = True
|
||||
resp = resp.form.submit('submit').follow()
|
||||
msg = TranslatableMessage.select([Equal('string', 'First Status')])[0]
|
||||
assert msg.translatable is False
|
||||
|
||||
resp = app.get('/backoffice/i18n/', status=200)
|
||||
assert resp.pyquery('tr').length == 1
|
||||
assert resp.pyquery('tr td:first-child').text() == 'Second Status'
|
||||
resp.form['non_translatable'].checked = True
|
||||
resp = resp.form.submit('submit')
|
||||
assert resp.pyquery('tr').length == 1
|
||||
assert resp.pyquery('tr td:first-child').text() == 'First Status'
|
||||
|
|
|
@ -32,7 +32,7 @@ from wcs.qommon import _, errors, get_cfg, misc, ods, template
|
|||
from wcs.qommon.afterjobs import AfterJob
|
||||
from wcs.qommon.backoffice.listing import pagination_links
|
||||
from wcs.qommon.backoffice.menu import html_top
|
||||
from wcs.qommon.form import FileWidget, Form, RadiobuttonsWidget, TextWidget
|
||||
from wcs.qommon.form import CheckboxWidget, FileWidget, Form, RadiobuttonsWidget, TextWidget
|
||||
from wcs.qommon.storage import Equal, FtsMatch, ILike, Or
|
||||
from wcs.workflows import Workflow
|
||||
|
||||
|
@ -69,6 +69,7 @@ class I18nDirectory(Directory):
|
|||
get_response().breadcrumb.append(('i18n/', _('Multilinguism')))
|
||||
|
||||
criterias = []
|
||||
criterias.append(Equal('translatable', not (bool(get_request().form.get('non_translatable')))))
|
||||
if get_request().form.get('q'):
|
||||
search_term = get_request().form.get('q')
|
||||
criterias.append(Or([ILike('string', search_term), FtsMatch(search_term)]))
|
||||
|
@ -85,6 +86,7 @@ class I18nDirectory(Directory):
|
|||
'pagination_links': pagination_links(offset, limit, total_count, load_js=False),
|
||||
'messages': TranslatableMessage.select(criterias, offset=offset, limit=limit, order_by='string'),
|
||||
'query': get_request().get_query(),
|
||||
'non_translatable': get_request().form.get('non-translatable'),
|
||||
}
|
||||
|
||||
get_response().add_javascript(['popup.js'])
|
||||
|
@ -211,6 +213,12 @@ class MessageDirectory(Directory):
|
|||
rows = min(10, max(2, self.msg.string.count('\n')))
|
||||
attr = 'string_%s' % self.lang
|
||||
form.add(TextWidget, 'translation', value=getattr(self.msg, attr), rows=rows)
|
||||
form.add(
|
||||
CheckboxWidget,
|
||||
'non_translatable',
|
||||
title=_('Mark as non-translatable'),
|
||||
value=not (self.msg.translatable),
|
||||
)
|
||||
form.add_submit('submit', _('Submit'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
if form.get_widget('cancel').parse():
|
||||
|
@ -218,6 +226,7 @@ class MessageDirectory(Directory):
|
|||
|
||||
if form.is_submitted() and not form.has_errors():
|
||||
setattr(self.msg, attr, form.get_widget('translation').parse())
|
||||
self.msg.translatable = not (form.get_widget('non_translatable').parse())
|
||||
self.msg.store()
|
||||
update_digests()
|
||||
return redirect('../../?' + get_request().get_query())
|
||||
|
|
|
@ -22,6 +22,7 @@ class TranslatableMessage(sql.TranslatableMessage):
|
|||
string = None
|
||||
context = None
|
||||
locations = None # list
|
||||
translatable = True
|
||||
|
||||
def translations(self):
|
||||
return {x.split('_', 1)[1]: getattr(self, x) for x in self.__dict__ if x.startswith('string_')}
|
||||
|
|
15
wcs/sql.py
15
wcs/sql.py
|
@ -4215,6 +4215,7 @@ class TranslatableMessage(SqlMixin):
|
|||
('context', 'varchar'),
|
||||
('locations', 'varchar[]'),
|
||||
('last_update_time', 'timestamptz'),
|
||||
('translatable', 'boolean'),
|
||||
]
|
||||
|
||||
id = None
|
||||
|
@ -4238,6 +4239,7 @@ class TranslatableMessage(SqlMixin):
|
|||
context VARCHAR,
|
||||
locations VARCHAR[],
|
||||
last_update_time TIMESTAMPTZ,
|
||||
translatable BOOLEAN DEFAULT TRUE,
|
||||
fts TSVECTOR
|
||||
)'''
|
||||
% table_name
|
||||
|
@ -4250,6 +4252,9 @@ class TranslatableMessage(SqlMixin):
|
|||
)
|
||||
existing_fields = {x[0] for x in cur.fetchall()}
|
||||
|
||||
if 'translatable' not in existing_fields:
|
||||
cur.execute('''ALTER TABLE %s ADD COLUMN translatable BOOLEAN DEFAULT(TRUE)''' % table_name)
|
||||
|
||||
# add columns for translations
|
||||
for field in cls.get_data_fields():
|
||||
if field not in existing_fields:
|
||||
|
@ -4306,7 +4311,10 @@ class TranslatableMessage(SqlMixin):
|
|||
@guard_postgres
|
||||
def load_as_catalog(cls, language):
|
||||
conn, cur = get_connection_and_cursor()
|
||||
sql_statement = 'SELECT context, string, string_%s FROM %s' % (language, cls._table_name)
|
||||
sql_statement = 'SELECT context, string, string_%s FROM %s WHERE translatable = TRUE' % (
|
||||
language,
|
||||
cls._table_name,
|
||||
)
|
||||
cur.execute(sql_statement)
|
||||
catalog = {(x[0], x[1]): x[2] for x in cur.fetchall()}
|
||||
conn.commit()
|
||||
|
@ -5060,7 +5068,7 @@ def get_period_total(
|
|||
# latest migration, number + description (description is not used
|
||||
# programmaticaly but will make sure git conflicts if two migrations are
|
||||
# separately added with the same number)
|
||||
SQL_LEVEL = (78, 'add audit table')
|
||||
SQL_LEVEL = (79, 'add translatable column to TranslatableMessage table')
|
||||
|
||||
|
||||
def migrate_global_views(conn, cur):
|
||||
|
@ -5239,8 +5247,9 @@ def migrate():
|
|||
# 67: re-migrate legacy tokens
|
||||
do_tokens_table()
|
||||
migrate_legacy_tokens()
|
||||
if sql_level < 68:
|
||||
if sql_level < 79:
|
||||
# 68: multilinguism
|
||||
# 79: add translatable column to TranslatableMessage table
|
||||
TranslatableMessage.do_table()
|
||||
if sql_level < 72:
|
||||
# 72: add testdef table
|
||||
|
|
|
@ -14,7 +14,12 @@
|
|||
{{ block.super }}
|
||||
|
||||
<form action="." class="i18n-filter-form">
|
||||
<label>{% trans "Search:" %} <input type="search" name="q" value="{{q|default:""}}"></label>
|
||||
<span>
|
||||
<label>{% trans "Search:" %} <input type="search" name="q" value="{{q|default:""}}"></label>
|
||||
<label><input name="non_translatable" type="checkbox"
|
||||
{% if non_translatable %}checked{% endif %}
|
||||
>{% trans "Search non-translatable strings" %}</label>
|
||||
</span>
|
||||
<fieldset class="radiogroup"><legend>{% trans "Language:" %}</legend>
|
||||
{% for language in supported_languages %}
|
||||
<input type="radio" name="lang" value="{{language.0}}" id="radio-lang-{{language.0}}"
|
||||
|
|
Loading…
Reference in New Issue