Skip to content

Commit 7db4339

Browse files
committed
fix(editor): translations on formly/primeng components
Co-Authored-by: Bertrand Zuchuat <[email protected]>
1 parent b575b74 commit 7db4339

File tree

19 files changed

+485
-172
lines changed

19 files changed

+485
-172
lines changed

projects/ng-core-tester/src/app/record/editor/recordData.json

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
"readonly_changeable": "Value 1",
1818
"hide_with_required_expression_control": "Optional",
1919
"treeSelect": "node5",
20-
"selectMultiple": ["value2", "value3"],
2120
"markdown": "Hello **world**.\nGreat day.",
2221
"array_with_multicheckbox": ["checkbox1", "checkbox2"],
2322
"input_with_default_value": "slrofar6uh",

projects/ng-core-tester/src/app/record/editor/schema.json

+9-12
Original file line numberDiff line numberDiff line change
@@ -1034,10 +1034,6 @@
10341034
"type": "array",
10351035
"minItems": 1,
10361036
"uniqueItems": true,
1037-
"default": [
1038-
"value2",
1039-
"value3"
1040-
],
10411037
"items": {
10421038
"type": "string",
10431039
"enum": [
@@ -1077,12 +1073,12 @@
10771073
"items": {
10781074
"type": "string",
10791075
"enum": [
1080-
"Epicea",
1081-
"Baobab",
1082-
"Foxglove",
1083-
"Crocus",
1084-
"Heather",
1085-
"Daffodil"
1076+
"epicea",
1077+
"baobab",
1078+
"foxglove",
1079+
"crocus",
1080+
"heather",
1081+
"daffodil"
10861082
]
10871083
},
10881084
"widget": {
@@ -1097,7 +1093,7 @@
10971093
"items": [
10981094
{
10991095
"label": "Epicea",
1100-
"value": "Epicea"
1096+
"value": "epicea"
11011097
},
11021098
{
11031099
"label": "Baobab",
@@ -1280,7 +1276,8 @@
12801276
"formlyConfig": {
12811277
"type": "passwordGenerator",
12821278
"props": {
1283-
"enabledEditMode": true
1279+
"enabledEditMode": true,
1280+
"styleClass": "surface-100"
12841281
}
12851282
}
12861283
}

projects/ng-core-tester/src/app/record/editor/simple-record-data.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"$schema": "https://bib.rero.ch/schemas/demo/demo.json",
99
"pid": "normal",
1010
"required": "value required",
11-
"textarea": "Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker."
11+
"textarea": "Le Lorem Ipsum est simplement du faux texte employé dans la composition et la mise en page avant impression. Le Lorem Ipsum est le faux texte standard de l'imprimerie depuis les années 1500, quand un imprimeur anonyme assembla ensemble des morceaux de texte pour réaliser un livre spécimen de polices de texte. Il n'a pas fait que survivre cinq siècles, mais s'est aussi adapté à la bureautique informatique, sans que son contenu n'en soit modifié. Il a été popularisé dans les années 1960 grâce à la vente de feuilles Letraset contenant des passages du Lorem Ipsum, et, plus récemment, par son inclusion dans des applications de mise en page de texte, comme Aldus PageMaker.",
12+
"select": "car"
1213
}
1314
}

projects/ng-core-tester/src/app/record/editor/simple-schema.json

+18-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"optional",
1111
"required",
1212
"essential",
13-
"textarea"
13+
"textarea",
14+
"select"
1415
],
1516
"properties": {
1617
"$schema": {
@@ -72,6 +73,22 @@
7273
}
7374
}
7475
}
76+
},
77+
"select": {
78+
"title": "Product",
79+
"type": "string",
80+
"widget": {
81+
"formlyConfig": {
82+
"type": "select",
83+
"props": {
84+
"options": [
85+
{ "label": "House", "value": "house" },
86+
{ "label": "Car", "value": "car" },
87+
{ "label": "Window", "value": "window" }
88+
]
89+
}
90+
}
91+
}
7592
}
7693
}
7794
}

projects/ng-core-tester/src/assets/i18n/de.json

+25-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,29 @@
2626
"Add mode": "hinzufügenmodus",
2727
"Please select a type": "Bitte wählen Sie einen Typ",
2828
"Full-text": "Volltext",
29-
"Main title": "Haupttitel"
29+
"Main title": "Haupttitel",
30+
"House": "Haus",
31+
"Car": "Auto",
32+
"Window": "Fenster",
33+
"Product": "Produkt",
34+
"Property 1": "Eigentum 1",
35+
"Property 2": "Eigentum 2",
36+
"Value 1": "Wert 1",
37+
"Value 2": "Wert 2",
38+
"Value 3": "Wert 3",
39+
"Select…": "Wählen…",
40+
"Default": "Standard",
41+
"group-preferred": "Bevorzugt",
42+
"English": "Englisch",
43+
"Node 1": "Knoten 1",
44+
"Node 2": "Knoten 2",
45+
"Node 3": "Knoten 3",
46+
"Node 4": "Knoten 4",
47+
"Node 5": "Knoten 5",
48+
"Node 6": "Knoten 6",
49+
"Node 7": "Knoten 7",
50+
"Checkbox 1": "Checkbox 1",
51+
"Checkbox 2": "Checkbox 2",
52+
"Checkbox 3": "Checkbox 3",
53+
"Checkbox 4": "Checkbox 4"
3054
}

projects/ng-core-tester/src/assets/i18n/en.json

+25-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,29 @@
66
"info": "Info",
77
"success": "Success",
88
"error": "Error",
9-
"warn": "Warn"
9+
"warn": "Warn",
10+
"House": "House",
11+
"Car": "Car",
12+
"Window": "Window",
13+
"Product": "Product",
14+
"Property 1": "Property 1",
15+
"Property 2": "Property 2",
16+
"Value 1": "Value 1",
17+
"Value 2": "Value 2",
18+
"Value 3": "Value 3",
19+
"Select…": "Select…",
20+
"Default": "Default",
21+
"group-preferred": "Preferred",
22+
"English": "English",
23+
"Node 1": "Node 1",
24+
"Node 2": "Node 2",
25+
"Node 3": "Node 3",
26+
"Node 4": "Node 4",
27+
"Node 5": "Node 5",
28+
"Node 6": "Node 6",
29+
"Node 7": "Node 7",
30+
"Checkbox 1": "Checkbox 1",
31+
"Checkbox 2": "Checkbox 2",
32+
"Checkbox 3": "Checkbox 3",
33+
"Checkbox 4": "Checkbox 4"
1034
}

projects/ng-core-tester/src/assets/i18n/fr.json

+25-1
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,29 @@
4242
"Add mode": "Mode ajout",
4343
"Please select a type": "Veuillez sélectionner un type",
4444
"Full-text": "Texte complet",
45-
"Main title": "Titre principal"
45+
"Main title": "Titre principal",
46+
"House": "Maison",
47+
"Car": "Voiture",
48+
"Window": "Fenêtre",
49+
"Product": "Produit",
50+
"Property 1": "Propriété 1",
51+
"Property 2": "Propriété 2",
52+
"Value 1": "Valeur 1",
53+
"Value 2": "Valeur 2",
54+
"Value 3": "Valeur 3",
55+
"Select…": "Sélectionner…",
56+
"Default": "Défaut",
57+
"group-preferred": "Préféré",
58+
"English": "Anglais",
59+
"Node 1": "Nœud 1",
60+
"Node 2": "Nœud 2",
61+
"Node 3": "Nœud 3",
62+
"Node 4": "Nœud 4",
63+
"Node 5": "Nœud 5",
64+
"Node 6": "Nœud 6",
65+
"Node 7": "Nœud 7",
66+
"Checkbox 1": "Case à cocher 1",
67+
"Checkbox 2": "Case à cocher 2",
68+
"Checkbox 3": "Case à cocher 3",
69+
"Checkbox 4": "Case à cocher 4"
4670
}

projects/ng-core-tester/src/assets/i18n/it.json

+25-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,29 @@
2626
"Add mode": "Aggiungi modalità",
2727
"Please select a type": "Selezionare un tipo",
2828
"Full-text": "Testo integrale",
29-
"Main title": "Titolo principale"
29+
"Main title": "Titolo principale",
30+
"House": "Casa",
31+
"Car": "Auto",
32+
"Window": "Finestra",
33+
"Product": "Prodotto",
34+
"Property 1": "Proprietà 1",
35+
"Property 2": "Proprietà 2",
36+
"Value 1": "Valore 1",
37+
"Value 2": "Valore 2",
38+
"Value 3": "Valore 3",
39+
"Select…": "Selezionare…",
40+
"Default": "Predefinito",
41+
"group-preferred": "Preferito",
42+
"English": "Inglese",
43+
"Node 1": "Nodo 1",
44+
"Node 2": "Nodo 2",
45+
"Node 3": "Nodo 3",
46+
"Node 4": "Nodo 4",
47+
"Node 5": "Nodo 5",
48+
"Node 6": "Nodo 6",
49+
"Node 7": "Nodo 7",
50+
"Checkbox 1": "Casella 1",
51+
"Checkbox 2": "Casella 2",
52+
"Checkbox 3": "Casella 3",
53+
"Checkbox 4": "Casella 4"
3054
}

projects/rero/ng-core/src/lib/record/editor/extensions.ts

+71-42
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* RERO angular core
3-
* Copyright (C) 2020-2024 RERO
3+
* Copyright (C) 2020-2025 RERO
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU Affero General Public License as published by
@@ -17,13 +17,12 @@
1717
import { inject } from '@angular/core';
1818
import { UntypedFormControl } from '@angular/forms';
1919
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
20-
import { FormlyExtension, FormlyFieldConfig } from '@ngx-formly/core';
20+
import { FormlyExtension, FormlyFieldConfig, FormlyFieldProps } from '@ngx-formly/core';
2121
import { TranslateService } from '@ngx-translate/core';
22-
import { isObservable, of } from 'rxjs';
23-
import { map } from 'rxjs/operators';
22+
import { isObservable } from 'rxjs';
23+
import { Validators } from '../../validator/validators';
2424
import { RecordService } from '../record.service';
2525
import { isEmpty, removeEmptyValues } from './utils';
26-
import { Validators } from '../../validator/validators';
2726

2827
export class NgCoreFormlyExtension {
2928

@@ -346,14 +345,7 @@ export class TranslateExtension implements FormlyExtension {
346345

347346
protected translate: TranslateService = inject(TranslateService);
348347

349-
/**
350-
* Translate some fields before populating the form.
351-
*
352-
* It translates the label, the description and the placeholder.
353-
* @param field formly field config
354-
*/
355-
356-
prePopulate(field: FormlyFieldConfig): void {
348+
prePopulate(field: FormlyFieldConfig<FormlyFieldProps & { [additionalProperties: string]: any; }>): void {
357349
const props: any = field.props || {};
358350

359351
// translate only once
@@ -393,36 +385,11 @@ export class TranslateExtension implements FormlyExtension {
393385
if (props.addonRight) {
394386
props.addonRightUntranslated = props.addonRight;
395387
}
396-
this.processAllAddon(props);
397-
this.translate.onLangChange.subscribe(() => this.processAllAddon(props));
398-
399-
// Options
400-
if (props.options && (isObservable(props.options) || props.options.some((o: any) => 'label' in o && 'value' in o))) {
401-
props.options = isObservable(props.options) ? props.options : of(props.options);
402-
props.options = props.options.pipe(
403-
map((options: any[]) => {
404-
if (options?.length > 0) {
405-
options.map((opt) => this.translateOptionsLabel(opt));
406-
}
407-
return options;
408-
})
409-
);
410-
}
411-
}
412388

413-
private translateOptionsLabel(node) {
414-
if (node?.label) {
415-
node.label = this.translate.instant(node.label);
416-
}
417-
if (node?.children?.length > 0) {
418-
node.children.map((child) => this.translateOptionsLabel(child));
419-
}
420-
if (node?.items?.length > 0) {
421-
node.items.map((child) => this.translateOptionsLabel(child));
422-
}
423-
if (node?.value && !node?.data) {
424-
node.data = node.value;
425-
}
389+
this.processAllAddon(props);
390+
this.translate.onLangChange.subscribe(() => {
391+
this.processAllAddon(props);
392+
});
426393
}
427394

428395
private processAllAddon(props: any): void {
@@ -439,6 +406,63 @@ export class TranslateExtension implements FormlyExtension {
439406
}
440407
}
441408

409+
export class FormOptionsProcessExtension implements FormlyExtension {
410+
prePopulate(field: FormlyFieldConfig<FormlyFieldProps & { [additionalProperties: string]: any; }>): void {
411+
// Process options
412+
if (field.props?.options && !isObservable(field.props?.options)) {
413+
field.props.options = this.processOptions(field.props);
414+
}
415+
}
416+
417+
private processOptions(props: any): any[] {
418+
this.processUntranslatedLabel(props.options);
419+
const preferredOptions = props.options.filter((option: any) => option.preferred);
420+
if (preferredOptions.length > 0) {
421+
const options = [];
422+
props.group = true;
423+
const otherOptions = props.options.filter((option: any) => !option.preferred);
424+
options.push({
425+
label: 'group-preferred',
426+
untranslatedLabel: 'group-preferred',
427+
items: props.sort ? this.sortOptions(preferredOptions) : preferredOptions
428+
});
429+
options.push({
430+
label: 'group-other',
431+
untranslatedLabel: 'group-other',
432+
items: props.sort ? this.sortOptions(otherOptions) : otherOptions
433+
});
434+
return options;
435+
} else {
436+
437+
return props.sort ? this.sortOptions(props.options) : props.options
438+
}
439+
}
440+
441+
private processUntranslatedLabel(options: any[]): void {
442+
options.map((option: any) => {
443+
option.untranslatedLabel = option.label;
444+
if (option.items) {
445+
this.processUntranslatedLabel(option.items);
446+
}
447+
if (option.children) {
448+
this.processUntranslatedLabel(option.children);
449+
}
450+
});
451+
}
452+
453+
private sortOptions(options: any) {
454+
options = options.sort((a: any, b: any) => a.label.localeCompare(b.label));
455+
if (options.filter((option: any) => option.items).length > 0) {
456+
options.forEach((option: any) => {
457+
if (option.items) {
458+
return this.sortOptions(option.items);
459+
}
460+
});
461+
}
462+
return options;
463+
}
464+
}
465+
442466
/**
443467
* To register an ngx-formly translations extension.
444468
*
@@ -566,6 +590,11 @@ export function registerNgCoreFormlyExtension(translate: TranslateService, recor
566590
},
567591
],
568592
extensions: [
593+
{
594+
name: 'form-options',
595+
extension: new FormOptionsProcessExtension(),
596+
priority: 12
597+
},
569598
{
570599
name: 'translate',
571600
extension: new TranslateExtension(),

0 commit comments

Comments
 (0)