twineCSV 1.0.5 → 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/README.md +18 -2
- data/bin/twineCSV +25 -6
- data/lib/twineCSV.rb +131 -26
- data/lib/twineCSV/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 648f2661b1037005868dfacdb2935d6b90f2c965
|
4
|
+
data.tar.gz: 9930d4500cb50651df57fd03e4f6995896187c03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2688ccc59362f51fdb4233d52c1a08e142ca7e436a34f6c2c199a9e95092cc3ca046726f99061710cff51d3e350d7bd971efce9663972532f55583e85a273a94
|
7
|
+
data.tar.gz: f1900f04b94c9b67428df7e71adc8e0f52efd320dd283c898c74a13ca32fb9c22d98830a189d596c81bcf78771442e75925dd7cfa1274dc954c2913569b447b7
|
data/README.md
CHANGED
@@ -18,7 +18,13 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
This micro gem converts twine formatted txt files to csv and vice versa. The reason for this is that the localisation
|
21
|
+
This micro gem converts twine formatted txt files to csv or xlsx and vice versa. The reason for this is that the localisation
|
22
|
+
information is often provided by external services, which do not want to deal with restricted file formats but rather
|
23
|
+
want to work with Excel or similar programs. Thus this gem was created to create csv or xlsx files from your twine files.
|
24
|
+
After you get your finalized csv or xlsx files back you can convert them to a txt file, with the proper twine formatting.
|
25
|
+
To get more information about twine in general visit their [github page](https://github.com/mobiata/twine).
|
26
|
+
|
27
|
+
Support for xlsx files since version 1.1.0.
|
22
28
|
|
23
29
|
### Convert to csv
|
24
30
|
|
@@ -26,6 +32,12 @@ This micro gem converts twine formatted txt files to csv and vice versa. The rea
|
|
26
32
|
twineCSV tocsv localisation.txt converted.csv
|
27
33
|
```
|
28
34
|
|
35
|
+
### Convert to xlsx
|
36
|
+
|
37
|
+
```
|
38
|
+
twineCSV toxlsx localisation.txt converted.xlsx
|
39
|
+
```
|
40
|
+
|
29
41
|
You have to provide at least the input file. When omitting the output file the filename is created based on the inputs filename.
|
30
42
|
|
31
43
|
### Convert to twine file
|
@@ -34,6 +46,10 @@ You have to provide at least the input file. When omitting the output file the f
|
|
34
46
|
twineCSV totwine converted.csv localisation.txt
|
35
47
|
```
|
36
48
|
|
49
|
+
```
|
50
|
+
twineCSV totwine converted.xlsx localisation.txt
|
51
|
+
```
|
52
|
+
|
37
53
|
You have to provide at least the input file. When omitting the output file the filename is created based on the inputs filename.
|
38
54
|
|
39
55
|
### Help
|
@@ -50,7 +66,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
50
66
|
|
51
67
|
## Contributing
|
52
68
|
|
53
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
69
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/dasheck0/twineCSV. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
54
70
|
|
55
71
|
|
56
72
|
## License
|
data/bin/twineCSV
CHANGED
@@ -10,20 +10,20 @@ program :description, 'Converts your twine formatted localisation file to CSV an
|
|
10
10
|
|
11
11
|
command :totwine do |c|
|
12
12
|
c.syntax = 'twineCSV totwine input [output]'
|
13
|
-
c.summary = 'Converts a csv file into a twine file'
|
14
|
-
c.description = 'Converts a csv file into a twine file. You have to provide at least the input file as first parameter. If the output file is omitted the output file will be named after the input file but with a proper extension.'
|
15
|
-
c.example 'Converts a csv file into a twine file', 'twineCSV totwine converted.csv localisation.txt'
|
13
|
+
c.summary = 'Converts a csv or xlsx file into a twine file'
|
14
|
+
c.description = 'Converts a csv or xslx file into a twine file. You have to provide at least the input file as first parameter. If the output file is omitted the output file will be named after the input file but with a proper extension.'
|
15
|
+
c.example 'Converts a csv or xslx file into a twine file', 'twineCSV totwine converted.csv localisation.txt'
|
16
16
|
|
17
17
|
c.action do |args, options|
|
18
18
|
abort("You have to provide at least a filename") if args[0].nil?
|
19
19
|
|
20
|
-
|
20
|
+
file = args[0]
|
21
21
|
twine = args[1].nil? ? "#{args[0].split(".")[0]}.txt" : args[1].dup
|
22
22
|
twine << ".txt" unless twine.split(".")[-1] == 'txt'
|
23
23
|
|
24
|
-
puts "Converting input file #{
|
24
|
+
puts "Converting input file #{file}"
|
25
25
|
|
26
|
-
TwineCSV::to_twine
|
26
|
+
TwineCSV::to_twine file, twine
|
27
27
|
|
28
28
|
puts "Done. Your output file is #{twine}"
|
29
29
|
end
|
@@ -49,3 +49,22 @@ command :tocsv do |c|
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
command :toxlsx do |c|
|
53
|
+
c.syntax = 'twinCSV toxlsx input [output]'
|
54
|
+
c.summary = 'Converts a twine file into an Excel Spreadsheet'
|
55
|
+
c.description = 'Converts a twine file into an Excel Spreadsheet. You have to provide at least the input file as first parameter. If the output file is omitted the output file will be named after the input file but with a proper extension.'
|
56
|
+
c.example 'Convert a twine file into a xlsx file', 'twineCSV toxlsx localisation.txt converted.xlsx'
|
57
|
+
c.action do |args, options|
|
58
|
+
abort('You have to provide at least a filename') if args[0].nil?
|
59
|
+
|
60
|
+
twine = args[0]
|
61
|
+
xlsx = args[1].nil? ? "#{args[0].split(".")[0]}.xlsx" : args[1].dup
|
62
|
+
xlsx << ".xlsx" unless xlsx.split('.')[-1] == 'xlsx'
|
63
|
+
|
64
|
+
puts "Converting input file #{twine}"
|
65
|
+
|
66
|
+
TwineCSV::to_xlsx twine, xlsx
|
67
|
+
|
68
|
+
puts "Done. Your output file is #{xlsx}"
|
69
|
+
end
|
70
|
+
end
|
data/lib/twineCSV.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require "twineCSV/version"
|
2
2
|
require 'rubygems'
|
3
|
+
require 'rubyXL'
|
3
4
|
|
4
5
|
module TwineCSV
|
5
6
|
|
6
7
|
def self.to_csv input, output
|
7
8
|
abort("The input file must not be nil") if input.nil? or output.nil?
|
8
9
|
content = File.open(input, 'r').read
|
9
|
-
lines = content.each_line.to_a.map {
|
10
|
+
lines = content.each_line.to_a.map {|line|
|
10
11
|
result = line.gsub("\n", '').strip
|
11
12
|
result[-1] == ";" ? result[0..-2] : result
|
12
13
|
}
|
@@ -15,7 +16,7 @@ module TwineCSV
|
|
15
16
|
current_key = ''
|
16
17
|
current_section = ''
|
17
18
|
|
18
|
-
lines.reject {
|
19
|
+
lines.reject {|line| line.length == 0}.each {|line|
|
19
20
|
if line.start_with? '[['
|
20
21
|
current_section = line[2..-3]
|
21
22
|
puts current_section
|
@@ -24,19 +25,19 @@ module TwineCSV
|
|
24
25
|
current_key = line[1..-2]
|
25
26
|
dictionary[current_section][current_key] = {}
|
26
27
|
elsif current_key.length > 0
|
27
|
-
lang, value = line.split("=").map(&:strip)
|
28
|
+
lang, value = line.split("=", 2).map(&:strip)
|
28
29
|
langs << lang
|
29
30
|
dictionary[current_section][current_key][lang] = value || ''
|
30
31
|
end
|
31
32
|
}
|
32
33
|
|
33
|
-
File.open(output, 'wb+') {
|
34
|
+
File.open(output, 'wb+') {|f|
|
34
35
|
|
35
36
|
f << 'section;key;' << langs.uniq.join(';') << "\n"
|
36
37
|
|
37
|
-
dictionary.each {
|
38
|
-
v.each {
|
39
|
-
vlangs = langs.uniq.map
|
38
|
+
dictionary.each {|k, v|
|
39
|
+
v.each {|k2, v2|
|
40
|
+
vlangs = langs.uniq.map {|lang| v2[lang]}
|
40
41
|
f << "#{k};#{k2};#{vlangs.join(";")}" << "\n"
|
41
42
|
}
|
42
43
|
}
|
@@ -46,41 +47,145 @@ module TwineCSV
|
|
46
47
|
|
47
48
|
def self.to_twine input, output
|
48
49
|
abort("The input file must not be nil") if input.nil? or output.nil?
|
49
|
-
|
50
|
+
extension = input.split('.')[-1]
|
51
|
+
|
52
|
+
if extension == 'csv'
|
53
|
+
check_for_separator(input)
|
54
|
+
|
55
|
+
content = File.open(input, 'r').read
|
56
|
+
lines = content.each_line.to_a.map {|line| line.gsub("\n", '').strip}
|
57
|
+
current_section = ''
|
58
|
+
result = []
|
59
|
+
langs = lines[0].split(';')[2..-1]
|
60
|
+
|
61
|
+
lines[1..-1].each {|line|
|
62
|
+
values = "#{line} ".split(";")
|
63
|
+
old_section = current_section
|
64
|
+
current_section = values.first
|
65
|
+
|
66
|
+
if current_section != old_section
|
67
|
+
result << "#{result.empty? ? '' : "\n"}[[#{current_section}]]"
|
68
|
+
result << " [#{values[1]}]" << values[2..-1].map.with_index {|value, i| " #{langs[i].downcase} = #{value.strip}" unless langs[i].nil?}
|
69
|
+
else
|
70
|
+
result << "\n [#{values[1]}]" << values[2..-1].map.with_index {|value, i| " #{langs[i].downcase} = #{value.strip}" unless langs[i].nil?}
|
71
|
+
end
|
72
|
+
}
|
73
|
+
|
74
|
+
File.open(output, 'wb+') {|f|
|
75
|
+
f << result.join("\n")
|
76
|
+
}
|
77
|
+
elsif extension == 'xlsx'
|
78
|
+
workbook = RubyXL::Parser.parse input
|
79
|
+
|
80
|
+
worksheet = workbook[0]
|
81
|
+
langs = []
|
82
|
+
result = []
|
83
|
+
|
84
|
+
current_section = ''
|
85
|
+
worksheet.each_with_index {|row, row_index|
|
86
|
+
row && row.cells.each_with_index {|cell, cell_index|
|
87
|
+
if cell_index > 1
|
88
|
+
if row_index == 0
|
89
|
+
langs << cell&.value
|
90
|
+
else
|
91
|
+
puts "cwl #{cell.value} #{row_index} #{cell_index}"
|
92
|
+
result << " #{langs[cell_index-2]} = #{(cell&.value || '').strip}#{"\n" if cell_index - 2 >= langs.length-1}" unless langs[cell_index-2].nil?
|
93
|
+
end
|
94
|
+
elsif cell_index == 1
|
95
|
+
result << " [#{cell&.value}]" unless row_index == 0
|
96
|
+
elsif cell_index == 0
|
97
|
+
old_section = current_section
|
98
|
+
current_section = cell&.value
|
99
|
+
|
100
|
+
result << "[[#{cell&.value}]]" unless row_index == 0 or old_section == current_section
|
101
|
+
end
|
102
|
+
}
|
103
|
+
|
104
|
+
File.open(output, 'wb+') {|f|
|
105
|
+
f << result.join("\n")
|
106
|
+
}
|
107
|
+
}
|
108
|
+
else
|
109
|
+
abort("The filetype #{extension} is currently not supported")
|
110
|
+
end
|
111
|
+
end
|
50
112
|
|
113
|
+
def self.to_xlsx input, output
|
114
|
+
abort("The input file must not be nil") if input.nil? or output.nil?
|
51
115
|
content = File.open(input, 'r').read
|
52
|
-
|
116
|
+
|
117
|
+
lines = content.each_line.to_a.map {|line|
|
118
|
+
result = line.gsub("\n", '').strip
|
119
|
+
result[-1] == ";" ? result[0..-2] : result
|
120
|
+
}
|
121
|
+
dictionary = {}
|
122
|
+
langs = []
|
123
|
+
current_key = ''
|
53
124
|
current_section = ''
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
125
|
+
|
126
|
+
lines.reject {|line| line.length == 0}.each {|line|
|
127
|
+
if line.start_with? '[['
|
128
|
+
current_section = line[2..-3]
|
129
|
+
puts current_section
|
130
|
+
dictionary[current_section] = {}
|
131
|
+
elsif line.start_with? '['
|
132
|
+
current_key = line[1..-2]
|
133
|
+
dictionary[current_section][current_key] = {}
|
134
|
+
elsif current_key.length > 0
|
135
|
+
lang, value = line.split("=", 2).map(&:strip)
|
136
|
+
langs << lang
|
137
|
+
dictionary[current_section][current_key][lang] = value || ''
|
67
138
|
end
|
68
139
|
}
|
69
140
|
|
70
|
-
|
71
|
-
|
141
|
+
workbook = RubyXL::Workbook.new
|
142
|
+
worksheet = workbook[0]
|
143
|
+
worksheet.sheet_name = 'Translation'
|
144
|
+
|
145
|
+
worksheet.add_cell 0, 0, 'Section'
|
146
|
+
worksheet.add_cell 0, 1, 'Key'
|
147
|
+
|
148
|
+
worksheet.change_column_width 0, 0
|
149
|
+
worksheet.change_column_width 1, 0
|
150
|
+
|
151
|
+
langs.uniq.each_with_index.map {|item, index|
|
152
|
+
worksheet.add_cell 0, index + 2, item
|
153
|
+
worksheet.change_column_width index + 2, 80
|
154
|
+
}
|
155
|
+
|
156
|
+
worksheet.change_row_border 0, :bottom, 'medium'
|
157
|
+
worksheet.change_row_bold 0, true
|
158
|
+
|
159
|
+
row = 1
|
160
|
+
|
161
|
+
dictionary.each {|k, v|
|
162
|
+
v.each {|k2, v2|
|
163
|
+
vlangs = langs.uniq.map {|lang| v2[lang]}
|
164
|
+
worksheet.add_cell row, 0, k
|
165
|
+
worksheet.add_cell row, 1, k2
|
166
|
+
|
167
|
+
vlangs.each_with_index {|item, column|
|
168
|
+
cell = worksheet.add_cell row, column + 2, item
|
169
|
+
cell.change_text_wrap true
|
170
|
+
worksheet.change_row_fill row, 'cc3300' if item == ''
|
171
|
+
}
|
172
|
+
|
173
|
+
row += 1
|
174
|
+
}
|
72
175
|
}
|
176
|
+
|
177
|
+
workbook.write output
|
73
178
|
end
|
74
179
|
|
75
180
|
def self.check_for_separator(input)
|
76
181
|
allowed_separators = [';']
|
77
182
|
|
78
183
|
content = File.open(input, 'r').read
|
79
|
-
lines = content.each_line.to_a.map {
|
184
|
+
lines = content.each_line.to_a.map {|line| line.gsub("\n", '').strip}
|
80
185
|
header_line = lines[0]
|
81
186
|
|
82
187
|
unless header_line.nil?
|
83
|
-
abort('No valid separator was found in the csv. Please use one of the following: ' + allowed_separators.join(' ')) unless allowed_separators.any? {
|
188
|
+
abort('No valid separator was found in the csv. Please use one of the following: ' + allowed_separators.join(' ')) unless allowed_separators.any? {|separator| header_line.include?(separator)}
|
84
189
|
end
|
85
190
|
end
|
86
191
|
|
data/lib/twineCSV/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twineCSV
|
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
|
- Stefan Neidig
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
103
|
version: '0'
|
104
104
|
requirements: []
|
105
105
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
106
|
+
rubygems_version: 2.6.14
|
107
107
|
signing_key:
|
108
108
|
specification_version: 4
|
109
109
|
summary: twineCSV converts your twine localisation file to CSV and vice versa.
|