2011-09-01 19 views
16

Ho cercato di ordinare un file YAML di traduzione i18n con Ruby in modo da poter gestire le nuove traduzioni in un modo migliore e organizzato, ma mi sono chiesto se c'è qualcosa per facilitare l'operazione.Come posso ordinare i file YAML?

Ho trovato uno scrittore di file YAML in modo da poter scrivere un hash in un file, ma il mio problema è di ordinare correttamente l'hash. Se ho ottenuto l'hash h, h.sort restituisce un array e non ho ancora trovato un modo semplice per farlo.

Ho i file YAML come questo:

pt-br:  
    global: 
    misc: 
     total: "Total" 
     all: "Todos" 
     close: "Fechar" 
     cancel: "Cancelar" 

    crud: 
     access: "Acessar" 
     back: "Voltar" 
     edit: "Editar" 
     confirm: "Confirmar" 
     send: "Enviar" 

... 

(I file sono il modo più grande di questo)

Ma voglio ordinare loro in questo modo:

pt-br:  
    global: 
    crud: 
     access: "Acessar" 
     back: "Voltar" 
     confirm: "Confirmar" 
     edit: "Editar" 
     send: "Enviar" 

    misc: 
     all: "Todos" 
     cancel: "Cancelar" 
     close: "Fechar"   
     total: "Total" 

ho pensato che qualche semplice metodo ricorsivo mi può aiutare in questo modo:

def translation_sort(h) 
    if h.class == Hash 
    h = h.sort 
    h.each{|item| translation_sort(item)} 
    end 
    h 
end 

require "yaml" 
h=YAML.load_file(File.open("~/pt-br.sample.yml")) 
translation_sort(h) 
+0

c'è alcun plugin sublime per la stessa? –

risposta

9

In realtà questa è una bella domanda. Vuoi ordinare gli hash in profondità. Quindi non mi piace re-inventare la ruota e poi ho cercato una buona implementazione e ne ho trovata una che mi piace. Dai un'occhiata a questo https://gist.github.com/1083930. Funziona bene.

+0

ha funzionato, grazie lucapette! – AndreDurao

+0

Questa soluzione ha un bel problema: ordina anche i valori. – Ando

+0

Adoro questa soluzione ma non ci sono doppie virgolette nel mio file Yaml (assomiglia a questo: 'sub_diagnostics_count:! '# Sous-diagnostics'' che è ancora interpretato come String ma sembra male). C'è qualche soluzione per correggere quel @lucapette? – MrYoshiji

1

In Ruby 1.8 gli hash non hanno un ordine particolare, quindi non è possibile ordinarli.

Si potrebbe scimmia-patch/sovrascrivere il metodo to_yaml di Hash come questo:

#!/usr/local/bin/ruby -w 

require 'yaml' 

class Hash 
    def to_yaml(opts = {}) 
    YAML::quick_emit(self, opts) do |out| 
     out.map(taguri, to_yaml_style) do |map| 
     keys.sort.each do |k| 
      v = self[k] 
      map.add(k, v) 
     end 
     end 
    end 
    end 
end 

dict = YAML.load($<.read) 

puts dict.to_yaml 

Naturalmente, i dettagli esatti può dipendere la vostra versione di YAML/Ruby. L'esempio sopra riportato è per Ruby 1.8.6.

1

Ecco un'altra alternativa per chiunque altro che si imbatte in questo ..

require 'yaml' 

yaml = YAML.load(IO.read(File.join(File.dirname(__FILE__), 'example.yml'))) 

@yml_string = "---\n" 

def recursive_hash_to_yml_string(hash, depth=0) 
    spacer = "" 
    depth.times { spacer += " "} 
    hash.keys.sort.each do |sorted_key| 
    @yml_string += spacer + sorted_key + ": " 
    if hash[sorted_key].is_a?(Hash) 
     @yml_string += "\n" 
     recursive_hash_to_yml_string(hash[sorted_key], depth+1) 
    else 
     @yml_string += "#{hash[sorted_key].to_s}\n" 
    end 
    end 
end 

recursive_hash_to_yml_string(yaml) 

open(File.join(File.dirname(__FILE__), 'example.yml'), 'w') { |f| 
    f.write @yml_string 
} 
9

Si consiglia di non utilizzare la libreria YAML, come suggerito in altre risposte. Sviterà la formattazione dei valori di stringa lunga, rimuoverà i tuoi commenti e sputerà i caratteri di escape illeggibili quando usi accenti e caratteri speciali (cosa che farai, dato che stai facendo i18n). Utilizzare questo gioiello ho creato:

https://github.com/redealumni/i18n_yaml_sorter

Sarà ordinare solo le linee sul file, quindi tutto rimarrà allo stesso modo in cui era sul YAML originale (i vostri accenti, il YAML costrutto utilizzato per immettere le stringhe, indentazione, ecc.). Funzionerà con yamls profondamente annidati e i risultati sono abbastanza solidi. La gemma include i test e fa bene a ruby ​​1.8 o 1.9.

Viene fornito con un pacchetto TextMate (Shift + Command + S) e un rake Rails in modo da poter ordinare i file facilmente e immediatamente nell'editor. È molto veloce

per illustrare la differenza:

originale:

pt-BR: 
    # Note how this is a nice way of inputing 
    # paragraphs of text in YAML. 
    apples: > 
     Maçãs são boas, 
     só não coma 
     seus iPods! 
    grapes: Não comemos elas. 
    bananas: | 
     Bananas são "legais": 
     - Elas são <b> doces </b>. 
     isto: não é chave 

     Por isto todos gostam de bananas! 

I risultati per YAML :: discarica:

pt-BR: 
    apples: "Ma\xC3\xA7\xC3\xA3s s\xC3\xA3o boas, s\xC3\xB3 n\xC3\xA3o coma seus iPods!\n" 
    bananas: "Bananas s\xC3\xA3o \"legais\":\n - Elas s\xC3\xA3o <b> doces </b>.\n isto: n\xC3\xA3o \xC3\xA9 chave\n\n\ Por isto todos gostam de bananas!\n" 
    grapes: "N\xC3\xA3o comemos elas." 

I risultati per i18n_yaml_sorter:

pt-BR: 
    # Note how this is a nice way of inputing 
    # paragraphs of text in YAML. 
    apples: > 
     Maçãs são boas, 
     só não coma 
     seus iPods! 
    bananas: | 
     Bananas são "legais": 
     - Elas são <b> doces </b>. 
     isto: não é chave 

     Por isto todos gostam de bananas! 
    grapes: Não comemos elas. 
+0

Sembra interessante, ci proverò! Obrigado Bernardo. – AndreDurao

+0

Ho appena provato questo gioiello per l'ordinamento di un file config.yml e non ha funzionato. Il risultato è stato ordinato ma anche diverso. – Ando

+0

Oops, sono scivolato di nuovo su questa gemma, dopo molti anni. Il motivo per cui questa gemma non funziona è perché ignora i riferimenti, il che significa che le dipendenze non sono ordinate correttamente. Per rendere il file YAML resiliente all'ordinamento dei tasti, rinominare le chiavi nominate in modo che vengano prima di essere referenziate. EG: (1) Per prima cosa ho ribattezzato 'some_key: & some_name' a' _some_key: & some_name' e aggiunto 'some_key: \ n <<: * some_name'. (2) Quindi ho spostato tutte le chiavi con nome e i loro valori nella parte superiore del file e aggiunto numeri alle chiavi dove necessario. Si noti che questa regolazione manuale è necessaria solo una volta. – Ando

6

https://gist.github.com/1083930 non funziona come mi aspettavo. Ordina in profondità NON SOLO i tasti hash MA ANCHE i valori hash. Nei miei casi d'uso in cui è necessario un ordinamento profondo di un hash, l'hash è sempre un albero in cui le chiavi sono etichette ei valori sono (sotto) alberi (se hash) o lascia (altrimenti). Ho bisogno di ordinare in profondità solo le etichette degli alberi.

ho ottenuto questo

before: {"a":[2,10,{"5":null,"1":null,"3":null}],"x":{"5":null,"1":null,"3":null},"a2":{"5":[2,10,5],"1":null,"3":null}} 
after: {"a":[2,10,{"5":null,"1":null,"3":null}],"a2":{"1":null,"3":null,"5":[2,10,5]},"x":{"1":null,"3":null,"5":null}} 

con questo

require 'active_support' 

def deeply_sort_hash(object) 
    return object unless object.is_a?(Hash) 
    hash = RUBY_VERSION >= '1.9' ? Hash.new : ActiveSupport::OrderedHash.new 
    object.each { |k, v| hash[k] = deeply_sort_hash(v) } 
    sorted = hash.sort { |a, b| a[0].to_s <=> b[0].to_s } 
    hash.class[sorted] 
end 
6

aggiornamento di aprile 2014:

Utilizzando Rails 3 .2.13 , Ruby 1.9 .3p489:

ho appena usato la gemma i18n_yaml_sorter (https://github.com/redealumni/i18n_yaml_sorter).

sufficiente aggiungere al vostro Gemfile:

gem 'i18n_yaml_sorter', group: :development 

Quindi eseguire il compito rastrello per ordinare i file tuoi locali:

rake i18n:sort 

funzionato perfettamente, anche se la gemma ha stato creato l'ultima volta 2 anni fa. Ci sono voluti 5 minuti al massimo.

1

C'è anche un pacchetto di atomo che farà anche questo https://github.com/akfernun/yaml-sortkeys

+3

Un collegamento a una potenziale soluzione è sempre il benvenuto, ma per favore [aggiungi contesto intorno al link] (http://meta.stackoverflow.com/a/8259/169503) in modo che i tuoi utenti abbiano un'idea di cosa sia e perché È lì. Citare sempre la parte più rilevante di un link importante, nel caso in cui il sito target non sia raggiungibile o sia permanentemente offline. Considera che essere _barely più di un link a un sito esterno_ è una possibile ragione per [Perché e come vengono eliminate alcune risposte?] (Http://stackoverflow.com/help/deleted-answers). – Tunaki