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