Cómo formatear números ordinales como 1.º, 2.º, 3.º
Usa JavaScript para mostrar números ordinales con sufijos y formato apropiados para cada configuración regional
Introducción
Los números ordinales indican posición o rango en una secuencia. En español, se escribe 1.º, 2.º, 3.º, 4.º para describir posiciones de llegada 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 codificas sufijos ordinales en inglés de forma fija, asumes 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 configuración regional.
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 recuentos de objetos. Uno, dos, tres describen cantidades.
El mismo valor numérico cumple ambos propósitos dependiendo del contexto. El número 5 es cardinal en "5 manzanas" pero ordinal en "5.º lugar". La distinción importa porque muchos idiomas formatean los ordinales de manera diferente a los cardinales.
En inglés, los ordinales menores de 10 tienen formas de palabra únicas. First, second, third, fourth, fifth son palabras distintas. Por encima de 10, el inglés forma ordinales añadiendo sufijos. Eleventh, twelfth, twentieth, twenty-first siguen patrones pero requieren sufijos.
Al escribir ordinales como números en lugar de palabras, el inglés añade los sufijos st, nd, rd o th. Estos sufijos siguen reglas específicas basadas en los últimos dígitos del número.
Por qué el formato de ordinales varía según el locale
Diferentes idiomas desarrollaron sistemas distintos 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 usan cuatro sufijos diferentes. Los números que terminan en 1 usan st, los que terminan en 2 usan nd, los 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 todos usan th. Esto crea 1st, 2nd, 3rd, 4th, 11th, 12th, 13th, 21st, 22nd, 23rd.
En francés, los ordinales usan 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 usan un punto después del número. La notación 1., 2., 3. representa primero, segundo, tercero. Este punto indica que el lector debe añadir mentalmente la terminación gramatical apropiada al leer en voz alta.
En español, los ordinales usan 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 añaden 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 personas que esperan formatos diferentes.
Entender 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. Aunque 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 del 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));
// Output: "one"
console.log(rules.select(2));
// Output: "two"
console.log(rules.select(3));
// Output: "few"
console.log(rules.select(4));
// Output: "other"
Las categorías devueltas son términos lingüísticos, no los sufijos reales. La categoría "one" corresponde a números que llevan 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.
Mapeas estos nombres de categoría 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.
Construir una función formateadora de ordinales
Para formatear números ordinales, combinas 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 de pluralización 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 de plural 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 permanecen iguales, 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.
Entendiendo las categorías de plural ordinal
La API Intl.PluralRules utiliza seis posibles nombres de categoría. Diferentes locales usan 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 usan solo cuatro: one, two, few y other.
Los nombres de las categorías no se corresponden directamente con los valores numéricos. La categoría "one" incluye 1, 21, 31, 41 y todos los números que terminan en 1 excepto 11. La categoría "two" incluye 2, 22, 32, 42 y todos los números que terminan en 2 excepto 12.
Puedes verificar qué categorías usa 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);
// Output: ["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);
// Output: ["one", "other"]
Los ordinales en francés solo distinguen entre uno y otros. 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 usar 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));
// Output varies by user's locale
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.
Los rankings y tablas de clasificación muestran las posiciones de los usuarios. Una aplicación de juegos muestra "1.º lugar", "2.º lugar", "3.º 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 "1 de enero" en lugar de "enero 1".
Las instrucciones paso a paso utilizan ordinales para numerar cada paso. Un tutorial muestra "1.º paso: instalar el software", "2.º paso: configurar ajustes", "3.º 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.
Reutilizando objetos de reglas para rendimiento
Crear una nueva instancia de Intl.PluralRules implica cargar datos de configuración regional y procesar opciones. Cuando formateas múltiples números ordinales con la misma configuración regional, 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 al formatear arrays con cientos o miles de valores.
También puedes crear una factoría de formateadores que devuelva una función configurada para una configuración regional específica.
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.