Cómo cambiar el mensaje «No se ha seleccionado ningún archivo» en PrimeFaces

Para cambiar el texto predeterminado «No se ha seleccionado ningún archivo» y el botón «Examinar» de un componente p:fileUpload en PrimeFaces, utiliza los atributos de texto del propio componente, principalmente chooseLabel y uploadLabel. El atributo chooseLabel modifica el texto del botón utilizado para seleccionar el archivo, mientras que uploadLabel modifica el texto del botón de subida cuando el modo del componente lo muestra.

En el código mostrado, el componente utiliza mode="simple". En este modo, el texto visible junto al control de selección puede depender de la versión de PrimeFaces y del navegador, por lo que, si necesitas controlar completamente la presentación, también puedes utilizar un texto internacionalizado mediante un archivo de mensajes o aplicar una configuración específica de la versión utilizada.

Configuración básica con etiquetas de PrimeFaces

Una configuración habitual consiste en añadir chooseLabel al componente y definir el texto que debe aparecer en el botón de selección:

chooseLabel modifica la etiqueta del botón que permite escoger un archivo, mientras que uploadLabel se utiliza para personalizar la etiqueta del botón que inicia la carga en los modos que muestran ese control.

Un ejemplo de configuración es el siguiente:

<p:fileUpload id="fileUp"
fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
value="#{fileUploadController.file}"
mode="simple"
allowTypes="/(\.|\/)(xml)$/"
multiple="false"
dragDropSupport="true"
invalidFileMessage="Only XML are allowed to upload!"
chooseLabel="Seleccionar archivo"
uploadLabel="Subir archivo"/>

Si solo necesitas cambiar el botón de selección, basta con utilizar chooseLabel:

<p:fileUpload id="fileUp"
mode="simple"
chooseLabel="Seleccionar archivo"/>

Diferencia entre chooseLabel, uploadLabel y otros atributos

  • chooseLabel: cambia el texto del botón utilizado para seleccionar un archivo.
  • uploadLabel: cambia el texto del botón utilizado para iniciar la carga.
  • cancelLabel: cambia el texto del botón de cancelación cuando está disponible.
  • invalidFileMessage: cambia el mensaje mostrado cuando el archivo no cumple las restricciones configuradas.
  • requiredMessage: define el mensaje de validación cuando el campo es obligatorio y no se proporciona un archivo.
  • messageTemplate: controla el formato de determinados mensajes de carga, pero no sustituye necesariamente el texto interno del control de selección.

Por esta razón, label, requiredMessage y messageTemplate no cumplen la misma función que chooseLabel. El mensaje «No se ha seleccionado ningún archivo» pertenece a la interfaz del selector de archivos, mientras que requiredMessage corresponde a la validación del componente.

Ejemplo para carga de archivos XML

Para permitir únicamente archivos XML y mostrar textos en español, el componente puede quedar configurado de esta forma:

<p:fileUpload id="fileUp"
fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
value="#{fileUploadController.file}"
mode="simple"
allowTypes="/(\.|\/)(xml)$/"
multiple="false"
dragDropSupport="true"
chooseLabel="Seleccionar archivo"
uploadLabel="Cargar archivo"
cancelLabel="Cancelar"
invalidFileMessage="Solo se permiten archivos XML."/>

El patrón configurado mediante allowTypes restringe la selección a archivos cuya extensión es XML. La propiedad multiple="false" impide seleccionar más de un archivo.

Uso con internacionalización

Si la aplicación está internacionalizada, los textos pueden definirse en un archivo de recursos y referenciarse desde la página XHTML. De este modo, la etiqueta cambia automáticamente según el idioma seleccionado por la aplicación.

Por ejemplo, en un archivo de mensajes en español puedes definir:

file.choose=Seleccionar archivo
file.upload=Cargar archivo
file.cancel=Cancelar
file.invalid=Solo se permiten archivos XML.

Después, puedes utilizar esas claves como valores de los atributos del componente:

<p:fileUpload id="fileUp"
fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
value="#{fileUploadController.file}"
mode="simple"
allowTypes="/(\.|\/)(xml)$/"
multiple="false"
dragDropSupport="true"
chooseLabel="#{msg['file.choose']}"
uploadLabel="#{msg['file.upload']}"
cancelLabel="#{msg['file.cancel']}"
invalidFileMessage="#{msg['file.invalid']}"/>

El nombre exacto del bean utilizado para acceder al archivo de mensajes depende de la configuración de internacionalización de la aplicación. Si el proyecto utiliza otro nombre, debes sustituir msg por el identificador correspondiente.

Cuando el texto sigue apareciendo en inglés o no cambia

Las propiedades disponibles pueden variar entre versiones de PrimeFaces. Si chooseLabel no produce ningún efecto, conviene comprobar la versión exacta de PrimeFaces y consultar la documentación correspondiente a esa versión.

También es importante distinguir entre el texto generado por PrimeFaces y el texto generado directamente por el navegador. En un selector HTML nativo, el navegador puede mostrar etiquetas como «Examinar» o «No se ha seleccionado ningún archivo», y esos textos no siempre pueden cambiarse mediante atributos HTML, porque dependen del idioma y de la configuración del sistema operativo.

En los diálogos nativos para examinar archivos, los textos del diálogo se presentan en el idioma configurado en el sistema operativo.

Cuando se utiliza un componente de PrimeFaces en modo simple, parte de la interfaz puede apoyarse en el control de archivo del navegador. En ese caso, cambiar el texto del botón mediante PrimeFaces puede no modificar el mensaje nativo que aparece junto al campo.

Alternativa mediante CSS

Si la versión de PrimeFaces o el navegador mantiene el texto nativo, puede ocultarse visualmente el control original y mostrar un botón personalizado asociado al campo de archivo. Esta alternativa requiere conservar la funcionalidad del campo y aplicar los estilos con cuidado para no perjudicar la accesibilidad.

La solución preferible es utilizar primero chooseLabel, porque conserva la estructura y el comportamiento del componente. El uso de CSS debe reservarse para los casos en los que el texto procede del control nativo y no puede personalizarse mediante las propiedades disponibles.

Relación con la selección de archivos en otros entornos

La selección de archivos no es exclusiva de PrimeFaces. Tk proporciona funciones para desplegar diálogos para examinar archivos o carpetas en Windows, Linux (o cualquier otro sistema basado en Unix) y macOS.

En Python las funciones son accesibles a través del módulo tkinter.filedialog. Las principales son: askopenfilename() / askopenfilenames() askdirectory() asksaveasfilename().

Las funciones askopenfilename() y askopenfilenames() muestran un diálogo para abrir uno o más archivos. askdirectory() hace lo propio para examinar una carpeta (no es posible seleccionar más de una carpeta). asksaveasfilename() despliega un cuadro similar al de las primeras dos funciones, pero para guardar un archivo en lugar de abrirlo.

En Windows y macOS las funciones trabajan internamente con cuadros nativos del sistema operativo, lo cual nos asegura que siempre obtendremos una herramienta actualizada y moderna para examinar archivos o carpetas.

En sistemas Unix los diálogos simulan la ventana de Windows (95) y están escritos directamente en Tcl en el archivo tkfbox.tcl.

Por qué aparece el mensaje cuando no se selecciona un archivo

Las funciones askopenfilename() y askopenfilenames() muestran un diálogo para abrir uno o más archivos.

Si el usuario cancela o cierra el diálogo, el resultado es una cadena o tupla vacía (dependiendo del sistema operativo), por lo cual generalmente querremos hacer un condicional luego de llamar a la función.

Puesto que tanto tuplas como cadenas vacías se evalúan como False, no es necesario distinguir un caso del otro.

Por ejemplo:

from pathlib import Path
from tkinter import filedialog
filename = filedialog.askopenfilename()
if filename:
    # Leer e imprimir el contenido (en bytes) del archivo.
    print(Path(filename).read_bytes())
else:
    print("No se ha seleccionado ningún archivo.")

En este ejemplo, el texto «No se ha seleccionado ningún archivo» no pertenece al diálogo de selección, sino al mensaje definido explícitamente en el bloque else. Para cambiarlo, basta con reemplazar la cadena por el texto deseado:

else:
    print("No se ha seleccionado ningún archivo XML.")

La ruta del archivo seleccionado por el usuario es retornada como una cadena y guardada, en este caso, en la variable filename.

Selección de varios archivos

La función askopenfilenames() (nótese la «s» al final) permite al usuario seleccionar más de un archivo en la misma carpeta.

El resultado es en este caso una tupla que contiene las rutas de los archivos seleccionados.

Ejemplo:

filenames = filedialog.askopenfilenames()
if filenames:
    print("Archivos seleccionados:")
    for filename in filenames:
        print(filename)
else:
    print("No se ha seleccionado ningún archivo.")

En un selector múltiple, el mensaje de ausencia debe modificarse en el bloque else, del mismo modo que en la selección de un solo archivo.

Filtros de archivos XML

Por defecto, los diálogos producidos por las tres funciones para examinar archivos muestran todo tipo de archivos.

Podemos configurar el diálogo para mostrar solo determinados tipos de archivos vía el argumento filetype:

filename = filedialog.askopenfilename(
    filetypes=(
        ("Archivos XML", "*.xml"),
        ("Todos los archivos", "*.*")
    )
)

El argumento recibe una tupla de tuplas de dos elementos.

El primer elemento de las tuplas interiores indica el nombre del tipo de archivo que será mostrado al usuario.

El segundo puede ser una cadena o una tupla de cadenas indicando los patrones a utilizar.

Por ejemplo, la cadena *.txt muestra solo los archivos que terminan en .txt, mientras que la tupla ("*.py", "*.pyx") muestra archivos que terminan en .py o .pyx.

El patrón *.* sirve para mostrar archivos con cualquier nombre y extensión.

Cuando el argumento filetypes está presente, el diálogo incluye una lista desplegable con la cual el usuario puede indicar el tipo de archivo que quiere visualizar.

Personalización del título y la carpeta inicial

En todas las funciones puede indicarse el argumento intialdir para definir la ruta inicial en la que aparecerá el diálogo.

Por ejemplo:

filename = filedialog.askopenfilename(initialdir="C:/")

O para iniciar en la carpeta donde se encuentra el intérprete de Python:

from pathlib import Path
from tkinter import filedialog
import sys
filename = filedialog.askopenfilename(
    initialdir=Path(sys.executable).parent
)

Si intialdir no es indicado, la ruta inicial depende del sistema operativo.

En sistemas Unix y macOS es el directorio actual de trabajo, que por lo general coincide con la ruta donde se encuentra nuestro archivo de Python.

En Windows es la última ruta desde la cual se seleccionó un archivo en esa misma aplicación.

En macOS a veces el valor de initialdir es ignorado, según la configuración del usuario.

Por último, el título y la ventana padre del diálogo pueden indicarse vía los parámetros title y parent, respectivamente.

El diálogo se cierra automáticamente si la ventana padre es destruida.

noimgs

tags: #change #no #se #ha #seleccionado #ningun