Merge pull request #4231 from tsiegleauq/enter-custom-translations
Add custom translation settings
This commit is contained in:
commit
44bc03b300
@ -2,12 +2,12 @@ import { TranslateDefaultParser, TranslateStore } from '@ngx-translate/core';
|
|||||||
import { ConfigService } from '../services/config.service';
|
import { ConfigService } from '../services/config.service';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
interface CustomTranslation {
|
export interface CustomTranslation {
|
||||||
original: string;
|
original: string;
|
||||||
translation: string;
|
translation: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomTranslations = CustomTranslation[];
|
export type CustomTranslations = CustomTranslation[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom translate parser. Intercepts and use custom translations from the configservice.
|
* Custom translate parser. Intercepts and use custom translations from the configservice.
|
||||||
|
@ -69,6 +69,11 @@
|
|||||||
<h4>{{ configItem.label | translate }}</h4>
|
<h4>{{ configItem.label | translate }}</h4>
|
||||||
<editor formControlName="value" [init]="tinyMceSettings"></editor>
|
<editor formControlName="value" [init]="tinyMceSettings"></editor>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Custom Translations -->
|
||||||
|
<div *ngIf="configItem.inputType === 'translations'">
|
||||||
|
<os-custom-translation formControlName="value"></os-custom-translation>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,7 +54,7 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input()
|
@Input()
|
||||||
public set item(value: ViewConfig) {
|
public set item(value: ViewConfig) {
|
||||||
if (value.hasConstantsInfo) {
|
if (value && value.hasConstantsInfo) {
|
||||||
this.configItem = value;
|
this.configItem = value;
|
||||||
|
|
||||||
if (this.form) {
|
if (this.form) {
|
||||||
@ -155,10 +155,7 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
|
|||||||
if (this.configItem.inputType === 'datetimepicker') {
|
if (this.configItem.inputType === 'datetimepicker') {
|
||||||
value = Date.parse(value);
|
value = Date.parse(value);
|
||||||
}
|
}
|
||||||
// TODO: Solve this via a custom input form.
|
|
||||||
if (this.configItem.inputType === 'translations') {
|
|
||||||
value = JSON.parse(value);
|
|
||||||
}
|
|
||||||
this.debounceTimeout = null;
|
this.debounceTimeout = null;
|
||||||
this.repo.update({ value: value }, this.configItem).then(() => {
|
this.repo.update({ value: value }, this.configItem).then(() => {
|
||||||
this.error = null;
|
this.error = null;
|
||||||
@ -215,7 +212,7 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
|
|||||||
* @returns wheather it should be excluded or not
|
* @returns wheather it should be excluded or not
|
||||||
*/
|
*/
|
||||||
public isExcludedType(type: string): boolean {
|
public isExcludedType(type: string): boolean {
|
||||||
const excluded = ['boolean', 'markupText', 'text'];
|
const excluded = ['boolean', 'markupText', 'text', 'translations'];
|
||||||
return excluded.includes(type);
|
return excluded.includes(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|||||||
import { E2EImportsModule } from '../../../../../e2e-imports.module';
|
import { E2EImportsModule } from '../../../../../e2e-imports.module';
|
||||||
import { ConfigListComponent } from './config-list.component';
|
import { ConfigListComponent } from './config-list.component';
|
||||||
import { ConfigFieldComponent } from '../config-field/config-field.component';
|
import { ConfigFieldComponent } from '../config-field/config-field.component';
|
||||||
|
import { CustomTranslationComponent } from '../custom-translation/custom-translation.component';
|
||||||
|
|
||||||
describe('ConfigListComponent', () => {
|
describe('ConfigListComponent', () => {
|
||||||
let component: ConfigListComponent;
|
let component: ConfigListComponent;
|
||||||
@ -11,7 +12,7 @@ describe('ConfigListComponent', () => {
|
|||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [E2EImportsModule],
|
imports: [E2EImportsModule],
|
||||||
declarations: [ConfigListComponent, ConfigFieldComponent]
|
declarations: [ConfigListComponent, ConfigFieldComponent, CustomTranslationComponent]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
<!-- Add new translation button -->
|
||||||
|
<div *ngFor="let translation of translations; let i = index">
|
||||||
|
<form>
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput [value]="translation.original" (input)="onChangeOriginal($event.target.value, i)" />
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-icon>arrow_forward</mat-icon>
|
||||||
|
<mat-form-field>
|
||||||
|
<input matInput [value]="translation.translation" (input)="onChangeTranslation($event.target.value, i)" />
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-icon-button>
|
||||||
|
<mat-icon (click)="onRemoveTranslation(i)">close</mat-icon>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Add new translation button -->
|
||||||
|
<button mat-button (click)="onAddNewTranslation()">{{ 'Add new custom translation' | translate }}</button>
|
@ -0,0 +1,26 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CustomTranslationComponent } from './custom-translation.component';
|
||||||
|
import { E2EImportsModule } from 'e2e-imports.module';
|
||||||
|
|
||||||
|
describe('CustomTranslationComponent', () => {
|
||||||
|
let component: CustomTranslationComponent;
|
||||||
|
let fixture: ComponentFixture<CustomTranslationComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [E2EImportsModule],
|
||||||
|
declarations: [CustomTranslationComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CustomTranslationComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,118 @@
|
|||||||
|
import { Component, forwardRef } from '@angular/core';
|
||||||
|
|
||||||
|
import { CustomTranslation, CustomTranslations } from 'app/core/translate/translation-parser';
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom translations as custom form component
|
||||||
|
*
|
||||||
|
* @example:
|
||||||
|
* ```html
|
||||||
|
* <os-custom-translation formControlName="value"></os-custom-translation>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'os-custom-translation',
|
||||||
|
templateUrl: './custom-translation.component.html',
|
||||||
|
styleUrls: ['./custom-translation.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => CustomTranslationComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CustomTranslationComponent implements ControlValueAccessor {
|
||||||
|
/**
|
||||||
|
* Holds the custom translations in a list
|
||||||
|
*/
|
||||||
|
public translations: CustomTranslations = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty constructor
|
||||||
|
*/
|
||||||
|
public constructor() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to determine which information to give to the parent form
|
||||||
|
*/
|
||||||
|
private propagateChange = (_: any) => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value from the FormControl
|
||||||
|
*
|
||||||
|
* @param obj the value from the parent form. Type "any" is required by the interface
|
||||||
|
*/
|
||||||
|
public writeValue(obj: any): void {
|
||||||
|
if (obj) {
|
||||||
|
this.translations = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hands changes back to the parent form
|
||||||
|
*
|
||||||
|
* @param fn the function to propagate the changes
|
||||||
|
*/
|
||||||
|
public registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To satisfy the interface.
|
||||||
|
*
|
||||||
|
* @param fn
|
||||||
|
*/
|
||||||
|
public registerOnTouched(fn: any): void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To satisfy the interface
|
||||||
|
*
|
||||||
|
* @param isDisabled
|
||||||
|
*/
|
||||||
|
public setDisabledState?(isDisabled: boolean): void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects changes to the "original" word
|
||||||
|
*
|
||||||
|
* @param value the value that was typed
|
||||||
|
* @param index the index of the change
|
||||||
|
*/
|
||||||
|
public onChangeOriginal(value: string, index: number): void {
|
||||||
|
this.translations[index].original = value;
|
||||||
|
this.propagateChange(this.translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects changes to the translation
|
||||||
|
* @param value the value that was typed
|
||||||
|
* @param index the index of the change
|
||||||
|
*/
|
||||||
|
public onChangeTranslation(value: string, index: number): void {
|
||||||
|
this.translations[index].translation = value;
|
||||||
|
this.propagateChange(this.translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a custom translation
|
||||||
|
* @param index the translation to remove
|
||||||
|
*/
|
||||||
|
public onRemoveTranslation(index: number): void {
|
||||||
|
this.translations.splice(index, 1);
|
||||||
|
this.propagateChange(this.translations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new custom translation to the list and to the server
|
||||||
|
*/
|
||||||
|
public onAddNewTranslation(): void {
|
||||||
|
const newCustomTranslation: CustomTranslation = {
|
||||||
|
original: 'New',
|
||||||
|
translation: 'New'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.translations.push(newCustomTranslation);
|
||||||
|
this.propagateChange(this.translations);
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,11 @@ import { SharedModule } from '../../shared/shared.module';
|
|||||||
import { ConfigRoutingModule } from './config-routing.module';
|
import { ConfigRoutingModule } from './config-routing.module';
|
||||||
import { ConfigListComponent } from './components/config-list/config-list.component';
|
import { ConfigListComponent } from './components/config-list/config-list.component';
|
||||||
import { ConfigFieldComponent } from './components/config-field/config-field.component';
|
import { ConfigFieldComponent } from './components/config-field/config-field.component';
|
||||||
|
import { CustomTranslationComponent } from './components/custom-translation/custom-translation.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [CommonModule, ConfigRoutingModule, SharedModule],
|
imports: [CommonModule, ConfigRoutingModule, SharedModule],
|
||||||
declarations: [ConfigListComponent, ConfigFieldComponent]
|
declarations: [ConfigListComponent, ConfigFieldComponent, CustomTranslationComponent],
|
||||||
|
entryComponents: [CustomTranslationComponent]
|
||||||
})
|
})
|
||||||
export class ConfigModule {}
|
export class ConfigModule {}
|
||||||
|
@ -112,7 +112,9 @@ export class ViewConfig extends BaseViewModel {
|
|||||||
* like the type="color" input...
|
* like the type="color" input...
|
||||||
*/
|
*/
|
||||||
public getDebouncingTimeout(): number {
|
public getDebouncingTimeout(): number {
|
||||||
if (this.inputType === 'string' || this.inputType === 'text' || this.inputType === 'markupText') {
|
if (this.inputType === 'markupText' || this.inputType === 'translations') {
|
||||||
|
return 2500;
|
||||||
|
} else if (this.inputType === 'string' || this.inputType === 'text') {
|
||||||
return 1000;
|
return 1000;
|
||||||
} else {
|
} else {
|
||||||
return 100;
|
return 100;
|
||||||
|
Loading…
Reference in New Issue
Block a user