any2tmx 1.0.4 → 1.1.0
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.
- checksums.yaml +4 -4
- data/History.txt +14 -11
- data/any2tmx.gemspec +10 -10
- data/bin/android2tmx +3 -5
- data/bin/json2tmx +3 -5
- data/bin/yaml2tmx +3 -5
- data/lib/any2tmx.rb +3 -6
- data/lib/any2tmx/options.rb +17 -25
- data/lib/any2tmx/tmx_writer.rb +11 -13
- data/lib/any2tmx/transformer.rb +60 -0
- data/lib/any2tmx/version.rb +1 -1
- metadata +11 -20
- data/lib/any2tmx/android_xml_parser.rb +0 -146
- data/lib/any2tmx/phrase_set.rb +0 -14
- data/lib/any2tmx/transforms.rb +0 -9
- data/lib/any2tmx/transforms/android_transform.rb +0 -18
- data/lib/any2tmx/transforms/json_transform.rb +0 -19
- data/lib/any2tmx/transforms/result.rb +0 -24
- data/lib/any2tmx/transforms/transform.rb +0 -39
- data/lib/any2tmx/transforms/yaml_transform.rb +0 -25
- data/lib/any2tmx/traversable.rb +0 -127
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfbf800c45d800fa53efa6f1f142f154e6ea2be6
|
4
|
+
data.tar.gz: 19c4b39b0252af8fb49cbeb4fc994c14f5c79571
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2a67b0fce2c98fe75e198f12822df3567138a4a11f2abae9b8255836c0a724a719912fa3db011b0b6c26f9036ddeee7e197fbb1cd87b564009dfcb5b0e29820
|
7
|
+
data.tar.gz: 19e26011be1125aa387c05b6cc7ae388ef1ff04766bee422f9341e8fd630d602a635f03067ca10f8545a34cbb61a281ef94d9d4a5275a5ca304e3153c4b76804
|
data/History.txt
CHANGED
@@ -1,24 +1,27 @@
|
|
1
|
-
== 1.
|
1
|
+
== 1.1.0
|
2
2
|
|
3
|
-
*
|
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.
|
7
|
+
== 1.0.4
|
6
8
|
|
7
|
-
*
|
8
|
-
* Added support for JSON and Android XML.
|
9
|
+
* Fixing bug with JSON processor causing crash.
|
9
10
|
|
10
|
-
== 1.0.
|
11
|
+
== 1.0.3
|
11
12
|
|
12
|
-
*
|
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.
|
19
|
+
== 1.0.1
|
19
20
|
|
20
|
-
*
|
21
|
+
* Add ability to load files by name or by contents.
|
21
22
|
|
22
|
-
== 1.0.
|
23
|
+
== 1.0.0
|
23
24
|
|
24
|
-
*
|
25
|
+
* Birthday!
|
26
|
+
* Renamed gem from yaml2tmx to any2tmx.
|
27
|
+
* Added support for JSON and Android XML.
|
data/any2tmx.gemspec
CHANGED
@@ -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 =
|
5
|
+
s.name = 'any2tmx'
|
6
6
|
s.version = ::Any2Tmx::VERSION
|
7
|
-
s.authors = [
|
8
|
-
s.email = [
|
9
|
-
s.homepage =
|
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 =
|
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 '
|
16
|
+
s.add_dependency 'abroad', '~> 4.0'
|
17
17
|
s.add_dependency 'nokogiri', '~> 1.6'
|
18
|
-
s.add_dependency '
|
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}/**/*",
|
25
|
+
s.files = Dir["{lib,spec}/**/*", 'Gemfile', 'History.txt', 'README.md', 'Rakefile', 'any2tmx.gemspec']
|
26
26
|
end
|
data/bin/android2tmx
CHANGED
@@ -14,10 +14,8 @@ if options.help?
|
|
14
14
|
exit 0
|
15
15
|
end
|
16
16
|
|
17
|
-
transform = Any2Tmx::
|
18
|
-
result = transform
|
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
|
-
|
26
|
+
Any2Tmx::TmxWriter.write(result, options, stream)
|
29
27
|
|
30
28
|
if options.output
|
31
29
|
STDERR.write("Wrote #{options.output}\n")
|
data/bin/json2tmx
CHANGED
@@ -14,10 +14,8 @@ if options.help?
|
|
14
14
|
exit 0
|
15
15
|
end
|
16
16
|
|
17
|
-
transform = Any2Tmx::
|
18
|
-
result = transform
|
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
|
-
|
26
|
+
Any2Tmx::TmxWriter.write(result, options, stream)
|
29
27
|
|
30
28
|
if options.output
|
31
29
|
STDERR.write("Wrote #{options.output}\n")
|
data/bin/yaml2tmx
CHANGED
@@ -14,10 +14,8 @@ if options.help?
|
|
14
14
|
exit 0
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
result = transform
|
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
|
-
|
26
|
+
Any2Tmx::TmxWriter.write(result, options, stream)
|
29
27
|
|
30
28
|
if options.output
|
31
29
|
STDERR.write("Wrote #{options.output}\n")
|
data/lib/any2tmx.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
module Any2Tmx
|
2
|
-
autoload :
|
3
|
-
autoload :
|
4
|
-
autoload :
|
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
|
data/lib/any2tmx/options.rb
CHANGED
@@ -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[:
|
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
|
52
|
-
@options[:
|
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
|
-
|
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
|
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
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
110
|
-
|
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
|
-
|
107
|
+
if output && !File.exist?(File.dirname(output))
|
116
108
|
errors << 'Output path does not exist.'
|
117
109
|
end
|
118
110
|
end
|
data/lib/any2tmx/tmx_writer.rb
CHANGED
@@ -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,
|
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:
|
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 |
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
data/lib/any2tmx/version.rb
CHANGED
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
|
+
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-
|
11
|
+
date: 2016-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: abroad
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
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: '
|
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:
|
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: '
|
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: '
|
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/
|
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
|
data/lib/any2tmx/phrase_set.rb
DELETED
@@ -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
|
data/lib/any2tmx/transforms.rb
DELETED
@@ -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
|
data/lib/any2tmx/traversable.rb
DELETED
@@ -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
|