LionInputFile: Customize the text content of the selected files for screen reader if uploadOnSelect is enabled (#2509)

* update lion input file component and en translations

* update tests for input file

* add changeset

* add german and russian translations

* chore: add NL translations and fix small 2 bugs in fileNameDescriptionLabels

* fix lint error

---------

Co-authored-by: gerjanvangeest <Gerjan.van.Geest@ing.com>
This commit is contained in:
Vladimir Skorokhod 2025-05-13 13:00:20 +02:00 committed by GitHub
parent 07b089e80f
commit f9f55193c3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 127 additions and 30 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
LionInputFile: Customize the text content of the selected files for screen reader if uploadOnSelect is enabled

View file

@ -758,15 +758,39 @@ export class LionInputFile extends ScopedElementsMixin(LocalizeMixin(LionField))
const selectedFiles = this.querySelector('[slot="after"]'); const selectedFiles = this.querySelector('[slot="after"]');
if (selectedFiles) { if (selectedFiles) {
if (!this._selectedFilesMetaData || this._selectedFilesMetaData.length === 0) { if (!this._selectedFilesMetaData || this._selectedFilesMetaData.length === 0) {
if (this.uploadOnSelect) {
selectedFiles.textContent = /** @type {string} */ (
this.msgLit('lion-input-file:noFilesUploaded')
);
} else {
selectedFiles.textContent = /** @type {string} */ ( selectedFiles.textContent = /** @type {string} */ (
this.msgLit('lion-input-file:noFilesSelected') this.msgLit('lion-input-file:noFilesSelected')
); );
}
} else if (this._selectedFilesMetaData.length === 1) { } else if (this._selectedFilesMetaData.length === 1) {
const { name } = this._selectedFilesMetaData[0].systemFile;
if (this.uploadOnSelect) {
selectedFiles.textContent = /** @type {string} */ ( selectedFiles.textContent = /** @type {string} */ (
errorMessage || this._selectedFilesMetaData[0].systemFile.name errorMessage || this.msgLit('lion-input-file:fileUploaded') + (name ?? '')
); );
} else { } else {
selectedFiles.textContent = `${this.msgLit('lion-input-file:numberOfFiles', { selectedFiles.textContent = /** @type {string} */ (
errorMessage || this.msgLit('lion-input-file:fileSelected') + (name ?? '')
);
}
} else if (this.uploadOnSelect) {
selectedFiles.textContent = `${this.msgLit('lion-input-file:filesUploaded', {
numberOfFiles: this._selectedFilesMetaData.length,
})} ${
errorMessage
? this.msgLit('lion-input-file:generalValidatorMessage', {
validatorMessage: errorMessage,
listOfErroneousFiles: erroneousFilesNames.join(', '),
})
: ''
}`;
} else {
selectedFiles.textContent = `${this.msgLit('lion-input-file:filesSelected', {
numberOfFiles: this._selectedFilesMetaData.length, numberOfFiles: this._selectedFilesMetaData.length,
})} ${ })} ${
errorMessage errorMessage

View file

@ -212,7 +212,6 @@ export class LionSelectedFileList extends LocalizeMixin(ScopedElementsMixin(LitE
.sr-only { .sr-only {
position: absolute; position: absolute;
top: 0;
width: 1px; width: 1px;
height: 1px; height: 1px;
overflow: hidden; overflow: hidden;

View file

@ -1197,7 +1197,29 @@ describe('lion-input-file', () => {
); );
}); });
it('after contains upload name of file when SUCCESS', async () => { it('after contains upload name of file when uploadOnSelect is true and status is SUCCESS', async () => {
const uploadResponse = [
{
name: 'file1.txt',
status: 'SUCCESS',
errorMessage: '',
downloadUrl: '/downloadFile',
},
];
const el = await fixture(html`
<lion-input-file label="Select" upload-on-select></lion-input-file>
`);
expect(el.querySelector('[slot="after"]')?.textContent).to.equal('No files uploaded.');
// @ts-expect-error
el.uploadResponse = uploadResponse;
await el.updateComplete;
expect(el.querySelector('[slot="after"]')?.textContent).to.equal(
'Uploaded file: file1.txt',
);
});
it('after contains upload name of file when uploadOnSelect is false and status is SUCCESS', async () => {
const uploadResponse = [ const uploadResponse = [
{ {
name: 'file1.txt', name: 'file1.txt',
@ -1212,7 +1234,9 @@ describe('lion-input-file', () => {
// @ts-expect-error // @ts-expect-error
el.uploadResponse = uploadResponse; el.uploadResponse = uploadResponse;
await el.updateComplete; await el.updateComplete;
expect(el.querySelector('[slot="after"]')?.textContent).to.equal('file1.txt'); expect(el.querySelector('[slot="after"]')?.textContent).to.equal(
'Selected file: file1.txt',
);
}); });
it('after contains upload validator message of file when FAIL', async () => { it('after contains upload validator message of file when FAIL', async () => {
@ -1233,7 +1257,34 @@ describe('lion-input-file', () => {
expect(el.querySelector('[slot="after"]')?.textContent).to.equal('something went wrong'); expect(el.querySelector('[slot="after"]')?.textContent).to.equal('something went wrong');
}); });
it('after contains upload status of files when multiple files have been uploaded', async () => { it('after contains upload status of files when uploadOnSelect is true and multiple files have been selected', async () => {
const uploadResponse = [
{
name: 'file1.txt',
status: 'SUCCESS',
errorMessage: '',
downloadUrl: '/downloadFile',
},
{
name: 'file2.txt',
status: 'FAIL',
errorMessage: 'something went wrong',
downloadUrl: '/downloadFile',
},
];
const el = await fixture(html`
<lion-input-file label="Select" multiple upload-on-select></lion-input-file>
`);
// @ts-expect-error
el.uploadResponse = uploadResponse;
await el.updateComplete;
expect(el.querySelector('[slot="after"]')?.textContent?.trim()).to.equal(
'Uploaded files: 2 files. "something went wrong", for file2.txt.',
);
});
it('after contains upload status of files when uploadOnSelect is false and multiple files have been selected', async () => {
const uploadResponse = [ const uploadResponse = [
{ {
name: 'file1.txt', name: 'file1.txt',
@ -1256,7 +1307,7 @@ describe('lion-input-file', () => {
await el.updateComplete; await el.updateComplete;
expect(el.querySelector('[slot="after"]')?.textContent?.trim()).to.equal( expect(el.querySelector('[slot="after"]')?.textContent?.trim()).to.equal(
'2 files. "something went wrong", for file2.txt.', 'Selected files: 2 files. "something went wrong", for file2.txt.',
); );
}); });
}); });

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Моля, качете файл от тип {allowedTypesArray} или {allowedTypesLastItem} с макс. размер {maxSize}.', 'Моля, качете файл от тип {allowedTypesArray} или {allowedTypesLastItem} с макс. размер {maxSize}.',
dragAndDropText: 'Плъзнете и пуснете Вашите файлове тук или', dragAndDropText: 'Плъзнете и пуснете Вашите файлове тук или',
fileNameDescriptionLabel: 'Име на файл: {fileName}', fileNameDescriptionLabel: 'Име на файл: ',
generalValidatorMessage: '"{validatorMessage}", за {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", за {listOfErroneousFiles}.',
noFilesSelected: 'Не са избрани файлове.', noFilesSelected: 'Не са избрани файлове.',
numberOfFiles: '{numberOfFiles} файла.', numberOfFiles: '{numberOfFiles} файла.',

View file

@ -5,7 +5,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Nahrajte soubor typu {allowedTypesArray} nebo {allowedTypesLastItem} s max. velikostí {maxSize}.', 'Nahrajte soubor typu {allowedTypesArray} nebo {allowedTypesLastItem} s max. velikostí {maxSize}.',
dragAndDropText: 'Přetáhněte soubory sem nebo', dragAndDropText: 'Přetáhněte soubory sem nebo',
fileNameDescriptionLabel: 'Název souboru: {fileName}', fileNameDescriptionLabel: 'Název souboru: ',
generalValidatorMessage: '"{validatorMessage}", pro {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", pro {listOfErroneousFiles}.',
noFilesSelected: 'Nebyly vybrány žádné soubory.', noFilesSelected: 'Nebyly vybrány žádné soubory.',
numberOfFiles: '{numberOfFiles} soubory/souborů.', numberOfFiles: '{numberOfFiles} soubory/souborů.',

View file

@ -4,9 +4,14 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Laden Sie eine {allowedTypesArray} oder {allowedTypesLastItem}-Datei mit max. {maxSize} hoch.', 'Laden Sie eine {allowedTypesArray} oder {allowedTypesLastItem}-Datei mit max. {maxSize} hoch.',
dragAndDropText: 'Ziehen Sie Ihre Dateien per Drag & Drop hierher oder', dragAndDropText: 'Ziehen Sie Ihre Dateien per Drag & Drop hierher oder',
fileNameDescriptionLabel: 'Dateiname: {fileName}', fileNameDescriptionLabel: 'Dateiname: ',
generalValidatorMessage: '"{validatorMessage}", für {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", für {listOfErroneousFiles}.',
noFilesSelected: 'Keine Dateien ausgewählt.', noFilesSelected: 'Keine Dateien ausgewählt.',
noFilesUploaded: 'Keine Dateien hochgeladen.',
fileSelected: 'Ausgewählte Datei: ',
fileUploaded: 'Hochgeladene Datei: ',
filesSelected: 'Ausgewählte Dateien: {numberOfFiles} Dateien.',
filesUploaded: 'Hochgeladene Dateien: {numberOfFiles} Dateien.',
numberOfFiles: '{numberOfFiles} Dateien.', numberOfFiles: '{numberOfFiles} Dateien.',
removeButtonLabel: 'Datei {fileName} entfernen', removeButtonLabel: 'Datei {fileName} entfernen',
selectTextDuplicateFileName: 'Eine Datei mit demselben Dateinamen war bereits vorhanden.', selectTextDuplicateFileName: 'Eine Datei mit demselben Dateinamen war bereits vorhanden.',

View file

@ -4,10 +4,14 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Please select a {allowedTypesArray} or {allowedTypesLastItem} file with max {maxSize}.', 'Please select a {allowedTypesArray} or {allowedTypesLastItem} file with max {maxSize}.',
dragAndDropText: 'Drag & Drop your files here or', // TODO: or what? Why is Drag & Drop capitalized? dragAndDropText: 'Drag & Drop your files here or', // TODO: or what? Why is Drag & Drop capitalized?
fileNameDescriptionLabel: 'File name: {fileName}', fileNameDescriptionLabel: 'File name: ',
generalValidatorMessage: '"{validatorMessage}", for {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", for {listOfErroneousFiles}.',
noFilesSelected: 'No files selected.', noFilesSelected: 'No files selected.',
numberOfFiles: '{numberOfFiles} files.', noFilesUploaded: 'No files uploaded.',
fileSelected: 'Selected file: ',
fileUploaded: 'Uploaded file: ',
filesSelected: 'Selected files: {numberOfFiles} files.',
filesUploaded: 'Uploaded files: {numberOfFiles} files.',
removeButtonLabel: 'Remove {fileName} file', removeButtonLabel: 'Remove {fileName} file',
selectTextDuplicateFileName: 'A file with same filename was already present.', selectTextDuplicateFileName: 'A file with same filename was already present.',
selectTextMultipleFile: 'Select files', selectTextMultipleFile: 'Select files',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Cargue un archivo {allowedTypesArray} o {allowedTypesLastItem} de {maxSize} como máximo.', 'Cargue un archivo {allowedTypesArray} o {allowedTypesLastItem} de {maxSize} como máximo.',
dragAndDropText: 'Arrastre y suelte los archivos aquí o', dragAndDropText: 'Arrastre y suelte los archivos aquí o',
fileNameDescriptionLabel: 'Nombre de archivo: {fileName}', fileNameDescriptionLabel: 'Nombre de archivo: ',
generalValidatorMessage: '"{validatorMessage}", para {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", para {listOfErroneousFiles}.',
noFilesSelected: 'No se han seleccionado archivos.', noFilesSelected: 'No se han seleccionado archivos.',
numberOfFiles: '{numberOfFiles} archivos.', numberOfFiles: '{numberOfFiles} archivos.',

View file

@ -5,7 +5,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Veuillez télécharger un fichier {allowedTypesArray} ou {allowedTypesLastItem} avec une taille maximale de {maxSize}.', 'Veuillez télécharger un fichier {allowedTypesArray} ou {allowedTypesLastItem} avec une taille maximale de {maxSize}.',
dragAndDropText: 'Glissez et déposez vos fichiers ici ou', dragAndDropText: 'Glissez et déposez vos fichiers ici ou',
fileNameDescriptionLabel: 'Nom de fichier: {fileName}', fileNameDescriptionLabel: 'Nom de fichier: ',
generalValidatorMessage: '"{validatorMessage}", pour {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", pour {listOfErroneousFiles}.',
noFilesSelected: 'Aucun fichier sélectionné.', noFilesSelected: 'Aucun fichier sélectionné.',
numberOfFiles: '{numberOfFiles} fichiers.', numberOfFiles: '{numberOfFiles} fichiers.',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Töltsön fel egy legfeljebb {maxSize} méretű {allowedTypesArray} vagy {allowedTypesLastItem} fájlt.', 'Töltsön fel egy legfeljebb {maxSize} méretű {allowedTypesArray} vagy {allowedTypesLastItem} fájlt.',
dragAndDropText: 'Húzza át a fájlokat ide vagy', dragAndDropText: 'Húzza át a fájlokat ide vagy',
fileNameDescriptionLabel: 'Fájlnév: {fileName}', fileNameDescriptionLabel: 'Fájlnév: ',
generalValidatorMessage: '"{validatorMessage}", ehhez: {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", ehhez: {listOfErroneousFiles}.',
noFilesSelected: 'Nincs fájl kiválasztva.', noFilesSelected: 'Nincs fájl kiválasztva.',
numberOfFiles: '{numberOfFiles} fájl.', numberOfFiles: '{numberOfFiles} fájl.',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Caricare un file {allowedTypesArray} o {allowedTypesLastItem} di {maxSize} max.', 'Caricare un file {allowedTypesArray} o {allowedTypesLastItem} di {maxSize} max.',
dragAndDropText: 'Trascinare i file qui o', dragAndDropText: 'Trascinare i file qui o',
fileNameDescriptionLabel: 'Nome file: {fileName}', fileNameDescriptionLabel: 'Nome file: ',
generalValidatorMessage: '"{validatorMessage}", per {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", per {listOfErroneousFiles}.',
noFilesSelected: 'Nessun file selezionato.', noFilesSelected: 'Nessun file selezionato.',
numberOfFiles: '{numberOfFiles} file.', numberOfFiles: '{numberOfFiles} file.',

View file

@ -4,10 +4,15 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Upload een {allowedTypesArray} of {allowedTypesLastItem}-bestand van maximaal {maxSize}.', 'Upload een {allowedTypesArray} of {allowedTypesLastItem}-bestand van maximaal {maxSize}.',
dragAndDropText: 'Sleep uw bestanden hierheen of', dragAndDropText: 'Sleep uw bestanden hierheen of',
fileNameDescriptionLabel: 'Bestandsnaam: {fileName}', fileNameDescriptionLabel: 'Bestandsnaam: ',
generalValidatorMessage: '"{validatorMessage}", voor {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", voor {listOfErroneousFiles}.',
noFilesSelected: 'Geen bestanden geselecteerd.', noFilesSelected: 'Geen bestanden geselecteerd.',
numberOfFiles: '{numberOfFiles} bestanden.', numberOfFiles: '{numberOfFiles} bestanden.',
noFilesUploaded: 'Geen bestanden geüpload.',
fileSelected: 'Geselecteerd bestand: ',
fileUploaded: 'Geüpload bestand: ',
filesSelected: 'Geselecteerde bestanden: {numberOfFiles} bestanden.',
filesUploaded: 'Geüploade bestanden: {numberOfFiles} bestanden.',
removeButtonLabel: 'Verwijder het bestand {fileName}', removeButtonLabel: 'Verwijder het bestand {fileName}',
selectTextDuplicateFileName: 'Er bestaat al een bestand met dezelfde bestandsnaam.', selectTextDuplicateFileName: 'Er bestaat al een bestand met dezelfde bestandsnaam.',
selectTextMultipleFile: 'Selecteer bestanden', selectTextMultipleFile: 'Selecteer bestanden',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Prześlij plik {allowedTypesArray} lub {allowedTypesLastItem} o maks. rozmiarze {maxSize}.', 'Prześlij plik {allowedTypesArray} lub {allowedTypesLastItem} o maks. rozmiarze {maxSize}.',
dragAndDropText: 'Przeciągnij i upuść pliki tutaj lub', dragAndDropText: 'Przeciągnij i upuść pliki tutaj lub',
fileNameDescriptionLabel: 'Nazwa pliku: {fileName}', fileNameDescriptionLabel: 'Nazwa pliku: ',
generalValidatorMessage: '"{validatorMessage}", dla {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", dla {listOfErroneousFiles}.',
noFilesSelected: 'Nie wybrano żadnych plików.', noFilesSelected: 'Nie wybrano żadnych plików.',
numberOfFiles: 'Liczba plików: {numberOfFiles}.', numberOfFiles: 'Liczba plików: {numberOfFiles}.',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Încărcaţi un fişier {allowedTypesArray} sau {allowedTypesLastItem} de max. {maxSize}.', 'Încărcaţi un fişier {allowedTypesArray} sau {allowedTypesLastItem} de max. {maxSize}.',
dragAndDropText: 'Glisaţi şi fixaţi fişierele aici sau', dragAndDropText: 'Glisaţi şi fixaţi fişierele aici sau',
fileNameDescriptionLabel: 'Nume fişier: {fileName}', fileNameDescriptionLabel: 'Nume fişier: ',
generalValidatorMessage: '"{validatorMessage}", pentru {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", pentru {listOfErroneousFiles}.',
noFilesSelected: 'Niciun fișier selectat.', noFilesSelected: 'Niciun fișier selectat.',
numberOfFiles: '{numberOfFiles} fișiere.', numberOfFiles: '{numberOfFiles} fișiere.',

View file

@ -4,10 +4,14 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Загрузите файл {allowedTypesArray} или {allowedTypesLastItem} размером не более {maxSize}.', 'Загрузите файл {allowedTypesArray} или {allowedTypesLastItem} размером не более {maxSize}.',
dragAndDropText: 'Перетащите файлы сюда или', dragAndDropText: 'Перетащите файлы сюда или',
fileNameDescriptionLabel: 'Название файла: {fileName}', fileNameDescriptionLabel: 'Название файла: ',
generalValidatorMessage: '"{validatorMessage}", для {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", для {listOfErroneousFiles}.',
noFilesSelected: 'Файлы не выбраны.', noFilesSelected: 'Не выбрано ни одного файла.',
numberOfFiles: 'Файлов: {numberOfFiles}.', noFilesUploaded: 'Не загружено ни одного файла.',
fileSelected: 'Выбранный файл: ',
fileUploaded: 'Загруженный файл: ',
filesSelected: 'Выбранные файлы: {numberOfFiles} файлов.',
filesUploaded: 'Загруженные файлы: {numberOfFiles} файлов.',
removeButtonLabel: 'Удалить файл {fileName}', removeButtonLabel: 'Удалить файл {fileName}',
selectTextDuplicateFileName: 'Файл с таким названием уже существует.', selectTextDuplicateFileName: 'Файл с таким названием уже существует.',
selectTextMultipleFile: 'Выберите файлы', selectTextMultipleFile: 'Выберите файлы',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Nahrajte súbor {allowedTypesArray} alebo {allowedTypesLastItem} s maximálnou veľkosťou {maxSize}.', 'Nahrajte súbor {allowedTypesArray} alebo {allowedTypesLastItem} s maximálnou veľkosťou {maxSize}.',
dragAndDropText: 'Súbory presuňte sem alebo', dragAndDropText: 'Súbory presuňte sem alebo',
fileNameDescriptionLabel: 'Názov súboru: {fileName}', fileNameDescriptionLabel: 'Názov súboru: ',
generalValidatorMessage: '"{validatorMessage}", pre {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", pre {listOfErroneousFiles}.',
noFilesSelected: 'Neboli vybrané žiadne súbory.', noFilesSelected: 'Neboli vybrané žiadne súbory.',
numberOfFiles: 'Počet súborov: {numberOfFiles}.', numberOfFiles: 'Počet súborov: {numberOfFiles}.',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'Завантажте файл {allowedTypesArray} або {allowedTypesLastItem} розміром до {maxSize}.', 'Завантажте файл {allowedTypesArray} або {allowedTypesLastItem} розміром до {maxSize}.',
dragAndDropText: 'Перетягніть файли сюди або', dragAndDropText: 'Перетягніть файли сюди або',
fileNameDescriptionLabel: 'Ім’я файлу: {fileName}', fileNameDescriptionLabel: 'Ім’я файлу: ',
generalValidatorMessage: '"{validatorMessage}", для {listOfErroneousFiles}.', generalValidatorMessage: '"{validatorMessage}", для {listOfErroneousFiles}.',
noFilesSelected: 'Не вибрано жодного файлу.', noFilesSelected: 'Не вибрано жодного файлу.',
numberOfFiles: '{numberOfFiles} файли(-ів).', numberOfFiles: '{numberOfFiles} файли(-ів).',

View file

@ -4,7 +4,7 @@ export default {
allowedFileValidatorComplex: allowedFileValidatorComplex:
'请上传最大 {maxSize} 的 {allowedTypesArray} 或 {allowedTypesLastItem} 文件。', '请上传最大 {maxSize} 的 {allowedTypesArray} 或 {allowedTypesLastItem} 文件。',
dragAndDropText: '将您的文件拖放到此处,或', dragAndDropText: '将您的文件拖放到此处,或',
fileNameDescriptionLabel: '文件名: {fileName}', fileNameDescriptionLabel: '文件名: ',
generalValidatorMessage: '"{validatorMessage}", 例如 {listOfErroneousFiles}。', generalValidatorMessage: '"{validatorMessage}", 例如 {listOfErroneousFiles}。',
noFilesSelected: '未选择任何文件。', noFilesSelected: '未选择任何文件。',
numberOfFiles: '{numberOfFiles} 个文件。', numberOfFiles: '{numberOfFiles} 个文件。',