Merge pull request #3595 from alfonso-salces/MOBILE-4292

MOBILE-4292 multilang2: Create new multilang filter
main
Dani Palou 2023-04-13 09:02:41 +02:00 committed by GitHub
commit 520ec75b1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 157 additions and 3 deletions

View File

@ -25,6 +25,7 @@ import { AddonFilterGlossaryModule } from './glossary/glossary.module';
import { AddonFilterMathJaxLoaderModule } from './mathjaxloader/mathjaxloader.module';
import { AddonFilterMediaPluginModule } from './mediaplugin/mediaplugin.module';
import { AddonFilterMultilangModule } from './multilang/multilang.module';
import { AddonFilterMultilang2Module } from './multilang2/multilang2.module';
import { AddonFilterTexModule } from './tex/tex.module';
import { AddonFilterTidyModule } from './tidy/tidy.module';
import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module';
@ -42,6 +43,7 @@ import { AddonFilterUrlToLinkModule } from './urltolink/urltolink.module';
AddonFilterMathJaxLoaderModule,
AddonFilterMediaPluginModule,
AddonFilterMultilangModule,
AddonFilterMultilang2Module,
AddonFilterTexModule,
AddonFilterTidyModule,
AddonFilterUrlToLinkModule,

View File

@ -0,0 +1,29 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { CoreFilterDelegate } from '@features/filter/services/filter-delegate';
import { AddonFilterMultilang2Handler } from './services/handlers/multilang2';
@NgModule({
providers: [
{
provide: APP_INITIALIZER,
multi: true,
useValue: () => CoreFilterDelegate.registerHandler(AddonFilterMultilang2Handler.instance),
},
],
})
export class AddonFilterMultilang2Module {}

View File

@ -0,0 +1,104 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreLang } from '@services/lang';
import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter';
import { makeSingleton } from '@singletons';
/**
* Handler to support the Multilang filter.
*/
@Injectable({ providedIn: 'root' })
export class AddonFilterMultilang2HandlerService extends CoreFilterDefaultHandler {
name = 'AddonFilterMultilang2Handler';
filterName = 'multilang2';
replacementDone = false;
/**
* This function filters the received text based on the language
* tags embedded in the text, and the current user language or
* 'other', if present.
*
* @param text The text to filter.
* @returns string The filtered text for this multilang block.
*/
async filter(text: string): Promise<string> {
if (text.indexOf('mlang') === -1) {
return text;
}
const currentLang = await CoreLang.getCurrentLanguage();
this.replacementDone = false;
const parentLanguage = CoreLang.getParentLanguage(currentLang);
const search = /{\s*mlang\s+((?:[a-z0-9_-]+)(?:\s*,\s*[a-z0-9_-]+\s*)*)\s*}(.*?){\s*mlang\s*}/gim;
const result = text.replace(
search,
(subString, language, content) => this.replaceLangs(currentLang, [subString, language, content], parentLanguage),
);
if (result === null) {
return text; // Error during regex processing, keep original text.
}
if (this.replacementDone) {
return result;
}
const result2 = text.replace(
search,
(subString, language, content) => this.replaceLangs('other', [subString, language, content], parentLanguage),
);
return result2 ?? text;
}
/**
* This function filters the current block of multilang tag. If
* any of the tag languages (or their parent languages) match the
* specified filtering language, it returns the text of the
* block. Otherwise it returns an empty string.
*
* @param replaceLang A string that specifies the language used to filter the matches.
* @param langBlock An array containing the matching captured pieces of the
* regular expression. They are the languages of the tag, and the text associated with those languages.
* @param parentLanguage A string that contains the parent language.
*
* @returns replaced string.
*/
protected replaceLangs(replaceLang: string, langBlock: string[], parentLanguage: string | undefined): string {
// Normalize languages.
const blockLangs = (langBlock[1] ?? '').replace(/ /g, '').replace(/_/g, '-').toLowerCase().split(',');
const blockText = langBlock[2] ?? '';
for (const blockLang of blockLangs) {
/* We don't check for empty values of blockLang as they simply don't
* match any language and they don't produce any errors or warnings.
*/
if (blockLang === replaceLang || parentLanguage === blockLang) {
this.replacementDone = true;
return blockText;
}
}
return '';
}
}
export const AddonFilterMultilang2Handler = makeSingleton(AddonFilterMultilang2HandlerService);

View File

@ -1559,6 +1559,7 @@ export type AddonModAssignParticipant = {
customfields?: { // User custom fields (also known as user profile fields).
type: string; // The type of the custom field - text field, checkbox...
value: string; // The value of the custom field.
displayvalue: string; // @since 4.2.Formatted value of the custom field.
name: string; // The name of the custom field.
shortname: string; // The shortname of the custom field - to be able to build the field class in the code.
}[];

View File

@ -2,7 +2,8 @@
<ion-item *ngIf="!edit && field && field.name">
<ion-label>
<p class="item-heading">{{ field.name }}</p>
<p>{{ valueNumber * 1000 | coreFormatDate }}</p>
<p *ngIf="valueNumber">{{ valueNumber * 1000 | coreFormatDate }}</p>
<p *ngIf="displayValue">{{ displayValue }}</p>
</ion-label>
</ion-item>

View File

@ -36,7 +36,8 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField
format?: string;
min?: string;
max?: string;
valueNumber = 0;
valueNumber?: number;
displayValue?: string;
monthNames?: string[];
displayTimezone?: string;
@ -46,6 +47,12 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField
* @param field Field to render.
*/
protected initForNonEdit(field: CoreUserProfileField): void {
if (field.displayvalue) {
this.displayValue = field.displayvalue;
return;
}
this.valueNumber = Number(field.value);
}

View File

@ -69,7 +69,7 @@ export abstract class CoreUserProfileFieldBaseComponent implements OnInit {
* @param field Field to render.
*/
protected initForNonEdit(field: CoreUserProfileField): void {
this.value = field.value;
this.value = field.displayvalue ?? field.value;
}
/**

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// 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 { FormGroup } from '@angular/forms';
@ -51,6 +53,11 @@ export class CoreUserProfileFieldComponent implements OnInit {
this.componentClass = await CoreUserProfileFieldDelegate.getComponent(this.field, this.signup);
if ('param1' in this.field && this.field.param1) {
this.field.param1 = await AddonFilterMultilangHandler.filter(<string> this.field.param1);
this.field.param1 = await AddonFilterMultilang2Handler.filter(<string> this.field.param1);
}
this.data.field = this.field;
this.data.edit = CoreUtils.isTrueOrOne(this.edit);
if (this.edit) {

View File

@ -892,6 +892,7 @@ export type CoreUserPreference = {
export type CoreUserProfileField = {
type: string; // The type of the custom field - text field, checkbox...
value: string; // The value of the custom field.
displayvalue: string; // @since 4.2. Formatted value of the custom field.
name: string; // The name of the custom field.
shortname: string; // The shortname of the custom field - to be able to build the field class in the code.
};

View File

@ -58,6 +58,7 @@ import { CoreSiteError } from '@classes/errors/siteerror';
import { CoreUserSupport } from '@features/user/services/support';
import { CoreErrorInfoComponent } from '@components/error-info/error-info';
import { CorePlatform } from '@services/platform';
import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2';
/*
* "Utils" service with helper functions for UI, DOM elements and HTML code.
@ -1170,6 +1171,7 @@ export class CoreDomUtilsProvider {
if (hasHTMLTags && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.7')) {
// Treat multilang.
options.message = await AddonFilterMultilangHandler.filter(<string> options.message);
options.message = await AddonFilterMultilang2Handler.filter(<string> options.message);
}
const alertId = <string> Md5.hashAsciiStr((options.header || '') + '#' + (options.message || ''));