Греческое и текстовое преобразование: в верхнем регистре
Я написал веб-приложение, которое содержит переводы на нескольких языках (один из которых является греческим.)
При отображении определенного перевода в заголовке правило проектирования заключалось в том, что текст должен быть верхний, что на любом другом языке в мире в порядке, но когда дело доходит до греческого языка, браузеры не знают, что сделайте с акцентами (см. this), чтобы они отображали неверную строчку сверху.
Из этого патча, который я связал выше, я преобразовал его в Javascript, использовал некоторые варианты использования, и он работает. Теперь все, что я должен сделать, это следующее:
Без добавления класса uppercase
для каждого элемента, который должен быть в верхнем регистре (их довольно много), могу ли я запросить DOM
с помощью свойства вычисленного стиля? То есть. дайте мне все элементы, которые имеют вычисленный text-transform: uppercase
Ответы
Ответ 1
Я настоятельно рекомендую не использовать 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 в 595ms
JS обрабатывается в 60 мс
Итак, JavaScript примерно в 10 раз быстрее, чем jQuery.
EDIT: Еще одно испытание, на этот раз с 100 000 элементов:
jQuery failed.TypeError: объект не поддерживает свойство или метод "каждый"
JS обработано в 577 мс
Ответ 2
Решение этой проблемы описано выше примера 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;
}
Ответ 3
ОК, только для справки, вот мое решение:
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)
Это адаптация кофе script из патча, поставляемого в ошибке выше.
Вот то, что я делаю после просмотра:
# 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())
)
Это не очень приятно, по какой-то части воображения, но оно работает.
Две вещи, которые мне не следует делать здесь, и могут измениться: hijack toUpperCase()
и иметь специальные правила, чтобы не анализировать теги. Все еще открыты для лучших предложений!
Ответ 4
Я использую эту функцию PHP:
function toUpper($str){
$search = array('Ά', 'Έ', 'Ί', 'Ή', 'Ύ', 'Ό', 'Ώ');
$replace = array('Α', 'Ε', 'Ι', 'Η', 'Υ', 'Ο', 'Ω');
$str = mb_strtoupper($str, "UTF-8");
return str_replace($search, $replace, $str);
}
Ответ 5
Это не поможет греческим символам, но мне было любопытно найти все элементы с заданным свойством css.
Я установил это: http://jsfiddle.net/pQfUv/1/
Бит, который вас интересует, будет следующим:
$('*').each(function() {
if ($(this).css('text-transform') == 'uppercase') {
//Do Stuff to the element
}
});
Проникновение через все элементы, вероятно, довольно дорогое дело.
Надеюсь, что это поможет.
Cheers,
изо
Ответ 6
Я могу заверить вас, что затрагивается не только грек. У вас наверняка возникают проблемы с немецким Sharp S и турецким буквы i.
Я не совсем уверен, что было целью использования этих преобразований, но имейте в виду, что многие языки написаны со сценариями, которые не имеют понятия символов верхнего и нижнего регистра. Если вы используете это для акцента, я предлагаю полностью удалить все преобразования и просто написать часть текста с надлежащим случаем. Таким образом, переводчики могут решить, как они могут подчеркнуть слово или предложение.
BTW. Разрешить элементы span в переводах с определенным классом также может быть хорошей идеей - таким образом, кто-то может использовать, например, цвет для маркировки текста по-разному (хотя это не помогло бы цветным слепым людям.)
Ответ 7
Мне нравится ответ Otovo как самый изящный и быстрый. Я бы не рекомендовал сканировать все элементы для text-transform
. Для больших страниц на мобильных устройствах заметна неэффективность в скорости.
Поэтому я бы рекомендовал просто записать все селекторы с text-transform
из файлов CSS. Это должно быть возможно в большинстве случаев. Затем используйте jQuery непосредственно на этих селекторах.
Итак, чтобы расширить ответ Otovo, добавьте уникальный класс, например i18n-el
на язык где-нибудь, как в body
(это значение по умолчанию для Drupal, но что-то подобное будет работать). Затем запустите:
$('.i18n-el').find('.all-relevant-selectors').attr('lang', 'el');
Obviouslt замените .all-relevant-selectors
на селектора, которые вы отметили из файлов CSS, разделенных запятой.
Кроме того, стоит упомянуть, что это работает только для text-transform: uppercase
, а не font-variant: small-caps
для Chrome 39.
Кроме того, для этого вопроса есть плагин jQuery под названием jquery-remove-upcase-accents, хотя я его вообще не оценил.