CSS: text-transform not working properly for Turkish characters

Here's a quick and dirty workaround example - it's faster than I thought (tested in a document with 2400 tags -> no delay). But I see that js workarounds are not the very best 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>

The next version of Firefox Nightly (which should become Firefox 14) has a fix for this problem and should handle the case without any hack (as the CSS3 specs request it).

The gory details are available in that bug : https://bugzilla.mozilla.org/show_bug.cgi?id=231162

They also fixed the problem for font-variant I think (For those not knowing what font-variant does, see https://developer.mozilla.org/en/CSS/font-variant , not yet up-to-date with the change but the doc is browser-agnostic and a wiki, so...)


Here's my enhanced version of alex's code that I am using in 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);

Note that I am using jQuery here only for the ready() function. The jQuery compatibility wrapper is also as a convenient way to namespace the functions. Other than that, the two functions do not rely on jQuery at all, so you could pull them out.

Compared to alex's original version this one solves a couple problems:

  • It keeps track of the lang attribute as it recurses through, since if you have mixed Turkish and other latin content you will get improper transforms on the non-Turkish without it. Pursuant to this I pass in the base html element, not the body. You can stick lang="en" on any tag that is not Turkish to prevent improper capitalization.

  • It applies the transformation only to TEXT_NODES because the previous innerHTML method did not work with mixed text/element nodes such as labels with text and checkboxes inside them.

While having some notable deficiencies compared to a server side solution, it also has some major advantages, the chief of which is guaranteed coverage without the server-side having to be aware of what styles are applied to what content. If any of the content is being indexed and shown in Google summaries (for example) it is much better if it stays lowercase when served.


You can add lang attribute and set its value to tr to solve this:

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

Here is working example.