smartling_xcode 0.1.3 → 0.1.5
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.
- checksums.yaml +4 -4
- data/bin/smartling_xcode +14 -41
- data/lib/smartling_xcode/backend.rb +86 -65
- data/lib/smartling_xcode/version.rb +32 -1
- data/lib/smartling_xcode/xcode.rb +72 -70
- data/lib/smartling_xcode.rb +21 -19
- data/smartling_xcode.gemspec +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fd8109b6538b3512dfecf179841422d88d788d31
|
4
|
+
data.tar.gz: b1ee650d51f1dde4cd9e41f45e5d409fc3225f14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a45eb744de29013ba281a183ccdb89595027a502be0ec50e060a0bc8dc3d575f23a5ffdad345c046acf02a5f9ea88a55695a404bf4b3c2791e8a6ee219787f3a
|
7
|
+
data.tar.gz: cc1dff99bc4a14d35090958e26d73e758c3cfd931f9a5af245ec18a5b8af7433def339c3097320c4f8ebf07628b4537770a79d439c56a338c5a916057cffae2a
|
data/bin/smartling_xcode
CHANGED
@@ -2,67 +2,40 @@
|
|
2
2
|
|
3
3
|
require "smartling_xcode"
|
4
4
|
|
5
|
-
|
6
|
-
USAGE = <<ENDUSAGE
|
7
|
-
Smartling utility to extract strings from an Xcode project
|
8
|
-
and add them to a Smartling project.
|
9
|
-
Version #{SmartlingXcode::VERSION}
|
10
|
-
|
11
|
-
Usage:
|
12
|
-
smartling_xcode command [project_path] [-v version]
|
13
|
-
smartling_xcode -h/--help
|
14
|
-
|
15
|
-
Commands:
|
16
|
-
init Configure the current folder with Smartling
|
17
|
-
project credentials to be able to push
|
18
|
-
strings.
|
19
|
-
extract Extract all strings from the Xcode project
|
20
|
-
and print out the list of .strings files.
|
21
|
-
push Extract all strings from the Xcode project
|
22
|
-
and send them to your Smartling project.
|
23
|
-
|
24
|
-
Options:
|
25
|
-
project_path Specify a path for the Xcode project.
|
26
|
-
Uses the first .xcodeproj file in the
|
27
|
-
current directory by default.
|
28
|
-
-v version Specify an app version for the strings
|
29
|
-
files upload. Uses the version found in
|
30
|
-
the project's info.plist file by default,
|
31
|
-
but will prompt for a choice if multiple
|
32
|
-
plist files are found.
|
33
|
-
|
34
|
-
ENDUSAGE
|
35
|
-
|
36
|
-
# Parse CLI arguments
|
37
|
-
project_path = nil
|
5
|
+
sl = SmartlingXcode::Project.new()
|
38
6
|
command = nil
|
39
|
-
version = nil
|
40
7
|
version_is_next = false
|
8
|
+
|
9
|
+
# Parse CLI arguments
|
41
10
|
ARGV.each do |arg|
|
42
11
|
case arg
|
43
12
|
# Flags
|
44
13
|
when '-v'
|
45
14
|
version_is_next = true
|
46
15
|
when '-h', '--help'
|
47
|
-
puts USAGE
|
16
|
+
puts SmartlingXcode::USAGE
|
48
17
|
Kernel.exit(0)
|
18
|
+
when '-s'
|
19
|
+
sl.sandbox = true
|
49
20
|
|
50
21
|
# Commands
|
51
22
|
when 'init', 'extract', 'push' then command = arg
|
52
23
|
|
53
24
|
else
|
54
25
|
if command.nil?
|
55
|
-
Kernel.abort(USAGE)
|
26
|
+
Kernel.abort(SmartlingXcode::USAGE)
|
56
27
|
elsif version_is_next
|
57
|
-
version = arg
|
28
|
+
sl.version = arg
|
58
29
|
version_is_next = false
|
59
30
|
else
|
60
|
-
project_path = arg
|
31
|
+
sl.project_path = arg
|
61
32
|
end
|
62
33
|
end
|
63
34
|
end
|
64
35
|
|
65
|
-
|
66
|
-
|
67
|
-
|
36
|
+
# Execute command
|
37
|
+
unless command.nil?
|
38
|
+
sl.send(command)
|
39
|
+
else
|
40
|
+
Kernel.abort(SmartlingXcode::USAGE)
|
68
41
|
end
|
@@ -3,89 +3,110 @@ require 'json'
|
|
3
3
|
require 'shellwords'
|
4
4
|
|
5
5
|
module SmartlingXcode
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
6
|
+
class API
|
7
|
+
CREDFILE = './.smartling.json'
|
8
|
+
attr_accessor :userId, :userSecret, :projectId, :sandbox
|
9
|
+
|
10
|
+
def initialize(args = {})
|
11
|
+
@sandbox = args[:sandbox]
|
12
|
+
end
|
13
|
+
|
14
|
+
def fileApi
|
15
|
+
if @sandbox
|
16
|
+
return Smartling::File.sandbox(:userId => @userId, :userSecret => @userSecret, :projectId => @projectId)
|
16
17
|
else
|
17
|
-
|
18
|
+
return Smartling::File.new(:userId => @userId, :userSecret => @userSecret, :projectId => @projectId)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
def requestCredentials
|
23
|
+
# Check for existing credentials
|
24
|
+
if File.exist?(CREDFILE)
|
25
|
+
puts "Credentials found in this directory. Overwrite? (y/N)"
|
26
|
+
confirm = STDIN.gets.chomp
|
27
|
+
case confirm
|
28
|
+
when 'y', 'Y'
|
29
|
+
# Continue
|
30
|
+
else
|
31
|
+
Kernel.abort("⚠️ Init cancelled")
|
32
|
+
end
|
33
|
+
end
|
24
34
|
|
25
|
-
|
26
|
-
|
35
|
+
# Prompt for credentials
|
36
|
+
puts "Smartling User ID:"
|
37
|
+
@userId = STDIN.gets.chomp
|
27
38
|
|
28
|
-
|
29
|
-
|
30
|
-
begin
|
31
|
-
sl = Smartling::File.new(:apiKey => api_key, :projectId => project_id)
|
32
|
-
res = sl.list
|
33
|
-
rescue
|
34
|
-
Kernel.abort("⚠️ Invalid credentials")
|
35
|
-
end
|
39
|
+
puts "Smartling User Secret:"
|
40
|
+
@userSecret = STDIN.gets.chomp
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
puts "Credentials saved"
|
40
|
-
end
|
41
|
-
end
|
42
|
+
puts "Smartling Project ID:"
|
43
|
+
@projectId = STDIN.gets.chomp
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
45
|
+
# Dummy request to validate creds
|
46
|
+
puts "Validating credentials..."
|
47
|
+
begin
|
48
|
+
sl = fileApi()
|
49
|
+
res = sl.list
|
50
|
+
rescue
|
51
|
+
Kernel.abort("⚠️ Invalid credentials")
|
52
|
+
end
|
53
|
+
|
54
|
+
File.open(CREDFILE, "w") do |f|
|
55
|
+
f.write({:userId => @userId, :userSecret => @userSecret, :projectId => @projectId}.to_json)
|
56
|
+
puts "Credentials saved"
|
51
57
|
end
|
52
|
-
else
|
53
|
-
Kernel.abort("⚠️ Credentials not found. Please run smartling_xcode init.")
|
54
58
|
end
|
55
|
-
end
|
56
59
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
+
def loadCredentials
|
61
|
+
if File.exist?(CREDFILE)
|
62
|
+
file = File.read(CREDFILE)
|
63
|
+
creds = JSON.parse(file)
|
60
64
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
next
|
65
|
-
end
|
65
|
+
@userId = creds['userId']
|
66
|
+
@userSecret = creds['userSecret']
|
67
|
+
@projectId = creds['projectId']
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
next
|
69
|
+
if @userId.nil? || @userSecret.nil? || @projectId.nil?
|
70
|
+
Kernel.abort("⚠️ Invalid credentials")
|
71
|
+
end
|
72
|
+
else
|
73
|
+
Kernel.abort("⚠️ Credentials not found. Please run smartling_xcode init.")
|
73
74
|
end
|
75
|
+
end
|
74
76
|
|
75
|
-
|
77
|
+
def pushStringsFromFiles(files, version)
|
78
|
+
sl = fileApi()
|
79
|
+
files.each do |f|
|
76
80
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
# Check if file exists
|
82
|
+
if !f || !File.exist?(f)
|
83
|
+
puts "File not found #{f}"
|
84
|
+
next
|
85
|
+
end
|
86
|
+
|
87
|
+
# Check if file contains at least one string
|
88
|
+
file = File.open(f)
|
89
|
+
line = file.read.scrub.tr("\000", '').gsub(/\s+/, "")
|
90
|
+
if !line.include?('=')
|
91
|
+
puts "No strings in #{f}"
|
92
|
+
next
|
82
93
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
94
|
+
|
95
|
+
remote_path = "/#{version}/#{f.to_s.split('/').last}"
|
96
|
+
|
97
|
+
# Upload
|
98
|
+
begin
|
99
|
+
res = sl.upload(f.to_s, remote_path, "ios", {:authorize => true})
|
100
|
+
if res
|
101
|
+
puts "Uploaded #{res['stringCount']} strings from #{f}"
|
102
|
+
end
|
103
|
+
rescue Exception => e
|
104
|
+
puts "⚠️ Upload failed for #{f}"
|
105
|
+
if e.message
|
106
|
+
puts e.message
|
107
|
+
end
|
87
108
|
end
|
88
109
|
end
|
89
110
|
end
|
90
111
|
end
|
91
|
-
end
|
112
|
+
end
|
@@ -1,3 +1,34 @@
|
|
1
1
|
module SmartlingXcode
|
2
|
-
VERSION = "0.1.
|
2
|
+
VERSION = "0.1.5"
|
3
|
+
USAGE = <<ENDUSAGE
|
4
|
+
Smartling utility to extract strings from an Xcode project
|
5
|
+
and add them to a Smartling project.
|
6
|
+
Version #{VERSION}
|
7
|
+
|
8
|
+
Usage:
|
9
|
+
smartling_xcode command [project_path] [-v version]
|
10
|
+
smartling_xcode -h/--help
|
11
|
+
|
12
|
+
Commands:
|
13
|
+
init Configure the current folder with Smartling
|
14
|
+
project credentials to be able to push
|
15
|
+
strings.
|
16
|
+
extract Extract all strings from the Xcode project
|
17
|
+
and print out the list of .strings files.
|
18
|
+
push Extract all strings from the Xcode project
|
19
|
+
and send them to your Smartling project.
|
20
|
+
|
21
|
+
Options:
|
22
|
+
project_path Specify a path for the Xcode project.
|
23
|
+
Uses the first .xcodeproj file in the
|
24
|
+
current directory by default.
|
25
|
+
-v version Specify an app version for the strings
|
26
|
+
files upload. Uses the version found in
|
27
|
+
the project's info.plist file by default,
|
28
|
+
but will prompt for a choice if multiple
|
29
|
+
plist files are found.
|
30
|
+
-s Use the sandbox server.
|
31
|
+
|
32
|
+
ENDUSAGE
|
33
|
+
|
3
34
|
end
|
@@ -1,91 +1,93 @@
|
|
1
1
|
require 'xcodeproj'
|
2
2
|
|
3
|
-
module
|
4
|
-
def self.openProject(path)
|
5
|
-
# Get .xcodeproj path
|
6
|
-
if path.nil?
|
7
|
-
project_file = Dir.entries('./').select {|f| f.end_with?(".xcodeproj") }.first
|
8
|
-
path = "./#{project_file}"
|
9
|
-
end
|
3
|
+
module Xcodeproj
|
10
4
|
|
11
|
-
|
12
|
-
# Open project
|
13
|
-
begin
|
14
|
-
project = Xcodeproj::Project.open(path)
|
15
|
-
rescue
|
16
|
-
Kernel.abort("⚠️ Failed to open project file")
|
17
|
-
end
|
5
|
+
class Project
|
18
6
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
7
|
+
def self.find(path)
|
8
|
+
# Get .xcodeproj path
|
9
|
+
if path.nil?
|
10
|
+
project_file = Dir.entries('./').select {|f| f.end_with?(".xcodeproj") }.first
|
11
|
+
path = "./#{project_file}"
|
12
|
+
end
|
24
13
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
14
|
+
if !path.nil? && File.exist?(path)
|
15
|
+
# Open project
|
16
|
+
begin
|
17
|
+
return Xcodeproj::Project.open(path)
|
18
|
+
rescue
|
19
|
+
Kernel.abort("⚠️ Failed to open project file")
|
20
|
+
end
|
21
|
+
else
|
22
|
+
Kernel.abort("⚠️ No .xcodeproj file found")
|
23
|
+
end
|
31
24
|
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.extract(project)
|
35
|
-
strings_files = []
|
36
25
|
|
37
|
-
#
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Kernel.system("ibtool --generate-strings-file \"#{output_path}\" \"#{f.real_path}\"")
|
45
|
-
strings_files.push(output_path)
|
26
|
+
# Returns true if the file is from Base localization or unlocalized
|
27
|
+
def self.fromBase(path)
|
28
|
+
if path.include?('.lproj')
|
29
|
+
return path.include?('Base.lproj')
|
30
|
+
else
|
31
|
+
return true
|
32
|
+
end
|
46
33
|
end
|
47
34
|
|
48
|
-
|
49
|
-
|
50
|
-
f.path.end_with?(".strings") && fromBase(f.path)
|
51
|
-
}.each do |f|
|
52
|
-
strings_files.push(f.real_path)
|
53
|
-
end
|
35
|
+
def extract
|
36
|
+
strings_files = []
|
54
37
|
|
55
|
-
|
56
|
-
|
38
|
+
# Loop on IB files from Base localization
|
39
|
+
self.files.select{|f|
|
40
|
+
f.path.end_with?(".xib", ".storyboard") && Project.fromBase(f.path)
|
41
|
+
}.each do |f|
|
42
|
+
output_name = f.path.gsub(/[\/\.]/, '_')
|
43
|
+
output_path = "/tmp/#{output_name}.strings"
|
44
|
+
puts "Extracting strings from #{f.path} into #{output_path}"
|
45
|
+
Kernel.system("ibtool --generate-strings-file \"#{output_path}\" \"#{f.real_path}\"")
|
46
|
+
strings_files.push(output_path)
|
47
|
+
end
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
versions.push({:version => contents['CFBundleShortVersionString'], :file => f.path})
|
49
|
+
# Loop on .strings files
|
50
|
+
self.files.select{|f|
|
51
|
+
f.path.end_with?(".strings") && Project.fromBase(f.path)
|
52
|
+
}.each do |f|
|
53
|
+
strings_files.push(f.real_path)
|
64
54
|
end
|
55
|
+
|
56
|
+
return strings_files
|
65
57
|
end
|
66
58
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
else
|
75
|
-
puts "Multiple Info.plist files found."
|
76
|
-
versions.each_with_index do |v, i|
|
77
|
-
puts "#{i}. #{v[:version]} from #{v[:file]}"
|
59
|
+
def getVersion
|
60
|
+
versions = []
|
61
|
+
self.files.select{|f| f.path.end_with?(".plist")}.each do |f|
|
62
|
+
contents = Xcodeproj::Plist.read_from_path(f.real_path)
|
63
|
+
if contents['CFBundleShortVersionString']
|
64
|
+
versions.push({:version => contents['CFBundleShortVersionString'], :file => f.path})
|
65
|
+
end
|
78
66
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
67
|
+
|
68
|
+
case versions.count
|
69
|
+
when 0
|
70
|
+
puts "No app version found in project.\nPlease enter a version number:"
|
71
|
+
version = STDIN.gets.chomp
|
72
|
+
return version
|
73
|
+
when 1
|
74
|
+
return versions.first[:version]
|
75
|
+
else
|
76
|
+
puts "Multiple Info.plist files found."
|
77
|
+
versions.each_with_index do |v, i|
|
78
|
+
puts "#{i}. #{v[:version]} from #{v[:file]}"
|
85
79
|
end
|
80
|
+
puts "Please select which version number to use:"
|
86
81
|
choice = nil
|
82
|
+
while choice.nil?
|
83
|
+
choice = STDIN.gets.chomp.to_i
|
84
|
+
if choice < versions.count
|
85
|
+
return versions[choice][:version]
|
86
|
+
end
|
87
|
+
choice = nil
|
88
|
+
end
|
87
89
|
end
|
88
90
|
end
|
89
|
-
end
|
90
91
|
|
92
|
+
end
|
91
93
|
end
|
data/lib/smartling_xcode.rb
CHANGED
@@ -3,29 +3,31 @@ require "smartling_xcode/backend"
|
|
3
3
|
require "smartling_xcode/version"
|
4
4
|
|
5
5
|
module SmartlingXcode
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
class Project
|
7
|
+
attr_accessor :projectPath, :version, :sandbox
|
8
|
+
|
9
|
+
def init
|
10
|
+
api = API.new({:sandbox => @sandbox})
|
11
|
+
api.requestCredentials
|
12
|
+
end
|
13
|
+
|
14
|
+
def extract
|
15
|
+
project = Xcodeproj::Project.find(@projectPath)
|
16
|
+
files = project.extract
|
14
17
|
puts "\nOutput:"
|
15
18
|
puts files
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
end
|
20
|
+
|
21
|
+
def push
|
22
|
+
api = API.new({:sandbox => @sandbox})
|
23
|
+
api.loadCredentials()
|
24
|
+
project = Xcodeproj::Project.find(@projectPath)
|
25
|
+
files = project.extract
|
26
|
+
if @version.nil?
|
27
|
+
@version = project.getVersion
|
23
28
|
end
|
24
|
-
pushStringsFromFiles(files, version
|
29
|
+
api.pushStringsFromFiles(files, @version)
|
25
30
|
puts "\nYour files are now available in the Files section of your Smartling project."
|
26
|
-
return 0
|
27
|
-
else
|
28
|
-
return 1
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
data/smartling_xcode.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
|
29
29
|
spec.add_dependency "xcodeproj", ">= 1.1"
|
30
30
|
spec.add_dependency "json", ">= 1.8.1"
|
31
|
-
spec.add_dependency "smartling", ">=
|
31
|
+
spec.add_dependency "smartling", ">= 2.0.0"
|
32
32
|
|
33
33
|
spec.add_development_dependency "bundler", "~> 1.11"
|
34
34
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smartling_xcode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emilien Huet
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xcodeproj
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 2.0.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: 2.0.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
136
|
version: '0'
|
137
137
|
requirements: []
|
138
138
|
rubyforge_project:
|
139
|
-
rubygems_version: 2.
|
139
|
+
rubygems_version: 2.5.2
|
140
140
|
signing_key:
|
141
141
|
specification_version: 4
|
142
142
|
summary: Smartling utility to extract strings from an Xcode project and add them to
|