Skip to content

Commit f228789

Browse files
Angamangatuxpiper
authored andcommitted
Translations v1 (#1505)
* Adding translations-button to post-head * Adding post-translations component * Fix language-length check * Translations component for posts * Moving permissions-check * Sending base-language when saving a post * Displaying existing post-translations in the translation-edit view * Saving translations properly * Displaying translations in post-details * Fixing error when saving translations * New alert for success/info * Info/alert-box in posts when showing a translated post * Displaying post in translated language after saving post * Displaying survey-questions in selected language if available * Hiding translation-icon in list * Preserving translations when editing a post * Using full language-list for post-translations * Adding validation+small style-fixes * CSS-cleanup for post-translations * Moving strings to en.json * Removing console.log * Using site-language if no base_language is set * Hiding translations-icon everywhere except in details * Adding strings to en.json * Displaying translation-info in post-modal * Using full language-list for translations * Only displaying icon if translations are available (for non-edit-users) * Remove line under dropdown but keep spacing * Displaying original language for the post
1 parent c49e719 commit f228789

24 files changed

+1097
-15
lines changed

apps/web-mzima-client/src/app/core/enums/icons.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,5 @@ export enum Icons {
7575
thumbUp = 'thumb-up',
7676
ellipses = 'ellipses',
7777
lock = 'lock',
78+
translate = 'translate',
7879
}

apps/web-mzima-client/src/app/core/services/event-bus.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const enum EventType {
2222
RefreshSurveysCounters = 'REFRESH_SURVEYS_COUNTERS',
2323
StopExportPolling = 'STOP_EXPORT_POLLING',
2424
ExportDone = 'EXPORT_DONE',
25+
DisplayTranslatedPost = 'DISPLAY_TRANSLATED_POST',
2526
StatusChange = 'STATUS_CHANGE',
2627
}
2728

apps/web-mzima-client/src/app/core/services/language.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { TranslateService } from '@ngx-translate/core';
44
import { BehaviorSubject } from 'rxjs';
55
import { LanguageInterface } from '@mzima-client/sdk';
66
import LangJSON from '../../../assets/locales/languages.json';
7+
import entityLanguages from '../../../assets/locales/entity-languages.json';
78
import { SessionService } from './session.service';
89

910
@Injectable({
@@ -41,6 +42,9 @@ export class LanguageService {
4142
private set initialLanguage(value: string) {
4243
localStorage.setItem(this.languageKey, value);
4344
}
45+
getEntityLanguages() {
46+
return entityLanguages;
47+
}
4448

4549
getLanguages(): LanguageInterface[] {
4650
if (LangJSON.languages && LangJSON.languages.length > 0) {

apps/web-mzima-client/src/app/post/post-details/post-details.component.html

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,43 @@
1717
[deleteable]="post.allowed_privileges.includes('delete')"
1818
(statusChanged)="statusChangedHandle()"
1919
(deleted)="deletedHandle()"
20+
(openTranslationModal)="openTranslatePost()"
2021
>
2122
</app-post-head>
2223
</div>
23-
24+
<app-post-translated
25+
*ngIf="displayLanguage"
26+
(openTranslationModal)="openTranslatePost()"
27+
(displayOriginalPost)="displayOriginalPost()"
28+
[baseLanguage]="post.base_language"
29+
[displayLanguage]="displayLanguage"
30+
></app-post-translated>
2431
<div class="post__twitter" *ngIf="post.source === 'Twitter' && post.data_source_message_id">
2532
<app-twitter-widget [id]="post.data_source_message_id"></app-twitter-widget>
2633
</div>
2734

2835
<div class="post__survey" *ngIf="post.form">
29-
<h3>{{ post.form.name }}</h3>
30-
<p>{{ post.form.description }}</p>
36+
<h3>{{ post.form.translations[displayLanguage]?.name || post.form.name }}</h3>
37+
<p>{{ post.form.translations[displayLanguage]?.description || post.form.description }}</p>
3138
</div>
3239

3340
<h2 *ngIf="post.title?.length || post.content?.length" data-qa="postTitleValue">
34-
{{ post.title || post.content }}
41+
{{
42+
post.translations[displayLanguage]?.title ||
43+
post.title ||
44+
post.translations[displayLanguage]?.description ||
45+
post.content
46+
}}
3547
</h2>
3648
<div class="post__metadata-container">
3749
<app-post-metadata *ngIf="post.id" [post]="post"></app-post-metadata>
3850
</div>
3951

4052
<div class="post__description" *ngIf="post.title?.length && post.content?.length">
41-
<p [innerHTML]="post.content" data-qa="postDescriptionValue"></p>
53+
<p
54+
[innerHTML]="post.translations[displayLanguage]?.description || post.content"
55+
data-qa="postDescriptionValue"
56+
></p>
4257
</div>
4358

4459
<ng-container *ngFor="let post_content of post.post_content; let i = index">
@@ -60,7 +75,7 @@ <h2 *ngIf="post.title?.length || post.content?.length" data-qa="postTitleValue">
6075
*ngIf="field.input !== 'tags' ? field.value : field.value?.length"
6176
class="post__group"
6277
>
63-
<h3>{{ field.label }}</h3>
78+
<h3>{{ field.translations[displayLanguage]?.label || field.label }}</h3>
6479

6580
<ng-container *ngIf="field.input === 'tags'">
6681
<ng-container *ngFor="let category of field.value">
@@ -121,12 +136,21 @@ <h3>{{ field.label }}</h3>
121136
<p *ngIf="!field.value.value">-</p>
122137
</ng-container>
123138
<ng-container *ngIf="field.label !== 'Media Link'">
124-
<p>{{ field.value.value || '-' }}</p>
139+
<p>
140+
{{
141+
field.value.translations[displayLanguage]?.value || field.value.value || '-'
142+
}}
143+
</p>
125144
</ng-container>
126145
</ng-container>
127146

128147
<ng-container *ngIf="field.input === 'textarea'">
129-
<p [innerHTML]="field.value.value" data-qa="longTextValue"></p>
148+
<p
149+
[innerHTML]="
150+
field.value.translations[displayLanguage]?.value || field.value.value
151+
"
152+
data-qa="longTextValue"
153+
></p>
130154
</ng-container>
131155

132156
<ng-container *ngIf="field.input === 'checkbox'">
@@ -228,7 +252,9 @@ <h3>{{ field.label }}</h3>
228252

229253
<ng-container *ngIf="field.input === 'markdown'">
230254
<span class="code-container">
231-
<code>{{ field.value.value || '-' }}</code>
255+
<code>{{
256+
field.value.translations[displayLanguage]?.value || field.value.value || '-'
257+
}}</code>
232258
</span>
233259
</ng-container>
234260
</div>

apps/web-mzima-client/src/app/post/post-details/post-details.component.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ import {
2525
SurveysService,
2626
} from '@mzima-client/sdk';
2727
import { TranslateService } from '@ngx-translate/core';
28+
import { untilDestroyed } from '@ngneat/until-destroy';
2829
import { lastValueFrom, Subscription } from 'rxjs';
2930
import { BaseComponent } from '../../base.component';
3031
import { preparingVideoUrl } from '../../core/helpers/validators';
3132
import { dateHelper } from '@helpers';
3233
import { BreakpointService, EventBusService, EventType, SessionService } from '@services';
34+
import { LanguageService } from '../../core/services/language.service';
35+
import { PostTranslateComponent } from '../post-translate/post-translate.component';
3336

3437
@Component({
3538
selector: 'app-post-details',
@@ -51,6 +54,8 @@ export class PostDetailsComponent extends BaseComponent implements OnChanges, On
5154
public isPostLoading: boolean = true;
5255
public isManagePosts: boolean = false;
5356
public postChanged: boolean;
57+
public displayLanguage: string;
58+
5459
public post: PostResult;
5560
private dataSubscription: Subscription;
5661
constructor(
@@ -66,6 +71,7 @@ export class PostDetailsComponent extends BaseComponent implements OnChanges, On
6671
private surveyService: SurveysService,
6772
protected sanitizer: DomSanitizer,
6873
private eventBusService: EventBusService,
74+
private languageService: LanguageService,
6975
) {
7076
super(sessionService, breakpointService);
7177
this.getUserData();
@@ -86,6 +92,7 @@ export class PostDetailsComponent extends BaseComponent implements OnChanges, On
8692
//----------------------
8793
this.allowed_privileges = localStorage.getItem('USH_allowed_privileges') ?? '';
8894
this.postId = Number(params['id']);
95+
this.translatePost();
8996
}
9097
});
9198

@@ -104,6 +111,16 @@ export class PostDetailsComponent extends BaseComponent implements OnChanges, On
104111
});
105112
}
106113
}
114+
translatePost() {
115+
this.eventBusService
116+
.on(EventType.DisplayTranslatedPost)
117+
.pipe(untilDestroyed(this))
118+
.subscribe({
119+
next: (language) => {
120+
this.displayLanguage = language.code;
121+
},
122+
});
123+
}
107124

108125
loadData(): void {}
109126

@@ -320,4 +337,27 @@ export class PostDetailsComponent extends BaseComponent implements OnChanges, On
320337
public getDate(value: any, format: string): string {
321338
return dateHelper.getDateWithTz(value, format);
322339
}
340+
341+
public openTranslatePost() {
342+
const dialogRef = this.dialog.open(PostTranslateComponent, {
343+
width: '100%',
344+
maxWidth: '768px',
345+
panelClass: ['modal', 'select-languages-modal'],
346+
data: {
347+
post: this.post,
348+
languages: this.languageService.getEntityLanguages(),
349+
},
350+
});
351+
352+
dialogRef.afterClosed().subscribe((response) => {
353+
if (response) {
354+
this.post = response.post;
355+
this.displayLanguage = response.displayLanguage.code;
356+
}
357+
});
358+
}
359+
360+
public displayOriginalPost() {
361+
this.displayLanguage = '';
362+
}
323363
}

apps/web-mzima-client/src/app/post/post-edit/post-edit.component.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -565,11 +565,12 @@ export class PostEditComponent extends BaseComponent implements OnInit, OnChange
565565
}
566566

567567
async preparationData(): Promise<any> {
568-
for (const task of this.tasks) {
568+
for (const [index, task] of this.tasks.entries()) {
569569
task.fields = await Promise.all(
570570
task.fields.map(
571571
async (field: { key: string | number; input: string; type: string; options: any }) => {
572572
let value: any = {
573+
translations: [],
573574
value: this.form.value[field.key],
574575
};
575576

@@ -705,6 +706,12 @@ export class PostEditComponent extends BaseComponent implements OnInit, OnChange
705706
this.form.value[field.key]?.map((fieldValue: any) => fieldValue.value) || [];
706707
break;
707708
default:
709+
if (this.post?.post_content) {
710+
const postField = this.post.post_content[index].fields.find(
711+
(f: any) => f.key === field.key,
712+
);
713+
value.translations = postField?.value?.translations || [];
714+
}
708715
value.value = this.form.value[field.key] || null;
709716
}
710717
return {
@@ -725,24 +732,26 @@ export class PostEditComponent extends BaseComponent implements OnInit, OnChange
725732
try {
726733
await this.preparationData();
727734
} catch (error: any) {
735+
console.log(error);
728736
this.form.enable();
729737
this.submitted = false;
730738
this.showMessage(error, 'error');
731739
return;
732740
}
733741

742+
const postLanguage = this.selectedLanguage?.code || this.languageService.initialLanguage;
734743
const postData = {
735-
base_language: 'en',
744+
base_language: postLanguage,
736745
completed_stages: this.completeStages,
737746
content: this.description,
738747
description: '',
739-
enabled_languages: {},
740748
form_id: this.formId,
741749
locale: 'en_US',
742750
post_content: this.tasks,
743751
published_to: [],
744752
title: this.title,
745753
type: 'report',
754+
translations: this.post?.translations || [],
746755
};
747756

748757
if (!this.form.valid) this.form.markAllAsTouched();

apps/web-mzima-client/src/app/post/post-head/post-head.component.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@
3333
>
3434
<mat-icon icon svgIcon="share" [data-qa]="'share-post'" [attr.post]="post.id"></mat-icon>
3535
</mzima-client-button>
36+
<mzima-client-button
37+
fill="clear"
38+
color="gray"
39+
tabindex="-1"
40+
[iconOnly]="true"
41+
(buttonClick)="openTranslationModal.emit()"
42+
*ngIf="showTranslationsIcon()"
43+
class="post-head__control post-head__control--share"
44+
>
45+
<mat-icon
46+
icon
47+
svgIcon="translate"
48+
[data-qa]="'translate-post'"
49+
[attr.post]="post.id"
50+
></mat-icon>
51+
</mzima-client-button>
3652
<mzima-client-button
3753
*ngIf="!!user?.userId"
3854
fill="clear"

apps/web-mzima-client/src/app/post/post-head/post-head.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ export class PostHeadComponent extends BaseComponent implements OnInit {
2020
@Input() public editable: boolean;
2121
@Input() public feedView: boolean;
2222
@Input() public deleteable: boolean;
23+
@Input() public hideTranslationsIcon: boolean;
2324
@Output() edit = new EventEmitter();
2425
@Output() refresh = new EventEmitter();
2526
@Output() deleted = new EventEmitter();
2627
@Output() statusChanged = new EventEmitter();
28+
@Output() openTranslationModal = new EventEmitter();
2729
public isLocked: boolean;
2830

2931
constructor(
@@ -165,4 +167,8 @@ export class PostHeadComponent extends BaseComponent implements OnInit {
165167
duration,
166168
});
167169
}
170+
public showTranslationsIcon() {
171+
const languagesAvailabe = this.post?.enabled_languages?.available?.length > 0;
172+
return !this.hideTranslationsIcon && (languagesAvailabe || this.editable);
173+
}
168174
}

apps/web-mzima-client/src/app/post/post-preview/post-preview.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
[deleteable]="post.allowed_privileges.includes('delete')"
2222
(deleted)="deletedHandle()"
2323
(statusChanged)="statusChangedHandle()"
24+
[hideTranslationsIcon]="true"
2425
>
2526
</app-post-head>
2627
</div>

0 commit comments

Comments
 (0)