2011-09-01 57 views
16

我一直在尝试对i18n进行排序来翻译Ruby的YAML文件,这样我就可以以更好和有组织的方式管理新的翻译,但我一直在想是否有什么可以缓解任务。如何分类YAML文件?

我发现一个YAML文件编写器,所以我可以写一个哈希到一个文件,但我的问题是正确排序哈希。如果我得到散列hh.sort返回一个数组,我仍然没有想到一个简单的方法来做到这一点。

我有YAML文件是这样的:

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

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

... 

(该文件的方式比这个更大)

但我想这种方式对它们进行排序:

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

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

我认为一些简单的递归方法可以帮助我这样:

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

是否有任何崇高的插件为相同? –

回答

9

其实这是一个很好的问题。你想深入排序哈希。所以我不喜欢重新发明轮子,然后寻找一个好的实现,并找到我喜欢的一个。看看它https://gist.github.com/1083930。它工作正常。

+0

它的工作,谢谢lucapette! – AndreDurao

+0

这个解决方案有一个小故障:它也排序值。 – Ando

+0

我喜欢这个解决方案,但是在我的Yaml文件中没有双引号(它看起来像这样:'sub_diagnostics_count:!'#Sous-diagnostics''仍然被解释为String但看起来很糟糕)。有没有解决方案来纠正@lucapette? – MrYoshiji

1

在Ruby 1.8中,哈希函数没有特定的顺序,所以您不能对它们进行排序。

你可以猴子补丁/覆盖的Hash这样的to_yaml方法:

#!/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 

当然,具体细节可能取决于你的YAML/Ruby的版本。上面的例子适用于Ruby 1.8.6。

1

这里的另一种选择为别人谁碰到这个来..

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

你不应该使用YAML库的建议一样在其他的答案。当你使用重音和特殊字符(你会,因为你正在做i18n),它会搞乱长字符串值的格式,删除你的注释并吐出不可读的字符转义。 使用此宝石我创建:

https://github.com/redealumni/i18n_yaml_sorter

它只会在文件中的行排序,所以一切都将保持它的方式是对原有YAML一样(你的口音,在YAML构建你用来进入字符串,缩进等)。它将与深层嵌套yamls一起工作,结果非常稳固。宝石包括测试,对红宝石1.8或1.9有好处。

它带有一个TextMate软件包(Shift + Command + S)和一个Rails rake任务,因此您可以在编辑器中轻松快捷地对文件进行排序。这真的很快。

为了说明差异:

原文:

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! 

结果通过YAML ::转储:

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

结果通过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

这似乎很有趣,我会尝试! Obrigado Bernardo。 – AndreDurao

+0

我只是尝试这个gem排序config.yml文件,它没有工作。结果被排序但是也不同。 – Ando

+0

糟糕,多年后,我再次滑入这颗宝石。这个gem不工作的原因是因为它忽略了引用,这意味着依赖关系没有正确排序。 为了让您的YAML文件具有弹性,可以按照键排序方式重命名已命名的键,以便在引用之前它们会出现。 EG: (1)首先,我将'some_key:&some_name'重命名为'_some_key:&some_name'并添加了'some_key:\ n <<:* some_name'。 (2)然后,我将所有已命名的键和它们的值移到文件的顶部,并在需要的地方向键添加数字。 请注意,此手动调整只需要一次。 – Ando

6

https://gist.github.com/1083930不按预期工作。它不仅对散列键进行深度排序,而且对散列值进行深度排序。在我需要深度排序哈希的用例中,哈希总是一棵树,其中键是标签,值是(子)树(如果散列)或叶(否则)。我只需要深入分类树的标签。

我得到这个

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

与此

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

UPDATE 2014年4月:

使用的Rails 3 .2.13 ,Ruby 1.9 .3p489:

我刚使用了i18n_yaml_sorter gem(https://github.com/redealumni/i18n_yaml_sorter)。

只需添加到您的Gemfile

gem 'i18n_yaml_sorter', group: :development 

然后运行 rake任务到您的语言环境文件排序:

rake i18n:sort 

工作完美,尽管创业板最近一次是在2年前撰写的。最多花了5分钟。

1

还有一个原子包,也会这样做https://github.com/akfernun/yaml-sortkeys

+3

一个潜在的解决方案的链接总是受欢迎的,但请[在链接周围添加上下文](http://meta.stackoverflow.com/a/8259/169503),以便您的同行用户可以了解它是什么以及为什么在那。如果目标网站无法访问或永久离线,请始终引用重要链接中最相关的部分。考虑到_barely不仅仅是一个链接到外部网站_是一个可能的原因[为什么和如何删除一些答案?](http://stackoverflow.com/help/deleted-answers)。 – Tunaki