i18n_kit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "nokogiri"
4
+ gem "ya2yaml"
5
+
6
+ group :development do
7
+ gem "rspec", "~> 2.3.0"
8
+ gem "bundler", "~> 1.0.0"
9
+ gem "jeweler", "~> 1.6.2"
10
+ gem "rcov", ">= 0"
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,32 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ jeweler (1.6.2)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ nokogiri (1.4.4)
11
+ rake (0.8.7)
12
+ rcov (0.9.9)
13
+ rspec (2.3.0)
14
+ rspec-core (~> 2.3.0)
15
+ rspec-expectations (~> 2.3.0)
16
+ rspec-mocks (~> 2.3.0)
17
+ rspec-core (2.3.1)
18
+ rspec-expectations (2.3.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.3.0)
21
+ ya2yaml (0.30)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ bundler (~> 1.0.0)
28
+ jeweler (~> 1.6.2)
29
+ nokogiri
30
+ rcov
31
+ rspec (~> 2.3.0)
32
+ ya2yaml
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 funkensturm.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,145 @@
1
+ h2. I18nKit
2
+
3
+ You can import XML files that were exported using Excel, or standard i18n hierarchical YML files. Both will be normalized as I18nKit::Document objects so that they can be compared with each other. You need implement the comparison method yourself, however. I18nKit only provides the Iterator.
4
+
5
+ h3. Importing
6
+
7
+ Say you have an Excel file like this
8
+
9
+ <pre>
10
+ 1 | key | english | swedish | german | comments |
11
+ 2 | customer.invoice.create | Create invoice | Skapa intyg | Rechnung anlegen | |
12
+ 3 | customer.invoice.delete | Delete invoice | Radera intyg | Rechnung löschen | Wow... |
13
+ </pre>
14
+
15
+ and you export it as XML. Then you can import it with I18nKit like this:
16
+
17
+ <pre>
18
+ require 'i18n_kit'
19
+ documents = I18nKit::Importer::ExcelXML.new('my_export.xml').parse
20
+
21
+ # Or use the shortcut:
22
+ documents = I18nKit.import_excel("'my_export.xml')
23
+ </pre>
24
+
25
+ you could also pass the file as a String:
26
+
27
+ <pre>
28
+ documents = I18nKit::Importer::ExcelXML.new(File.read('my_export.xml')).parse
29
+ </pre>
30
+
31
+ The first row will be used to identify the locale language. Note that there are more options for how to import Excel files depending on whether there is a headline or not. Or whether you want to import only the first X columns, like so:
32
+
33
+ <pre>
34
+ importer = I18nKit::Importer::ExcelXML.new(XML_PATH, :ignore_headline => true, :locales => [:sv, :en, :fi])
35
+ </pre>
36
+
37
+ That will ignore the last column (comments) and use "sv" instead of "swedish", for example.
38
+
39
+ At any rate, @documents@ will hold an Array of @I18nKit::Document@ objects. Each representing one language. You might want to give them names so that you can compare them better later:
40
+
41
+ <pre>
42
+ documents[0] = 'Excel: English'
43
+ documents[1] = 'Excel: Swedish'
44
+ documents[2] = 'Excel: German'
45
+
46
+ # Note: By default they're called :excel_en, :excel_sv, etc...
47
+ </pre>
48
+
49
+ Now let's import a YML file from your Rails project:
50
+
51
+ <pre>
52
+ more_documents = I18nKit::Importer::YAML.new('config/locales/fi.yml').parse
53
+ more_documents[0].name = 'My Rails App: Finnish'
54
+
55
+ # Or just use the shortcut:
56
+ I18nKit.import_yaml("config/locales/fi.yml")
57
+
58
+ # Note: The default document name is: :yaml_fi
59
+ </pre>
60
+
61
+ What can you do with a @I18nKit::Document@ entity? If you used the Excel import, then you have e.g. these instance methods:
62
+
63
+ <pre>
64
+ document.name => 'Excel: German'
65
+ document.locale => 'de'
66
+ document.to_flat_hash => { 'customer.invoice.create' => 'Rechnung anlegen',
67
+ 'customer.invoice.delete' => 'Rechnung löschen' }
68
+ document.keys => ['customer.invoice.create', 'customer.invoice.delete']
69
+ </pre>
70
+
71
+ You can do the same with files imported from YML, but additionally you have:
72
+
73
+ <pre>
74
+ document.to_hierarchical_hash => { 'customer' => { 'invoice' => { 'create' => 'Rechnung anlegen', etc... } } }
75
+ document.to_i18n_hash => { 'de' => { 'customer' => { 'invoice' => { etc... } } }
76
+
77
+ # You can even access and update values directly:
78
+
79
+ document['customer.invoice.create'] => 'Rechnung anlegen'
80
+ document['customer.invoice.create'] = 'New Value'
81
+
82
+ document.write_i18n_file('path/to/output_file.yml')
83
+ </pre>
84
+
85
+ As you may notice, the whole idea is to update a Rails app according to a Excel file that is out-of-sync. In the future there could be lots more handy features, but for now, you can perform some good deal of tasks a lot easier than manually. For instance, you could quickly compare two YML I18n files with each other and automate some synchronization.
86
+
87
+ @I18nKit:Comparer@ will compare each @I18nKit::Document@ with each document:
88
+
89
+ <pre>
90
+ # Loading an Excel file and a YML file
91
+ documents = ::I18nKit::Importer::ExcelXML.new(XML_PATH, :ignore_headline => true, :locales => [:sv, :en, :fi]).parse +
92
+ ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse
93
+
94
+ # Giving the Documents smart names
95
+ documents[0].name = 'First'
96
+ documents[1].name = 'Second'
97
+ documents[2].name = 'Third'
98
+ documents[3].name = 'Fourth'
99
+
100
+ # Load the comparer
101
+ comparer = I18nKit::Comparer.new(documents)
102
+
103
+ # Iterate the comparison
104
+ comparer.documents_to_compare.each do |left, right|
105
+ puts "#{left.name} <=> #{right.name}"
106
+ end
107
+ </pre>
108
+
109
+ will output:
110
+
111
+ <pre>
112
+ First <=> Second
113
+ First <=> Third
114
+ First <=> Fourth
115
+ Second <=> Third
116
+ Second <=> Fourth
117
+ Third <=> Fourth
118
+ </pre>
119
+
120
+ You can also access individual documents by their name by using [] on the Comparer:
121
+
122
+ <pre>
123
+ comparer[:excel_sv].keys.each do |key|
124
+ if comparer[:yaml_sv].has_key?(key)
125
+ # Do something because :excel_sv has a key that also exists in :yaml_sv
126
+ end
127
+ end
128
+ </pre>
129
+
130
+ Of course you can then compare them as you wish and merge them in some specific way (depending on your needs).
131
+
132
+ h3. Development
133
+
134
+ Fork the i18n_kit project from Github and run the tests with
135
+
136
+ <pre>
137
+ bundle install
138
+ rake spec
139
+ </pre>
140
+
141
+ h4. Copyright
142
+
143
+ External library in @lib/yamlator.rb@: YAMLator by Henrik Nyh "http://henrik.nyh.se":http://henrik.nyh.se 2010-02-03 under the MIT license.
144
+
145
+ All other files are as well free for all under the MIT license. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "i18n_kit"
18
+ gem.homepage = "http://github.com/funkensturm/i18n_kit"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A small tool to import I18n files from Excel and YML and compare them}
21
+ gem.description = %Q{You can import XML files that were exported using Excel, or standard i18n hierarchical YML files. Both will be normalized as I18nKit::Document objects so that they can be compared with each other. You need implement the comparison method yourself, however. I18nKit only provides the Iterator. )}
22
+ gem.email = "commanda.keen@gmail.com"
23
+ gem.authors = ["funkensturm."]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "i18n_kit #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/i18n_kit.gemspec ADDED
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{i18n_kit}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["funkensturm."]
12
+ s.date = %q{2011-06-07}
13
+ s.description = %q{You can import XML files that were exported using Excel, or standard i18n hierarchical YML files. Both will be normalized as I18nKit::Document objects so that they can be compared with each other. You need implement the comparison method yourself, however. I18nKit only provides the Iterator. )}
14
+ s.email = %q{commanda.keen@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.textile"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.textile",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "i18n_kit.gemspec",
28
+ "lib/i18n_kit.rb",
29
+ "lib/i18n_kit/comparer.rb",
30
+ "lib/i18n_kit/document.rb",
31
+ "lib/i18n_kit/importer.rb",
32
+ "lib/i18n_kit/importer/excel_xml.rb",
33
+ "lib/i18n_kit/importer/yaml.rb",
34
+ "lib/yamlator.rb",
35
+ "spec/assets/excel_export.xml",
36
+ "spec/assets/fi_hierarchical.yml",
37
+ "spec/compare_spec.rb",
38
+ "spec/document_spec.rb",
39
+ "spec/importer_excel_xml_spec.rb",
40
+ "spec/importer_yml_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/funkensturm/i18n_kit}
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.5.3}
47
+ s.summary = %q{A small tool to import I18n files from Excel and YML and compare them}
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
54
+ s.add_runtime_dependency(%q<ya2yaml>, [">= 0"])
55
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
56
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
57
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
58
+ s.add_development_dependency(%q<rcov>, [">= 0"])
59
+ else
60
+ s.add_dependency(%q<nokogiri>, [">= 0"])
61
+ s.add_dependency(%q<ya2yaml>, [">= 0"])
62
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
64
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
65
+ s.add_dependency(%q<rcov>, [">= 0"])
66
+ end
67
+ else
68
+ s.add_dependency(%q<nokogiri>, [">= 0"])
69
+ s.add_dependency(%q<ya2yaml>, [">= 0"])
70
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
71
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
72
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
73
+ s.add_dependency(%q<rcov>, [">= 0"])
74
+ end
75
+ end
76
+
@@ -0,0 +1,41 @@
1
+ require 'i18n_kit/importer'
2
+ require 'i18n_kit/document'
3
+ require 'yamlator'
4
+
5
+ module I18nKit
6
+ class Comparer
7
+ attr_accessor :documents
8
+
9
+ def initialize(documents)
10
+ @documents = documents
11
+ end
12
+
13
+ def [](document_name)
14
+ @documents.each { |doc| return doc if doc.name == document_name }
15
+ nil
16
+ end
17
+
18
+ def compare
19
+ documents_to_compare.each do |left, right|
20
+ #puts "#{left.name} <=> #{right.name}"
21
+ end
22
+ end
23
+
24
+ def documents_to_compare(&block)
25
+ docs = @documents.dup
26
+ pairs = []
27
+ while base = docs.shift do
28
+ docs.each do |doc|
29
+ #break if doc == docs.last
30
+ if block_given?
31
+ yield(base, doc)
32
+ else
33
+ pairs << [base, doc]
34
+ end
35
+ end
36
+ end
37
+ pairs
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,100 @@
1
+ require "ya2yaml" # Dumps with unescaped UTF-8.
2
+ require 'pp'
3
+
4
+ module I18nKit
5
+ class Document
6
+ attr_accessor :locale, :name
7
+
8
+ def initialize(opts={})
9
+ @name = opts.fetch(:name, :undefined)
10
+ # Each Document can only have one locale
11
+ @locale = opts.fetch(:locale, :undefined)
12
+ # This is the hierarchical format that is commonly used in standard I18n
13
+ # Note that the root node (i.e. 'en') is *not* supposed to be included
14
+ @hash = opts.fetch(:hash, {})
15
+ # This is a flattened version of the hierarchical hash
16
+ # There is again no locale at the beginning of the keys (i.e. 'one.two' instead of 'en.one.two')
17
+ @flat_hash = if opts.has_key?(:flat_hash)
18
+ opts[:flat_hash]
19
+ else
20
+ {}
21
+ end
22
+ self
23
+ end
24
+
25
+ def []=(key, value)
26
+ yamlator = YAMLator.new(@hash)
27
+ yamlator[key] = value
28
+ @hash = yamlator.hash
29
+ @flat_hash = {}
30
+ end
31
+
32
+ def [](chain)
33
+ to_flat_hash[chain]
34
+ end
35
+
36
+ def has_key?(key)
37
+ to_flat_hash.has_key?(key)
38
+ end
39
+
40
+ def keys
41
+ to_flat_hash.keys
42
+ end
43
+
44
+ def values
45
+ to_flat_hash.values
46
+ end
47
+
48
+ # Without locale name as root
49
+ def to_hierarchical_hash
50
+ @hash
51
+ end
52
+
53
+ # With locale name as root
54
+ def to_i18n_hash
55
+ { @locale => @hash }
56
+ end
57
+
58
+ def to_i18n_yaml
59
+ to_i18n_hash.ya2yaml
60
+ end
61
+
62
+ def write_i18n_file(path)
63
+ File.open(path, 'w') do |file|
64
+ file.write to_i18n_yaml
65
+ end
66
+ end
67
+
68
+ def to_flat_hash
69
+ # On demand flattening
70
+ populate_flat_hash(@hash) if @flat_hash.size == 0 and @hash.size > 1
71
+ @flat_hash
72
+ end
73
+
74
+ def to_flat_yaml
75
+ to_flat_hash.ya2yaml
76
+ end
77
+
78
+ def to_s
79
+ @name
80
+ end
81
+
82
+ protected
83
+
84
+ def populate_flat_hash(data, root=[])
85
+ data.each do |key, value|
86
+ if value.is_a?(Hash)
87
+ new_root = root + [key]
88
+ populate_flat_hash(value, new_root)
89
+ else
90
+ data.each do |k, v|
91
+ flat_key = [root] + [k]
92
+ @flat_hash[flat_key.join('.')] = v
93
+ end
94
+ return
95
+ end
96
+ end
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,63 @@
1
+ require 'i18n_kit/document'
2
+ require 'nokogiri'
3
+
4
+ module I18nKit
5
+ module Importer
6
+ class ExcelXML
7
+ attr_accessor :locales, :nokodoc, :ignore_headline
8
+ attr_reader :path_or_string, :hash
9
+
10
+ def initialize(path_or_string, opts={})
11
+ @path_or_string = path_or_string
12
+ @locales = opts.fetch(:locales, [])
13
+ @ignore_headline = opts.fetch(:ignore_headline, false)
14
+ @nokodoc = if File.file?(@path_or_string)
15
+ Nokogiri::XML(File.open(@path_or_string))
16
+ else
17
+ Nokogiri::XML(@path_or_string)
18
+ end
19
+ @result = {}
20
+ self
21
+ end
22
+
23
+ # This method uses Nokogiri to parse the XML data
24
+ def parse
25
+ # First, we're loading all Rows of the sheet
26
+ @nokodoc.css('Row').each_with_index do |row, row_index|
27
+ # In each row, we load the columns (i.e. row cells)
28
+ columns = row.css('Cell > Data')
29
+ # We skip empty rows (i.e. rows with no or just one column)
30
+ next unless columns.size > 1
31
+ # The first row might be a header column containing the names of the columns
32
+ # In case the locales are unknown and we're in the header row, let's derive the locales from this header row
33
+ next if @ignore_headline && row_index == 0
34
+ if @locales == [] && row_index == 0
35
+ # Going through the cells of the header row
36
+ columns.each_with_index do |column, column_index|
37
+ # The first column is expected to contain the key, all others we interpret as locale name
38
+ @locales << column.text.to_sym unless column_index == 0
39
+ end
40
+ else
41
+ # This is every row except the header row
42
+ # The key is expected to be in the first column
43
+ key = columns[0].text
44
+ # Now let's read the translations for this key. I.e. all columns except the first one
45
+ locales.each_with_index do |locale, locale_index|
46
+ locale = locale.to_s
47
+ @result[locale] ||= {}
48
+ @result[locale][key] = (columns[locale_index+1] == nil ? '' : columns[locale_index+1].text)
49
+ end
50
+ end
51
+ end
52
+
53
+ documents = []
54
+ @result.each { |locale, hash|
55
+ documents << ::I18nKit::Document.new(:locale => locale, :flat_hash => hash)
56
+ documents.last.name = "excel_#{locale}".to_sym
57
+ }
58
+ documents
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ require 'i18n_kit/document'
2
+ require 'yaml'
3
+
4
+ module I18nKit
5
+ module Importer
6
+ class YAML
7
+ attr_reader :hash, :locale
8
+
9
+ def initialize(path_or_string, opts={})
10
+ raw = File.file?(path_or_string) ? File.read(path_or_string) : path_or_string
11
+ @hash = ::YAML.load(raw)
12
+ @locale = @hash.keys.first
13
+ @name = "yaml_#{@locale}".to_sym
14
+ @hash = @hash.values.first # Removing the root node
15
+ self
16
+ end
17
+
18
+ def parse
19
+ [::I18nKit::Document.new :locale => @locale, :hash => @hash, :name => @name]
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ require 'i18n_kit/importer/excel_xml'
2
+ require 'i18n_kit/importer/yaml'
3
+
4
+ module I18nKit
5
+
6
+ def self.import_excel(*args)
7
+ Importer::ExcelXML.new(*args).parse
8
+ end
9
+
10
+ def self.import_yaml(*args)
11
+ Importer::YAML.new(*args).parse
12
+ end
13
+
14
+ end
data/lib/i18n_kit.rb ADDED
@@ -0,0 +1,5 @@
1
+ # "External" dependencies
2
+ require 'yamlator'
3
+
4
+ # Loading all files in the subdirectory `i18n_kit´
5
+ Dir[File.join(File.dirname(__FILE__), 'i18n_kit', '*.rb')].sort.each { |path| require "i18n_kit/#{File.basename(path, '.rb')}" }
data/lib/yamlator.rb ADDED
@@ -0,0 +1,60 @@
1
+ # YAMLator by Henrik Nyh <http://henrik.nyh.se> 2010-02-03 under the MIT license.
2
+ # Helps you update Rails i18n YAML files programmatically, to be used e.g. for
3
+ # editor extraction tools.
4
+
5
+ $KCODE = 'u'
6
+
7
+ require "yaml"
8
+ require "rubygems"
9
+ require "ya2yaml" # Dumps with unescaped UTF-8.
10
+
11
+ class YAMLator
12
+ attr_reader :hash
13
+
14
+ def initialize(hash)
15
+ #@data = File.file?(path_or_string) ? File.read(path_or_string) : path_or_string
16
+ @hash = hash
17
+ end
18
+
19
+ def to_yaml
20
+ #[preamble, yaml].join
21
+ yaml
22
+ end
23
+
24
+ def []=(key, value)
25
+ chain = key.split('.')
26
+ this_hash = @hash
27
+ chain.each_with_index do |part, index|
28
+ is_last = index==chain.length-1
29
+ key_this_far = chain[0..index].join('.')
30
+
31
+ case this_hash[part]
32
+ when Hash
33
+ raise("trying to add a string to a hash key in use: #{key_this_far.inspect}") if is_last
34
+ # Uncomment the following two lines if you would like to prevent overwriting existing keys
35
+ #when String
36
+ # raise("trying to add to a string key in use: #{key_this_far.inspect}")
37
+ else
38
+ this_hash[part] = is_last ? value : {}
39
+ end
40
+ this_hash = this_hash[part]
41
+ end
42
+ value
43
+ end
44
+
45
+ private
46
+
47
+ # Comments and blank lines in the beginning of the file.
48
+ def preamble
49
+ #@data[/\A(\s*(#.*?)?\n)+/]
50
+ end
51
+
52
+ def yaml
53
+ @hash.ya2yaml
54
+ end
55
+
56
+ end
57
+
58
+ #y = YAMLator.new(DATA)
59
+ #y['sv.some.foo.bar.baz'] = "boink"
60
+ #puts y.to_yaml
@@ -0,0 +1,190 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <?mso-application progid="Excel.Sheet"?>
3
+
4
+ <Workbook xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x2="http://schemas.microsoft.com/office/excel/2003/xml" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel">
5
+
6
+ <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
7
+ <Colors>
8
+ <Color>
9
+ <Index>3</Index>
10
+ <RGB>#c0c0c0</RGB>
11
+ </Color>
12
+ <Color>
13
+ <Index>4</Index>
14
+ <RGB>#dd0806</RGB>
15
+ </Color>
16
+ <Color>
17
+ <Index>5</Index>
18
+ <RGB>#ff0000</RGB>
19
+ </Color>
20
+ </Colors>
21
+ </OfficeDocumentSettings>
22
+
23
+ <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
24
+ <WindowHeight>9000</WindowHeight>
25
+ <WindowWidth>13860</WindowWidth>
26
+ <WindowTopX>240</WindowTopX>
27
+ <WindowTopY>75</WindowTopY>
28
+ <ProtectStructure>False</ProtectStructure>
29
+ <ProtectWindows>False</ProtectWindows>
30
+ </ExcelWorkbook>
31
+
32
+ <Styles>
33
+ <Style ss:ID="Default" ss:Name="Default">
34
+ <Font ss:FontName="Arial1"/>
35
+ </Style>
36
+ <Style ss:ID="Result" ss:Name="Result">
37
+ <Font ss:Bold="1" ss:FontName="Arial1" ss:Italic="1" ss:Underline="Single"/>
38
+ </Style>
39
+ <Style ss:ID="Result2" ss:Name="Result2">
40
+ <Font ss:Bold="1" ss:FontName="Arial1" ss:Italic="1" ss:Underline="Single"/>
41
+ <NumberFormat ss:Format="Currency"/>
42
+ </Style>
43
+ <Style ss:ID="Heading" ss:Name="Heading">
44
+ <Font ss:Bold="1" ss:FontName="Arial1" ss:Italic="1" ss:Size="16"/>
45
+ </Style>
46
+ <Style ss:ID="Heading1" ss:Name="Heading1">
47
+ <Alignment ss:Rotate="90"/>
48
+ <Font ss:Bold="1" ss:FontName="Arial1" ss:Italic="1" ss:Size="16"/>
49
+ </Style>
50
+ <Style ss:ID="co1"/>
51
+ <Style ss:ID="co2"/>
52
+ <Style ss:ID="co3"/>
53
+ <Style ss:ID="co4"/>
54
+ <Style ss:ID="co5"/>
55
+ <Style ss:ID="ta1"/>
56
+ <Style ss:ID="ce1">
57
+ <Font ss:Bold="1" ss:FontName="Arial2" ss:Size="10"/>
58
+ <NumberFormat ss:Format="General"/>
59
+ </Style>
60
+ <Style ss:ID="ce2">
61
+ <Font ss:FontName="Arial1" ss:Size="10"/>
62
+ <NumberFormat ss:Format="General"/>
63
+ </Style>
64
+ <Style ss:ID="ce3">
65
+ <Alignment ss:Vertical="Automatic" ss:WrapText="1" ss:Indent="0" ss:Rotate="0"/>
66
+ <Font ss:Bold="1" ss:FontName="Arial2" ss:Size="10"/>
67
+ <NumberFormat ss:Format="General"/>
68
+ </Style>
69
+ <Style ss:ID="ce4">
70
+ <Alignment ss:Vertical="Automatic" ss:WrapText="1" ss:Indent="0" ss:Rotate="0"/>
71
+ <Font ss:FontName="Arial1" ss:Size="10"/>
72
+ <NumberFormat ss:Format="General"/>
73
+ </Style>
74
+ <Style ss:ID="ce5">
75
+ <Alignment ss:Vertical="Automatic" ss:WrapText="1" ss:Indent="0" ss:Rotate="0"/>
76
+ </Style>
77
+ <Style ss:ID="ce6">
78
+ <Alignment ss:Vertical="Automatic" ss:WrapText="1" ss:Indent="0" ss:Rotate="0"/>
79
+ <Font ss:Color="#dd0806" ss:FontName="Arial1" ss:Size="10"/>
80
+ <NumberFormat ss:Format="General"/>
81
+ </Style>
82
+ <Style ss:ID="ce7">
83
+ <Font ss:Bold="1" ss:Color="#dd0806" ss:FontName="Arial1" ss:Size="10"/>
84
+ <NumberFormat ss:Format="General"/>
85
+ </Style>
86
+ <Style ss:ID="ce8">
87
+ <Font ss:Color="#dd0806" ss:FontName="Arial1" ss:Size="10"/>
88
+ </Style>
89
+ <Style ss:ID="ce9">
90
+ <Font ss:Color="#dd0806" ss:FontName="Arial1" ss:Size="10"/>
91
+ <NumberFormat ss:Format="General"/>
92
+ </Style>
93
+ <Style ss:ID="ta_extref"/>
94
+ <Style ss:ID="T1">
95
+ <Font ss:Color="#dd0806" ss:FontName="Arial1" ss:Size="10" ss:VerticalAlign="Subscript"/>
96
+ </Style>
97
+ <Style ss:ID="T2">
98
+ <Font ss:FontName="Arial1" ss:Size="10" ss:VerticalAlign="Subscript"/>
99
+ </Style>
100
+ <Style ss:ID="T3">
101
+ <Font ss:FontName="Times New Roman" ss:Size="12" ss:VerticalAlign="Subscript"/>
102
+ </Style>
103
+ </Styles>
104
+
105
+ <ss:Worksheet ss:Name="Translations">
106
+
107
+ <Table ss:StyleID="ta1">
108
+ <Column ss:Width="232.1568"/>
109
+ <Column ss:Width="232.1568"/>
110
+ <Column ss:Width="199.8144"/>
111
+ <Column ss:Width="285.8472"/>
112
+ <Column ss:Width="171.1008"/>
113
+ <Column ss:Span="1018" ss:Width="63.8352"/>
114
+
115
+ <Row ss:Height="11.988">
116
+ <Cell ss:StyleID="ce1">
117
+ <Data ss:Type="String">nyckel</Data>
118
+ </Cell>
119
+ <Cell ss:StyleID="ce3">
120
+ <Data ss:Type="String">svenska</Data>
121
+ </Cell>
122
+ <Cell ss:StyleID="ce3">
123
+ <Data ss:Type="String">engelska</Data>
124
+ </Cell>
125
+ <Cell ss:StyleID="ce3">
126
+ <Data ss:Type="String">finska</Data>
127
+ </Cell>
128
+ <Cell ss:StyleID="ce7">
129
+ <Data ss:Type="String">GM Kommentar</Data>
130
+ </Cell>
131
+ <Cell ss:Index="1024"/>
132
+ </Row>
133
+
134
+ <Row ss:Height="11.988">
135
+ <Cell ss:StyleID="ce2">
136
+ <Data ss:Type="String">base_helper.all</Data>
137
+ </Cell>
138
+ <Cell ss:StyleID="ce4">
139
+ <Data ss:Type="String">Alla</Data>
140
+ </Cell>
141
+ <Cell ss:StyleID="ce4">
142
+ <Data ss:Type="String">All</Data>
143
+ </Cell>
144
+ <Cell ss:StyleID="ce4">
145
+ <Data ss:Type="String">Kaikki</Data>
146
+ </Cell>
147
+ <Cell ss:Index="1024"/>
148
+ </Row>
149
+
150
+ <Row ss:Height="11.988">
151
+ <Cell ss:StyleID="ce2">
152
+ <Data ss:Type="String">base_helper.time_left</Data>
153
+ </Cell>
154
+ <Cell ss:StyleID="ce4">
155
+ <Data ss:Type="String">%{time} kvar</Data>
156
+ </Cell>
157
+ <Cell ss:StyleID="ce4">
158
+ <Data ss:Type="String">%{time} left</Data>
159
+ </Cell>
160
+ <Cell ss:StyleID="ce4">
161
+ <Data ss:Type="String">%{time} jäljellä</Data>
162
+ </Cell>
163
+ <Cell ss:Index="1024"/>
164
+ </Row>
165
+
166
+ <Row ss:Height="11.988">
167
+ <Cell ss:StyleID="ce2">
168
+ <Data ss:Type="String">support.select.prompt</Data>
169
+ </Cell>
170
+ <Cell ss:StyleID="ce4">
171
+ <Data ss:Type="String">Välj</Data>
172
+ </Cell>
173
+ <Cell ss:StyleID="ce4">
174
+ <Data ss:Type="String">Please select</Data>
175
+ </Cell>
176
+ <Cell ss:StyleID="ce4">
177
+ <Data ss:Type="String">Valitse</Data>
178
+ </Cell>
179
+ <Cell ss:StyleID="ce4">
180
+ <Data ss:Type="String">This is a comment</Data>
181
+ </Cell>
182
+ <Cell ss:Index="1024"/>
183
+ </Row>
184
+
185
+ </Table>
186
+
187
+ <x:WorksheetOptions/>
188
+
189
+ </ss:Worksheet>
190
+ </Workbook>
@@ -0,0 +1,22 @@
1
+ fi:
2
+ activerecord:
3
+ attributes:
4
+ account:
5
+ account_type: "Pankkitilin tyyppi"
6
+ number: Tilinumero
7
+ auction:
8
+ estimate: Lähtöhinta
9
+ estimate_upper: "Lähtöhinta alkaen"
10
+ reserve_price: Pohjahinta
11
+ percentage_fee:
12
+ manual_unspecified: ~
13
+ percent_thereafter: "%{percent} sen jälkeen"
14
+ percent_to_limit: "%{percent} - %{limit}"
15
+ seller_invoice:
16
+ description_with_vat: "Toimeksiantolaskelma #%{ocr}"
17
+ description_without_vat: "Toimeksiantolaskelma (ilman alv) #%{ocr}"
18
+ shared:
19
+ actions:
20
+ add: Lisää
21
+ log_in: "Kirjaudu sisään"
22
+ order: Tilaa
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'pp'
3
+
4
+ describe "I18nKit Comparer Test" do
5
+
6
+ it "should know which documents to compare to one another" do
7
+ one = I18nKit::Document.new
8
+ two = I18nKit::Document.new
9
+ three = I18nKit::Document.new
10
+ four = I18nKit::Document.new
11
+ array = [one, two, three, four]
12
+ comparer = I18nKit::Comparer.new array
13
+ comparer.documents.should == array
14
+ comparer.documents_to_compare.should == [[one, two], [one, three], [one, four], [two, three], [two, four], [three, four]]
15
+ end
16
+
17
+ it "should compare" do
18
+ documents = ::I18nKit::Importer::ExcelXML.new(XML_PATH, :ignore_headline => true, :locales => [:sv, :en, :fi]).parse +
19
+ ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse
20
+ documents[0].name = 'First'
21
+ documents[1].name = 'Second'
22
+ documents[2].name = 'Third'
23
+ documents[3].name = 'Fourth'
24
+ comparer = I18nKit::Comparer.new(documents)
25
+ # TODO: test automated comparison in the future :)
26
+ # comparer.compare
27
+ end
28
+
29
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'pp'
3
+
4
+ describe "I18nKit Document Test" do
5
+
6
+ it "should store an hierarchical hash" do
7
+ document = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse.first
8
+ document.to_hierarchical_hash.should == YAML.load(File.read(YML_FI_HIERARCHICAL_PATH)).values.first
9
+ end
10
+
11
+ it "should flatten a hierarchical hash" do
12
+ document = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse.first
13
+ document.to_flat_hash.should == YML_FI_FLAT
14
+ end
15
+
16
+ it "should spill out a yaml file without locale as root node" do
17
+ document = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse.first
18
+ YAML.load(document.to_flat_yaml).should == YML_FI_FLAT # Hard to test because Hashes are unordered when exported to YML
19
+ end
20
+
21
+ it "should export proper i18n yaml files" do
22
+ document = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse.first
23
+ document.to_i18n_hash.should == YAML.load(File.read(YML_FI_HIERARCHICAL_PATH))
24
+ end
25
+
26
+ it "should replace a value for a given chain" do
27
+ document = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse.first
28
+ document['activerecord.attributes.account.number'] = 'New Value'
29
+ document.to_i18n_hash['fi']['activerecord']['attributes']['account']['number'].should == 'New Value'
30
+ end
31
+
32
+ end
@@ -0,0 +1,80 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "I18nKit ExcelXML Importer Test" do
4
+
5
+ it "should import a file at a given path and load it with Nokogiri" do
6
+ importer = ::I18nKit::Importer::ExcelXML.new(XML_PATH)
7
+ importer.path_or_string.should == XML_PATH
8
+ importer.nokodoc.should be_an_instance_of Nokogiri::XML::Document
9
+ importer.nokodoc.children.size.should be > 0
10
+ end
11
+
12
+ it "should import a String and load it with Nokogiri" do
13
+ importer = ::I18nKit::Importer::ExcelXML.new File.read(XML_PATH)
14
+ importer.path_or_string.should == File.read(XML_PATH)
15
+ importer.nokodoc.should be_an_instance_of Nokogiri::XML::Document
16
+ importer.nokodoc.children.size.should be > 0
17
+ end
18
+
19
+ it "should know how to parse an .xml file" do
20
+ documents = ::I18nKit::Importer::ExcelXML.new(XML_PATH).parse
21
+ documents.should be_an_instance_of Array
22
+ documents.each do |doc|
23
+ doc.should be_an_instance_of I18nKit::Document
24
+ case doc.locale
25
+ when 'svenska'
26
+ doc.to_flat_hash.should == XML_HASH_SV
27
+ when "engelska"
28
+ doc.to_flat_hash.should == XML_HASH_EN
29
+ when "finska"
30
+ doc.to_flat_hash.should == XML_HASH_FI
31
+ when "GM Kommentar"
32
+ doc.to_flat_hash.should == XML_HASH_COMMENTS
33
+ else
34
+ flunk 'There is one translation too much'
35
+ end
36
+ end
37
+ end
38
+
39
+ it "should know how to parse an .xml file with manually defined column names" do
40
+ importer = ::I18nKit::Importer::ExcelXML.new(XML_PATH, :ignore_headline => true, :locales => [:sv, :en, :fi, :comment])
41
+ documents = importer.parse
42
+ documents.should be_an_instance_of Array
43
+ documents.each do |doc|
44
+ doc.should be_an_instance_of I18nKit::Document
45
+ case doc.locale
46
+ when "sv"
47
+ doc.to_flat_hash.should == XML_HASH_SV
48
+ when "en"
49
+ doc.to_flat_hash.should == XML_HASH_EN
50
+ when "fi"
51
+ doc.to_flat_hash.should == XML_HASH_FI
52
+ when "comment"
53
+ doc.to_flat_hash.should == XML_HASH_COMMENTS
54
+ else
55
+ flunk 'There is one translation too much'
56
+ end
57
+ end
58
+ end
59
+
60
+ it "should know how to parse an .xml file with a subset of manually defined column names" do
61
+ importer = ::I18nKit::Importer::ExcelXML.new(XML_PATH, :ignore_headline => true, :locales => [:sv, :en, :fi])
62
+ documents = importer.parse
63
+ documents.should be_an_instance_of Array
64
+ documents.each do |doc|
65
+ doc.should be_an_instance_of I18nKit::Document
66
+ case doc.locale
67
+ when "sv"
68
+ doc.to_flat_hash.should == XML_HASH_SV
69
+ when "en"
70
+ doc.to_flat_hash.should == XML_HASH_EN
71
+ when "fi"
72
+ doc.to_flat_hash.should == XML_HASH_FI
73
+ else
74
+ flunk 'There is one translation too much'
75
+ end
76
+ end
77
+ end
78
+
79
+ end
80
+
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "I18nKit Importer Test" do
4
+
5
+ it "should identify the locale of a standard Rails i18n yml file" do
6
+ documents = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH).parse
7
+ documents.should be_an_instance_of Array
8
+ documents.size.should == 1
9
+ documents.first.should be_an_instance_of I18nKit::Document
10
+ documents.first.locale.should == 'fi'
11
+ end
12
+
13
+ it "should chop of the root of imported yaml files" do
14
+ importer = ::I18nKit::Importer::YAML.new(YML_FI_HIERARCHICAL_PATH)
15
+ hierarchical_hash = YAML.load(File.read(YML_FI_HIERARCHICAL_PATH)).values.first
16
+ importer.hash.should == hierarchical_hash
17
+ importer.parse.first.to_hierarchical_hash.should == hierarchical_hash
18
+ end
19
+
20
+ end
@@ -0,0 +1,46 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'i18n_kit'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ XML_PATH = File.join(File.dirname(__FILE__), 'assets', 'excel_export.xml')
11
+
12
+ XML_HASH_FI = { "support.select.prompt" => "Valitse",
13
+ "base_helper.time_left" => "%{time} j\303\244ljell\303\244",
14
+ "base_helper.all" => "Kaikki" }
15
+
16
+ XML_HASH_SV = { "support.select.prompt" => "V\303\244lj",
17
+ "base_helper.time_left" => "%{time} kvar",
18
+ "base_helper.all" => "Alla" }
19
+
20
+ XML_HASH_EN = { "support.select.prompt" => "Please select",
21
+ "base_helper.time_left" => "%{time} left",
22
+ "base_helper.all" => "All" }
23
+
24
+ XML_HASH_COMMENTS = { "support.select.prompt" => "This is a comment",
25
+ "base_helper.time_left" => "",
26
+ "base_helper.all" => "" }
27
+
28
+ YML_FI_HIERARCHICAL_PATH = File.join(File.dirname(__FILE__), 'assets', 'fi_hierarchical.yml')
29
+
30
+ YML_FI_FLAT = { "activerecord.attributes.account.account_type" => "Pankkitilin tyyppi",
31
+ "activerecord.attributes.account.number" => "Tilinumero",
32
+ "activerecord.attributes.auction.estimate" => "L\303\244ht\303\266hinta",
33
+ "activerecord.attributes.auction.estimate_upper" => "L\303\244ht\303\266hinta alkaen",
34
+ "activerecord.attributes.auction.reserve_price" => "Pohjahinta",
35
+ "percentage_fee.manual_unspecified" => nil,
36
+ "percentage_fee.percent_thereafter" => "%{percent} sen j\303\244lkeen",
37
+ "percentage_fee.percent_to_limit" => "%{percent} - %{limit}",
38
+ "seller_invoice.description_without_vat" => "Toimeksiantolaskelma (ilman alv) #%{ocr}",
39
+ "seller_invoice.description_with_vat" => "Toimeksiantolaskelma #%{ocr}",
40
+ "shared.actions.add" => "Lis\303\244\303\244",
41
+ "shared.actions.order" => "Tilaa",
42
+ "shared.actions.log_in" => "Kirjaudu sis\303\244\303\244n" }
43
+
44
+ RSpec.configure do |config|
45
+
46
+ end
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i18n_kit
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - funkensturm.
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-07 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :runtime
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ name: nokogiri
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ prerelease: false
37
+ type: :runtime
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ name: ya2yaml
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ prerelease: false
51
+ type: :development
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 2
60
+ - 3
61
+ - 0
62
+ version: 2.3.0
63
+ name: rspec
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ prerelease: false
67
+ type: :development
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ hash: 23
74
+ segments:
75
+ - 1
76
+ - 0
77
+ - 0
78
+ version: 1.0.0
79
+ name: bundler
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ prerelease: false
83
+ type: :development
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ hash: 11
90
+ segments:
91
+ - 1
92
+ - 6
93
+ - 2
94
+ version: 1.6.2
95
+ name: jeweler
96
+ version_requirements: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ prerelease: false
99
+ type: :development
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ name: rcov
110
+ version_requirements: *id006
111
+ description: You can import XML files that were exported using Excel, or standard i18n hierarchical YML files. Both will be normalized as I18nKit::Document objects so that they can be compared with each other. You need implement the comparison method yourself, however. I18nKit only provides the Iterator. )
112
+ email: commanda.keen@gmail.com
113
+ executables: []
114
+
115
+ extensions: []
116
+
117
+ extra_rdoc_files:
118
+ - LICENSE.txt
119
+ - README.textile
120
+ files:
121
+ - .document
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - LICENSE.txt
125
+ - README.textile
126
+ - Rakefile
127
+ - VERSION
128
+ - i18n_kit.gemspec
129
+ - lib/i18n_kit.rb
130
+ - lib/i18n_kit/comparer.rb
131
+ - lib/i18n_kit/document.rb
132
+ - lib/i18n_kit/importer.rb
133
+ - lib/i18n_kit/importer/excel_xml.rb
134
+ - lib/i18n_kit/importer/yaml.rb
135
+ - lib/yamlator.rb
136
+ - spec/assets/excel_export.xml
137
+ - spec/assets/fi_hierarchical.yml
138
+ - spec/compare_spec.rb
139
+ - spec/document_spec.rb
140
+ - spec/importer_excel_xml_spec.rb
141
+ - spec/importer_yml_spec.rb
142
+ - spec/spec_helper.rb
143
+ has_rdoc: true
144
+ homepage: http://github.com/funkensturm/i18n_kit
145
+ licenses:
146
+ - MIT
147
+ post_install_message:
148
+ rdoc_options: []
149
+
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ hash: 3
158
+ segments:
159
+ - 0
160
+ version: "0"
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ hash: 3
167
+ segments:
168
+ - 0
169
+ version: "0"
170
+ requirements: []
171
+
172
+ rubyforge_project:
173
+ rubygems_version: 1.5.3
174
+ signing_key:
175
+ specification_version: 3
176
+ summary: A small tool to import I18n files from Excel and YML and compare them
177
+ test_files: []
178
+