2012-02-24 7 views
12

Ho scritto un'applicazione web che contiene le traduzioni in diverse linguegreco e text-transform: (. Uno dei quali è greco) maiuscolo

Quando si visualizza una certa traduzione sul titolo, la regola di progettazione era che il il testo dovrebbe essere in maiuscolo, che in qualsiasi altra lingua del mondo va bene, ma quando si parla di greco, i browser non sanno cosa fare con gli accenti (vedere this) in modo che visualizzino la stringa maiuscola errata.

Da quella patch che ho collegato sopra, l'ho trasformato in Javascript, ho usato alcuni casi d'uso e funziona. Ora tutto ciò che devo fare è questo:

Senza aggiungere una classe uppercase a ogni elemento che deve essere in maiuscolo (ce ne sono alcuni), è possibile interrogare lo DOM utilizzando una proprietà di stile calcolata? Vale a dire. darmi tutti gli elementi che hanno una calcolata text-transform: uppercase

risposta

10

ho vivamente di non suggerisco di usare jQuery per questo. Eseguire invece questa operazione:

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

Testato con 10.000 elementi, di cui 2.500 con testo "trasformato in maiuscolo".

jQuery processed in 595ms
JS processed in 60ms

Quindi JavaScript è circa 10 volte più veloce di questo rispetto a jQuery.

EDIT: Un altro test, questa volta con 100.000 elementi:

jQuery failed.TypeError: Object doesn't support property or method 'each'
JS processed in 577ms

+0

Bello! Aggiungerò questo :-) – changelog

+0

dove dovrei inserire questo codice? – zekia

3

OK, appena per riferimento, ecco la mia soluzione finora:

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) 

Si tratta di un adattamento sceneggiatura caffè dalla patch fornita nel bug di cui sopra.

Ecco quello che faccio dopo la vista è resa:

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

Questo non è molto bello, con uno sforzo di immaginazione, ma funziona.

Due cose che non dovrei fare qui e che potrebbero cambiare: dirottare toUpperCase() e avere regole specifiche per non analizzare i tag. Ancora aperto a suggerimenti migliori!

1

Questo non aiuterà con i caratteri greci, ma ero curioso di trovare tutti gli elementi con una proprietà css data. Ho impostato questa funzione: http://jsfiddle.net/pQfUv/1/

Il bit che avrebbe interesse si sarebbe:

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

Looping attraverso tutti gli elementi è probabilmente una cosa piuttosto costoso da fare, però. Spero che aiuti.

Cheers, iso

1

Vi posso assicurare che, non solo greca è interessato. Stai sicuramente avendo problemi con il tedesco Sharp S e il turco letters i.

Non sono veramente sicuro di quale fosse lo scopo dell'utilizzo di queste trasformazioni, ma si tenga presente che molte lingue sono scritte con gli script che non hanno un concetto di caratteri maiuscoli e minuscoli. Se si utilizza questo per l'enfasi, suggerisco di rimuovere tutte le trasformazioni del tutto e semplicemente scrivere parte del testo con il caso corretto. In questo modo i traduttori potrebbero decidere il loro modo di sottolineare la parola o la frase.

BTW. La possibilità di utilizzare gli elementi nella traduzione con una classe specifica potrebbe anche essere una buona idea - in questo modo qualcuno potrebbe utilizzare, ad esempio il colore per contrassegnare il testo in modo diverso (anche se non sarebbe di aiuto ai daltonici.)

3

I am usando questa funzione PHP:

function toUpper($str){ 
     $search = array('Ά', 'Έ', 'Ί', 'Ή', 'Ύ', 'Ό', 'Ώ'); 
     $replace = array('Α', 'Ε', 'Ι', 'Η', 'Υ', 'Ο', 'Ω'); 
     $str = mb_strtoupper($str, "UTF-8"); 
     return str_replace($search, $replace, $str); 
    } 
+0

Il problema con il tuo approccio è che non è così semplice. Alcune trasformazioni si riferiscono alle lettere precedenti, precedenti 2 o precedenti 3. – changelog

+0

Non capisco cosa intendi per essere onesto.La funzione che ho postato capitalizza tutte le lettere senza il segno di stress e tu usi lo str_replace per il resto. Ora, come un greco mi fido, è un approccio lato server e l'ho postato da quando hai detto che stavi usando PHP. Ora, l'ho usato in diversi siti Web senza problemi mai. Le lettere precedenti non hanno nulla a che fare con questo. E siccome è la mia lingua madre, saprei se tradurrebbe qualcosa di sbagliato! : p P.S. <3 Portogallo! :) –

+0

Ho ottenuto il funzionamento interno della mia soluzione da qui: https://bug307039.bugzilla.mozilla.org/attachment.cgi?id=588764 Non sto usando PHP (io uso Ruby sul lato server) e questa è una regola di presentazione, quindi si adatta a Javascript. Questa patch è sbagliata? Dovrei sostituire quello che ho da qualcosa di più semplice? – changelog

11

La soluzione in questo problema è descritto sopra esempio 3 here

This is an example che dovrebbe funzionare su qualsiasi browser (testato solo 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; 
} 

È inoltre possibile utilizzare l'attributo lang nel livello superiore, per esempio a tag body.

HTML:

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

CSS:

#withlang{ 
    text-transform: uppercase; 
} 

#withlangsmall{ 
    font-variant: small-caps; 
} 
+1

Risposta molto utile, svalutato! – Elio

+3

Non funziona in IE e Chrome, per Chrome funzionerà se hai aggiunto il tag lang = "el" al tag html –

1

mi piace la risposta di Otovo come la più elegante e veloce. Non consiglierei sicuramente di scansionare tutti gli elementi per text-transform. Per le pagine di grandi dimensioni su dispositivi mobili, l'inefficienza della velocità è notevole.

Pertanto, si consiglia di prendere nota di tutti i selettori con text-transform dai file CSS. Questo dovrebbe essere possibile nella maggior parte dei casi. Quindi, usa jQuery direttamente su quei selettori.

Quindi, per estendere la risposta di Otovo, aggiungere una classe univoca come i18n-el per lingua da qualche parte come in body (questo è il valore predefinito per Drupal ma qualsiasi cosa simile potrebbe funzionare). Quindi eseguire:

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

Obviouslt sostituire .all-relevant-selectors con i selettori che si è preso nota giù dalle file CSS, separati da virgola.

Inoltre, vale la pena ricordare che questo funziona solo per text-transform: uppercase e non font-variant: small-caps per Chrome 39.

In alternativa, v'è un plugin jQuery per questa materia chiamato jquery-remove-upcase-accents, anche se non ho valutato affatto.

Problemi correlati