i18n_kit 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+