applocale 0.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.
@@ -0,0 +1,69 @@
1
+ require 'google/apis/drive_v3'
2
+ require 'googleauth'
3
+ require 'googleauth/stores/file_token_store'
4
+ require 'google/apis/sheets_v4'
5
+ require 'fileutils'
6
+ require File.expand_path('../../Util/file_util.rb', __FILE__)
7
+ require File.expand_path('../../Util/color_util.rb', __FILE__)
8
+ require File.expand_path('../../Util/error_util.rb', __FILE__)
9
+
10
+ module Applocale
11
+
12
+ class GoogleHelper
13
+ OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
14
+ APPLICATION_NAME = 'AppLocale'
15
+ CLIENT_SECRETS_PATH = 'client_secret.json'
16
+ CREDENTIALS_PATH = File.join(Dir.home, '.applan_credentials',
17
+ "drive-ruby-applocale.yaml")
18
+ SCOPE = [Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY, Google::Apis::DriveV3::AUTH_DRIVE, Google::Apis::DriveV3::AUTH_DRIVE_FILE]
19
+
20
+ def self.isGoogleLink(link)
21
+ if !link.nil? && link.length > 0
22
+ if link.match(/https:\/\/docs.google.com\/spreadsheets\/d\/([^\/]*)/i)
23
+ if $1.length > 0
24
+ return $1
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def self.downloadSpreadSheet(spreadSheetId, filename)
31
+ puts "Start download from google, fileId: #{spreadSheetId} ...".green
32
+ service = Google::Apis::DriveV3::DriveService.new
33
+ service.client_options.application_name = APPLICATION_NAME
34
+ service.authorization = self.authorize
35
+ content = service.export_file(spreadSheetId,
36
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
37
+ download_dest: filename)
38
+ if File.exist? filename
39
+ puts "Download from google finished".green
40
+ else
41
+ ErrorUtil::DownloadXlsxError.new("Cannot download from google").raise
42
+ end
43
+ end
44
+
45
+ private
46
+ def self.authorize
47
+
48
+ FileUtils.mkdir_p(File.dirname(CREDENTIALS_PATH))
49
+ client_id = Google::Auth::ClientId.from_file(File.expand_path(CLIENT_SECRETS_PATH, File.dirname(__FILE__)))
50
+ token_store = Google::Auth::Stores::FileTokenStore.new(file: CREDENTIALS_PATH)
51
+ authorizer = Google::Auth::UserAuthorizer.new(
52
+ client_id, SCOPE, token_store)
53
+ user_id = 'default'
54
+ credentials = authorizer.get_credentials(user_id)
55
+ if credentials.nil?
56
+ url = authorizer.get_authorization_url(
57
+ base_url: OOB_URI)
58
+ puts "!!! Open the following URL in the browser and enter the ".red +
59
+ "resulting code after authorization:".red
60
+ puts url.blue.on_white
61
+ code = STDIN.gets.chomp
62
+ credentials = authorizer.get_and_store_credentials_from_code(
63
+ user_id: user_id, code: code, base_url: OOB_URI)
64
+ end
65
+ credentials
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../setting.rb', __FILE__)
2
+ require File.expand_path('../google_helper.rb', __FILE__)
3
+ require File.expand_path('../parse_xlsx', __FILE__)
4
+ require File.expand_path('../convert_to_str_file', __FILE__)
5
+
6
+ module Applocale
7
+ def self.start(is_localupdate, setting)
8
+ if !is_localupdate
9
+ google_file_id = GoogleHelper.isGoogleLink(setting.link)
10
+ if !google_file_id.nil?
11
+ GoogleHelper.downloadSpreadSheet(google_file_id,setting.xlsxpath)
12
+ end
13
+ end
14
+
15
+ parseXlsx = ParseXLSX.new()
16
+ ConvertToStrFile.convert(parseXlsx.result)
17
+ end
18
+
19
+ end
@@ -0,0 +1,166 @@
1
+ require File.expand_path('../setting.rb', __FILE__)
2
+ require File.expand_path('../parse_xlsx_module.rb', __FILE__)
3
+ require File.expand_path('../../Util/error_util.rb', __FILE__)
4
+ require File.expand_path('../../Util/color_util.rb', __FILE__)
5
+ require File.expand_path('../../Util/regex_util.rb', __FILE__)
6
+
7
+ require 'rubyXL'
8
+
9
+
10
+ module Applocale
11
+ class ParseXLSX
12
+
13
+ @xlsx = nil
14
+ @sheetcontent_list = nil
15
+ @allError = nil
16
+ @setting = Setting
17
+
18
+ def initialize()
19
+ @setting = Setting
20
+ puts "Start to Parse XLSX: \"#{@setting.xlsxpath}\" ...".green
21
+ # @xlsx = Roo::Spreadsheet.open(@@setting.xlsxpath)
22
+ @sheetcontent_list = Array.new
23
+ @allKeyDict = {}
24
+ @allError = Array.new
25
+
26
+ self.parse()
27
+ end
28
+
29
+ def result
30
+ return @sheetcontent_list
31
+ end
32
+
33
+ def parse()
34
+
35
+ workbook = RubyXL::Parser.parse(@setting.xlsxpath)
36
+ workbook.worksheets.each do |worksheet|
37
+ sheetName = worksheet.sheet_name
38
+ sheetcontent = ParseXLSXModule::SheetContent.new(sheetName)
39
+
40
+ rowno = -1
41
+ worksheet.each {|row|
42
+ rowno += 1
43
+ # colno = 0
44
+ next if row.nil?
45
+ cells = row && row.cells
46
+ if sheetcontent.header_rowno.nil?
47
+ headerinfo = findHeader(cells)
48
+ if !headerinfo.nil?
49
+ sheetcontent.header_rowno = rowno
50
+ sheetcontent.keyStrWithColNo = headerinfo[:keystr_colno]
51
+ sheetcontent.langWithColNo_list = headerinfo[:lang_colno]
52
+ end
53
+ else
54
+ begin
55
+ rowcontent = parseRow(sheetName, rowno, worksheet.sheet_data[rowno], sheetcontent.keyStrWithColNo, sheetcontent.langWithColNo_list)
56
+ if !rowcontent.nil?
57
+ prev_rowcontent = @allKeyDict[rowcontent.key_str.downcase]
58
+ if prev_rowcontent.nil?
59
+ @allKeyDict[rowcontent.key_str.downcase] = rowcontent
60
+ sheetcontent.rowinfo_list.push(rowcontent)
61
+ else
62
+ error = ErrorUtil::ParseXlsxError::ErrorDuplicateKey.new(rowcontent, "duplicate with sheet '#{prev_rowcontent.sheetname}' row '#{prev_rowcontent.rowno}'")
63
+ @allError.push(error)
64
+ end
65
+ end
66
+ rescue ErrorUtil::ParseXlsxError::ParseError => e
67
+ @allError.push(e)
68
+
69
+ end
70
+ end
71
+ }
72
+ if sheetcontent.header_rowno.nil?
73
+ ErrorUtil::ParseXlsxError::HeadeNotFoundError.new("Header not found in sheet: #{sheetName}").to_warn
74
+ end
75
+ @sheetcontent_list.push(sheetcontent)
76
+ end
77
+ if @allError.length > 0
78
+ ErrorUtil::ParseXlsxError::ParseError.raiseArr(@allError)
79
+ end
80
+
81
+ end
82
+
83
+ def parseRow(sheetname, rowno, cells, keyStrWithColNo, langWithColNo_list)
84
+ begin
85
+ cell = cells[keyStrWithColNo.colno]
86
+ val = cell && cell.value
87
+ keystr = toValueKey(val)
88
+ rescue ErrorUtil::ParseXlsxError::ErrorInValidKey => e
89
+ e.rowinfo.sheetname = sheetname
90
+ e.rowinfo.rowno = rowno
91
+ raise e
92
+ end
93
+
94
+ if !keystr.nil?
95
+ rowinfo = ParseXLSXModule::RowInfo.new(sheetname, rowno, keystr)
96
+ for k in 0..langWithColNo_list.length-1
97
+ langWithColNo = langWithColNo_list[k]
98
+ cell = cells[langWithColNo.colno]
99
+ val = cell && cell.value
100
+ cell_value = val.to_s
101
+ lang_name = langWithColNo.lang
102
+ rowinfo.content_dict[lang_name] = convertContect(cell_value)
103
+ end
104
+ return rowinfo
105
+ end
106
+ return nil
107
+ end
108
+
109
+ def toValueKey(value)
110
+ if !value.nil? && value != ""
111
+ new_value = value.to_s
112
+ if ValidKey.isValidKey(@setting.platform, new_value)
113
+ return new_value
114
+ else
115
+ rowinfo = ParseXLSXModule::RowInfo.new(nil, nil, value)
116
+ raise ErrorUtil::ParseXlsxError::ErrorInValidKey.new(rowinfo, "Invaild Key: #{value}")
117
+ end
118
+ end
119
+ return nil
120
+ end
121
+
122
+ def convertContect(cell_value)
123
+ if cell_value.nil?
124
+ return ""
125
+ else
126
+ return ContentUtil.addEscapedDoubleQuote(cell_value)
127
+ end
128
+ end
129
+
130
+ def findHeader(cells)
131
+ keyStrWithColNo = nil
132
+ langWithColNo_list = Array.new()
133
+ k_header_lang_dict = []
134
+ colno = 0
135
+ cells.each{ |cell|
136
+ value = cell && cell.value
137
+ if !value.nil?
138
+ if value == @setting.keystr && keyStrWithColNo.nil?
139
+ keyStrWithColNo = ParseXLSXModule::KeyStrWithColNo.new(value, colno)
140
+ else
141
+ @setting.langlist.each do |lang, info|
142
+ if value == info[:xlsheader] && k_header_lang_dict.index(lang).nil?
143
+ langWithColNo_list.push(ParseXLSXModule::LangWithColNo.new(info[:xlsheader], lang, colno))
144
+ k_header_lang_dict.push(lang)
145
+ end
146
+ end
147
+ end
148
+ end
149
+ colno += 1
150
+ }
151
+
152
+ allPass = true
153
+ for i in 0..langWithColNo_list.length-1
154
+ if langWithColNo_list[i].nil?
155
+ allPass = false
156
+ break
157
+ end
158
+ end
159
+ if !keyStrWithColNo.nil? && langWithColNo_list.length == @setting.langlist.length
160
+ return {:keystr_colno => keyStrWithColNo, :lang_colno => langWithColNo_list}
161
+ end
162
+ return nil
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,91 @@
1
+ module Applocale
2
+
3
+ module ParseXLSXModule
4
+ class SheetContent
5
+ attr_accessor :sheetname, :header_rowno, :keyStrWithColNo, :langWithColNo_list, :rowinfo_list, :comment
6
+
7
+ def initialize(sheetname)
8
+ self.sheetname = sheetname
9
+ self.rowinfo_list = Array.new()
10
+ self.langWithColNo_list = Array.new()
11
+ self.comment = sheetname
12
+ end
13
+
14
+ def getRowInfoSortByKey()
15
+ return self.rowinfo_list.sort_by { |obj| obj.key_str.to_s }
16
+ end
17
+
18
+ def getRowInfoSortByRowNo()
19
+ return self.rowinfo_list.sort_by { |obj| obj.rowno.to_i }
20
+ end
21
+
22
+ def to_s
23
+ str_keyStrWithColNo = ""
24
+ if !keyStrWithColNo.nil?
25
+ str_keyStrWithColNo = "\n\t#{keyStrWithColNo.to_s}"
26
+ end
27
+ str_langWithColNo_list = ""
28
+ self.langWithColNo_list.each do |langWithColNo|
29
+ str_langWithColNo_list += "\n\t#{langWithColNo.to_s}"
30
+ end
31
+ str_contentlist = "\n"
32
+ self.getRowInfoSortByRowNo().each do |value|
33
+ str_contentlist += "\t #{value.to_s}\n"
34
+ end
35
+
36
+ "sheetname = #{sheetname}\n" +
37
+ "header_rowno = #{header_rowno}\n" +
38
+ "keyStrWithColNo = #{str_keyStrWithColNo}\n" +
39
+ "langWithColNo_list = #{str_langWithColNo_list}\n" +
40
+ "rowinfo_list = #{str_contentlist}"
41
+ end
42
+ end
43
+
44
+ class RowInfo
45
+
46
+ attr_accessor :sheetname, :rowno, :key_str, :content_dict
47
+
48
+ def initialize(sheetname = nil, rowno = nil, key_str = nil)
49
+ self.sheetname = sheetname
50
+ self.rowno = rowno
51
+ self.key_str = key_str
52
+ self.content_dict = {}
53
+ end
54
+
55
+ def to_s
56
+ "sheetname = #{sheetname}, rowno = #{rowno}, key_str = #{key_str}, content_dict = #{content_dict}"
57
+ end
58
+
59
+ end
60
+
61
+ class KeyStrWithColNo
62
+
63
+ attr_accessor :header_str, :colno
64
+
65
+ def initialize(header_str, colno)
66
+ self.header_str = header_str
67
+ self.colno = colno
68
+ end
69
+
70
+ def to_s
71
+ "{header_str => #{header_str}, colno => #{colno}}"
72
+ end
73
+
74
+ end
75
+
76
+ class LangWithColNo
77
+ attr_accessor :header_str, :lang, :colno
78
+
79
+ def initialize(header_str, lang, colno)
80
+ self.header_str = header_str
81
+ self.lang = lang
82
+ self.colno = colno
83
+ end
84
+
85
+ def to_s
86
+ "{header_str => #{header_str}, lang => #{lang}, colno => #{colno}}"
87
+ end
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../../Util/color_util.rb', __FILE__)
2
+
3
+ module Applocale
4
+ class Setting
5
+ class <<self
6
+ attr_accessor :link, :platform, :keystr, :langlist, :xlsxpath
7
+ end
8
+
9
+ def self.printlog
10
+ puts " In Setting"
11
+ puts " link = #{self.link}"
12
+ puts " platform = #{self.platform}"
13
+ puts " keystr = #{self.keystr}"
14
+ puts " langlist = #{self.langlist}"
15
+ puts " xlsxpath = #{self.xlsxpath}"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'colorize'
2
+
3
+
4
+ # class String
5
+ # def black; "\e[30m#{self}\e[0m" end
6
+ # def red; "\e[31m#{self}\e[0m" end
7
+ # def green; "\e[32m#{self}\e[0m" end
8
+ # def brown; "\e[33m#{self}\e[0m" end
9
+ # def blue; "\e[34m#{self}\e[0m" end
10
+ # def magenta; "\e[35m#{self}\e[0m" end
11
+ # def cyan; "\e[36m#{self}\e[0m" end
12
+ # def gray; "\e[37m#{self}\e[0m" end
13
+ #
14
+ # def bg_black; "\e[40m#{self}\e[0m" end
15
+ # def bg_red; "\e[41m#{self}\e[0m" end
16
+ # def bg_green; "\e[42m#{self}\e[0m" end
17
+ # def bg_brown; "\e[43m#{self}\e[0m" end
18
+ # def bg_blue; "\e[44m#{self}\e[0m" end
19
+ # def bg_magenta; "\e[45m#{self}\e[0m" end
20
+ # def bg_cyan; "\e[46m#{self}\e[0m" end
21
+ # def bg_gray; "\e[47m#{self}\e[0m" end
22
+ #
23
+ # def bold; "\e[1m#{self}\e[22m" end
24
+ # def italic; "\e[3m#{self}\e[23m" end
25
+ # def underline; "\e[4m#{self}\e[24m" end
26
+ # def blink; "\e[5m#{self}\e[25m" end
27
+ # def reverse_color; "\e[7m#{self}\e[27m" end
28
+ # end
@@ -0,0 +1,169 @@
1
+ require 'yaml'
2
+ require File.expand_path('../file_util.rb', __FILE__)
3
+ require File.expand_path('../error_util.rb', __FILE__)
4
+ require File.expand_path('../platform.rb', __FILE__)
5
+ require File.expand_path('../../Core/setting.rb', __FILE__)
6
+
7
+ require 'pathname'
8
+
9
+ module Applocale
10
+ class ConfigUtil
11
+ def self.createConfigFileIfNeed(platform)
12
+ pathstr = FileUtil.configFilePathStr
13
+ self.createConfigFile(platform, pathstr) unless File.exist?(pathstr)
14
+ end
15
+
16
+ def self.createConfigFile(platform, configfile_pathstr)
17
+ src_pathstr = File.expand_path("../../#{FileUtil.filename_config}", __FILE__)
18
+
19
+ File.open(src_pathstr, "r") do |form|
20
+ File.open(configfile_pathstr, "w") do |to|
21
+ form.each_line do |line|
22
+ newline = line.gsub("\#{platform}", "#{platform.to_s}")
23
+ newline = newline.gsub("\#{path_zh_TW}", FileUtil.defaultLocaleFileRelativePathStr(platform, Locale::ZH_TW))
24
+ newline = newline.gsub("\#{path_zh_CN}", FileUtil.defaultLocaleFileRelativePathStr(platform, Locale::ZH_CN))
25
+ newline = newline.gsub("\#{path_en_US}", FileUtil.defaultLocaleFileRelativePathStr(platform, Locale::EN_US))
26
+ newline = newline.gsub("\#{xlsxpath}", FileUtil.defaultXlsxRelativePathStr())
27
+ to.puts(newline)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.loadAndValidateForXlsxToStringFile(is_local_update)
35
+ config_yaml = self.load_config
36
+ self.validateForXlsxToStringFile(config_yaml, is_local_update)
37
+ end
38
+
39
+ def self.loadAndValidateForStringFileToXlsx()
40
+ config_yaml = self.load_config
41
+ self.validateForStringFileToXlsx(config_yaml)
42
+ end
43
+
44
+ # private
45
+ def self.load_config
46
+ configfile_path = FileUtil.configFilePathStr
47
+ unless File.exist?(configfile_path)
48
+ ErrorUtil::MissingConfigFileError.new("Missing ConfigFile").raise
49
+ end
50
+ config_yaml = YAML.load_file configfile_path
51
+ return config_yaml
52
+ end
53
+
54
+ def self.validateForXlsxToStringFile(config_yaml, is_local_update)
55
+ error_list = self.validateCommon(config_yaml)
56
+ if is_local_update
57
+ if !File.exist? Setting.xlsxpath
58
+ error = ErrorUtil::ConfigFileValidError.new("#{Setting.xlsxpath} do not exist")
59
+ error_list.push(error)
60
+ end
61
+ else
62
+ if Setting.link.nil?
63
+ error = ErrorUtil::ConfigFileValidError.new("[link] should not be empty")
64
+ error_list.push(error)
65
+ end
66
+ end
67
+ ErrorUtil::ConfigFileValidError.raiseArr(error_list)
68
+ end
69
+
70
+ def self.validateForStringFileToXlsx(config_yaml)
71
+ error_list = self.validateCommon(config_yaml)
72
+ Setting.langlist.each do |lang, langinfo|
73
+ if !File.exist? langinfo[:path]
74
+ error = ErrorUtil::ConfigFileValidError.new("#{langinfo[:path]} do not exist")
75
+ error_list.push(error)
76
+ end
77
+ end
78
+ ErrorUtil::ConfigFileValidError.raiseArr(error_list)
79
+ end
80
+
81
+ def self.validateCommon(config_yaml)
82
+ error_list = Array.new
83
+ link = config_yaml["link"].to_s
84
+ platform = config_yaml["platform"].to_s
85
+ keystr = config_yaml["keystr"].to_s
86
+ langlist = config_yaml["langlist"]
87
+ xlsxpath = config_yaml["xlsxpath"].to_s
88
+
89
+ newlink = nil
90
+ newplatform = nil
91
+ newkeystr = nil
92
+ newlanglist = Hash.new
93
+ newxlsxpath = nil
94
+
95
+ if !(link.nil? || link.length == 0)
96
+ if (link =~ /^https/).nil? && (link =~ /^http/).nil?
97
+ error = ErrorUtil::ConfigFileValidError.new("Invalid link for [link] : #{link}")
98
+ error_list.push(error)
99
+ else
100
+ newlink = link
101
+ end
102
+ end
103
+
104
+ if !(xlsxpath.nil? || xlsxpath.length == 0)
105
+ if !(Pathname.new xlsxpath).absolute?
106
+ newxlsxpath = File.expand_path(xlsxpath, File.dirname(FileUtil.configFilePathStr))
107
+ else
108
+ newxlsxpath = xlsxpath
109
+ end
110
+ else
111
+ error = ErrorUtil::ConfigFileValidError.new("[xlsxpath] should not be empty or missing")
112
+ error_list.push(error)
113
+ end
114
+
115
+ if platform.nil? || platform.length == 0
116
+ error = ErrorUtil::ConfigFileValidError.new("[platform] should not be empty")
117
+ error_list.push(error)
118
+ else
119
+ if Platform.init(platform).nil?
120
+ error = ErrorUtil::ConfigFileValidError.new("[platform] can only be 'ios' or 'android' ")
121
+ error_list.push(error)
122
+ else
123
+ newplatform = Platform.init(platform)
124
+ end
125
+ end
126
+
127
+ if keystr.nil? || keystr.length == 0
128
+ error = ErrorUtil::ConfigFileValidError.new("[keystr] should not be empty")
129
+ error_list.push(error)
130
+ else
131
+ newkeystr = keystr
132
+ end
133
+
134
+ if langlist.nil?
135
+ error = ErrorUtil::ConfigFileValidError.new("[langlist] should not be empty or missing")
136
+ error_list.push(error)
137
+ elsif !(langlist.is_a? Hash)
138
+ error = ErrorUtil::ConfigFileValidError.new("[langlist] wrong format")
139
+ error_list.push(error)
140
+ else
141
+ if langlist.length <= 0
142
+ error = ErrorUtil::ConfigFileValidError.new("[langlist] should not be empty ")
143
+ error_list.push(error)
144
+ end
145
+ langlist.each do |lang, arr|
146
+ if arr.length != 2
147
+ error = ErrorUtil::ConfigFileValidError.new("[langlist] wrong format")
148
+ error_list.push(error)
149
+ else
150
+ path = arr[1]
151
+ if !(Pathname.new path).absolute?
152
+ path = File.expand_path(path, File.dirname(FileUtil.configFilePathStr))
153
+ end
154
+ newlanglist[lang] = {:xlsheader => arr[0], :path => path}
155
+ end
156
+ end
157
+ end
158
+
159
+ Setting.link = newlink
160
+ Setting.platform = newplatform
161
+ Setting.keystr = newkeystr
162
+ Setting.langlist = newlanglist
163
+ Setting.xlsxpath = newxlsxpath
164
+
165
+ return error_list
166
+ end
167
+
168
+ end
169
+ end