Греческий и преобразование текста: прописные буквы - PullRequest
12 голосов
/ 24 февраля 2012

Я написал веб-приложение, которое содержит переводы на несколько языков (один из них греческий.)

При отображении определенного перевода в заголовке, правило оформления заключалось в том, что текст должен быть прописным, что на любом другом языке в мире хорошо, но когда дело доходит до греческого, браузеры не знают, что делать с акцентами (см. это ), чтобы они отображали неправильную строку в верхнем регистре.

Из этого патча, который я связал выше, я преобразовал его в Javascript, запустил несколько вариантов использования, и он работает. Теперь все, что мне нужно сделать, это:

Без добавления класса uppercase к каждому элементу, который должен быть в верхнем регистре (их довольно много), могу ли я запросить DOM, используя свойство вычисляемого стиля? То есть. дайте мне все элементы, которые имеют вычисленный text-transform: uppercase

Ответы [ 7 ]

12 голосов
/ 08 ноября 2013

Решение этой проблемы описано в примере выше 3 здесь

Это пример , который должен работать в любом браузере (проверено только на Firefox 25)

HTML:

<body>
  <p id="withlang" lang="el">κεφαλαία με μετατροπή σύμφωνα με την γλώσσα</p>
  <p id="withoutlang">κεφαλαία με μετατροπή σύμφωνα με αντιστοιχίσεις unicode</p>
  <p id="withlangsmall" lang="el">μικρά κεφαλαία με μετατροπή σύμφωνα με την γλώσσα</p>
  <p id="withoutlangsmall">μικρά κεφαλαία με μετατροπή σύμφωνα με αντιστοιχίσεις unicode</p>
</body>

CSS:

#withlang, #withoutlang{
  text-transform: uppercase;
}

#withlangsmall, #withoutlangsmall{
  font-variant: small-caps;
}

Вы также можете использовать атрибут lang на более высоком уровне, например, в теге body.

HTML:

<body lang="el">
  <p id="withlang">κεφαλαία με μετατροπή σύμφωνα με την γλώσσα</p>
  <p id="withlangsmall">μικρά κεφαλαία με μετατροπή σύμφωνα με την γλώσσα</p>
</body>

CSS:

#withlang{
  text-transform: uppercase;
}

#withlangsmall{
  font-variant: small-caps;
}
11 голосов
/ 24 февраля 2012

Я настоятельно рекомендую не использовать jQuery для этого. Вместо этого сделайте это:

var e = document.getElementsByTagName('*'), l = e.length, i;
if( typeof getComputedStyle == "undefined")
    getComputedStyle = function(e) {return e.currentStyle;};
for( i=0; i<l; i++) {
    if( getComputedStyle(e[i]).textTransform == "uppercase") {
        // do stuff with e[i] here.
    }
}

Протестировано с 10 000 элементов, из которых 2500 имели преобразование текста в верхнем регистре.

JQuery обрабатывается за 595 мс
JS обработано в 60мс

Так что JavaScript примерно в 10 раз быстрее, чем jQuery.

РЕДАКТИРОВАТЬ: еще один тест, на этот раз с 100 000 элементов:

jQuery fail.TypeError: Объект не поддерживает свойство или метод 'each'
JS обработано за 577мс

4 голосов
/ 17 апреля 2012

Я использую эту функцию PHP:

function toUpper($str){
        $search = array('Ά', 'Έ', 'Ί', 'Ή', 'Ύ', 'Ό', 'Ώ');
        $replace = array('Α', 'Ε', 'Ι', 'Η', 'Υ', 'Ο', 'Ω');
        $str = mb_strtoupper($str,  "UTF-8");
        return str_replace($search, $replace, $str);
    }
3 голосов
/ 24 февраля 2012

ОК, просто для справки, вот мое решение:

GREEK_CHARS = {
  LOWER_ALPHA                : 0x03B1
  LOWER_ALPHA_ACC            : 0x03AC
  LOWER_EPSILON              : 0x03B5
  LOWER_EPSILON_ACC          : 0x03AD
  LOWER_ETA                  : 0x03B7
  LOWER_ETA_ACC              : 0x03AE
  LOWER_IOTA                 : 0x03B9
  LOWER_IOTA_ACC             : 0x03AF
  LOWER_IOTA_ACC_DIAERESIS   : 0x0390
  LOWER_OMICRON              : 0x03BF
  LOWER_OMICRON_ACC          : 0x03CC
  LOWER_UPSILON              : 0x03C5
  LOWER_UPSILON_ACC          : 0x03CD
  LOWER_UPSILON_ACC_DIAERESIS: 0x03B0
  LOWER_OMEGA_ACC            : 0x03CE
  UPPER_ALPHA                : 0x0391
  UPPER_EPSILON              : 0x0395
  UPPER_ETA                  : 0x0397
  UPPER_IOTA                 : 0x0399
  UPPER_IOTA_DIAERESIS       : 0x03AA
  UPPER_OMICRON              : 0x039F
  UPPER_UPSILON              : 0x03A5
  UPPER_UPSILON_DIAERESIS    : 0x03AB
  UPPER_OMEGA                : 0x03A9
  UPPER_ALPHA_ACC            : 0x0386
  UPPER_EPSILON_ACC          : 0x0388
  UPPER_ETA_ACC              : 0x0389
  UPPER_IOTA_ACC             : 0x038A
  UPPER_OMICRON_ACC          : 0x038C
  UPPER_UPSILON_ACC          : 0x038E
  UPPER_OMEGA_ACC            : 0x038F
  COMBINING_ACUTE_ACCENT           : 0x0301
  COMBINING_DIAERESIS              : 0x0308
  COMBINING_ACUTE_TONE_MARK        : 0x0341
  COMBINING_GREEK_DIALYTIKA_TONOS  : 0x0344
}

String::toUpperCaseWithoutGreek = String::toUpperCase
String::toUpperCase = ->
  newStringCharCodes  = []
  insideTag           = false
  for char, idx in this
    insideTag = true if char == '<'
    insideTag = false if char == '>'
    charCode      = char.charCodeAt(0)

    if insideTag
      newStringCharCodes.push charCode
      continue

    prev          = if idx > 0 then newStringCharCodes[idx-1] else GREEK_CHARS.UPPER_ALPHA
    prevPrev      = if idx > 1 then newStringCharCodes[idx-2] else GREEK_CHARS.UPPER_ALPHA
    prevPrevPrev  = if idx > 2 then newStringCharCodes[idx-3] else GREEK_CHARS.UPPER_ALPHA

    switch charCode
      when GREEK_CHARS.LOWER_ALPHA_ACC, GREEK_CHARS.UPPER_ALPHA_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_ALPHA
      when GREEK_CHARS.LOWER_EPSILON_ACC, GREEK_CHARS.UPPER_EPSILON_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_EPSILON
      when GREEK_CHARS.LOWER_ETA_ACC, GREEK_CHARS.UPPER_ETA_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_ETA
      when GREEK_CHARS.LOWER_IOTA_ACC, GREEK_CHARS.UPPER_IOTA_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_IOTA
      when GREEK_CHARS.LOWER_IOTA_ACC_DIAERESIS
        newStringCharCodes.push GREEK_CHARS.UPPER_IOTA_DIAERESIS
      when GREEK_CHARS.LOWER_OMICRON_ACC, GREEK_CHARS.UPPER_OMICRON_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_OMICRON
      when GREEK_CHARS.LOWER_UPSILON_ACC, GREEK_CHARS.UPPER_UPSILON_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_UPSILON
      when GREEK_CHARS.LOWER_UPSILON_ACC_DIAERESIS
        newStringCharCodes.push GREEK_CHARS.UPPER_UPSILON_DIAERESIS
      when GREEK_CHARS.LOWER_OMEGA_ACC, GREEK_CHARS.UPPER_OMEGA_ACC
        newStringCharCodes.push GREEK_CHARS.UPPER_OMEGA

      when GREEK_CHARS.LOWER_IOTA
        switch prev
          when GREEK_CHARS.LOWER_ALPHA_ACC, GREEK_CHARS.LOWER_EPSILON_ACC, GREEK_CHARS.LOWER_OMICRON_ACC
            newStringCharCodes.push GREEK_CHARS.UPPER_IOTA_DIAERESIS
          when GREEK_CHARS.LOWER_UPSILON_ACC
            if prevPrev == GREEK_CHARS.LOWER_OMICRON
              newStringCharCodes.push GREEK_CHARS.UPPER_IOTA
            else
              newStringCharCodes.push GREEK_CHARS.UPPER_IOTA_DIAERESIS
          when GREEK_CHARS.COMBINING_ACUTE_ACCENT, GREEK_CHARS.COMBINING_ACUTE_TONE_MARK
            switch prevPrev
              when GREEK_CHARS.LOWER_ALPHA, GREEK_CHARS.LOWER_EPSILON, GREEK_CHARS.LOWER_OMICRON
                newStringCharCodes.push GREEK_CHARS.UPPER_IOTA_DIAERESIS
              when GREEK_CHARS.LOWER_UPSILON
                if prevPrevPrev == GREEK_CHARS.LOWER_OMICRON
                  newStringCharCodes.push GREEK_CHARS.UPPER_IOTA
                else
                  newStringCharCodes.push GREEK_CHARS.UPPER_IOTA_DIAERESIS
              else
                newStringCharCodes.push GREEK_CHARS.UPPER_IOTA
          else
            newStringCharCodes.push GREEK_CHARS.UPPER_IOTA

      when GREEK_CHARS.LOWER_UPSILON
        switch prev
          when GREEK_CHARS.LOWER_ALPHA_ACC, GREEK_CHARS.LOWER_EPSILON_ACC, GREEK_CHARS.LOWER_ETA_ACC, GREEK_CHARS.LOWER_OMICRON_ACC
            newStringCharCodes.push GREEK_CHARS.UPPER_UPSILON_DIAERESIS
          when GREEK_CHARS.COMBINING_ACUTE_ACCENT, GREEK_CHARS.COMBINING_ACUTE_TONE_MARK
            switch prevPrev
              when GREEK_CHARS.LOWER_ALPHA, GREEK_CHARS.LOWER_EPSILON, GREEK_CHARS.LOWER_ETA, GREEK_CHARS.LOWER_OMICRON
                newStringCharCodes.push GREEK_CHARS.UPPER_UPSILON_DIAERESIS
              else
                newStringCharCodes.push GREEK_CHARS.UPPER_UPSILON
          else
            newStringCharCodes.push GREEK_CHARS.UPPER_UPSILON

      when GREEK_CHARS.COMBINING_GREEK_DIALYTIKA_TONOS
        newStringCharCodes.push GREEK_CHARS.COMBINING_DIAERESIS
      when GREEK_CHARS.COMBINING_ACUTE_ACCENT, GREEK_CHARS.COMBINING_ACUTE_TONE_MARK
        if prev < GREEK_CHARS.LOWER_OMEGA_ACC && prev > GREEK_CHARS.UPPER_ALPHA_ACC
          newStringCharCodes.push null
      else
        newStringCharCodes.push(String.fromCharCode(charCode).toUpperCaseWithoutGreek().charCodeAt(0))

  String.fromCharCode.apply(null, newStringCharCodes)

Это адаптация кофейного сценария из патча, представленного в сообщении об ошибке выше.

Вот что я делаю после отображения вида:

# Fix greek uppercase.
[].concat($('*').get()).filter((elm) ->
  window.getComputedStyle(elm).getPropertyValue('text-transform') == "uppercase";
).forEach((elm) ->
  if elm.value
    elm.value = elm.value.toUpperCase()
  else
    $elm = $(elm)
    $elm.html($elm.html().toUpperCase())
)

Это не очень приятно, по любому поводу, но это работает.

Две вещи, которые я не должен здесь делать, и которые могут измениться: угнать toUpperCase() и иметь определенные правила, чтобы не анализировать теги. Все еще открыты для лучших предложений!

1 голос
/ 20 января 2015

Мне нравится ответ Отово как самый элегантный и быстрый.Я бы, конечно, не рекомендовал сканировать все элементы на text-transform.Для больших страниц на мобильных устройствах заметна неэффективность в скорости.

Поэтому я бы рекомендовал просто записать все селекторы с text-transform из файлов CSS.Это должно быть возможно в большинстве случаев.Затем используйте jQuery непосредственно для этих селекторов.

Итак, чтобы расширить ответ Otovo, добавьте уникальный класс, например i18n-el для каждого языка, где-то как body (это значение по умолчанию для Drupal, но все аналогичное будет работать).Затем выполните:

$('.i18n-el').find('.all-relevant-selectors').attr('lang', 'el');

Очевидно, замените .all-relevant-selectors селекторами, которые вы отметили в файлах CSS, через запятую.

Также стоит упомянуть, что это работает только дляtext-transform: uppercase, а не font-variant: small-caps для Chrome 39.

Кроме того, для этого существует плагин jQuery под названием jquery-remove-upcase-accents , хотя я не оценивал его ввсе.

1 голос
/ 24 февраля 2012

Я могу заверить вас, что это касается не только греческого языка.У вас наверняка есть проблемы с немецкими Sharp S и турецкими буквами i .

. Я не совсем уверен, с какой целью использовались эти преобразования, но, пожалуйста, имейтеИмейте в виду, что многие языки написаны с использованием сценариев, которые не имеют понятия символов верхнего и нижнего регистра.Если вы используете это для выделения, я предлагаю полностью удалить все преобразования и просто написать часть текста в соответствующем регистре.Таким образом, переводчики могут решить, как подчеркнуть слово или предложение.

Кстати.Разрешить использование span элементов в переводах с определенным классом также может быть хорошей идеей - таким образом кто-то может использовать, например, цвет для разметки текста по-разному (хотя это не очень поможет дальтоникам).*

1 голос
/ 24 февраля 2012

Это не поможет с греческими символами, но мне было любопытно найти все элементы с данным свойством css. Я настроил это: http://jsfiddle.net/pQfUv/1/

Интересующий вас бит будет:

$('*').each(function() {
            if ($(this).css('text-transform') == 'uppercase') {
                //Do Stuff to the element
            }
        });

Цикл по всем элементам, вероятно, довольно дорогая вещь. Надеюсь, это поможет.

Ура, изо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...