Cómo formatear números ordinales como 1º, 2º, 3º
Utiliza JavaScript para mostrar números ordinales con sufijos y formato apropiados para cada localización
Introducción
Los números ordinales indican posición o rango en una secuencia. En inglés, se escribe 1st, 2nd, 3rd, 4th para describir posiciones finales en una carrera o elementos en una lista. Estos sufijos ayudan a distinguir los números ordinales de los números cardinales regulares.
Diferentes idiomas utilizan convenciones completamente distintas para los ordinales. El inglés añade sufijos como st, nd, rd y th. El francés usa letras en superíndice como 1er y 2e. El alemán añade un punto después del número como 1. y 2. El japonés antepone a los números el carácter 第. Cuando se codifican los sufijos ordinales en inglés, se asume que todos los usuarios siguen la misma convención.
JavaScript proporciona la API Intl.PluralRules con un tipo ordinal para manejar estas diferencias automáticamente. Esta lección explica qué son los números ordinales, por qué su formato varía entre idiomas y cómo formatearlos correctamente para cualquier localización.
Qué son los números ordinales
Los números ordinales expresan posición, rango u orden en una secuencia. Responden a la pregunta "¿cuál?" en lugar de "¿cuántos?". Los números 1º, 2º, 3º describen posiciones en una carrera. Primero, segundo, tercero describen elementos en una lista.
Los números cardinales expresan cantidad o monto. Responden a la pregunta "¿cuántos?". Los números 1, 2, 3 describen cantidades de objetos. Uno, dos, tres describen cantidades.
El mismo valor numérico sirve para ambos propósitos dependiendo del contexto. El número 5 es cardinal en "5 manzanas" pero ordinal en "5º lugar". La distinción es importante porque muchos idiomas formatean los ordinales de manera diferente a los cardinales.
En español, los ordinales tienen formas de palabra únicas. Primero, segundo, tercero, cuarto, quinto son palabras distintas. Por encima de 10, el español forma ordinales siguiendo patrones específicos. Undécimo, duodécimo, vigésimo, vigésimo primero siguen patrones pero requieren sufijos específicos.
Al escribir ordinales como números en lugar de palabras, el español añade sufijos como º, ª o er. Estos sufijos siguen reglas específicas basadas en el género y el contexto.
Por qué el formato ordinal varía según la configuración regional
Diferentes idiomas desarrollaron distintos sistemas para expresar números ordinales. Estas convenciones reflejan reglas gramaticales, sistemas de escritura y prácticas culturales únicas de cada idioma.
En inglés, los ordinales utilizan cuatro sufijos diferentes. Los números que terminan en 1 usan st, los números que terminan en 2 usan nd, los números que terminan en 3 usan rd, y todos los demás números usan th. Sin embargo, los números que terminan en 11, 12 o 13 usan th. Esto crea 1st, 2nd, 3rd, 4th, 11th, 12th, 13th, 21st, 22nd, 23rd.
En francés, los ordinales utilizan abreviaturas en superíndice. El primer elemento usa 1er para masculino o 1re para femenino. Todos los demás ordinales usan e en superíndice, como 2e, 3e, 4e. El formato incluye tipografía en superíndice, no solo letras de sufijo.
En alemán, los ordinales utilizan un punto después del número. La notación 1., 2., 3. representa primero, segundo, tercero. Este punto indica que el lector debe agregar mentalmente la terminación gramatical apropiada al leer en voz alta.
En español, los ordinales utilizan indicadores de género en superíndice. Los ordinales masculinos usan 1.º, 2.º, 3.º mientras que los ordinales femeninos usan 1.ª, 2.ª, 3.ª. El punto separa el número del indicador.
En japonés, los ordinales agregan el prefijo 第 antes del número. Primero, segundo, tercero aparecen como 第一, 第二, 第三. Este prefijo cambia el significado de cardinal a ordinal.
Cuando construyes cadenas ordinales concatenando números con sufijos codificados, obligas a todos los usuarios a interpretar las convenciones del inglés. Esto hace que tu aplicación sea más difícil de usar para las personas que esperan formatos diferentes.
Entendiendo Intl.PluralRules con tipo ordinal
La API Intl.PluralRules determina a qué categoría plural pertenece un número para una configuración regional determinada. Si bien esta API se usa comúnmente para elegir entre formas de palabras singulares y plurales, también maneja números ordinales.
El constructor acepta un identificador de configuración regional y un objeto de opciones. Establece la opción type en "ordinal" para trabajar con números ordinales en lugar de números cardinales.
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
Esto crea un objeto de reglas que entiende los patrones ordinales en inglés. El método select() devuelve un nombre de categoría para cualquier número que le pases.
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
console.log(rules.select(1));
// Salida: "one"
console.log(rules.select(2));
// Salida: "two"
console.log(rules.select(3));
// Salida: "few"
console.log(rules.select(4));
// Salida: "other"
Las categorías devueltas son términos lingüísticos, no los sufijos reales. La categoría "one" corresponde a números que toman el sufijo st en inglés. La categoría "two" corresponde a sufijos nd. La categoría "few" corresponde a sufijos rd. La categoría "other" corresponde a sufijos th.
Debes mapear estos nombres de categorías a los sufijos apropiados para tu configuración regional. La API maneja las reglas complejas para determinar a qué categoría pertenece cada número.
Construyendo una función formateadora de números ordinales
Para formatear números ordinales, se combina Intl.PluralRules con un mapeo de categorías plurales a sufijos. Crea una función formateadora que tome un número y devuelva la cadena formateada.
function formatOrdinal(number, locale) {
const rules = new Intl.PluralRules(locale, { type: 'ordinal' });
const category = rules.select(number);
const suffixes = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
};
const suffix = suffixes[category];
return `${number}${suffix}`;
}
console.log(formatOrdinal(1, 'en-US'));
// Output: "1st"
console.log(formatOrdinal(2, 'en-US'));
// Output: "2nd"
console.log(formatOrdinal(3, 'en-US'));
// Output: "3rd"
console.log(formatOrdinal(4, 'en-US'));
// Output: "4th"
Esta función crea una nueva instancia de PluralRules cada vez que se ejecuta. Para un mejor rendimiento, crea el objeto de reglas una vez y reutilízalo para múltiples números.
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const suffixes = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
};
function formatOrdinal(number) {
const category = rules.select(number);
const suffix = suffixes[category];
return `${number}${suffix}`;
}
console.log(formatOrdinal(1));
// Output: "1st"
console.log(formatOrdinal(21));
// Output: "21st"
console.log(formatOrdinal(22));
// Output: "22nd"
console.log(formatOrdinal(23));
// Output: "23rd"
La API maneja correctamente números como 11, 12 y 13, que todos usan th a pesar de sus dígitos finales.
console.log(formatOrdinal(11));
// Output: "11th"
console.log(formatOrdinal(12));
// Output: "12th"
console.log(formatOrdinal(13));
// Output: "13th"
Las reglas plurales codifican todos los casos especiales y excepciones para el locale. No necesitas escribir lógica condicional para manejar estos casos extremos.
Formateando números ordinales para diferentes locales
Las categorías plurales y sus significados cambian entre locales. Algunos idiomas tienen menos categorías que el inglés. Otros tienen reglas diferentes para qué números caen en cada categoría.
El galés utiliza un sistema de categorización diferente. Las reglas identifican más categorías, cada una correspondiente a diferentes formas ordinales en galés.
const enRules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const cyRules = new Intl.PluralRules('cy', { type: 'ordinal' });
console.log(enRules.select(1));
// Output: "one"
console.log(cyRules.select(1));
// Output: "one"
console.log(enRules.select(2));
// Output: "two"
console.log(cyRules.select(2));
// Output: "two"
console.log(enRules.select(5));
// Output: "other"
console.log(cyRules.select(5));
// Output: "many"
Para soportar múltiples locales, necesitas diferentes mapeos de sufijos para cada locale. Las categorías siguen siendo las mismas, pero los sufijos cambian.
const ordinalSuffixes = {
'en-US': {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
},
'fr-FR': {
one: 'er',
other: 'e'
}
};
function formatOrdinal(number, locale) {
const rules = new Intl.PluralRules(locale, { type: 'ordinal' });
const category = rules.select(number);
const suffixes = ordinalSuffixes[locale];
const suffix = suffixes[category] || suffixes.other;
return `${number}${suffix}`;
}
console.log(formatOrdinal(1, 'en-US'));
// Output: "1st"
console.log(formatOrdinal(1, 'fr-FR'));
// Output: "1er"
console.log(formatOrdinal(2, 'en-US'));
// Output: "2nd"
console.log(formatOrdinal(2, 'fr-FR'));
// Output: "2e"
Este enfoque funciona bien cuando controlas las cadenas de sufijos para cada locale. Sin embargo, requiere mantener datos de sufijos para cada locale que soportes.
Comprendiendo las categorías de plurales ordinales
La API Intl.PluralRules utiliza seis posibles nombres de categorías. Diferentes locales utilizan diferentes subconjuntos de estas categorías.
Las categorías son zero, one, two, few, many y other. No todos los idiomas distinguen entre las seis categorías. Los ordinales en inglés utilizan solo cuatro: one, two, few y other.
Los nombres de las categorías no corresponden directamente a los valores numéricos. La categoría "one" incluye 1, 21, 31, 41 y todos los números que terminan en 1 excepto el 11. La categoría "two" incluye 2, 22, 32, 42 y todos los números que terminan en 2 excepto el 12.
Puedes verificar qué categorías utiliza un locale llamando al método resolvedOptions() y examinando la propiedad pluralCategories.
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const options = rules.resolvedOptions();
console.log(options.pluralCategories);
// Salida: ["one", "two", "few", "other"]
Esto muestra que los ordinales en inglés utilizan cuatro categorías. Otros locales utilizan diferentes conjuntos de categorías.
const rules = new Intl.PluralRules('fr-FR', { type: 'ordinal' });
const options = rules.resolvedOptions();
console.log(options.pluralCategories);
// Salida: ["one", "other"]
Los ordinales en francés solo distinguen entre one y other. Esta categorización más simple refleja las reglas de sufijos más simples en francés.
Formateando números ordinales para el locale del usuario
En lugar de codificar un locale específico, puedes utilizar el idioma preferido del usuario desde el navegador. La propiedad navigator.language devuelve la preferencia de idioma principal del usuario.
const userLocale = navigator.language;
const rules = new Intl.PluralRules(userLocale, { type: 'ordinal' });
const suffixes = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
};
function formatOrdinal(number) {
const category = rules.select(number);
const suffix = suffixes[category] || suffixes.other;
return `${number}${suffix}`;
}
console.log(formatOrdinal(1));
// La salida varía según el locale del usuario
Este enfoque se adapta automáticamente a la preferencia de idioma del usuario. Sin embargo, aún necesitas proporcionar mapeos de sufijos apropiados para cada locale que tu aplicación soporte.
Para locales sin mapeos de sufijos específicos, puedes recurrir a un comportamiento predeterminado o mostrar el número sin sufijo.
function formatOrdinal(number, locale = navigator.language) {
const rules = new Intl.PluralRules(locale, { type: 'ordinal' });
const category = rules.select(number);
const localeMapping = ordinalSuffixes[locale];
if (!localeMapping) {
return String(number);
}
const suffix = localeMapping[category] || localeMapping.other || '';
return `${number}${suffix}`;
}
Esta función devuelve solo el número cuando no existe un mapeo de sufijos para el locale.
Casos de uso comunes para números ordinales
Los números ordinales aparecen en varios contextos comunes en las interfaces de usuario. Comprender estos casos de uso te ayuda a decidir cuándo formatear números como ordinales.
Las clasificaciones y tablas de posiciones muestran las posiciones de los usuarios. Una aplicación de juegos muestra "1er lugar", "2do lugar", "3er lugar" en lugar de "lugar 1", "lugar 2", "lugar 3".
function formatRanking(position) {
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const category = rules.select(position);
const suffixes = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
};
const suffix = suffixes[category];
return `${position}${suffix} place`;
}
console.log(formatRanking(1));
// Output: "1st place"
console.log(formatRanking(42));
// Output: "42nd place"
El formato de fechas a veces utiliza ordinales para el día del mes. Algunos locales escriben "1ro de enero" en lugar de "1 de enero".
Las instrucciones paso a paso utilizan ordinales para numerar cada paso. Un tutorial muestra "1er paso: Instalar el software", "2do paso: Configurar ajustes", "3er paso: Iniciar la aplicación".
Los elementos de lista en secuencias largas se benefician del formato ordinal cuando enfatizar la posición importa más que solo la enumeración.
Reutilización de objetos de reglas para mejorar el rendimiento
Crear una nueva instancia de Intl.PluralRules implica cargar datos de localización y procesar opciones. Cuando formateas múltiples números ordinales con el mismo locale, crea el objeto de reglas una vez y reutilízalo.
const rules = new Intl.PluralRules('en-US', { type: 'ordinal' });
const suffixes = {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
};
function formatOrdinal(number) {
const category = rules.select(number);
const suffix = suffixes[category];
return `${number}${suffix}`;
}
const positions = [1, 2, 3, 4, 5];
positions.forEach(position => {
console.log(formatOrdinal(position));
});
// Output:
// "1st"
// "2nd"
// "3rd"
// "4th"
// "5th"
Este enfoque es más eficiente que crear un nuevo objeto de reglas para cada número. La diferencia de rendimiento se vuelve significativa cuando se formatean arrays con cientos o miles de valores.
También puedes crear una fábrica de formateadores que devuelva una función configurada para un locale específico.
function createOrdinalFormatter(locale, suffixMapping) {
const rules = new Intl.PluralRules(locale, { type: 'ordinal' });
return function(number) {
const category = rules.select(number);
const suffix = suffixMapping[category] || suffixMapping.other || '';
return `${number}${suffix}`;
};
}
const formatEnglishOrdinal = createOrdinalFormatter('en-US', {
one: 'st',
two: 'nd',
few: 'rd',
other: 'th'
});
console.log(formatEnglishOrdinal(1));
// Output: "1st"
console.log(formatEnglishOrdinal(2));
// Output: "2nd"
Este patrón encapsula el objeto de reglas y el mapeo de sufijos juntos, haciendo que el formateador sea fácil de reutilizar en toda tu aplicación.