web-dev-qa-db-fra.com

CSS: la transformation de texte ne fonctionne pas correctement pour les caractères turcs

Les implémentations des principaux navigateurs semblent avoir des problèmes avec text-transform: uppercase avec des caractères turcs. Autant que je sache (je ne suis pas turc.), Il y a quatre caractères i différents: ı i I İ où les deux derniers sont les représentations majuscules des deux premiers.

Cependant, en appliquant text-transform:uppercase à ı i, les navigateurs (cochés IE, Firefox, Chrome et Safari) donnent I I ce qui n'est pas correct et peut changer le sens des mots à tel point qu'ils deviennent des insultes. (C'est ce qu'on m'a dit)

Comme ma recherche de solutions n'en a révélé aucune, ma question est la suivante: existe-t-il des solutions de contournement pour ce problème? La première solution de contournement pourrait être de supprimer text-transform: uppercase entièrement, mais c'est une sorte de dernier recours.

Chose amusante, le W3C a des tests pour ce problème sur leur site, mais manque d'informations supplémentaires sur ce problème. http://www.w3.org/International/tests/tests-html-css/tests-text-transform/generate?test=5

J'apprécie toute aide et j'attends avec impatience vos réponses :-)

Voici un codepen

51
Malax

Vous pouvez ajouter l'attribut lang et définir sa valeur sur tr pour résoudre ce problème:

<html lang="tr"> ou <div lang="tr">

Voici un exemple de travail.

76
Hkan

Voici un exemple de solution de contournement rapide et sale - c'est plus rapide que je ne le pensais (testé dans un document avec 2400 balises -> pas de retard). Mais je vois que les solutions de contournement js ne sont pas la meilleure solution

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-3">
</head>
<body>
<div style="text-transform:uppercase">a b c ç d e f g ğ h ı i j k l m n o ö p r s ş t u ü v y z (source)</div> <div>A B C Ç D E F G Ğ H I İ J K L M N O Ö P R S Ş T U Ü V Y Z (should be like this)</div>

<script>
    function getStyle(element, style) {
        var result;

        if (document.defaultView && document.defaultView.getComputedStyle) {
            result = document.defaultView.getComputedStyle(element, '').getPropertyValue(style);
        } else if(element.currentStyle) {
            style = style.replace(/\-(\w)/g, function (strMatch, p1) {
                return p1.toUpperCase();
            });
            result = element.currentStyle[style];
        }
        return result;
    }

    function replaceRecursive(element) {
        if (element && element.style && getStyle(element, 'text-transform') == 'uppercase') {
            element.innerHTML = element.innerHTML.replace(/ı/g, 'I');
            element.innerHTML = element.innerHTML.replace(/i/g, 'İ');    // replaces 'i' in tags too, regular expression should be extended if necessary
        }

        if (!element.childNodes || element.childNodes.length == 0) return;

        for (var n in element.childNodes) {
            replaceRecursive(element.childNodes[n]);
        }
    }

    window.onload = function() {    // as appropriate 'ondomready'
        alert('before...');
        replaceRecursive(document.getElementsByTagName('body')[0]);
        alert('...after');
    }
</script>

</body>
</html>
15
alex

Voici ma version améliorée du code d'Alex que j'utilise en production:

(function($) {
  function getStyle(element, style) {
    var result;

    if (document.defaultView && document.defaultView.getComputedStyle) {
      result = document.defaultView.getComputedStyle(element, '').getPropertyValue(style);
    } else if(element.currentStyle) {
      style = style.replace(/\-(\w)/g, function (strMatch, p1) {
        return p1.toUpperCase();
      });
      result = element.currentStyle[style];
    }
    return result;
  }

  function replaceRecursive(element, lang) {
    if(element.lang) {
      lang = element.lang; // Maintain language context
    }

    if (element && element.style && getStyle(element, 'text-transform') == 'uppercase') {
      if (lang == 'tr' && element.value) {
        element.value = element.value.replace(/ı/g, 'I');
        element.value = element.value.replace(/i/g, 'İ');
      }

      for (var i = 0; i < element.childNodes.length; ++i) {
        if (lang == 'tr' && element.childNodes[i].nodeType == Node.TEXT_NODE) {
          element.childNodes[i].textContent = element.childNodes[i].textContent.replace(/ı/g, 'I');
          element.childNodes[i].textContent = element.childNodes[i].textContent.replace(/i/g, 'İ');
        } else {
          replaceRecursive(element.childNodes[i], lang);
        }
      }
    } else {
      if (!element.childNodes || element.childNodes.length == 0) return;

      for (var i = 0; i < element.childNodes.length; ++i) {
        replaceRecursive(element.childNodes[i], lang);
      }
    }
  }

  $(document).ready(function(){ replaceRecursive(document.getElementsByTagName('html')[0], ''); })
})(jQuery);

Notez que j'utilise jQuery ici uniquement pour la fonction ready(). L'encapsuleur de compatibilité jQuery est également un moyen pratique pour l'espace de noms des fonctions. À part cela, les deux fonctions ne reposent pas du tout sur jQuery, vous pouvez donc les extraire.

Par rapport à la version originale d'Alex, celle-ci résout quelques problèmes:

  • Il garde la trace de l'attribut lang au fur et à mesure qu'il se répète, car si vous avez mélangé du turc et d'autres contenus latins, vous obtiendrez des transformations incorrectes sur le non-turc sans lui. En conséquence, je passe l'élément de base html, pas le body. Vous pouvez coller lang="en" Sur n'importe quelle balise qui n'est pas turque pour éviter une casse incorrecte.

  • Elle applique la transformation uniquement à TEXT_NODES Car la méthode innerHTML précédente ne fonctionnait pas avec des nœuds de texte/élément mixtes tels que des étiquettes contenant du texte et des cases à cocher.

Tout en présentant des lacunes notables par rapport à une solution côté serveur, elle présente également des avantages majeurs, dont le principal est une couverture garantie sans que le côté serveur n'ait à savoir quels styles sont appliqués à quel contenu. Si l'un des contenus est indexé et affiché dans les résumés Google (par exemple), il est préférable qu'il reste en minuscules lorsqu'il est diffusé.

7
gtd

La prochaine version de Firefox Nightly (qui devrait devenir Firefox 14) a un correctif pour ce problème et devrait gérer le cas sans aucun hack (comme le demandent les spécifications CSS3).

Les détails sanglants sont disponibles dans ce bogue: https://bugzilla.mozilla.org/show_bug.cgi?id=231162

Ils ont également résolu le problème de font-variant je pense (Pour ceux qui ne savent pas ce que font-variant fait, voir https://developer.mozilla.org/en/CSS/font-variant , pas encore à jour avec le changement mais le document est indépendant du navigateur et un wiki, donc ...)

4
teoli

Cette solution de contournement nécessite du Javascript. Si vous ne voulez pas faire cela, mais que vous avez quelque chose côté serveur qui peut prétraiter le texte, cette idée fonctionnera là aussi (je pense).

Tout d'abord, détectez si vous utilisez le turc. Si c'est le cas, scannez ce que vous allez mettre en majuscules pour voir s'il contient les caractères problématiques. Si tel est le cas, remplacez tous ces caractères par leur version majuscule. Ensuite, appliquez le CSS majuscule. Puisque les caractères problématiques sont déjà en majuscules, cela devrait être une solution (ghetto) totalement correcte. Pour Javascript, j'imagine devoir gérer du .innerHTML sur vos éléments impactés.

Faites-moi savoir si vous avez besoin de détails d'implémentation, j'ai une bonne idée de la façon de le faire en Javascript en utilisant les méthodes de manipulation de chaînes Javascript. Cette idée générale devrait vous aider à y arriver (et j'espère que vous me rapporterez une prime!)

-Brian J. Stinar-

0
Brian Stinar

Si vous ne pouvez pas vous fier à la transformation de texte et aux navigateurs, vous devrez vous-même rendre votre texte en majuscules sur le serveur (j'espère que vous ne mettez pas le texte en majuscule lorsque l'utilisateur le tape). Vous devriez avoir un meilleur support pour l'internationalisation là-bas.

0
Jakub Konecki

La cause première de ce problème doit être une gestion incorrecte de ces caractères turcs par la bibliothèque Unicode utilisée dans tous ces navigateurs. Je doute donc qu'il y ait une solution frontale pour cela.

Quelqu'un doit signaler ce problème aux développeurs de ces bibliothèques Unicode, et il serait résolu dans quelques semaines/mois.

0
BarsMonster