Skip to content

Commit

Permalink
Show dependencies on edit translation view
Browse files Browse the repository at this point in the history
  • Loading branch information
kaedroho committed Nov 9, 2020
1 parent f272215 commit 53fb2dd
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 3 deletions.
3 changes: 3 additions & 0 deletions wagtail_localize/models.py
Expand Up @@ -1242,6 +1242,9 @@ class RelatedObjectSegment(BaseSegment):
TranslatableObject, on_delete=models.CASCADE, related_name="references"
)

def get_source_instance(self):
return self.object.get_instance_or_none(self.source.locale)

@classmethod
def from_value(cls, source, value):
context, context_created = TranslationContext.objects.get_or_create(
Expand Down
Expand Up @@ -77,7 +77,31 @@ export interface SynchronisedValueSegment extends SegmentCommon {
editUrl: string;
}

export type Segment = StringSegment | SynchronisedValueSegment;
export interface RelatedObjectSegment extends SegmentCommon {
type: 'related_object';
source: {
title: string;
isLive: boolean;
liveUrl?: string;
editUrl?: string;
createTranslationRequestUrl?: string;
} | null;
dest: {
title: string;
isLive: boolean;
liveUrl?: string;
editUrl?: string;
} | null;
translationProgress: {
totalSegments: number;
translatedSegments: number;
} | null; // Null if translated without wagtail-localize
}

export type Segment =
| StringSegment
| SynchronisedValueSegment
| RelatedObjectSegment;

export interface StringTranslationAPI {
string_id: number;
Expand Down
Expand Up @@ -18,7 +18,8 @@ import {
StringTranslationAPI,
SegmentOverride,
SegmentOverrideAPI,
Locale
Locale,
RelatedObjectSegment
} from '.';
import {
EditorState,
Expand Down Expand Up @@ -718,6 +719,92 @@ const EditorSynchronisedValueSegment: FunctionComponent<
);
};

interface EditorRelatedObjectSegmentProps {
segment: RelatedObjectSegment;
}

const EditorRelatedObjectSegment: FunctionComponent<
EditorRelatedObjectSegmentProps
> = ({ segment }) => {
const openEditUrl = () => {
if (segment.dest) {
window.open(segment.dest.editUrl);
}
};

const openCreateTranslationRequestUrl = () => {
if (!!segment.source && segment.source.createTranslationRequestUrl) {
window.open(segment.source.createTranslationRequestUrl);
}
};

let message = <></>;

if (segment.dest) {
if (segment.translationProgress !== null) {
// Translated with Wagtail localize. Show progress
message = (
<>
{segment.translationProgress.translatedSegments} /{' '}
{segment.translationProgress.totalSegments}{' '}
{gettext('segments translated')}
{segment.translationProgress.translatedSegments ==
segment.translationProgress.totalSegments && (
<Icon name="tick" className="icon--green" />
)}
</>
);
} else {
// Segment translated without Wagtail localize. Just show a tick
message = <Icon name="tick" className="icon--green" />;
}
} else {
// Not translated
message = (
<>
{gettext('Not translated')}{' '}
<Icon name="warning" className="icon--red" />
</>
);
}

return (
<li>
{segment.location.subField && (
<SegmentFieldLabel>
{segment.location.subField}
</SegmentFieldLabel>
)}
<SegmentValue>
<p>
{segment.source
? segment.source.title
: gettext('[DELETED]')}
</p>
</SegmentValue>
<SegmentToolbar>
<li>{message}</li>
<li>
{segment.dest && segment.dest.editUrl && (
<ActionButton onClick={openEditUrl}>
{gettext('Edit')}
</ActionButton>
)}
{!segment.dest &&
!!segment.source &&
segment.source.createTranslationRequestUrl && (
<ActionButton
onClick={openCreateTranslationRequestUrl}
>
{gettext('Translate')}
</ActionButton>
)}
</li>
</SegmentToolbar>
</li>
);
};

interface EditorSegmentListProps extends EditorProps, EditorState {
dispatch: React.Dispatch<EditorAction>;
csrfToken: string;
Expand Down Expand Up @@ -777,6 +864,9 @@ const EditorSegmentList: FunctionComponent<EditorSegmentListProps> = ({
/>
);
}
case 'related_object': {
return <EditorRelatedObjectSegment segment={segment} />;
}
}
});

Expand Down
28 changes: 28 additions & 0 deletions wagtail_localize/tests/test_edit_translation.py
Expand Up @@ -187,6 +187,34 @@ def test_edit_page_translation(self):
self.assertEqual(props['segments'][9]['location'], {'tab': 'content', 'field': 'Text block', 'blockId': str(STREAM_BLOCK_ID), 'fieldHelpText': '', 'subField': None, 'widget': None})
# TODO: Examples that use fieldHelpText and subField

# Check related object
related_object_segment = props['segments'][10]
self.assertEqual(related_object_segment['type'], 'related_object')
self.assertEqual(related_object_segment['contentPath'], 'test_snippet')
self.assertEqual(related_object_segment['location'], {'tab': 'content', 'field': 'Test snippet', 'blockId': None, 'fieldHelpText': '', 'subField': None, 'widget': None})
self.assertEqual(related_object_segment['source']['title'], str(self.snippet))
self.assertEqual(related_object_segment['dest']['title'], str(self.fr_snippet))
self.assertEqual(related_object_segment['translationProgress'], {'totalSegments': 1, 'translatedSegments': 0})

def test_manually_translated_related_object(self):
# Related objects don't have to be translated by Wagtail localize so test with the snippet's translation record deleted
self.snippet_translation.delete()

response = self.client.get(reverse('wagtailadmin_pages:edit', args=[self.fr_page.id]))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'wagtail_localize/admin/edit_translation.html')

props = json.loads(response.context['props'])

# Check related object
related_object_segment = props['segments'][10]
self.assertEqual(related_object_segment['type'], 'related_object')
self.assertEqual(related_object_segment['contentPath'], 'test_snippet')
self.assertEqual(related_object_segment['location'], {'tab': 'content', 'field': 'Test snippet', 'blockId': None, 'fieldHelpText': '', 'subField': None, 'widget': None})
self.assertEqual(related_object_segment['source']['title'], str(self.snippet))
self.assertEqual(related_object_segment['dest']['title'], str(self.fr_snippet))
self.assertIsNone(related_object_segment['translationProgress'])

def test_override_types(self):
# Similar to above but adds some more overridable things to test with
self.page.test_synchronized_image = Image.objects.create(
Expand Down
71 changes: 70 additions & 1 deletion wagtail_localize/views/edit_translation.py
Expand Up @@ -355,6 +355,7 @@ def edit_translation(request, translation, instance):

overridable_segments = translation.source.overridablesegment_set.all().order_by('order')
segment_overrides = overridable_segments.get_overrides(translation.target_locale)
related_object_segments = translation.source.relatedobjectsegment_set.all().order_by('order')

tab_helper = TabHelper(source_instance)

Expand Down Expand Up @@ -407,7 +408,75 @@ def edit_translation(request, translation, instance):
for segment in overridable_segments
]

segments = string_segment_data + syncronised_value_segment_data
def get_source_object_info(segment):
instance = segment.get_source_instance()

if isinstance(instance, Page):
return {
'title': str(instance),
'isLive': instance.live,
'liveUrl': instance.full_url,
'editUrl': reverse('wagtailadmin_pages:edit', args=[instance.id]),
'createTranslationRequestUrl': reverse('wagtail_localize:submit_page_translation', args=[instance.id]),
}

else:
return {
'title': str(instance),
'isLive': True,
'editUrl': reverse('wagtailsnippets:edit', args=[instance._meta.app_label, instance._meta.model_name, quote(instance.id)]),
'createTranslationRequestUrl': reverse('wagtail_localize:submit_snippet_translation', args=[instance._meta.app_label, instance._meta.model_name, quote(instance.id)]),
}

def get_dest_object_info(segment):
instance = segment.object.get_instance_or_none(translation.target_locale)
if not instance:
return

if isinstance(instance, Page):
return {
'title': str(instance),
'isLive': instance.live,
'liveUrl': instance.full_url,
'editUrl': reverse('wagtailadmin_pages:edit', args=[instance.id]),
}

else:
return {
'title': str(instance),
'isLive': True,
'editUrl': reverse('wagtailsnippets:edit', args=[instance._meta.app_label, instance._meta.model_name, quote(instance.id)]),
}

def get_translation_progress(segment, locale):
try:
translation = Translation.objects.get(source__object_id=segment.object_id, target_locale=locale, enabled=True)

except Translation.DoesNotExist:
return None

total_segments, translated_segments = translation.get_progress()

return {
'totalSegments': total_segments,
'translatedSegments': translated_segments,
}

related_object_segment_data = [
{
'type': 'related_object',
'id': segment.id,
'contentPath': segment.context.path,
'location': get_segment_location_info(source_instance, tab_helper, segment.context.path),
'order': segment.order,
'source': get_source_object_info(segment),
'dest': get_dest_object_info(segment),
'translationProgress': get_translation_progress(segment, translation.target_locale),
}
for segment in related_object_segments
]

segments = string_segment_data + syncronised_value_segment_data + related_object_segment_data
segments.sort(key=lambda segment: segment['order'])

return render(request, 'wagtail_localize/admin/edit_translation.html', {
Expand Down

0 comments on commit 53fb2dd

Please sign in to comment.