2
0
Fork 0

Merge pull request #3626 from NoelDeMartin/MOBILE-4288

MOBILE-4288: Filter multilang group strings
main
Dani Palou 2023-04-24 14:31:01 +02:00 committed by GitHub
commit 77605b87f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 126 additions and 36 deletions

View File

@ -42,6 +42,7 @@ import { AddonCalendarEventsSource } from '@addons/calendar/classes/events-sourc
import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager'; import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager';
import { CoreReminders, CoreRemindersService } from '@features/reminders/services/reminders'; import { CoreReminders, CoreRemindersService } from '@features/reminders/services/reminders';
import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/components/set-reminder-menu/set-reminder-menu'; import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/components/set-reminder-menu/set-reminder-menu';
import { CoreLang } from '@services/lang';
/** /**
* Page that displays a single calendar event. * Page that displays a single calendar event.
@ -370,7 +371,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
const groups = await CoreGroups.getUserGroupsInCourse(courseId); const groups = await CoreGroups.getUserGroupsInCourse(courseId);
const group = groups.find((group) => group.id == event.groupid); const group = groups.find((group) => group.id == event.groupid);
this.groupName = group ? group.name : ''; this.groupName = group ? await CoreLang.filterMultilang(group.name) : '';
} catch { } catch {
// Error getting groups, just don't show the group name. // Error getting groups, just don't show the group name.

View File

@ -21,7 +21,7 @@ import { CoreSite } from '@classes/site';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
/** /**
* Handler to support the Multilang filter. * Handler to support the Multilang filter in core.
*/ */
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class AddonFilterMultilangHandlerService extends CoreFilterDefaultHandler { export class AddonFilterMultilangHandlerService extends CoreFilterDefaultHandler {

View File

@ -19,7 +19,9 @@ import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/def
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
/** /**
* Handler to support the Multilang filter. * Handler to support the multilang2 community filter.
*
* @see https://moodle.org/plugins/filter_multilang2
*/ */
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class AddonFilterMultilang2HandlerService extends CoreFilterDefaultHandler { export class AddonFilterMultilang2HandlerService extends CoreFilterDefaultHandler {

View File

@ -33,6 +33,7 @@ import { CoreError } from '@classes/errors/error';
import { AddonMessagesSyncEvents, AddonMessagesSyncProvider } from './messages-sync'; import { AddonMessagesSyncEvents, AddonMessagesSyncProvider } from './messages-sync';
import { CoreWSError } from '@classes/errors/wserror'; import { CoreWSError } from '@classes/errors/wserror';
import { AddonNotificationsPreferencesNotificationProcessorState } from '@addons/notifications/services/notifications'; import { AddonNotificationsPreferencesNotificationProcessorState } from '@addons/notifications/services/notifications';
import { MultilangString } from '@services/lang';
const ROOT_CACHE_KEY = 'mmaMessages:'; const ROOT_CACHE_KEY = 'mmaMessages:';
@ -2970,7 +2971,7 @@ export type AddonMessagesConversationMember = {
conversations?: { // Conversations between users. conversations?: { // Conversations between users.
id: number; // Conversations id. id: number; // Conversations id.
type: number; // Conversation type: private or public. type: number; // Conversation type: private or public.
name: string; // Multilang compatible conversation name2. name: MultilangString; // Multilang compatible conversation name2.
timecreated: number; // The timecreated timestamp for the conversation. timecreated: number; // The timecreated timestamp for the conversation.
}[]; }[];
}; };
@ -3495,7 +3496,7 @@ export type AddonMessagesGetUserContactsWSResponse = {
conversations?: { // Conversations between users. conversations?: { // Conversations between users.
id: number; // Conversations id. id: number; // Conversations id.
type: number; // Conversation type: private or public. type: number; // Conversation type: private or public.
name: string; // Multilang compatible conversation name2. name: MultilangString; // Multilang compatible conversation name2.
timecreated: number; // The timecreated timestamp for the conversation. timecreated: number; // The timecreated timestamp for the conversation.
}[]; }[];
}[]; }[];
@ -3535,7 +3536,7 @@ export type AddonMessagesGetContactRequestsWSResponse = {
conversations?: { // Conversations between users. conversations?: { // Conversations between users.
id: number; // Conversations id. id: number; // Conversations id.
type: number; // Conversation type: private or public. type: number; // Conversation type: private or public.
name: string; // Multilang compatible conversation name2. name: MultilangString; // Multilang compatible conversation name2.
timecreated: number; // The timecreated timestamp for the conversation. timecreated: number; // The timecreated timestamp for the conversation.
}[]; }[];
}[]; }[];

View File

@ -1147,10 +1147,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
if (this.assign.teamsubmission) { if (this.assign.teamsubmission) {
if (lastAttempt.submissiongroup) { if (lastAttempt.submissiongroup) {
// Get the name of the group. // Get the name of the group.
promises.push(CoreGroups.getActivityAllowedGroups(this.assign.cmid).then((result) => { promises.push(CoreGroups.getActivityAllowedGroups(this.assign.cmid).then(async (result) => {
const group = result.groups.find((group) => group.id === lastAttempt.submissiongroup); const group = result.groups.find((group) => group.id === lastAttempt.submissiongroup);
if (group) { if (group) {
lastAttempt.submissiongroupname = group.name; lastAttempt.submissiongroupname = await CoreLang.filterMultilang(group.name);
} }
return; return;

View File

@ -35,6 +35,7 @@ import { AddonModAssignSync, AddonModAssignSyncResult } from '../assign-sync';
import { CoreUser } from '@features/user/services/user'; import { CoreUser } from '@features/user/services/user';
import { CoreGradesHelper } from '@features/grades/services/grades-helper'; import { CoreGradesHelper } from '@features/grades/services/grades-helper';
import { CoreCourses } from '@features/courses/services/courses'; import { CoreCourses } from '@features/courses/services/courses';
import { multilangString } from '@services/lang';
/** /**
* Handler to prefetch assigns. * Handler to prefetch assigns.
@ -355,7 +356,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
// Teacher, prefetch all submissions. // Teacher, prefetch all submissions.
if (!groupInfo.groups || groupInfo.groups.length == 0) { if (!groupInfo.groups || groupInfo.groups.length == 0) {
groupInfo.groups = [{ id: 0, name: '' }]; groupInfo.groups = [{ id: 0, name: multilangString() }];
} }
const promises = groupInfo.groups.map((group) => const promises = groupInfo.groups.map((group) =>

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { multilangString } from '@services/lang';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreComments } from '@features/comments/services/comments'; import { CoreComments } from '@features/comments/services/comments';
import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler';
@ -98,7 +99,7 @@ export class AddonModDataPrefetchHandlerService extends CoreCourseActivityPrefet
const groupInfo = await CoreGroups.getActivityGroupInfo(module.id, false, undefined, options.siteId); const groupInfo = await CoreGroups.getActivityGroupInfo(module.id, false, undefined, options.siteId);
if (!groupInfo.groups || groupInfo.groups.length == 0) { if (!groupInfo.groups || groupInfo.groups.length == 0) {
groupInfo.groups = [{ id: 0, name: '' }]; groupInfo.groups = [{ id: 0, name: multilangString() }];
} }
groups = groupInfo.groups || []; groups = groupInfo.groups || [];

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { multilangString } from '@services/lang';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler';
import { CoreCourseAnyModuleData, CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseAnyModuleData, CoreCourseCommonModWSOptions } from '@features/course/services/course';
@ -187,7 +188,7 @@ export class AddonModFeedbackPrefetchHandlerService extends CoreCourseActivityPr
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];
if (!groupInfo.groups || groupInfo.groups.length == 0) { if (!groupInfo.groups || groupInfo.groups.length == 0) {
groupInfo.groups = [{ id: 0, name: '' }]; groupInfo.groups = [{ id: 0, name: multilangString() }];
} }
groupInfo.groups.forEach((group) => { groupInfo.groups.forEach((group) => {

View File

@ -44,6 +44,7 @@ import { AddonModForumDiscussionsSwipeManager } from '../../classes/forum-discus
import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router'; import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';
import { AddonModForumDiscussionsSource } from '../../classes/forum-discussions-source'; import { AddonModForumDiscussionsSource } from '../../classes/forum-discussions-source';
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker'; import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
import { CoreLang, multilangString } from '@services/lang';
type NewDiscussionData = { type NewDiscussionData = {
subject: string; subject: string;
@ -190,14 +191,14 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
} }
// eslint-disable-next-line promise/no-nesting // eslint-disable-next-line promise/no-nesting
return promise.then((forumGroups) => { return promise.then(async (forumGroups) => {
if (forumGroups.length > 0) { if (forumGroups.length > 0) {
this.groups = forumGroups; this.groups = forumGroups;
this.groupIds = forumGroups.map((group) => group.id).filter((id) => id > 0); this.groupIds = forumGroups.map((group) => group.id).filter((id) => id > 0);
// Do not override group id. // Do not override group id.
this.newDiscussion.groupId = this.newDiscussion.groupId || this.getInitialGroupId(); this.newDiscussion.groupId = this.newDiscussion.groupId || this.getInitialGroupId();
this.showGroups = true; this.showGroups = true;
this.calculateGroupName(); await this.calculateGroupName();
if (this.groupIds.length <= 1) { if (this.groupIds.length <= 1) {
this.newDiscussion.postToAllGroups = false; this.newDiscussion.postToAllGroups = false;
} }
@ -271,7 +272,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
this.newDiscussion.subscribe = !!discussion.options.discussionsubscribe; this.newDiscussion.subscribe = !!discussion.options.discussionsubscribe;
this.newDiscussion.pin = !!discussion.options.discussionpinned; this.newDiscussion.pin = !!discussion.options.discussionpinned;
this.messageControl.setValue(discussion.message); this.messageControl.setValue(discussion.message);
this.calculateGroupName(); await this.calculateGroupName();
// Treat offline attachments if any. // Treat offline attachments if any.
if (typeof discussion.options.attachmentsid === 'object' && discussion.options.attachmentsid.offline) { if (typeof discussion.options.attachmentsid === 'object' && discussion.options.attachmentsid.offline) {
@ -426,7 +427,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
groups.unshift({ groups.unshift({
courseid: this.courseId, courseid: this.courseId,
id: AddonModForumProvider.ALL_PARTICIPANTS, id: AddonModForumProvider.ALL_PARTICIPANTS,
name: Translate.instant('core.allparticipants'), name: multilangString(Translate.instant('core.allparticipants')),
}); });
} }
@ -611,11 +612,13 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
/** /**
* Calculate current group's name. * Calculate current group's name.
*/ */
calculateGroupName(): void { async calculateGroupName(): Promise<void> {
if (this.newDiscussion.groupId <= 0) { if (this.newDiscussion.groupId <= 0) {
this.groupName = undefined; this.groupName = undefined;
} else { } else {
this.groupName = this.groups.find(group => group.id === this.newDiscussion.groupId)?.name; const groupName = this.groups.find(group => group.id === this.newDiscussion.groupId)?.name;
this.groupName = groupName && await CoreLang.filterMultilang(groupName);
} }
} }

View File

@ -48,6 +48,7 @@ import {
import { AddonModLessonModuleHandlerService } from '../../services/handlers/module'; import { AddonModLessonModuleHandlerService } from '../../services/handlers/module';
import { CoreTime } from '@singletons/time'; import { CoreTime } from '@singletons/time';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { CoreLang } from '@services/lang';
/** /**
* Component that displays a lesson entry page. * Component that displays a lesson entry page.
@ -491,7 +492,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
// Search the name of the group if it isn't all participants. // Search the name of the group if it isn't all participants.
if (groupId && this.groupInfo && this.groupInfo.groups) { if (groupId && this.groupInfo && this.groupInfo.groups) {
const group = this.groupInfo.groups.find(group => groupId == group.id); const group = this.groupInfo.groups.find(group => groupId == group.id);
this.selectedGroupName = group?.name || ''; this.selectedGroupName = group ? await CoreLang.filterMultilang(group.name) : '';
} }
// Get the overview of retakes for the group. // Get the overview of retakes for the group.

View File

@ -55,6 +55,7 @@ import {
} from '../../services/wiki-sync'; } from '../../services/wiki-sync';
import { AddonModWikiMapModalComponent, AddonModWikiMapModalReturn } from '../map/map'; import { AddonModWikiMapModalComponent, AddonModWikiMapModalReturn } from '../map/map';
import { AddonModWikiSubwikiPickerComponent } from '../subwiki-picker/subwiki-picker'; import { AddonModWikiSubwikiPickerComponent } from '../subwiki-picker/subwiki-picker';
import { CoreLang } from '@services/lang';
/** /**
* Component that displays a wiki entry page. * Component that displays a wiki entry page.
@ -901,7 +902,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp
if (subwiki.groupid != 0 && userGroups.length > 0) { if (subwiki.groupid != 0 && userGroups.length > 0) {
// Get groupLabel if it has groupId. // Get groupLabel if it has groupId.
const group = userGroups.find(group => group.id == subwiki.groupid); const group = userGroups.find(group => group.id == subwiki.groupid);
groupLabel = group?.name || ''; groupLabel = group ? await CoreLang.filterMultilang(group.name) : '';
} else { } else {
groupLabel = Translate.instant('addon.mod_wiki.notingroup'); groupLabel = Translate.instant('addon.mod_wiki.notingroup');
} }

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { multilangString } from '@services/lang';
import { AddonModDataSyncResult } from '@addons/mod/data/services/data-sync'; import { AddonModDataSyncResult } from '@addons/mod/data/services/data-sync';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler';
@ -105,7 +106,7 @@ export class AddonModWorkshopPrefetchHandlerService extends CoreCourseActivityPr
if (access.canviewallsubmissions) { if (access.canviewallsubmissions) {
const groupInfo = await CoreGroups.getActivityGroupInfo(module.id, false, undefined, options.siteId); const groupInfo = await CoreGroups.getActivityGroupInfo(module.id, false, undefined, options.siteId);
if (!groupInfo.groups || groupInfo.groups.length == 0) { if (!groupInfo.groups || groupInfo.groups.length == 0) {
groupInfo.groups = [{ id: 0, name: '' }]; groupInfo.groups = [{ id: 0, name: multilangString() }];
} }
groups = groupInfo.groups; groups = groupInfo.groups;
} }

View File

@ -13,8 +13,8 @@
</ion-label> </ion-label>
<ion-select [(ngModel)]="selected" (ionChange)="selectedChange.emit(selected)" interface="action-sheet" <ion-select [(ngModel)]="selected" (ionChange)="selectedChange.emit(selected)" interface="action-sheet"
[interfaceOptions]="{header: 'core.group' | translate}"> [interfaceOptions]="{header: 'core.group' | translate}">
<ion-select-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id"> <ion-select-option *ngFor="let option of options" [value]="option.value">
{{groupOpt.name}} {{ option.text }}
</ion-select-option> </ion-select-option>
</ion-select> </ion-select>
</ion-item> </ion-item>

View File

@ -12,8 +12,18 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; import {
Component,
Input,
Output,
EventEmitter,
ChangeDetectionStrategy,
OnChanges,
SimpleChanges,
ChangeDetectorRef,
} from '@angular/core';
import { CoreGroupInfo } from '@services/groups'; import { CoreGroupInfo } from '@services/groups';
import { CoreLang } from '@services/lang';
/** /**
* Component to display a group selector. * Component to display a group selector.
@ -23,11 +33,51 @@ import { CoreGroupInfo } from '@services/groups';
templateUrl: 'group-selector.html', templateUrl: 'group-selector.html',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class CoreGroupSelectorComponent { export class CoreGroupSelectorComponent implements OnChanges {
@Input() groupInfo?: CoreGroupInfo; @Input() groupInfo?: CoreGroupInfo;
@Input() multipleGroupsMessage?: string; @Input() multipleGroupsMessage?: string;
@Input() selected!: number; @Input() selected!: number;
@Output() selectedChange = new EventEmitter<number>(); @Output() selectedChange = new EventEmitter<number>();
options: GroupOption[] = [];
constructor(protected changeDetectorRef: ChangeDetectorRef) {}
/**
* @inheritdoc
*/
async ngOnChanges(changes: SimpleChanges): Promise<void> {
if ('groupInfo' in changes) {
this.options = await this.getOptions();
this.changeDetectorRef.markForCheck();
}
}
/**
* Get options array.
*
* @returns Options.
*/
protected async getOptions(): Promise<GroupOption[]> {
const options = await Promise.all(
(this.groupInfo?.groups ?? []).map(async group => {
const text = await CoreLang.filterMultilang(group.name);
return { value: group.id, text };
}),
);
return options;
}
}
/**
* Group display info.
*/
interface GroupOption {
value: number;
text: string;
} }

View File

@ -12,11 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { AddonFilterMultilangHandler } from '@addons/filter/multilang/services/handlers/multilang';
import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2';
import { Component, Input, OnInit, Type } from '@angular/core'; import { Component, Input, OnInit, Type } from '@angular/core';
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { CoreLang, multilangString } from '@services/lang';
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper'; import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
import { CoreUserProfileField } from '@features/user/services/user'; import { CoreUserProfileField } from '@features/user/services/user';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate'; import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
@ -54,8 +52,7 @@ export class CoreUserProfileFieldComponent implements OnInit {
this.componentClass = await CoreUserProfileFieldDelegate.getComponent(this.field, this.signup); this.componentClass = await CoreUserProfileFieldDelegate.getComponent(this.field, this.signup);
if ('param1' in this.field && this.field.param1) { if ('param1' in this.field && this.field.param1) {
this.field.param1 = await AddonFilterMultilangHandler.filter(<string> this.field.param1); this.field.param1 = await CoreLang.filterMultilang(multilangString(this.field.param1));
this.field.param1 = await AddonFilterMultilang2Handler.filter(<string> this.field.param1);
} }
this.data.field = this.field; this.data.field = this.field;

View File

@ -20,6 +20,7 @@ import { CoreError } from '@classes/errors/error';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreWSExternalWarning } from '@services/ws'; import { CoreWSExternalWarning } from '@services/ws';
import { CoreCourses } from '@features/courses/services/courses'; import { CoreCourses } from '@features/courses/services/courses';
import { multilangString, MultilangString } from '@services/lang';
const ROOT_CACHE_KEY = 'mmGroups:'; const ROOT_CACHE_KEY = 'mmGroups:';
@ -174,7 +175,7 @@ export class CoreGroupsProvider {
groupInfo.defaultGroupId = 0; groupInfo.defaultGroupId = 0;
} else { } else {
if (result.canaccessallgroups || groupInfo.visibleGroups) { if (result.canaccessallgroups || groupInfo.visibleGroups) {
groupInfo.groups.push({ id: 0, name: Translate.instant('core.allparticipants') }); groupInfo.groups.push({ id: 0, name: multilangString(Translate.instant('core.allparticipants')) });
groupInfo.defaultGroupId = 0; groupInfo.defaultGroupId = 0;
} else { } else {
groupInfo.defaultGroupId = result.groups[0].id; groupInfo.defaultGroupId = result.groups[0].id;
@ -442,7 +443,7 @@ export const CoreGroups = makeSingleton(CoreGroupsProvider);
*/ */
export type CoreGroup = { export type CoreGroup = {
id: number; // Group ID. id: number; // Group ID.
name: string; // Multilang compatible name, course unique'. name: MultilangString; // Multilang compatible name, course unique'.
description?: string; // Group description text. description?: string; // Group description text.
descriptionformat?: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). descriptionformat?: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
idnumber?: string; // Id number. idnumber?: string; // Id number.
@ -526,7 +527,7 @@ type CoreGroupGetCourseUserGroupsWSParams = {
export type CoreGroupGetCourseUserGroupsWSResponse = { export type CoreGroupGetCourseUserGroupsWSResponse = {
groups: { groups: {
id: number; // Group record id. id: number; // Group record id.
name: string; // Multilang compatible name, course unique. name: MultilangString; // Multilang compatible name, course unique.
description: string; // Group description text. description: string; // Group description text.
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN). descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
idnumber: string; // Id number. idnumber: string; // Id number.

View File

@ -24,6 +24,9 @@ import { makeSingleton, Translate, Http } from '@singletons';
import moment from 'moment-timezone'; import moment from 'moment-timezone';
import { CoreSite } from '../classes/site'; import { CoreSite } from '../classes/site';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { AddonFilterMultilangHandler } from '@addons/filter/multilang/services/handlers/multilang';
import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2';
import { Brand } from '@/core/utils/types';
/* /*
* Service to handle language features, like changing the current language. * Service to handle language features, like changing the current language.
@ -516,6 +519,18 @@ export class CoreLangProvider {
return <Record<string, string>> await observable.toPromise(); return <Record<string, string>> await observable.toPromise();
} }
/**
* Filter a multilang string.
*
* @param text Multilang string.
* @returns Filtered string.
*/
async filterMultilang(text: MultilangString): Promise<string> {
return Promise.resolve(text as unknown as string)
.then(text => AddonFilterMultilangHandler.filter(text))
.then(text => AddonFilterMultilang2Handler.filter(text));
}
/** /**
* Unload custom or site plugin strings, removing them from the translations table. * Unload custom or site plugin strings, removing them from the translations table.
* *
@ -547,11 +562,27 @@ export class CoreLangProvider {
export const CoreLang = makeSingleton(CoreLangProvider); export const CoreLang = makeSingleton(CoreLangProvider);
/**
* Make a multilang string.
*
* @param text String.
* @returns Multilang string.
*/
export function multilangString(text: string = ''): MultilangString {
return text as unknown as MultilangString;
}
/** /**
* Language code. E.g. 'au', 'es', etc. * Language code. E.g. 'au', 'es', etc.
*/ */
export type CoreLangLanguage = string; export type CoreLangLanguage = string;
/**
* Branded type to mark multilang strings, this is useful to avoid rendering
* multilang strings without filtering.
*/
export type MultilangString = Brand<unknown, 'multilang'>;
/** /**
* Language object has two leves, first per language and second per string key. * Language object has two leves, first per language and second per string key.
*/ */

View File

@ -46,7 +46,6 @@ import { CoreViewerImageComponent } from '@features/viewer/components/image/imag
import { CoreFormFields, CoreForms } from '../../singletons/form'; import { CoreFormFields, CoreForms } from '../../singletons/form';
import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition'; import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition';
import { CoreZoomLevel } from '@features/settings/services/settings-helper'; import { CoreZoomLevel } from '@features/settings/services/settings-helper';
import { AddonFilterMultilangHandler } from '@addons/filter/multilang/services/handlers/multilang';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { NavigationStart } from '@angular/router'; import { NavigationStart } from '@angular/router';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
@ -58,8 +57,8 @@ import { CoreSiteError } from '@classes/errors/siteerror';
import { CoreUserSupport } from '@features/user/services/support'; import { CoreUserSupport } from '@features/user/services/support';
import { CoreErrorInfoComponent } from '@components/error-info/error-info'; import { CoreErrorInfoComponent } from '@components/error-info/error-info';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2';
import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { CoreLang, multilangString } from '@services/lang';
/* /*
* "Utils" service with helper functions for UI, DOM elements and HTML code. * "Utils" service with helper functions for UI, DOM elements and HTML code.
@ -1171,8 +1170,7 @@ export class CoreDomUtilsProvider {
if (hasHTMLTags && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.7')) { if (hasHTMLTags && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.7')) {
// Treat multilang. // Treat multilang.
options.message = await AddonFilterMultilangHandler.filter(<string> options.message); options.message = await CoreLang.filterMultilang(multilangString(<string> options.message));
options.message = await AddonFilterMultilang2Handler.filter(<string> options.message);
} }
const alertId = <string> Md5.hashAsciiStr((options.header || '') + '#' + (options.message || '')); const alertId = <string> Md5.hashAsciiStr((options.header || '') + '#' + (options.message || ''));