CSS:text-transform对土耳其字符的工作不正常

60
主要浏览器实现似乎存在对土耳其字符使用text-transform: uppercase时的问题。据我所知(我不是土耳其人),有四个不同的字符:ı i I İ其中后两个是前两个的大写表示形式。
然而,将text-transform:uppercase应用于ı i,浏览器(检查了IE、Firefox、Chrome和Safari)会得出错误的结果I I,这是不正确的,可能会使单词的含义发生如此大的变化,以至于它们变成侮辱性的话语。(这就是我被告知的情况)
由于我的解决方案研究没有取得任何成果,所以我的问题是:是否有解决此问题的方法?第一个解决办法可能是完全删除text-transform: uppercase,但那是某种最后的手段。
有趣的是,W3C在其网站上进行了这个问题的测试,但缺乏关于这个问题的进一步信息。这是测试的链接:http://www.w3.org/International/tests/tests-html-css/tests-text-transform/generate?test=5 我感谢任何帮助,并期待您的答案 :-)
这里是一个 codepen

你可以展示一个实际的、嗯,不成功的例子吗? - Tim
当然,请查看http://malax.de/turkish-css-text-transform.html。 - Malax
链接不再有效,请知悉。 - ahmet alp balkan
7个回答

105

1
我遇到了麻烦。在桌面上,使用Chrome和Safari都能完美运行。但是iOS浏览器似乎忽略了这个标签。在移动版的Chrome和Safari上失败了,有什么想法吗? - gok
好的,显然,在iOS 7及以上版本存在问题,它可以在iOS 8及以上版本上运行。 - gok
是的,我刚在iOS 8上的Chrome和Safari上进行了测试,看起来没问题。 - Hkan
1
感谢@Barlas的编辑。最近我发现lang属性适用于任何元素,但我没有想到去编辑答案。 - Hkan
@Hkan,老兄,我之前也被这个 bug 挑战过很多次,这里有一个 JavaScript 的解决方案:http://stackoverflow.com/a/33856951/1428241 - Barlas Apaydin
应该授予这个答案。 - Melih

15

这是一个快速而简单的解决方案示例 - 它比我想象的要快(在一个包含2400个标签的文档中测试->没有延迟)。但我认为 JavaScript 解决方案并不是最好的解决方法。

<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>

我喜欢你的实现方式,它只是将整个内容转换为大写,而不是替换特定字符并依赖CSS,正如我所建议的那样。但是,我对你的递归替换和.innerHTML有一个问题,主要是因为我不太了解这个属性。如果我有嵌套元素<div id="a1"> <div id="a2"> contents</div></div>,并调用你的replaceRecursive(),那么id会变成大写吗?谢谢你帮我理解你的实现方式。 - Brian Stinar
5
您可能需要为 lang="tr" 添加测试,并且绝对不应该使用 for...in 遍历 NodeList 对象:https://developer.mozilla.org/En/DOM/NodeList。否则,+1。 - Yi Jiang
好的观点,Yi。另外,这种方法不能处理混合元素/文本子节点(例如,当一个标签包含一个输入框及其描述时)。我已经解决了所有这些问题,并有一个在生产中使用的解决方案,我将在另一个回复中分享。 - gtd

7

以下是我在生产环境中使用的alex代码的增强版本:

(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);

请注意,此处仅使用jQuery的ready()函数。jQuery兼容包装器也是命名空间函数的便捷方式。除此之外,这两个函数完全不依赖于jQuery,所以你可以把它们拿出来。
与alex的原始版本相比,此版本解决了几个问题:
  • 随着递归的进行,它跟踪语言属性,因为如果您混合使用土耳其和其他拉丁文内容,则非土耳其语将无法正确转换。根据此,我传递基本的html元素而不是body。您可以在任何不是土耳其语的标签上添加lang="en"以防止不当大写。
  • 它仅将变换应用于TEXT_NODES,因为先前的innerHTML方法无法处理混合文本/元素节点,例如带有文本和复选框的标签。
与服务器端解决方案相比,它有一些明显的缺陷,但也有一些重要的优点,其中最重要的是保证覆盖范围而不需要服务器端知道应该应用哪些样式到哪些内容。如果任何内容正在被索引并显示在Google总结中(例如),则最好在提供服务时保持小写。

1
谢谢你在我需要之前一年就问了这个问题 :) - gtd

4
下一个版本的Firefox Nightly(应该成为Firefox 14)已经解决了这个问题,并且应该可以在不进行任何hack的情况下处理此情况(正如CSS3规范所要求的那样)。 详细信息请参见该错误:https://bugzilla.mozilla.org/show_bug.cgi?id=231162 我认为他们也解决了font-variant的问题(对于不知道font-variant是什么的人,请参见https://developer.mozilla.org/en/CSS/font-variant,尚未更新到最新更改,但该文档与浏览器无关且是一个wiki,所以...)。

0

这个问题的根本原因必须是所有这些浏览器中使用的Unicode库对这些土耳其字符的处理不正确。因此,我怀疑前端方面没有解决方法。

有人必须向这些Unicode库的开发人员报告此问题,并且它将在几周/几个月内得到修复。


他们并没有处理不当,只是没有任何方式知道它应该是土耳其语。 - tdammers
几周/几个月?试试几年/几十年。我在Firefox和Safari中找到了这些问题的未解决漏洞:https://bugzilla.mozilla.org/show_bug.cgi?id=231162 https://bugs.webkit.org/show_bug.cgi?id=21312 - gtd
@tdammers 这就是 HTML 中 lang 属性和 HTTP 中 Content-Language 头的目的。 - gtd

0

如果您不能依赖于text-transform和浏览器,那么您将不得不在服务器上自己呈现大写文本(希望您不会在用户输入时将文本转换为大写)。 在这里,您应该有更好的国际化支持。


0

这个解决方法需要一些Javascript。如果您不想这样做,但是有一些服务器端可以预处理文本的内容,在那里也可以使用这个想法(我认为)。

首先,检测是否在土耳其运行。如果是,则扫描要大写的任何内容,以查看它是否包含问题字符。如果包含,将所有这些字符替换为它们的大写版本。然后应用大写CSS。由于问题字符已经大写,因此应该是一个完全合适的(贫民)解决方法。对于Javascript,我设想需要在受影响的元素上处理一些.innerHTML。

如果您需要任何实现细节,请告诉我,我有一个很好的想法,可以使用Javascript字符串操作方法来完成此操作。这个通用的想法应该能够让您走得更远(并希望为我赢得奖励!)

- Brian J. Stinar -


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接