babelish_rnc 1.0.0.pre

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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.babelish.sample +35 -0
  3. data/.gitignore +34 -0
  4. data/.hound.yml +4 -0
  5. data/.travis.yml +15 -0
  6. data/CONTRIBUTING.md +12 -0
  7. data/Dockerfile +6 -0
  8. data/Gemfile +8 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +73 -0
  11. data/Rakefile +17 -0
  12. data/babelish.gemspec +41 -0
  13. data/babelish_rnc.gemspec +42 -0
  14. data/bin/babelish_rnc +6 -0
  15. data/lib/babelish_rnc.rb +31 -0
  16. data/lib/babelish_rnc/android2csv.rb +28 -0
  17. data/lib/babelish_rnc/base2csv.rb +103 -0
  18. data/lib/babelish_rnc/commandline.rb +188 -0
  19. data/lib/babelish_rnc/csv2android.rb +53 -0
  20. data/lib/babelish_rnc/csv2base.rb +189 -0
  21. data/lib/babelish_rnc/csv2json.rb +21 -0
  22. data/lib/babelish_rnc/csv2php.rb +25 -0
  23. data/lib/babelish_rnc/csv2strings.rb +34 -0
  24. data/lib/babelish_rnc/google_doc.rb +55 -0
  25. data/lib/babelish_rnc/json2csv.rb +20 -0
  26. data/lib/babelish_rnc/language.rb +30 -0
  27. data/lib/babelish_rnc/php2csv.rb +30 -0
  28. data/lib/babelish_rnc/strings2csv.rb +61 -0
  29. data/lib/babelish_rnc/version.rb +3 -0
  30. data/lib/babelish_rnc/xcode_macros.rb +49 -0
  31. data/test/babelish_rnc/commands/test_command_android2csv.rb +60 -0
  32. data/test/babelish_rnc/commands/test_command_csv2android.rb +35 -0
  33. data/test/babelish_rnc/commands/test_command_csv2strings.rb +139 -0
  34. data/test/babelish_rnc/commands/test_command_strings2csv.rb +110 -0
  35. data/test/babelish_rnc/test_android2csv.rb +53 -0
  36. data/test/babelish_rnc/test_base2csv.rb +43 -0
  37. data/test/babelish_rnc/test_bins.rb +32 -0
  38. data/test/babelish_rnc/test_commandline.rb +127 -0
  39. data/test/babelish_rnc/test_csv2android.rb +72 -0
  40. data/test/babelish_rnc/test_csv2base.rb +44 -0
  41. data/test/babelish_rnc/test_csv2json.rb +27 -0
  42. data/test/babelish_rnc/test_csv2php.rb +27 -0
  43. data/test/babelish_rnc/test_csv2strings.rb +154 -0
  44. data/test/babelish_rnc/test_json2csv.rb +34 -0
  45. data/test/babelish_rnc/test_php2csv.rb +73 -0
  46. data/test/babelish_rnc/test_strings2csv.rb +147 -0
  47. data/test/babelish_rnc/test_xcode_macros.rb +112 -0
  48. data/test/data/android-en.xml +9 -0
  49. data/test/data/android-fr.xml +9 -0
  50. data/test/data/android.xml +9 -0
  51. data/test/data/android_special_chars.csv +8 -0
  52. data/test/data/android_special_chars.xml +12 -0
  53. data/test/data/android_special_chars_test_result.xml +10 -0
  54. data/test/data/genstrings.strings +0 -0
  55. data/test/data/json.json +6 -0
  56. data/test/data/php_lang.php +8 -0
  57. data/test/data/test_comments.strings +2 -0
  58. data/test/data/test_data.csv +3 -0
  59. data/test/data/test_data.strings +2 -0
  60. data/test/data/test_data_fr_with_comments.strings +6 -0
  61. data/test/data/test_data_fr_with_comments.xml +9 -0
  62. data/test/data/test_data_multiple_langs.csv +3 -0
  63. data/test/data/test_data_with_comments.csv +3 -0
  64. data/test/data/test_data_with_percent.csv +3 -0
  65. data/test/data/test_data_with_percent_space.csv +4 -0
  66. data/test/data/test_data_with_semicolon.csv +3 -0
  67. data/test/data/test_data_with_spaces.csv +3 -0
  68. data/test/data/test_en.strings +2 -0
  69. data/test/data/test_fr.strings +2 -0
  70. data/test/data/test_space.strings +10 -0
  71. data/test/data/test_utf16.strings +0 -0
  72. data/test/data/test_with_nil.csv +3 -0
  73. data/test/data/test_with_nil.strings +4 -0
  74. data/test/data/xcode_empty.strings +7 -0
  75. data/test/test_helper.rb +17 -0
  76. metadata +311 -0
@@ -0,0 +1,25 @@
1
+ module BabelishRnc
2
+ class CSV2Php < Csv2Base
3
+ attr_accessor :php_tag
4
+
5
+ def initialize(filename, langs, args = {})
6
+ super(filename, langs, args)
7
+ # TODO: list this arg in commandline
8
+ @php_tag = args[:php_tag].nil? ? 'lang' : args[:php_tag]
9
+ end
10
+
11
+ def language_filepaths(language)
12
+ require 'pathname'
13
+ filepath = Pathname.new(@output_dir) + "#{language.code}" + "lang.php"
14
+ return filepath ? [filepath] : []
15
+ end
16
+
17
+ def get_row_format(row_key, row_value, comment = nil, indentation = 0)
18
+ "$" + @php_tag + "['#{row_key}']" + " " * indentation + " = \"#{row_value}\";\n"
19
+ end
20
+
21
+ def extension
22
+ "php"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ module BabelishRnc
2
+ class CSV2Strings < Csv2Base
3
+ attr_accessor :languages
4
+
5
+ def language_filepaths(language)
6
+ require 'pathname'
7
+ filepaths = []
8
+ if language.regions.empty?
9
+ filepaths << Pathname.new(@output_dir) + "#{language.code}.lproj/#{output_basename}.#{extension}"
10
+ else
11
+ language.regions.each do |region|
12
+ filepaths << Pathname.new(@output_dir) + "#{language.code}-#{region}.lproj/#{output_basename}.#{extension}"
13
+ end
14
+ end
15
+ filepaths
16
+ end
17
+
18
+ def get_row_format(row_key, row_value, comment = nil, indentation = 0, huy)
19
+ entry = comment.to_s.empty? ? "" : "\n/* #{comment} */\n"
20
+
21
+ row_value = row_value.to_s.empty? ? huy : row_value
22
+
23
+ entry + "\"#{row_key}\"" + " " * indentation + " = \"#{row_value}\";\n"
24
+ end
25
+
26
+ def extension
27
+ "strings"
28
+ end
29
+
30
+ def output_basename
31
+ @output_basename || 'Localizable'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ module BabelishRnc
2
+ # Faraday is a dependency of google_drive, this silents the warning
3
+ # see https://github.com/CocoaPods/CocoaPods/commit/f33f967427b857bf73645fd4d3f19eb05e9be0e0
4
+ # This is to make sure Faraday doesn't warn the user about the `system_timer` gem missing.
5
+ old_warn, $-w = $-w, nil
6
+ begin
7
+ require "google_drive"
8
+ ensure
9
+ $-w = old_warn
10
+ end
11
+
12
+ class GoogleDoc
13
+ attr_accessor :session
14
+
15
+ def download(requested_filename)
16
+ file = file_with_name(requested_filename)
17
+ return [] unless file
18
+ files = []
19
+ file.worksheets.each_with_index do |worksheet, index|
20
+ files << download_spreadsheet(requested_filename, "translations_#{worksheet.title}.csv", index)
21
+ end
22
+ files
23
+ end
24
+
25
+ def download_spreadsheet(requested_filename, output_filename, worksheet_index = 0)
26
+ output_filename ||= "translations.csv"
27
+ spreadsheet = file_with_name(requested_filename)
28
+ return nil unless spreadsheet
29
+ worksheet = spreadsheet.worksheets[worksheet_index]
30
+ worksheet.export_as_file(output_filename)
31
+ return output_filename
32
+ end
33
+
34
+ def open(requested_filename)
35
+ file = file_with_name(requested_filename)
36
+ if file
37
+ system "open \"#{file.human_url}\""
38
+ else
39
+ puts "can't open requested file"
40
+ end
41
+ end
42
+
43
+ def authenticate
44
+ # will try to get token and store in file below
45
+ @session = GoogleDrive.saved_session ".babelish.token"
46
+ end
47
+
48
+ def file_with_name(name)
49
+ unless @session
50
+ authenticate
51
+ end
52
+ @session.spreadsheet_by_title(name)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ module BabelishRnc
2
+ require 'json'
3
+ class JSON2CSV < Base2Csv
4
+
5
+ def initialize(args = {:filenames => []})
6
+ super(args)
7
+ end
8
+
9
+ def load_strings(strings_filename)
10
+ strings = {}
11
+ raise Errno::ENOENT unless File.exist?(strings_filename)
12
+ json_file = File.open(strings_filename, 'r')
13
+ json_string = json_file.read
14
+ json_file.close
15
+ strings = JSON.parse(json_string).to_hash
16
+ return strings
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ module BabelishRnc
2
+ class Language
3
+ attr_accessor :name, :content, :code, :regions
4
+
5
+ def initialize(name, content = {})
6
+ @name = name
7
+ @content = content
8
+ end
9
+
10
+ def add_content_pair(key, value)
11
+ @content[key] = value
12
+ end
13
+
14
+ def add_language_id(language_id)
15
+ code, region = language_id.split('-')
16
+ @code ||= code
17
+ @regions ||= []
18
+ @regions << region if region
19
+ end
20
+
21
+ def region
22
+ @regions.first
23
+ end
24
+
25
+ def content_for_key(key)
26
+ return @content[:key]
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module BabelishRnc
2
+ class Php2CSV < Base2Csv
3
+
4
+ def initialize(args = {:filenames => []})
5
+ super(args)
6
+ end
7
+
8
+ def load_strings(strings_filename)
9
+ strings = {}
10
+ File.open(strings_filename, 'r') do |strings_file|
11
+ strings_file.read.each_line do |line|
12
+ parsed_line = parse_dotstrings_line(line)
13
+ unless parsed_line.nil?
14
+ converted_line = parse_dotstrings_line(line)
15
+ strings.merge!(converted_line) unless converted_line.nil?
16
+ end
17
+ end
18
+ end
19
+ strings
20
+ end
21
+
22
+ def parse_dotstrings_line(line)
23
+ line.strip!
24
+ if line[0] != ?# && line[0] != ?=
25
+ m = line.match(/^[\$].*\[[\"\'](.*)[\"\']\]\s*=\s*[\"\'](.*)[\"\'];/)
26
+ return {m[1] => m[2]} unless m.nil?
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ module BabelishRnc
2
+ class Strings2CSV < Base2Csv
3
+ # default_lang is the the column to refer to if a value is missing
4
+ # actually default_lang = default_filename
5
+ attr_accessor :csv_filename, :headers, :filenames, :default_lang
6
+
7
+ def initialize(args = {:filenames => []})
8
+ super(args)
9
+ end
10
+
11
+ def parse_dotstrings_line(line)
12
+ line.strip!
13
+ if line[0] != ?# && line[0] != ?= && line[0] != ?/
14
+ m = line.match(/^[\s*]*\"(.+)\"[\s]*=\s*\"(.*)\"\s*;/)
15
+ return m[1], m[2] unless m.nil?
16
+ end
17
+ end
18
+
19
+ def parse_comment_line(line)
20
+ line.strip!
21
+ if line[0] != ?# && line[0] != ?=
22
+ m = line.match(/^\/\*(.*)\*\/\s*$/)
23
+ return m[1].strip! unless m.nil?
24
+ end
25
+ end
26
+
27
+ # Load all strings of a given file
28
+ def load_strings(strings_filename)
29
+ strings = {}
30
+ comments = {}
31
+ # genstrings uses utf16, so that's what we expect. utf8 should not be impact
32
+ file = File.open(strings_filename, "r:utf-16:utf-8")
33
+ begin
34
+ contents = file.read
35
+ if RUBY_VERSION == "1.9.2"
36
+ # fixes conversion, see http://po-ru.com/diary/fixing-invalid-utf-8-in-ruby-revisited/
37
+ require 'iconv'
38
+ ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
39
+ contents = ic.iconv(contents + ' ')[0..-2]
40
+ end
41
+ rescue Encoding::InvalidByteSequenceError => e
42
+ # silent error
43
+ # faults back to utf8
44
+ contents = File.open(strings_filename, "r:utf-8")
45
+ end
46
+ previous_comment = nil
47
+ contents.each_line do |line|
48
+ key, value = self.parse_dotstrings_line(line)
49
+ if key
50
+ strings.merge!({key => value})
51
+ comments[key] = previous_comment if previous_comment
52
+ else
53
+ previous_comment = self.parse_comment_line(line)
54
+ end
55
+ end
56
+
57
+ [strings, comments]
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module BabelishRnc
2
+ VERSION = "1.0.0.pre"
3
+ end
@@ -0,0 +1,49 @@
1
+ module BabelishRnc
2
+ class XcodeMacros
3
+ attr_accessor :content, :table, :keys
4
+ def initialize(table = "Localizable", keys = {})
5
+ @content = ""
6
+ @table = table
7
+ @keys = keys
8
+ end
9
+
10
+ def self.write_macros(file_path, table, keys, comments = {})
11
+ instance = XcodeMacros.new
12
+ instance.process(table, keys, comments)
13
+ instance.write_content(file_path)
14
+ end
15
+
16
+ def process(table, keys, comments = {})
17
+ keys.each do |key|
18
+ clean_key = key.gsub(' ', '')
19
+ clean_key.gsub!(/[[:punct:]]/, '_')
20
+ clean_key.gsub!('__', '_')
21
+ clean_key = clean_key[1..clean_key.size-1] if clean_key[0] == '_'
22
+ clean_key = clean_key[0..clean_key.size-2] if clean_key.size > 1 and clean_key[clean_key.size-1] == '_'
23
+ macro_name = "LS_#{clean_key.upcase}"
24
+ macro_name += "_#{table.upcase}" if table != "Localizable"
25
+ comment = comments[key]
26
+ @content << String.new(<<-EOS)
27
+ #define #{macro_name} NSLocalizedStringFromTable(@"#{key}",@"#{table}",@"#{comment.to_s}")
28
+ EOS
29
+ end
30
+ @content
31
+ end
32
+
33
+ def write_content(file_path)
34
+ header = String.new(<<-EOS)
35
+ //
36
+ // file_path
37
+ //
38
+ // This file was generated by babelish_rnc
39
+ //
40
+ // https://github.com/netbe/babelish
41
+ //
42
+ EOS
43
+ header.gsub! "file_path", File.basename(file_path)
44
+ file = File.new(file_path, "w")
45
+ file.write header + @content
46
+ file.close
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+ class TestAndroid2CSVCommand < Test::Unit::TestCase
3
+ def test_android2csv
4
+ options = {:filenames => ["test/data/android.xml"]}
5
+ Commandline.new([], options).android2csv
6
+
7
+ assert File.exist?("translations.csv")
8
+
9
+ # clean up
10
+ system("rm -f translations.csv")
11
+ end
12
+
13
+ def test_android2csv_with_dryrun_option
14
+ options = {:filenames => ["test/data/android.xml"], :dryrun => true}
15
+ Commandline.new([], options).android2csv
16
+
17
+ assert !File.exist?("translations.csv")
18
+
19
+ # clean up
20
+ system("rm -f translations.csv")
21
+ end
22
+
23
+ def test_android2csv_with_output_file
24
+ options = {:filenames => ["test/data/android.xml"], :csv_filename => "myfile.csv"}
25
+ # -i, -o
26
+ Commandline.new([], options).android2csv
27
+
28
+ assert File.exist?("myfile.csv")
29
+
30
+ # clean up
31
+ system("rm -f myfile.csv")
32
+ end
33
+
34
+ def test_android2csv_with_headers
35
+ options = {:filenames => ["test/data/android.xml"], :headers => ["constants", "english"]}
36
+ # -i, -h
37
+ Commandline.new([], options).android2csv
38
+
39
+ #TODO assertion or move test on at lib level
40
+
41
+ # clean up
42
+ system("rm -f translations.csv")
43
+ end
44
+
45
+ def test_android2csv_with_two_files
46
+ options = {
47
+ :filenames => ["test/data/android-en.xml", "test/data/android-fr.xml"],
48
+ :headers => %w{Constants English French},
49
+ :csv_filename => "enfr.csv"
50
+ }
51
+ # --filenames, --headers, -o
52
+ Commandline.new([], options).android2csv
53
+
54
+ #TODO assertion
55
+
56
+ # clean up
57
+ system("rm -f enfr.csv")
58
+ end
59
+
60
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+ class TestCSV2AndroidCommand < Test::Unit::TestCase
3
+
4
+ def test_csv2android_with_multiple_2_languages
5
+ options = {
6
+ :filename => "test/data/test_data_multiple_langs.csv",
7
+ :langs => {"English" => "en", "French" => "fr"}
8
+ }
9
+ Commandline.new([], options).csv2android
10
+
11
+ assert File.exist?("./values-en/strings.xml")
12
+ assert File.exist?("./values-fr/strings.xml")
13
+
14
+ # clean up
15
+ system("rm -rf ./values-en/")
16
+ system("rm -rf ./values-fr/")
17
+ end
18
+
19
+ def test_csv2android_with_output_dir
20
+ options = {
21
+ :filename => "test/data/test_data_multiple_langs.csv",
22
+ :langs => {"English" => "en", "French" => "fr"},
23
+ :output_dir => "mynewlocation"
24
+ }
25
+
26
+ Commandline.new([], options).csv2android
27
+ # testing
28
+ assert File.exist?("./mynewlocation/values-en/strings.xml"), "can't find output file for English"
29
+ assert File.exist?("./mynewlocation/values-fr/strings.xml"), "can't find output file for French"
30
+
31
+ # clean up
32
+ system("rm -rf ./mynewlocation")
33
+ end
34
+
35
+ end
@@ -0,0 +1,139 @@
1
+ require 'test_helper'
2
+ class TestCSV2StringsCommand < Test::Unit::TestCase
3
+
4
+ def test_csv2strings_with_multiple_2_languages
5
+ options = {
6
+ :filename => "test/data/test_data_multiple_langs.csv",
7
+ :langs => {"English" => "en", "French" => "fr"}
8
+ }
9
+ Commandline.new([], options).csv2strings
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_output_dir
20
+ options = {
21
+ :filename => "test/data/test_data_multiple_langs.csv",
22
+ :langs => {"English" => "en", "French" => "fr"},
23
+ :output_dir => "mynewlocation"
24
+ }
25
+ Commandline.new([], options).csv2strings
26
+
27
+ # testing
28
+ assert File.exist?("./mynewlocation/en.lproj/Localizable.strings"), "can't find output file for English in mynewlocation folder"
29
+ assert File.exist?("./mynewlocation/fr.lproj/Localizable.strings"), "can't find output file for French in mynewlocation folder"
30
+
31
+ # clean up
32
+ system("rm -rf ./mynewlocation")
33
+ end
34
+
35
+ def test_csv2strings_with_fetch_google_doc
36
+ omit if ENV['TRAVIS']
37
+ options = {
38
+ :filename => "my_strings",
39
+ :langs => {"English" => "en", "French" => "fr"},
40
+ :fetch => true
41
+ }
42
+ assert_nothing_raised do
43
+ Commandline.new([], options).csv2strings
44
+ end
45
+
46
+ # clean up
47
+ system("rm -rf ./en.lproj/")
48
+ system("rm -rf ./fr.lproj/")
49
+ end
50
+
51
+ def test_csv2strings_with_config_file
52
+ system("cp .babelish.sample .babelish")
53
+
54
+ assert_nothing_raised do
55
+ Commandline.new.csv2strings
56
+ end
57
+
58
+ # clean up
59
+ system("rm -rf ./en.lproj/")
60
+ system("rm -rf ./fr.lproj/")
61
+ end
62
+
63
+ def test_csv2strings_with_output_basenames_option
64
+ omit if ENV['TRAVIS']
65
+ options = {
66
+ :filename => "my_strings",
67
+ :langs => {"English" => "en", "French" => "fr"},
68
+ :fetch => true,
69
+ :output_basenames => %w(sheet1 sheet2),
70
+ }
71
+
72
+ Commandline.new([], options).csv2strings
73
+ # testing
74
+ assert File.exist?("./en.lproj/sheet1.strings"), "can't find output file for sheet1 English"
75
+ assert File.exist?("./fr.lproj/sheet1.strings"), "can't find output file for sheet1 French"
76
+ assert File.exist?("./en.lproj/sheet2.strings"), "can't find output file for sheet2 English"
77
+ assert File.exist?("./fr.lproj/sheet2.strings"), "can't find output file for sheet2 French"
78
+
79
+ # clean up
80
+ system("rm -rf ./en.lproj/")
81
+ system("rm -rf ./fr.lproj/")
82
+ end
83
+
84
+ def test_csv2strings_with_ignore_lang_path_option
85
+ omit if ENV['TRAVIS']
86
+ options = {
87
+ :filename => "my_strings",
88
+ :langs => {"English" => "en"},
89
+ :fetch => true,
90
+ :ignore_lang_path => true,
91
+ :output_basenames => %w(sheet1 sheet2),
92
+ }
93
+
94
+ Commandline.new([], options).csv2strings
95
+ # testing
96
+ assert File.exist?("./sheet1.strings"), "can't find output file for sheet1 English with_ignore_lang_path_option"
97
+ assert File.exist?("./sheet2.strings"), "can't find output file for sheet2 English with_ignore_lang_path_option"
98
+
99
+ # clean up
100
+ system("rm -f sheet1.strings")
101
+ system("rm -f sheet2.strings")
102
+ end
103
+
104
+ def test_csv2strings_with_ignore_lang_path_option_local
105
+ options = {
106
+ :filename => "test/data/test_data.csv",
107
+ :langs => {"English" => "en"},
108
+ :ignore_lang_path => true,
109
+ }
110
+
111
+ Commandline.new([], options).csv2strings
112
+ # testing
113
+ assert File.exist?("./Localizable.strings"), "can't find output file for English with_ignore_lang_path_option"
114
+
115
+ # clean up
116
+ system("rm -f ./Localizable.strings")
117
+ end
118
+
119
+ def test_csv2string_with_macros_filename
120
+ options = {
121
+ :filename => "test/data/test_data.csv",
122
+ :macros_filename => "Babelish.h",
123
+ :langs => { "English" => "en" }
124
+ }
125
+
126
+ Commandline.new([], options).csv2strings
127
+ # testing
128
+ assert File.exist?("./Babelish.h"), "can't find macros file"
129
+
130
+ # clean up
131
+ system("rm -f ./Localizable.strings")
132
+ system("rm -f ./Babelish.h")
133
+ end
134
+
135
+ def teardown
136
+
137
+ system("rm -f .babelish")
138
+ end
139
+ end