Los usuarios de distintos países esperan separadores decimales, símbolos de moneda, nombres de meses y reglas de ordenación acordes con su cultura. locale en Python permite acceder a la base POSIX del sistema operativo para formatear e interpretar esos valores.
La funcionalidad exige cuidado porque el locale es una propiedad global del proceso heredada de la biblioteca C. Cambiarlo afecta a otras partes de la aplicación y no es thread-safe en la mayoría de sistemas. Esta guía explica configuración inicial, categorías, números, moneda, fechas, collation, encodings, fallos de despliegue y alternativas para servidores concurrentes.
El contenido complementa nuestras guías sobre Decimal, zoneinfo, statistics, platform y sysconfig.
Qué representa un locale
Un locale reúne convenciones culturales instaladas en el sistema: separador decimal, agrupación de miles, símbolo monetario, posición del signo, nombres de meses y días, formatos de fecha y reglas de ordenación.
Los nombres disponibles dependen de la plataforma y de los datos instalados. Un locale presente en desarrollo puede faltar en un container de producción.
Estado inicial del proceso
Los programas C suelen empezar en el locale portátil C. Python configura aspectos de LC_CTYPE durante el arranque para establecer el encoding, pero las otras categorías conservan el comportamiento portátil hasta que la aplicación pide las preferencias del usuario.
import locale
locale.setlocale(locale.LC_ALL, "")La string vacía solicita la configuración predeterminada del usuario, normalmente definida por variables de entorno.
Consultar sin cambiar
actual = locale.setlocale(locale.LC_ALL)
print(actual)Si se omite el segundo argumento, setlocale() devuelve el estado actual. Guardar y restaurar sigue siendo peligroso si otras threads trabajan entre ambas llamadas.
setlocale no es thread-safe
La configuración es global. Una thread puede cambiar la coma decimal mientras otra genera una factura.
Configura el locale una sola vez al inicio de una herramienta de escritorio o línea de comandos. Un servidor para usuarios de culturas diferentes debe utilizar objetos de formato independientes por petición.
Categorías
LC_NUMERIC: números.LC_MONETARY: moneda.LC_TIME: fechas y horas.LC_COLLATE: ordenación de strings.LC_CTYPE: entorno de caracteres y encoding.LC_MESSAGES: mensajes del sistema en POSIX.LC_ALL: todas las categorías.
Cambiar una sola categoría reduce efectos, pero el estado sigue siendo global.
Locale no disponible
try:
locale.setlocale(locale.LC_ALL, "es_ES.UTF-8")
except locale.Error:
locale.setlocale(locale.LC_ALL, "")No supongas que el mismo nombre funciona en Windows, Linux y macOS. Instala los datos durante el deploy o define un fallback explícito.
Normalizar nombres
normalizado = locale.normalize("es_ES.UTF-8")La función aplica aliases, pero no instala el locale. Puede devolver el nombre original si no logra adaptarlo.
Convenciones numéricas y monetarias
convenciones = locale.localeconv()
print(convenciones["decimal_point"])
print(convenciones["thousands_sep"])
print(convenciones["currency_symbol"])El diccionario también informa agrupación, casas decimales monetarias, posición del símbolo y signos. Algunos campos pueden usar CHAR_MAX para indicar que no están definidos.
Formatear números
texto = locale.format_string(
"%.2f",
1234567.89,
grouping=True,
)La función usa LC_NUMERIC y la sintaxis del operador %.
Localizar una representación normalizada
localizado = locale.localize(
"1234567.89",
grouping=True,
)localize(), disponible desde Python 3.10, aplica separadores culturales a una string numérica normalizada.
Interpretar números localizados
valor = locale.atof("1.234,56")El ejemplo depende de un locale con punto para miles y coma decimal. atof() usa delocalize() y luego float.
Para dinero, pasa Decimal.
from decimal import Decimal
importe = locale.atof("1.234,56", func=Decimal)Interpretar enteros
cantidad = locale.atoi("1.234")Valida límites y rechaza formatos ambiguos. Un texto de otra cultura puede ser interpretado mal sin generar excepción.
delocalize
normalizado = locale.delocalize("1.234,56")La función elimina agrupación y adapta el separador decimal. No valida precisión, signo permitido ni reglas de negocio.
Formatear moneda
texto = locale.currency(
1234.50,
symbol=True,
grouping=True,
)currency() no funciona con el locale C. Configura una categoría monetaria válida.
Un símbolo como $ es ambiguo. Guarda siempre el código ISO de moneda como dato separado y considera international=True.
Locale no decide la moneda
El locale indica presentación, no qué moneda representa el número. Un usuario español puede consultar una factura en dólares. Mantén importe y código monetario explícitos.
Fechas y horas
strftime() usa LC_TIME para nombres y formatos.
from datetime import datetime
texto = datetime.now().strftime("%A, %d de %B de %Y")Locale no es timezone. Convierte el instante con zoneinfo antes de formatear.
Información del sistema
En plataformas compatibles, nl_langinfo() devuelve formatos de fecha, nombres, encoding y separadores.
if hasattr(locale, "nl_langinfo"):
formato = locale.nl_langinfo(locale.D_FMT)Las constantes disponibles varían. Prueba el entorno real.
Ordenación cultural
palabras = ["ábaco", "acción", "zebra"]
ordenadas = sorted(palabras, key=locale.strxfrm)strxfrm() crea claves adecuadas para comparaciones repetidas con el LC_COLLATE actual.
strcoll
resultado = locale.strcoll("fan", "fútbol")Un valor negativo, cero o positivo indica orden. Depende del locale activo.
Ordenación no es identidad
Dos strings cercanas en collation no son necesariamente iguales para login, claves o deduplicación. Define reglas Unicode y de dominio separadas.
Encoding preferido
encoding = locale.getpreferredencoding(False)La función estima el encoding preferido. En modo UTF-8 de Python y Android devuelve UTF-8.
Para archivos y protocolos nuevos, declara UTF-8 de forma explícita.
getencoding
Desde Python 3.11, getencoding() devuelve el encoding del locale actual ignorando el modo UTF-8.
encoding_actual = locale.getencoding()getlocale
idioma, encoding = locale.getlocale(locale.LC_NUMERIC)El locale C se representa como (None, None). LC_ALL no es válido para esta función.
Variables de entorno
En POSIX, LC_ALL, las variables por categoría y LANG influyen. Los containers suelen fallar cuando declaran un locale no instalado.
Usa imágenes con UTF-8 y prueba exactamente el entorno del deploy.
C y C.UTF-8
C es portátil y determinista. C.UTF-8 es común en Linux, pero no universal.
Python incluye coerción de locale y modo UTF-8 para reducir fallos de encoding.
Las bibliotecas no deben cambiarlo
Una biblioteca reutilizable desconoce qué threads comparten el proceso. Llamar setlocale() dentro de una función pública crea un efecto global inesperado.
Recibe valores normalizados o permite que el llamador proporcione el formatter.
Servidores web
No cambies el locale por petición. Dos peticiones simultáneas pueden mezclar comas, puntos, monedas y meses.
Usa bibliotecas con objetos de locale independientes, como Babel, o formatters deterministas con configuración explícita.
gettext
Locale gestiona convenciones, no la traducción completa de mensajes. Usa gettext para catálogos de la aplicación.
Pruebas
Comprueba solamente locales instalados y salta los ausentes de forma explícita. No cambies locale global en paralelo.
def intentar_locale(nombre):
try:
locale.setlocale(locale.LC_ALL, nombre)
except locale.Error:
return False
return TrueUsa procesos separados para probar varias culturas con fiabilidad.
Seguridad
Las strings localizadas siguen siendo entrada externa. Limita tamaño, valida caracteres y no uses el resultado directamente como SQL, comando o ruta.
La validez cultural no sustituye reglas de negocio. Importes negativos, infinitos o con demasiados decimales pueden estar prohibidos.
Errores frecuentes
- Cambiar locale en cada petición.
- Suponer que un nombre existe en todos los sistemas.
- Usar float para dinero.
- Confundir locale y timezone.
- Confundir locale y moneda.
- Comparar números localizados como strings.
- Usar collation como igualdad.
- Permitir que una biblioteca cambie el estado global.
Buenas prácticas
- Configura una vez al inicio de programas simples.
- Usa categorías específicas.
- Trata
locale.Error. - Usa Decimal para importes.
- Mantén moneda y timezone explícitos.
- Usa
strxfrm()para ordenar. - Prefiere UTF-8 en formatos persistentes.
- Usa formatters independientes en servidores.
Conclusión
locale en Python conecta la aplicación con convenciones culturales del sistema para números, moneda, fechas, encodings y ordenación.
Su principal límite es el estado global y no thread-safe. Funciona bien en herramientas locales configuradas una vez, mientras los servidores multiusuario deben usar formatters independientes. Consulta la documentación oficial de locale y Unicode CLDR.







