csv2strings 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -4
- data/.travis.yml +12 -4
- data/Gemfile +5 -1
- data/README.md +3 -6
- data/Rakefile +4 -2
- data/bin/csv2strings +2 -2
- data/bin/strings2csv +2 -2
- data/csv2strings.gemspec +5 -3
- data/lib/csvconverter.rb +11 -6
- data/lib/{command.rb → csvconverter/command.rb} +0 -3
- data/lib/{csv2strings_command.rb → csvconverter/commands/csv2strings_command.rb} +5 -6
- data/lib/{strings2csv_command.rb → csvconverter/commands/strings2csv_command.rb} +5 -7
- data/lib/csvconverter/csv2strings.rb +132 -0
- data/lib/{google_doc.rb → csvconverter/google_doc.rb} +13 -4
- data/lib/csvconverter/strings2csv.rb +96 -0
- data/test/csvconverter/commands/test_command_csv2strings.rb +36 -0
- data/test/csvconverter/commands/test_command_strings2csv.rb +77 -0
- data/test/{csv2strings/converter_test.rb → csvconverter/test_csv2strings.rb} +5 -7
- data/test/{strings2csv/converter_test.rb → csvconverter/test_strings2csv.rb} +26 -22
- data/test/data/test_with_nil.csv +3 -0
- data/test/data/test_with_nil.strings +4 -0
- data/test/test_helper.rb +8 -2
- metadata +152 -113
- data/Gemfile.lock +0 -49
- data/lib/csv2strings/converter.rb +0 -133
- data/lib/strings2csv/converter.rb +0 -95
- data/test/command_test.rb +0 -90
- data/test/google_doc_test.rb +0 -6
data/Gemfile.lock
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
csv2strings (0.2.1)
|
5
|
-
google_drive (= 0.3.6)
|
6
|
-
nokogiri (= 1.5.10)
|
7
|
-
thor
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: http://rubygems.org/
|
11
|
-
specs:
|
12
|
-
faraday (0.8.8)
|
13
|
-
multipart-post (~> 1.2.0)
|
14
|
-
google_drive (0.3.6)
|
15
|
-
nokogiri (>= 1.4.4, != 1.5.2, != 1.5.1)
|
16
|
-
oauth (>= 0.3.6)
|
17
|
-
oauth2 (>= 0.5.0)
|
18
|
-
httpauth (0.2.0)
|
19
|
-
jwt (0.1.6)
|
20
|
-
multi_json (>= 1.0)
|
21
|
-
multi_json (1.3.6)
|
22
|
-
multi_xml (0.5.5)
|
23
|
-
multipart-post (1.2.0)
|
24
|
-
nokogiri (1.5.10)
|
25
|
-
oauth (0.4.7)
|
26
|
-
oauth2 (0.9.2)
|
27
|
-
faraday (~> 0.8)
|
28
|
-
httpauth (~> 0.2)
|
29
|
-
jwt (~> 0.1.4)
|
30
|
-
multi_json (~> 1.0)
|
31
|
-
multi_xml (~> 0.5)
|
32
|
-
rack (~> 1.2)
|
33
|
-
rack (1.5.2)
|
34
|
-
rake (0.9.2.2)
|
35
|
-
simplecov (0.6.4)
|
36
|
-
multi_json (~> 1.0)
|
37
|
-
simplecov-html (~> 0.5.3)
|
38
|
-
simplecov-html (0.5.3)
|
39
|
-
test-unit (2.4.8)
|
40
|
-
thor (0.18.1)
|
41
|
-
|
42
|
-
PLATFORMS
|
43
|
-
ruby
|
44
|
-
|
45
|
-
DEPENDENCIES
|
46
|
-
csv2strings!
|
47
|
-
rake
|
48
|
-
simplecov
|
49
|
-
test-unit
|
@@ -1,133 +0,0 @@
|
|
1
|
-
module CSV2Strings
|
2
|
-
class Converter
|
3
|
-
attr_accessor :csv_filename, :output_file
|
4
|
-
attr_accessor :langs, :default_lang
|
5
|
-
attr_accessor :default_path
|
6
|
-
attr_accessor :excluded_states, :state_column, :keys_column
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(filename, langs, args = {})
|
10
|
-
args.merge!({
|
11
|
-
:excluded_states => [],
|
12
|
-
:state_column => nil,
|
13
|
-
:keys_column => 0})
|
14
|
-
|
15
|
-
@csv_filename = filename
|
16
|
-
@langs = langs
|
17
|
-
|
18
|
-
if !@langs.is_a?(Hash) || @langs.size == 0
|
19
|
-
raise "wrong format or/and languages parameter" + @langs.inspect
|
20
|
-
end
|
21
|
-
@output_file = (@langs.size == 1) ? args[:output_file] : nil
|
22
|
-
|
23
|
-
@default_path = args[:default_path].to_s
|
24
|
-
@excluded_states = args[:excluded_states]
|
25
|
-
@state_column = args[:state_column]
|
26
|
-
@keys_column = args[:keys_column]
|
27
|
-
@default_lang = args[:default_lang]
|
28
|
-
end
|
29
|
-
|
30
|
-
def create_file_from_path(file_path)
|
31
|
-
path = File.dirname(file_path)
|
32
|
-
FileUtils.mkdir_p path
|
33
|
-
return File.new(file_path,"w")
|
34
|
-
end
|
35
|
-
|
36
|
-
def process_header(excludedCols, files, row, index)
|
37
|
-
files[index] = []
|
38
|
-
lang_index = row[index]
|
39
|
-
|
40
|
-
# create output files here
|
41
|
-
if @output_file
|
42
|
-
# one single file
|
43
|
-
files[index] << self.create_file_from_path(@output_file)
|
44
|
-
else
|
45
|
-
# create one file for each languages
|
46
|
-
if self.langs[lang_index].is_a?(Array)
|
47
|
-
|
48
|
-
self.langs[lang_index].each do |locale|
|
49
|
-
filename = self.file_path_for_locale(locale)
|
50
|
-
files[index] << self.create_file_from_path(filename)
|
51
|
-
end
|
52
|
-
elsif self.langs[lang_index].is_a?(String)
|
53
|
-
locale = self.langs[lang_index]
|
54
|
-
filename = self.file_path_for_locale(locale)
|
55
|
-
files[index] << self.create_file_from_path(filename)
|
56
|
-
else
|
57
|
-
raise "wrong format or/and languages parameter"
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def file_path_for_locale(locale)
|
64
|
-
require 'pathname'
|
65
|
-
Pathname.new(self.default_path) + "#{locale}.lproj" + "Localizable.strings"
|
66
|
-
end
|
67
|
-
|
68
|
-
def process_value(row_value, default_value)
|
69
|
-
value = row_value.nil? ? default_value : row_value
|
70
|
-
value = "" if value.nil?
|
71
|
-
value.gsub!(/\\*\"/, "\\\"") #escape double quotes
|
72
|
-
value.gsub!(/\s*(\n|\\\s*n)\s*/, "\\n") #replace new lines with \n + strip
|
73
|
-
value.gsub!(/%\s+([a-zA-Z@])([^a-zA-Z@]|$)/, "%\\1\\2") #repair string formats ("% d points" etc)
|
74
|
-
value.gsub!(/([^0-9\s\(\{\[^])%/, "\\1 %")
|
75
|
-
value.strip!
|
76
|
-
return value
|
77
|
-
end
|
78
|
-
|
79
|
-
# Convert csv file to multiple Localizable.strings files for each column
|
80
|
-
def csv_to_dotstrings(name = self.csv_filename)
|
81
|
-
files = {}
|
82
|
-
rowIndex = 0
|
83
|
-
excludedCols = []
|
84
|
-
defaultCol = 0
|
85
|
-
nb_translations = 0
|
86
|
-
|
87
|
-
CSVParserClass.foreach(name, :quote_char => '"', :col_sep =>',', :row_sep => :auto) do |row|
|
88
|
-
|
89
|
-
if rowIndex == 0
|
90
|
-
return unless row.count > 1 #check there's at least two columns
|
91
|
-
else
|
92
|
-
next if row == nil or row[self.keys_column].nil? #skip empty lines (or sections)
|
93
|
-
end
|
94
|
-
|
95
|
-
row.size.times do |i|
|
96
|
-
next if excludedCols.include? i
|
97
|
-
if rowIndex == 0 #header
|
98
|
-
# ignore all headers not listed in langs to create files
|
99
|
-
(excludedCols << i and next) unless self.langs.has_key?(row[i])
|
100
|
-
self.process_header(excludedCols, files, row, i)
|
101
|
-
# define defaultCol
|
102
|
-
defaultCol = i if self.default_lang == row[i]
|
103
|
-
elsif !self.state_column || (row[self.state_column].nil? or row[self.state_column] == '' or !self.excluded_states.include? row[self.state_column])
|
104
|
-
# TODO: add option to strip the constant or referenced language
|
105
|
-
key = row[self.keys_column].strip
|
106
|
-
value = self.process_value(row[i], row[defaultCol])
|
107
|
-
# files for a given language, i.e could group english US with english UK.
|
108
|
-
localized_files = files[i]
|
109
|
-
if localized_files
|
110
|
-
localized_files.each do |file|
|
111
|
-
nb_translations += 1
|
112
|
-
file.write "\"#{key}\" = \"#{value}\";\n"
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
rowIndex += 1
|
118
|
-
end
|
119
|
-
info = "Created #{files.size} files. Content: #{nb_translations} translations\n"
|
120
|
-
info += "List of created files:\n"
|
121
|
-
|
122
|
-
# closing I/O
|
123
|
-
files.each do |key,locale_files|
|
124
|
-
locale_files.each do |file|
|
125
|
-
info += "#{file.path.to_s}\n"
|
126
|
-
file.close
|
127
|
-
end
|
128
|
-
end
|
129
|
-
info
|
130
|
-
end # end of method
|
131
|
-
|
132
|
-
end # end of class
|
133
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
module Strings2CSV
|
2
|
-
class Converter
|
3
|
-
|
4
|
-
attr_accessor :csv_filename, :headers, :filenames, :default_lang
|
5
|
-
|
6
|
-
def initialize(args = {:filenames => []})
|
7
|
-
if args[:filenames] && args[:headers]
|
8
|
-
raise ArgumentError.new("number of headers and files don't match, don't forget the constant column") unless args[:headers].size == (args[:filenames].size + 1)
|
9
|
-
end
|
10
|
-
|
11
|
-
@filenames = args[:filenames]
|
12
|
-
|
13
|
-
@csv_filename = args[:csv_filename] || "translations.csv"
|
14
|
-
@default_lang = args[:default_lang]
|
15
|
-
@headers = args[:headers] || self.default_headers
|
16
|
-
end
|
17
|
-
|
18
|
-
def default_headers
|
19
|
-
headers = ['Variables']
|
20
|
-
@filenames.each do |fname|
|
21
|
-
headers << basename(fname)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
# Load all strings of a given file
|
27
|
-
def load_strings(strings_filename)
|
28
|
-
strings = {}
|
29
|
-
File.open(strings_filename, 'r') do |strings_file|
|
30
|
-
strings_file.read.each_line do |line|
|
31
|
-
strings.merge!(self.parse_dotstrings_line(line))
|
32
|
-
end
|
33
|
-
end
|
34
|
-
strings
|
35
|
-
end
|
36
|
-
|
37
|
-
def parse_dotstrings_line(line)
|
38
|
-
line.strip!
|
39
|
-
if (line[0] != ?# and line[0] != ?=)
|
40
|
-
m = line.match(/^[^\"]*\"(.+)\"[^=]+=[^\"]*\"(.*)\";/)
|
41
|
-
return {m[1] => m[2]} unless m.nil?
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
# Convert Localizable.strings files to one CSV file
|
47
|
-
# output:
|
48
|
-
def dotstrings_to_csv(write_to_file = true)
|
49
|
-
# Parse .strings files
|
50
|
-
strings = {}
|
51
|
-
keys = nil
|
52
|
-
lang_order = []
|
53
|
-
|
54
|
-
@filenames.each do |fname|
|
55
|
-
header = basename(fname)
|
56
|
-
strings[header] = load_strings(fname)
|
57
|
-
lang_order << header
|
58
|
-
keys ||= strings[header].keys
|
59
|
-
end
|
60
|
-
|
61
|
-
if(write_to_file)
|
62
|
-
# Create csv file
|
63
|
-
puts "Creating #{@csv_filename}"
|
64
|
-
create_csv_file(keys, lang_order, strings)
|
65
|
-
else
|
66
|
-
return keys, lang_order, strings
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def basename(file_path)
|
71
|
-
filename = File.basename(file_path)
|
72
|
-
return filename.split('.')[0].to_sym if file_path
|
73
|
-
end
|
74
|
-
|
75
|
-
# Create the resulting file
|
76
|
-
def create_csv_file(keys, lang_order, strings)
|
77
|
-
raise "csv_filename must not be nil" unless self.csv_filename
|
78
|
-
CSVParserClass.open(self.csv_filename, "wb") do |csv|
|
79
|
-
csv << @headers
|
80
|
-
keys.each do |key|
|
81
|
-
line = [key]
|
82
|
-
default_val = strings[self.default_lang][key] if strings[self.default_lang]
|
83
|
-
lang_order.each do |lang|
|
84
|
-
current_val = strings[lang][key]
|
85
|
-
line << ((lang != self.default_lang and current_val == default_val) ? '' : current_val)
|
86
|
-
end
|
87
|
-
csv << line
|
88
|
-
end
|
89
|
-
puts "Done"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
data/test/command_test.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require File.expand_path('../../lib/command', __FILE__)
|
2
|
-
require File.expand_path('../test_helper', __FILE__)
|
3
|
-
|
4
|
-
class CommandTest < Test::Unit::TestCase
|
5
|
-
def test_csv2strings_with_multiple_2_languages
|
6
|
-
command = "./bin/csv2strings"
|
7
|
-
command += " --filename test/data/test_data_multiple_langs.csv"
|
8
|
-
command += " --langs=English:en French:fr"
|
9
|
-
system(command)
|
10
|
-
|
11
|
-
assert File.exist?("./en.lproj/Localizable.strings")
|
12
|
-
assert File.exist?("./fr.lproj/Localizable.strings")
|
13
|
-
|
14
|
-
#clean up
|
15
|
-
system("rm -rf ./en.lproj/")
|
16
|
-
system("rm -rf ./fr.lproj/")
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_csv2strings_with_default_path
|
20
|
-
command = "./bin/csv2strings"
|
21
|
-
command += " --filename test/data/test_data_multiple_langs.csv"
|
22
|
-
command += " --langs=English:en French:fr"
|
23
|
-
command += " --default_path=mynewlocation"
|
24
|
-
system(command)
|
25
|
-
|
26
|
-
# testing
|
27
|
-
assert File.exist?("./mynewlocation/en.lproj/Localizable.strings"), "can't find output file for English"
|
28
|
-
assert File.exist?("./mynewlocation/fr.lproj/Localizable.strings"), "can't find output file for French"
|
29
|
-
|
30
|
-
#clean up
|
31
|
-
system("rm -rf ./mynewlocation")
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_strings2csv
|
35
|
-
command = "./bin/strings2csv"
|
36
|
-
command += " --filenames test/data/test_data.strings"
|
37
|
-
system(command)
|
38
|
-
|
39
|
-
assert File.exist?("translations.csv")
|
40
|
-
|
41
|
-
#clean up
|
42
|
-
system("rm -f translations.csv")
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_strings2csv_with_dryrun_option
|
46
|
-
command = "./bin/strings2csv"
|
47
|
-
command += " --filenames test/data/test_data.strings"
|
48
|
-
command += " --dryrun"
|
49
|
-
system(command)
|
50
|
-
|
51
|
-
assert !File.exist?("translations.csv")
|
52
|
-
|
53
|
-
#clean up
|
54
|
-
system("rm -f translations.csv")
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_strings2csv_with_output_file
|
58
|
-
command = "./bin/strings2csv"
|
59
|
-
command += " -i=test/data/test_data.strings"
|
60
|
-
command += " -o=myfile.csv"
|
61
|
-
system(command)
|
62
|
-
|
63
|
-
assert File.exist?("myfile.csv")
|
64
|
-
|
65
|
-
#clean up
|
66
|
-
system("rm -f myfile.csv")
|
67
|
-
end
|
68
|
-
|
69
|
-
def test_strings2csv_with_headers
|
70
|
-
command = "./bin/strings2csv"
|
71
|
-
command += " -i=test/data/test_data.strings"
|
72
|
-
command += " -h=constants english"
|
73
|
-
system(command)
|
74
|
-
|
75
|
-
#TODO assertion or move test on at lib level
|
76
|
-
|
77
|
-
#clean up
|
78
|
-
system("rm -f translations.csv")
|
79
|
-
end
|
80
|
-
|
81
|
-
def test_strings2csv_with_two_files
|
82
|
-
command = "./bin/strings2csv"
|
83
|
-
command += " --filenames=test/data/test_en.strings test/data/test_fr.strings"
|
84
|
-
command += " --headers=Constants English French"
|
85
|
-
command += " -o=enfr.csv"
|
86
|
-
system(command)
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
|