any2tmx 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d90cd3e9e2eaec60045ed8bbebb270b875df53c
4
- data.tar.gz: ac99873e75d2594df5eece8e67cdd6eaa1588b9f
3
+ metadata.gz: dfbf800c45d800fa53efa6f1f142f154e6ea2be6
4
+ data.tar.gz: 19c4b39b0252af8fb49cbeb4fc994c14f5c79571
5
5
  SHA512:
6
- metadata.gz: 0fdc99691eca01b66e6f9ec78796befa10f7aa580a7a194c2c12e98a017df77217970e6993d7c2b0ab4d4024062d3945d5bf82d57290ebfede7d059cb2656e2d
7
- data.tar.gz: 091ca3fe3de6376ceea1ca6f5a1af4726e663dd5745e8fed261d67a0863a39dd5f4cecb1ffc0bae23a7264e2a5424168e586098dfaa1fb726a2b4debcaca98a2
6
+ metadata.gz: e2a67b0fce2c98fe75e198f12822df3567138a4a11f2abae9b8255836c0a724a719912fa3db011b0b6c26f9036ddeee7e197fbb1cd87b564009dfcb5b0e29820
7
+ data.tar.gz: 19e26011be1125aa387c05b6cc7ae388ef1ff04766bee422f9341e8fd630d602a635f03067ca10f8545a34cbb61a281ef94d9d4a5275a5ca304e3153c4b76804
@@ -1,24 +1,27 @@
1
- == 1.0.0
1
+ == 1.1.0
2
2
 
3
- * Birthday!
3
+ * Depend on Abroad for parsing, which removes a lot of code.
4
+ * General cleanup and refactoring.
5
+ * Added ability to specify more than one target file.
4
6
 
5
- == 1.0.0
7
+ == 1.0.4
6
8
 
7
- * Renamed gem from yaml2tmx to any2tmx.
8
- * Added support for JSON and Android XML.
9
+ * Fixing bug with JSON processor causing crash.
9
10
 
10
- == 1.0.1
11
+ == 1.0.3
11
12
 
12
- * Add ability to load files by name or by contents.
13
+ * Stringify keys when processing YAML
13
14
 
14
15
  == 1.0.2
15
16
 
16
17
  * Fix Android transform bug
17
18
 
18
- == 1.0.3
19
+ == 1.0.1
19
20
 
20
- * Stringify keys when processing YAML
21
+ * Add ability to load files by name or by contents.
21
22
 
22
- == 1.0.4
23
+ == 1.0.0
23
24
 
24
- * Fixing bug with JSON processor causing crash.
25
+ * Birthday!
26
+ * Renamed gem from yaml2tmx to any2tmx.
27
+ * Added support for JSON and Android XML.
@@ -2,25 +2,25 @@ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
2
  require 'any2tmx/version'
3
3
 
4
4
  Gem::Specification.new do |s|
5
- s.name = "any2tmx"
5
+ s.name = 'any2tmx'
6
6
  s.version = ::Any2Tmx::VERSION
7
- s.authors = ["Cameron Dutro"]
8
- s.email = ["camertron@gmail.com"]
9
- s.homepage = "http://github.com/camertron/any2tmx"
7
+ s.authors = ['Cameron Dutro']
8
+ s.email = ['camertron@gmail.com']
9
+ s.homepage = 'http://github.com/camertron/any2tmx'
10
10
 
11
- s.description = s.summary = "A command-line tool to convert certain file types to the standard TMX format for translation memories."
11
+ s.description = s.summary = 'A command-line tool to convert certain file types to the standard TMX format for translation memories.'
12
12
 
13
13
  s.platform = Gem::Platform::RUBY
14
14
  s.has_rdoc = true
15
15
 
16
- s.add_dependency 'xml-write-stream', '~> 1.0'
16
+ s.add_dependency 'abroad', '~> 4.0'
17
17
  s.add_dependency 'nokogiri', '~> 1.6'
18
- s.add_dependency 'htmlentities', '~> 4.3'
18
+ s.add_dependency 'xml-write-stream', '~> 1.0'
19
19
 
20
- s.executables << 'yaml2tmx'
21
- s.executables << 'json2tmx'
22
20
  s.executables << 'android2tmx'
21
+ s.executables << 'json2tmx'
22
+ s.executables << 'yaml2tmx'
23
23
 
24
24
  s.require_path = 'lib'
25
- s.files = Dir["{lib,spec}/**/*", "Gemfile", "History.txt", "README.md", "Rakefile", "any2tmx.gemspec"]
25
+ s.files = Dir["{lib,spec}/**/*", 'Gemfile', 'History.txt', 'README.md', 'Rakefile', 'any2tmx.gemspec']
26
26
  end
@@ -14,10 +14,8 @@ if options.help?
14
14
  exit 0
15
15
  end
16
16
 
17
- transform = Any2Tmx::Transforms::AndroidTransform.new(options)
18
- result = transform.result
19
-
20
- STDERR.write("Matched #{result.processed_count} of #{result.source_phrase_count} source phrases\n")
17
+ transform = Any2Tmx::Transformer.new(options)
18
+ result = transformer.transform
21
19
 
22
20
  stream = if options.output
23
21
  File.open(options.output, 'w+')
@@ -25,7 +23,7 @@ else
25
23
  STDOUT
26
24
  end
27
25
 
28
- result.write(stream)
26
+ Any2Tmx::TmxWriter.write(result, options, stream)
29
27
 
30
28
  if options.output
31
29
  STDERR.write("Wrote #{options.output}\n")
@@ -14,10 +14,8 @@ if options.help?
14
14
  exit 0
15
15
  end
16
16
 
17
- transform = Any2Tmx::Transforms::JsonTransform.new(options)
18
- result = transform.result
19
-
20
- STDERR.write("Matched #{result.processed_count} of #{result.source_phrase_count} source phrases\n")
17
+ transform = Any2Tmx::Transformer.new(options)
18
+ result = transformer.transform
21
19
 
22
20
  stream = if options.output
23
21
  File.open(options.output, 'w+')
@@ -25,7 +23,7 @@ else
25
23
  STDOUT
26
24
  end
27
25
 
28
- result.write(stream)
26
+ Any2Tmx::TmxWriter.write(result, options, stream)
29
27
 
30
28
  if options.output
31
29
  STDERR.write("Wrote #{options.output}\n")
@@ -14,10 +14,8 @@ if options.help?
14
14
  exit 0
15
15
  end
16
16
 
17
- transform = Any2Tmx::Transforms::YamlTransform.new(options)
18
- result = transform.result
19
-
20
- STDERR.write("Matched #{result.processed_count} of #{result.source_phrase_count} source phrases\n")
17
+ transformer = Any2Tmx::Transformer.new(options)
18
+ result = transformer.transform
21
19
 
22
20
  stream = if options.output
23
21
  File.open(options.output, 'w+')
@@ -25,7 +23,7 @@ else
25
23
  STDOUT
26
24
  end
27
25
 
28
- result.write(stream)
26
+ Any2Tmx::TmxWriter.write(result, options, stream)
29
27
 
30
28
  if options.output
31
29
  STDERR.write("Wrote #{options.output}\n")
@@ -1,8 +1,5 @@
1
1
  module Any2Tmx
2
- autoload :AndroidXmlParser, 'any2tmx/android_xml_parser'
3
- autoload :Options, 'any2tmx/options'
4
- autoload :PhraseSet, 'any2tmx/phrase_set'
5
- autoload :TmxWriter, 'any2tmx/tmx_writer'
6
- autoload :Transforms, 'any2tmx/transforms'
7
- autoload :Traversable, 'any2tmx/traversable'
2
+ autoload :Options, 'any2tmx/options'
3
+ autoload :TmxWriter, 'any2tmx/tmx_writer'
4
+ autoload :Transformer, 'any2tmx/transformer'
8
5
  end
@@ -5,7 +5,7 @@ module Any2Tmx
5
5
  attr_reader :errors
6
6
 
7
7
  def initialize(executable_name)
8
- @options = {}
8
+ @options = { targets: [] }
9
9
  @errors = []
10
10
 
11
11
  OptionParser.new do |opts|
@@ -13,14 +13,12 @@ module Any2Tmx
13
13
 
14
14
  opts.on('-s', '--source [file]:[locale]', 'File containing phrases in the source locale (locale appended with colon).') do |source|
15
15
  file, locale = source.split(':')
16
- @options[:source] = file
17
- @options[:source_locale] = locale
16
+ @options[:source] = { file: file, locale: locale }
18
17
  end
19
18
 
20
19
  opts.on('-t', '--target [file]:[locale]', 'File containing translations in the target locale (locale appended with colon).') do |target|
21
20
  file, locale = target.split(':')
22
- @options[:target] = file
23
- @options[:target_locale] = locale
21
+ @options[:targets] << { file: file, locale: locale }
24
22
  end
25
23
 
26
24
  opts.on('-o', '--output [file]', 'The TMX output file to write. If not specified, output is printed to stdout.') do |output|
@@ -48,16 +46,8 @@ module Any2Tmx
48
46
  @options[:source]
49
47
  end
50
48
 
51
- def target
52
- @options[:target]
53
- end
54
-
55
- def source_locale
56
- @options[:source_locale]
57
- end
58
-
59
- def target_locale
60
- @options[:target_locale]
49
+ def targets
50
+ @options[:targets]
61
51
  end
62
52
 
63
53
  def output
@@ -85,34 +75,36 @@ module Any2Tmx
85
75
  unless help?
86
76
  before_validate
87
77
  validate_source
88
- validate_target
78
+ validate_targets
89
79
  validate_output
90
80
  after_validate
91
81
  end
92
82
  end
93
83
 
94
84
  def validate_source
95
- unless File.exist?(source)
85
+ unless File.exist?(source[:file])
96
86
  errors << 'Source file does not exist.'
97
87
  end
98
88
 
99
- unless source_locale
89
+ unless source[:locale]
100
90
  errors << 'Source locale not provided. Try running with the -h option for usage details.'
101
91
  end
102
92
  end
103
93
 
104
- def validate_target
105
- unless File.exist?(target)
106
- errors << 'Target file does not exist.'
107
- end
94
+ def validate_targets
95
+ targets.each do |target|
96
+ unless File.exist?(target[:file])
97
+ errors << 'Target file does not exist.'
98
+ end
108
99
 
109
- unless target_locale
110
- errors << 'Target locale not provided. Try running with the -h option for usage details.'
100
+ unless target[:locale]
101
+ errors << 'Target locale not provided. Try running with the -h option for usage details.'
102
+ end
111
103
  end
112
104
  end
113
105
 
114
106
  def validate_output
115
- unless File.exist?(File.dirname(target))
107
+ if output && !File.exist?(File.dirname(output))
116
108
  errors << 'Output path does not exist.'
117
109
  end
118
110
  end
@@ -3,27 +3,25 @@ require 'xml-write-stream'
3
3
  module Any2Tmx
4
4
  class TmxWriter
5
5
  class << self
6
- def write(trans_map, source_locale, target_locale, io)
6
+ def write(trans_map, options, io)
7
7
  writer = XmlWriteStream.from_stream(io)
8
8
  writer.open_tag('tmx', version: '1.4')
9
- writer.open_single_line_tag('header', srclang: source_locale, datatype: 'plaintext', segtype: 'paragraph')
9
+ writer.open_single_line_tag('header', srclang: options.source[:locale], datatype: 'plaintext', segtype: 'paragraph')
10
10
  writer.close_tag
11
11
 
12
12
  writer.open_tag('body')
13
13
 
14
- trans_map.each_pair do |source_phrase, target_phrase|
14
+ trans_map.each_pair do |_, target_translations|
15
15
  writer.open_tag('tu')
16
- writer.open_tag('tuv', 'xml:lang' => source_locale)
17
- writer.open_single_line_tag('seg')
18
- writer.write_text(source_phrase)
19
- writer.close_tag # seg
20
- writer.close_tag # tuv
21
16
 
22
- writer.open_tag('tuv', 'xml:lang' => target_locale)
23
- writer.open_single_line_tag('seg')
24
- writer.write_text(target_phrase)
25
- writer.close_tag # seg
26
- writer.close_tag # tuv
17
+ target_translations.each do |locale, translation|
18
+ writer.open_tag('tuv', 'xml:lang' => locale)
19
+ writer.open_single_line_tag('seg')
20
+ writer.write_text(translation)
21
+ writer.close_tag # seg
22
+ writer.close_tag # tuv
23
+ end
24
+
27
25
  writer.close_tag # tu
28
26
  end
29
27
 
@@ -0,0 +1,60 @@
1
+ require 'abroad'
2
+
3
+ module Any2Tmx
4
+ class Transformer
5
+ EXTRACTOR_EXTENSIONS = {
6
+ '.yml' => 'yaml/rails',
7
+ '.json' => 'json/key-value',
8
+ '.xml' => 'android/xml'
9
+ }
10
+
11
+ attr_reader :options
12
+
13
+ def initialize(options)
14
+ @options = options
15
+ end
16
+
17
+ def transform
18
+ source_phrases = extract_from(options.source[:file])
19
+ result = source_phrases.each_with_object({}) do |(k, v), result|
20
+ result[k] = { options.source[:locale] => v.to_s }
21
+ end
22
+
23
+ options.targets.each do |target|
24
+ target_phrases = extract_from(target[:file])
25
+
26
+ source_phrases.each_pair do |source_key, _|
27
+ translation = target_phrases[source_key]
28
+
29
+ if !translation.nil?
30
+ result[source_key][target[:locale]] = translation.to_s
31
+ end
32
+ end
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ private
39
+
40
+ def extract_from(file)
41
+ {}.tap do |phrases|
42
+ extractor.open(file) do |extractor|
43
+ extractor.extract_each { |k, v| phrases[k] = v }
44
+ end
45
+ end
46
+ end
47
+
48
+ def extractor
49
+ @extractor ||= Abroad.extractor(extractor_id)
50
+ end
51
+
52
+ def extractor_id
53
+ EXTRACTOR_EXTENSIONS[source_extension]
54
+ end
55
+
56
+ def source_extension
57
+ File.extname(options.source[:file])
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module Any2Tmx
2
- VERSION = '1.0.4'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: any2tmx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-18 00:00:00.000000000 Z
11
+ date: 2016-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: xml-write-stream
14
+ name: abroad
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
26
+ version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -39,27 +39,27 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.6'
41
41
  - !ruby/object:Gem::Dependency
42
- name: htmlentities
42
+ name: xml-write-stream
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.3'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '4.3'
54
+ version: '1.0'
55
55
  description: A command-line tool to convert certain file types to the standard TMX
56
56
  format for translation memories.
57
57
  email:
58
58
  - camertron@gmail.com
59
59
  executables:
60
- - yaml2tmx
61
- - json2tmx
62
60
  - android2tmx
61
+ - json2tmx
62
+ - yaml2tmx
63
63
  extensions: []
64
64
  extra_rdoc_files: []
65
65
  files:
@@ -71,17 +71,9 @@ files:
71
71
  - bin/json2tmx
72
72
  - bin/yaml2tmx
73
73
  - lib/any2tmx.rb
74
- - lib/any2tmx/android_xml_parser.rb
75
74
  - lib/any2tmx/options.rb
76
- - lib/any2tmx/phrase_set.rb
77
75
  - lib/any2tmx/tmx_writer.rb
78
- - lib/any2tmx/transforms.rb
79
- - lib/any2tmx/transforms/android_transform.rb
80
- - lib/any2tmx/transforms/json_transform.rb
81
- - lib/any2tmx/transforms/result.rb
82
- - lib/any2tmx/transforms/transform.rb
83
- - lib/any2tmx/transforms/yaml_transform.rb
84
- - lib/any2tmx/traversable.rb
76
+ - lib/any2tmx/transformer.rb
85
77
  - lib/any2tmx/version.rb
86
78
  homepage: http://github.com/camertron/any2tmx
87
79
  licenses: []
@@ -108,4 +100,3 @@ specification_version: 4
108
100
  summary: A command-line tool to convert certain file types to the standard TMX format
109
101
  for translation memories.
110
102
  test_files: []
111
- has_rdoc: true
@@ -1,146 +0,0 @@
1
- require 'nokogiri'
2
- require 'htmlentities'
3
-
4
- # These classes have been adapted from:
5
- # https://github.com/rosette-proj/rosette-extractor-xml
6
-
7
- class HTMLEntities
8
- MAPPINGS['android_xml'] = MAPPINGS['xhtml1'].dup.tap do |mappings|
9
- mappings.delete('apos')
10
- end
11
-
12
- FLAVORS << 'android_xml'
13
-
14
- class AndroidXmlDecoder < Decoder
15
- def initialize
16
- super('android_xml')
17
- end
18
- end
19
- end
20
-
21
- module Any2Tmx
22
- class AndroidXmlParser
23
- class << self
24
- def parse(xml_content)
25
- doc = parse_xml(xml_content)
26
- result = {}.tap do |result|
27
- collector = lambda { |text, key| result[key] = text }
28
- each_string_entry(doc, &collector)
29
- each_array_entry(doc, &collector)
30
- each_plural_entry(doc, &collector)
31
- end
32
- end
33
-
34
- protected
35
-
36
- def parse_xml(xml_content)
37
- Nokogiri::XML(xml_content) do |config|
38
- config.options = Nokogiri::XML::ParseOptions::NONET
39
- end
40
- end
41
-
42
- def each_string_entry(doc)
43
- doc.xpath('//string').each do |node|
44
- yield(
45
- text_from(node),
46
- name_from(node)
47
- )
48
- end
49
- end
50
-
51
- def each_array_entry(doc)
52
- doc.xpath('//string-array').each do |array|
53
- prefix = name_from(array)
54
-
55
- array.xpath('item').each_with_index do |item, idx|
56
- yield(
57
- text_from(item),
58
- "#{prefix}.#{idx}"
59
- )
60
- end
61
- end
62
- end
63
-
64
- def each_plural_entry(doc)
65
- doc.xpath('//plurals').each do |plurals|
66
- prefix = name_from(plurals)
67
-
68
- plurals.xpath('item').each do |item|
69
- quantity = item.attributes['quantity'].value
70
-
71
- yield(
72
- text_from(item),
73
- "#{prefix}.#{quantity}"
74
- )
75
- end
76
- end
77
- end
78
-
79
- def text_from(node)
80
- builder = Nokogiri::XML::Builder.new do |builder|
81
- builder.root do
82
- node.children.each do |child|
83
- serialize(child, builder)
84
- end
85
- end
86
- end
87
-
88
- # safe to call `strip` after `to_xml` because any string that
89
- # needs leading or trailing whitespace preserved should be wrapped
90
- # in double quotes
91
- unescape(
92
- strip_enclosing_quotes(
93
- builder.doc.xpath('/root/node()').to_xml.strip
94
- )
95
- )
96
- end
97
-
98
- def serialize(node, builder)
99
- if node.text?
100
- builder.text(unescape(node.text))
101
- else
102
- builder.send("#{node.name}_", node.attributes) do
103
- node.children.each do |child|
104
- serialize(child, builder)
105
- end
106
- end
107
- end
108
- end
109
-
110
- def name_from(node)
111
- if attribute = node.attributes['name']
112
- attribute.value
113
- end
114
- end
115
-
116
- def unescape(text)
117
- text = text
118
- .gsub("\\'", "'")
119
- .gsub('\\"', '"')
120
- .gsub("\\n", "\n")
121
- .gsub("\\r", "\r")
122
- .gsub("\\t", "\t")
123
-
124
- coder.decode(text)
125
- end
126
-
127
- def coder
128
- @coder ||= HTMLEntities::AndroidXmlDecoder.new
129
- end
130
-
131
- def strip_enclosing_quotes(text)
132
- quote = case text[0]
133
- when "'", '"'
134
- text[0]
135
- end
136
-
137
- if quote
138
- text.gsub(/\A#{quote}(.*)#{quote}\z/) { $1 }
139
- else
140
- text
141
- end
142
- end
143
-
144
- end
145
- end
146
- end
@@ -1,14 +0,0 @@
1
- module Any2Tmx
2
- class PhraseSet
3
- attr_reader :traversable, :locale
4
-
5
- def initialize(traversable, locale)
6
- @traversable = traversable
7
- @locale = locale
8
- end
9
-
10
- def zip(other_set, &block)
11
- traversable.zip(other_set.traversable, &block)
12
- end
13
- end
14
- end
@@ -1,9 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- autoload :AndroidTransform, 'any2tmx/transforms/android_transform'
4
- autoload :JsonTransform, 'any2tmx/transforms/json_transform'
5
- autoload :Transform, 'any2tmx/transforms/transform'
6
- autoload :Result, 'any2tmx/transforms/result'
7
- autoload :YamlTransform, 'any2tmx/transforms/yaml_transform'
8
- end
9
- end
@@ -1,18 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- class AndroidTransform < Transform
4
- private
5
-
6
- def load_file(file, locale)
7
- phrases = File.read(file)
8
- load(phrases, locale)
9
- end
10
-
11
- def load(contents, locale)
12
- contents = Any2Tmx::AndroidXmlParser.parse(contents)
13
- traversable = Any2Tmx::Traversable.new(contents)
14
- Any2Tmx::PhraseSet.new(traversable, locale)
15
- end
16
- end
17
- end
18
- end
@@ -1,19 +0,0 @@
1
- require 'json'
2
-
3
- module Any2Tmx
4
- module Transforms
5
- class JsonTransform < Transform
6
- private
7
-
8
- def load_file(file, locale)
9
- phrases = File.read(file)
10
- load(phrases, locale)
11
- end
12
-
13
- def load(contents, locale)
14
- traversable = Any2Tmx::Traversable.new(JSON.parse(contents))
15
- Any2Tmx::PhraseSet.new(traversable, locale)
16
- end
17
- end
18
- end
19
- end
@@ -1,24 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- class Result
4
- attr_reader :source, :target, :collection, :processed_count
5
-
6
- def initialize(source, target, collection, processed_count)
7
- @source = source
8
- @target = target
9
- @collection = collection
10
- @processed_count = processed_count
11
- end
12
-
13
- def source_phrase_count
14
- source.traversable.size
15
- end
16
-
17
- def write(io)
18
- Any2Tmx::TmxWriter.write(
19
- collection, source.locale, target.locale, io
20
- )
21
- end
22
- end
23
- end
24
- end
@@ -1,39 +0,0 @@
1
- module Any2Tmx
2
- module Transforms
3
- class Transform
4
- attr_reader :options
5
-
6
- def initialize(options)
7
- @options = options
8
- end
9
-
10
- def result
11
- source = read(options.source, options.source_locale)
12
- target = read(options.target, options.target_locale)
13
- count = 0
14
- zipped = source.zip(target) { count += 1 }
15
- Result.new(source, target, zipped, count)
16
- end
17
-
18
- private
19
-
20
- def read(location_or_contents, locale)
21
- if File.exist?(location_or_contents)
22
- load_file(location_or_contents, locale)
23
- else
24
- load(location_or_contents, locale)
25
- end
26
- end
27
-
28
- def load_file(file, locale)
29
- raise NotImplementedError,
30
- "#{__method__} must be defined in derived classes"
31
- end
32
-
33
- def load(file, locale)
34
- raise NotImplementedError,
35
- "#{__method__} must be defined in derived classes"
36
- end
37
- end
38
- end
39
- end
@@ -1,25 +0,0 @@
1
- require 'yaml'
2
-
3
- module Any2Tmx
4
- module Transforms
5
- class YamlTransform < Transform
6
- private
7
-
8
- def load_file(file, locale)
9
- phrases = File.read(file)
10
- load(phrases, locale)
11
- end
12
-
13
- def load(contents, locale)
14
- contents = YAML.load(contents)
15
-
16
- if contents.include?(locale)
17
- contents = contents[locale]
18
- end
19
-
20
- traversable = Any2Tmx::Traversable.new(contents).stringify_keys
21
- Any2Tmx::PhraseSet.new(traversable, locale)
22
- end
23
- end
24
- end
25
- end
@@ -1,127 +0,0 @@
1
- module Any2Tmx
2
- class Traversable
3
- attr_reader :collection
4
-
5
- def initialize(collection)
6
- @collection = collection
7
- end
8
-
9
- def each_entry(&block)
10
- if block_given?
11
- each_entry_helper(collection, [], nil) do |entry, path, last_key|
12
- yield entry, path + [last_key]
13
- end
14
- else
15
- to_enum(__method__)
16
- end
17
- end
18
-
19
- def size
20
- each_entry.inject(0) { |ret, _| ret + 1 }
21
- end
22
-
23
- def dig_each(path)
24
- if block_given?
25
- path.inject(:start) do |ret, seg|
26
- if ret == :start
27
- yield collection, seg
28
- collection[seg]
29
- elsif ret
30
- if seg.is_a?(Numeric) && ret.is_a?(Array)
31
- yield ret, seg
32
- ret[seg] # array index case
33
- elsif ret.is_a?(Hash)
34
- yield ret, seg
35
- ret[seg] # hash key case
36
- end
37
- end
38
- end
39
- else
40
- to_enum(__method__, path)
41
- end
42
- end
43
-
44
- def dig(path)
45
- return collection if path.empty?
46
- dig_each(path) {}
47
- end
48
-
49
- def transform
50
- if block_given?
51
- self.class.new(make_empty(sym_from(collection))).tap do |copy|
52
- each_entry_helper(collection, [], nil) do |entry, path, last_key|
53
- dig_each(path).inject(copy.collection) do |copy_obj, (obj, key)|
54
- copy_obj[key] ||= make_empty(sym_from(obj[key]))
55
- copy_obj[key]
56
- end
57
-
58
- yield copy.dig(path), last_key, entry
59
- end
60
- end
61
- else
62
- to_enum(__method__)
63
- end
64
- end
65
-
66
- def zip(other_traversable)
67
- each_entry.each_with_object({}) do |(entry, path), ret|
68
- other_entry = other_traversable.dig(path)
69
- ret[entry] = other_entry if other_entry
70
- yield if block_given? && other_entry
71
- end
72
- end
73
-
74
- def stringify_keys
75
- transform do |obj, key, value|
76
- obj[stringify(key)] = value
77
- end
78
- end
79
-
80
- private
81
-
82
- def stringify(obj)
83
- obj.is_a?(Symbol) ? obj.to_s : obj
84
- end
85
-
86
- def sym_from(obj)
87
- case obj
88
- when Hash
89
- :hash
90
- when Array
91
- :array
92
- end
93
- end
94
-
95
- def make_empty(sym)
96
- case sym
97
- when :hash
98
- {}
99
- when :array
100
- []
101
- end
102
- end
103
-
104
- def each_entry_helper(coll, path, last_key, &block)
105
- next_path = if last_key
106
- path + [last_key]
107
- else
108
- path
109
- end
110
-
111
- case coll
112
- when Hash
113
- coll.each_pair do |key, value|
114
- each_entry_helper(value, next_path, key, &block)
115
- end
116
-
117
- when Array
118
- coll.each_with_index do |element, idx|
119
- each_entry_helper(element, next_path, idx, &block)
120
- end
121
-
122
- when String
123
- yield coll, path, last_key
124
- end
125
- end
126
- end
127
- end