¿Cómo muestro nombres de scripts como latino, cirílico, árabe?

Usa Intl.DisplayNames para convertir códigos de scripts en nombres legibles de sistemas de escritura en cualquier idioma.

Introducción

Un script es un sistema de escritura. El latino es el script utilizado para inglés, francés y español. El cirílico es el script utilizado para ruso, búlgaro y ucraniano. El árabe es el script utilizado para árabe, persa y urdu. Los scripts difieren de los idiomas porque el mismo idioma puede escribirse en múltiples scripts. El serbio utiliza tanto el script cirílico como el latino. Los usuarios en Serbia eligen qué script prefieren.

Cuando construyes selectores de idioma, selectores de fuentes o controles de entrada de texto, necesitas mostrar nombres de scripts para que los usuarios puedan identificar los sistemas de escritura. La API Intl.DisplayNames convierte códigos de scripts en nombres localizados y legibles sin requerir que mantengas tablas de traducción.

Entendiendo scripts e idiomas

Los scripts y los idiomas no son lo mismo. Un idioma es lo que la gente habla. Un script es cómo la gente lo escribe.

El inglés es un idioma. El latino es un script. El inglés utiliza el script latino, pero también lo hacen docenas de otros idiomas incluyendo español, francés, alemán, vietnamita y turco.

El serbio es un idioma que puede escribirse en dos scripts. El serbio escrito en cirílico se ve como "Српски". El serbio escrito en latino se ve como "Srpski". Ambos representan el mismo idioma con las mismas palabras y gramática. La diferencia es solo el sistema de escritura.

El chino tiene dos variantes de script comunes. El chino simplificado utiliza caracteres han simplificados. El chino tradicional utiliza caracteres han tradicionales. La misma oración aparece de manera diferente dependiendo de qué script uses.

Esta distinción importa al construir interfaces. Un usuario serbio podría preferir texto en cirílico sobre texto en latino. Un usuario chino necesita elegir entre caracteres simplificados y tradicionales. Tu interfaz necesita mostrar nombres de scripts para que los usuarios puedan hacer estas elecciones.

El problema de codificar nombres de scripts de forma fija

Puedes crear una tabla de búsqueda que mapee códigos de script a nombres de scripts.

const scriptNames = {
  Latn: "Latin",
  Cyrl: "Cyrillic",
  Arab: "Arabic",
  Hans: "Simplified Chinese",
  Hant: "Traditional Chinese"
};

console.log(scriptNames.Latn);
// "Latin"

Este enfoque solo funciona para hablantes de inglés. Los usuarios que hablan otros idiomas ven nombres de scripts en inglés que pueden no entender. Necesitas traducciones para cada idioma que soportes.

const scriptNames = {
  en: {
    Latn: "Latin",
    Cyrl: "Cyrillic",
    Arab: "Arabic"
  },
  es: {
    Latn: "latino",
    Cyrl: "cirílico",
    Arab: "árabe"
  },
  fr: {
    Latn: "latin",
    Cyrl: "cyrillique",
    Arab: "arabe"
  }
};

Esto se vuelve inmanejable rápidamente. Cada nuevo idioma requiere un conjunto completo de traducciones. Cada nuevo script requiere entradas en cada idioma. Necesitas una mejor solución.

Usando Intl.DisplayNames para obtener nombres de scripts

El constructor Intl.DisplayNames crea un formateador que convierte códigos de script en nombres legibles. Especificas una localización y estableces el tipo en "script".

const names = new Intl.DisplayNames(["en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"

El primer argumento es un array de identificadores de localización. El segundo argumento es un objeto de opciones donde type: "script" indica al formateador que quieres nombres de scripts. El método of() toma un código de script y devuelve su nombre.

Los códigos de script siguen el estándar ISO 15924. Cada script tiene un código de cuatro letras con la primera letra en mayúscula y las tres letras restantes en minúscula. Latino es Latn. Cirílico es Cyrl. Árabe es Arab.

const names = new Intl.DisplayNames(["en"], { type: "script" });

console.log(names.of("Latn"));
// "Latin"

console.log(names.of("Cyrl"));
// "Cyrillic"

console.log(names.of("Arab"));
// "Arabic"

console.log(names.of("Hani"));
// "Han"

console.log(names.of("Hira"));
// "Hiragana"

console.log(names.of("Kana"));
// "Katakana"

El formateador maneja toda la complejidad de mantener las traducciones de nombres de scripts. Solo necesitas proporcionar el código de script.

Códigos de script comunes

El estándar ISO 15924 define códigos para más de 160 scripts. Estos son los códigos más comúnmente utilizados.

const names = new Intl.DisplayNames(["en"], { type: "script" });

console.log(names.of("Latn"));
// "Latin"

console.log(names.of("Cyrl"));
// "Cyrillic"

console.log(names.of("Arab"));
// "Arabic"

console.log(names.of("Hebr"));
// "Hebrew"

console.log(names.of("Deva"));
// "Devanagari"

console.log(names.of("Thai"));
// "Thai"

console.log(names.of("Hani"));
// "Han"

console.log(names.of("Hans"));
// "Simplified Han"

console.log(names.of("Hant"));
// "Traditional Han"

console.log(names.of("Hang"));
// "Hangul"

console.log(names.of("Hira"));
// "Hiragana"

console.log(names.of("Kana"));
// "Katakana"

console.log(names.of("Beng"));
// "Bengali"

console.log(names.of("Grek"));
// "Greek"

El latino cubre la mayoría de los idiomas de Europa occidental. El cirílico cubre el ruso, búlgaro, ucraniano y otros idiomas eslavos. El árabe cubre el árabe, persa y urdu. El han cubre el chino, con hans para el chino simplificado y hant para el chino tradicional. El hangul cubre el coreano. El hiragana y katakana son scripts japoneses.

Mostrando nombres de scripts en diferentes locales

Los nombres de scripts se localizan según el locale de visualización. Crea formateadores con diferentes locales para ver los nombres en diferentes idiomas.

const enNames = new Intl.DisplayNames(["en"], { type: "script" });
const esNames = new Intl.DisplayNames(["es"], { type: "script" });
const frNames = new Intl.DisplayNames(["fr"], { type: "script" });
const jaNames = new Intl.DisplayNames(["ja"], { type: "script" });

console.log(enNames.of("Latn"));
// "Latin"

console.log(esNames.of("Latn"));
// "latino"

console.log(frNames.of("Latn"));
// "latin"

console.log(jaNames.of("Latn"));
// "ラテン文字"

Cada formateador devuelve el nombre del script en su locale de visualización. Esto maneja toda la complejidad de mantener las traducciones de nombres de scripts.

El mismo patrón funciona para cualquier código de script.

const enNames = new Intl.DisplayNames(["en"], { type: "script" });
const deNames = new Intl.DisplayNames(["de"], { type: "script" });
const zhNames = new Intl.DisplayNames(["zh"], { type: "script" });

console.log(enNames.of("Cyrl"));
// "Cyrillic"

console.log(deNames.of("Cyrl"));
// "Kyrillisch"

console.log(zhNames.of("Cyrl"));
// "西里尔文"

console.log(enNames.of("Arab"));
// "Arabic"

console.log(deNames.of("Arab"));
// "Arabisch"

console.log(zhNames.of("Arab"));
// "阿拉伯文"

El formateador aplica automáticamente las convenciones lingüísticas correctas para cada idioma.

Construyendo un selector de scripts para variantes de idioma

Algunos idiomas ofrecen a los usuarios una elección de scripts. El serbio puede escribirse en cirílico o latino. El chino puede escribirse en caracteres simplificados o tradicionales. Necesitas mostrar estas opciones para que los usuarios puedan elegir.

function getScriptOptions(language, userLocale) {
  const names = new Intl.DisplayNames([userLocale], { type: "script" });

  if (language === "sr") {
    return [
      { code: "Cyrl", name: names.of("Cyrl") },
      { code: "Latn", name: names.of("Latn") }
    ];
  }

  if (language === "zh") {
    return [
      { code: "Hans", name: names.of("Hans") },
      { code: "Hant", name: names.of("Hant") }
    ];
  }

  return [];
}

console.log(getScriptOptions("sr", "en"));
// [
//   { code: "Cyrl", name: "Cyrillic" },
//   { code: "Latn", name: "Latin" }
// ]

console.log(getScriptOptions("zh", "en"));
// [
//   { code: "Hans", name: "Simplified Han" },
//   { code: "Hant", name: "Traditional Han" }
// ]

console.log(getScriptOptions("zh", "es"));
// [
//   { code: "Hans", name: "han simplificado" },
//   { code: "Hant", name: "han tradicional" }
// ]

Esta función devuelve opciones de script en el idioma de interfaz del usuario. Los usuarios serbios ven opciones para scripts cirílico y latino. Los usuarios chinos ven opciones para scripts simplificado y tradicional. Los nombres aparecen en el idioma que el usuario entiende.

Mostrando identificadores de locale completos con información de script

Los identificadores de locale pueden incluir códigos de script para distinguir entre sistemas de escritura. El formato es language-script-region, como sr-Cyrl-RS para serbio escrito en cirílico en Serbia o zh-Hans-CN para chino simplificado en China.

Cuando muestres estos identificadores de locale, extrae el código de script y conviértelo en un nombre legible.

function parseLocaleWithScript(locale) {
  const parts = locale.split("-");

  if (parts.length < 2) {
    return null;
  }

  const [language, script] = parts;

  if (script.length === 4) {
    return {
      language,
      script: script.charAt(0).toUpperCase() + script.slice(1).toLowerCase()
    };
  }

  return null;
}

function formatLocaleWithScriptName(locale, displayLocale) {
  const parsed = parseLocaleWithScript(locale);

  if (!parsed) {
    return locale;
  }

  const languageNames = new Intl.DisplayNames([displayLocale], {
    type: "language"
  });
  const scriptNames = new Intl.DisplayNames([displayLocale], { type: "script" });

  const languageName = languageNames.of(parsed.language);
  const scriptName = scriptNames.of(parsed.script);

  return `${languageName} (${scriptName})`;
}

console.log(formatLocaleWithScriptName("sr-Cyrl", "en"));
// "Serbian (Cyrillic)"

console.log(formatLocaleWithScriptName("sr-Latn", "en"));
// "Serbian (Latin)"

console.log(formatLocaleWithScriptName("zh-Hans", "en"));
// "Chinese (Simplified Han)"

console.log(formatLocaleWithScriptName("zh-Hant", "en"));
// "Chinese (Traditional Han)"

console.log(formatLocaleWithScriptName("sr-Cyrl", "es"));
// "serbio (cirílico)"

Este patrón hace que los identificadores de locale sean legibles para humanos al combinar nombres de idiomas con nombres de scripts. Los usuarios ven "serbio (cirílico)" en lugar de "sr-Cyrl".

Crear un selector de fuentes con nombres de sistemas de escritura

Las interfaces de selección de fuentes a menudo agrupan las fuentes por los sistemas de escritura que admiten. Necesitas mostrar los nombres de los sistemas de escritura para que los usuarios comprendan qué sistemas cubre cada fuente.

function createFontOptions() {
  const fonts = [
    {
      name: "Arial",
      scripts: ["Latn", "Cyrl", "Grek", "Hebr", "Arab"]
    },
    {
      name: "Noto Sans CJK",
      scripts: ["Hans", "Hant", "Hira", "Kana", "Hang"]
    },
    {
      name: "Noto Sans Devanagari",
      scripts: ["Deva"]
    }
  ];

  const names = new Intl.DisplayNames(["en"], { type: "script" });

  return fonts.map((font) => ({
    name: font.name,
    scripts: font.scripts.map((code) => names.of(code))
  }));
}

console.log(createFontOptions());
// [
//   {
//     name: "Arial",
//     scripts: ["Latin", "Cyrillic", "Greek", "Hebrew", "Arabic"]
//   },
//   {
//     name: "Noto Sans CJK",
//     scripts: ["Simplified Han", "Traditional Han", "Hiragana", "Katakana", "Hangul"]
//   },
//   {
//     name: "Noto Sans Devanagari",
//     scripts: ["Devanagari"]
//   }
// ]

Esto crea una lista de fuentes con sus sistemas de escritura admitidos en forma legible. Los usuarios pueden elegir fuentes según los sistemas de escritura que necesiten.

Mostrar métodos de entrada disponibles por sistema de escritura

Los sistemas operativos y navegadores proporcionan métodos de entrada para diferentes sistemas de escritura. Un método de entrada japonés convierte caracteres latinos en hiragana, katakana o kanji. Un método de entrada chino convierte pinyin en caracteres chinos simplificados o tradicionales. Puedes mostrar los métodos de entrada disponibles con sus nombres de sistema de escritura.

function getInputMethods(userLocale) {
  const inputMethods = [
    { id: "latin-ime", script: "Latn" },
    { id: "japanese-ime", script: "Hira" },
    { id: "chinese-pinyin-simplified", script: "Hans" },
    { id: "chinese-pinyin-traditional", script: "Hant" },
    { id: "korean-ime", script: "Hang" },
    { id: "arabic-ime", script: "Arab" },
    { id: "hebrew-ime", script: "Hebr" }
  ];

  const names = new Intl.DisplayNames([userLocale], { type: "script" });

  return inputMethods.map((method) => ({
    id: method.id,
    name: names.of(method.script)
  }));
}

console.log(getInputMethods("en"));
// [
//   { id: "latin-ime", name: "Latin" },
//   { id: "japanese-ime", name: "Hiragana" },
//   { id: "chinese-pinyin-simplified", name: "Simplified Han" },
//   { id: "chinese-pinyin-traditional", name: "Traditional Han" },
//   { id: "korean-ime", name: "Hangul" },
//   { id: "arabic-ime", name: "Arabic" },
//   { id: "hebrew-ime", name: "Hebrew" }
// ]

console.log(getInputMethods("ja"));
// [
//   { id: "latin-ime", name: "ラテン文字" },
//   { id: "japanese-ime", name: "ひらがな" },
//   { id: "chinese-pinyin-simplified", name: "簡体字" },
//   { id: "chinese-pinyin-traditional", name: "繁体字" },
//   { id: "korean-ime", name: "ハングル" },
//   { id: "arabic-ime", name: "アラビア文字" },
//   { id: "hebrew-ime", name: "ヘブライ文字" }
// ]

Esto muestra los nombres de los métodos de entrada en el idioma del usuario. Los usuarios ven "Hiragana" cuando la interfaz está en inglés e "ひらがな" cuando la interfaz está en japonés.

Comprender el uso de mayúsculas en los códigos de sistema de escritura

Los códigos de sistema de escritura siguen un patrón específico de uso de mayúsculas. La primera letra es mayúscula. Las tres letras restantes son minúsculas. Latn es correcto. LATN, latn y LaTn no son estándar.

El método of() acepta códigos de sistema de escritura independientemente del uso de mayúsculas.

const names = new Intl.DisplayNames(["en"], { type: "script" });

console.log(names.of("Latn"));
// "Latin"

console.log(names.of("LATN"));
// "Latin"

console.log(names.of("latn"));
// "Latin"

console.log(names.of("LaTn"));
// "Latin"

El formateador maneja todas las variaciones correctamente. Sin embargo, usar el patrón de mayúsculas estándar hace que tu código sea más legible y coherente con el estándar ISO 15924.

Gestionar localizaciones de respaldo

El constructor Intl.DisplayNames acepta un array de localizaciones. Si la primera localización no está disponible, el formateador recurre a la siguiente localización del array.

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"

El formateador intenta primero "xx-XX", que no existe, y luego recurre a "en". Esto garantiza que tu código funcione incluso cuando la localización solicitada no esté disponible.

Puedes verificar qué localización utiliza realmente el formateador con el método resolvedOptions().

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "script" });
console.log(names.resolvedOptions().locale);
// "en"

Esto muestra que el formateador se resolvió a inglés después del fallback.

Construcción de un sistema de gestión de contenido multilingüe

Los sistemas de gestión de contenido que admiten múltiples escrituras necesitan mostrar qué escrituras están disponibles para cada pieza de contenido. Puedes mostrar los nombres de las escrituras para ayudar a los editores de contenido a elegir la versión correcta.

function getContentVersions(contentId, userLocale) {
  const versions = [
    { script: "Latn", url: `/content/${contentId}/latn` },
    { script: "Cyrl", url: `/content/${contentId}/cyrl` },
    { script: "Arab", url: `/content/${contentId}/arab` }
  ];

  const names = new Intl.DisplayNames([userLocale], { type: "script" });

  return versions.map((version) => ({
    script: version.script,
    name: names.of(version.script),
    url: version.url
  }));
}

console.log(getContentVersions("article-123", "en"));
// [
//   { script: "Latn", name: "Latin", url: "/content/article-123/latn" },
//   { script: "Cyrl", name: "Cyrillic", url: "/content/article-123/cyrl" },
//   { script: "Arab", name: "Arabic", url: "/content/article-123/arab" }
// ]

Este patrón ayuda a los editores de contenido a ver qué versiones de escritura existen y navegar entre ellas.

Compatibilidad con navegadores

La API Intl.DisplayNames con soporte de tipo de escritura está disponible en todos los navegadores modernos. Ha sido compatible desde marzo de 2021 en los principales navegadores, incluyendo Chrome, Firefox, Safari y Edge.

Puedes verificar si la API está disponible antes de usarla.

if (typeof Intl.DisplayNames !== "undefined") {
  const names = new Intl.DisplayNames(["en"], { type: "script" });
  console.log(names.of("Latn"));
} else {
  console.log("Intl.DisplayNames is not supported");
}

Para navegadores más antiguos, necesitas proporcionar un fallback o usar un polyfill. Un fallback simple utiliza un mapeo codificado de códigos de escritura a nombres.

function getScriptName(code, locale) {
  if (typeof Intl.DisplayNames !== "undefined") {
    const names = new Intl.DisplayNames([locale], { type: "script" });
    return names.of(code);
  }

  const fallbackNames = {
    Latn: "Latin",
    Cyrl: "Cyrillic",
    Arab: "Arabic",
    Hans: "Simplified Han",
    Hant: "Traditional Han"
  };

  return fallbackNames[code] || code;
}

console.log(getScriptName("Latn", "en"));
// "Latin"

Esto asegura que tu código funcione incluso en navegadores sin soporte de Intl.DisplayNames, aunque pierdes las funciones de localización automática.