phraseapp-rubymotion 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +1 -0
- data/lib/motion/project/phrase.rb +74 -0
- data/lib/phraseapp-rubymotion.rb +19 -0
- data/lib/phraseapp-rubymotion/api_client.rb +110 -0
- data/lib/phraseapp-rubymotion/nsstring.rb +41 -0
- data/lib/phraseapp-rubymotion/version.rb +3 -0
- data/phraseapp-rubymotion.gemspec +21 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 161e0947aa5f4e4b88550e5b5bbf45410a8a485d
|
4
|
+
data.tar.gz: 0a709e07f3c60a40a6f3673380257a7f52cf871d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d92796eac55fd7422e0ab047e3bd46570cb2cfba105f4dc5a837a05501d25bab048b681ebaa892c3e83beb3444f68f6e29100d4fc8b2c8016be498379a55e97
|
7
|
+
data.tar.gz: d92f102fd37bb3533837e890f9344e24b233149936ee3d4c105adb123e43c6a6e973aa25541a958da5bc5bf481fdfc0594b47e3163826bb273df280d9d921788
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 docstun
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# phraseapp-rubymotion
|
2
|
+
|
3
|
+
phraseapp-rubymotion lets you connect your RubyMotion application to PhraseApp and enables you to benefit from the best internationalization workflow for your (iOS) projects.
|
4
|
+
|
5
|
+
It lets you use iOS Localizable.strings files to store and read translations but at the same time work on your translation files collaboratively with translators, developers and product managers.
|
6
|
+
|
7
|
+
[Learn more about PhraseApp](https://phraseapp.com/)
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Using the service requires a PhraseApp account. Just sign up at [phraseapp.com/signup](https://phraseapp.com/signup) and get your free trial account (we offer free plans for small and open source projects).
|
12
|
+
|
13
|
+
You can skip the introduction wizard and simply create your first project to get your Auth Token directly from the project overview in PhraseApp.
|
14
|
+
|
15
|
+
### Install the Gem
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
gem 'phraseapp-rubymotion'
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install phraseapp-rubymotion
|
28
|
+
|
29
|
+
Require the gem (unless you use bundler):
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'phraseapp-rubymotion'
|
33
|
+
```
|
34
|
+
|
35
|
+
### Configure PhraseApp
|
36
|
+
|
37
|
+
Add the Auth Token to your application's Rakefile:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
Motion::Project::App.setup do |app|
|
41
|
+
app.name = "Test Application"
|
42
|
+
app.development do
|
43
|
+
app.phraseapp do
|
44
|
+
app.phraseapp.enabled = true
|
45
|
+
app.phraseapp.access_token = "YOUR_AUTH_TOKEN"
|
46
|
+
app.phraseapp.project_id = "YOUR_PROJECT_ID"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
This will automatically create the `phraseapp_config.rb` configuration file in your app folder during every build process.
|
53
|
+
|
54
|
+
**Please make sure that you only enable PhraseApp in development mode and never in release mode!**
|
55
|
+
|
56
|
+
## Usage
|
57
|
+
|
58
|
+
Using PhraseApp with phraseapp-rubymotion enables you to:
|
59
|
+
|
60
|
+
Send new translations to the PhraseApp API automatically without having to write them into your Localizable.strings file or uploading them - just by browsing the app.
|
61
|
+
|
62
|
+
### Localizing Strings ###
|
63
|
+
|
64
|
+
The first step towards a localized app is to localize all strings by extending them with their localized counterparts. This can be done by simply calling the `#__` method on each string that is implemented by phraseapp-rubymotion:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
"Hello World"
|
68
|
+
```
|
69
|
+
|
70
|
+
now becomes:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
"Hello World".__
|
74
|
+
```
|
75
|
+
|
76
|
+
or (when using a fallback translation):
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
"Hello World".__("My fallback translation")
|
80
|
+
```
|
81
|
+
|
82
|
+
Of course you can use more generic names for your keys as well, such as:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
"HOME_WELCOME_BUTTON_LABEL".__
|
86
|
+
```
|
87
|
+
|
88
|
+
[Learn more about localization in iOS](https://developer.apple.com/internationalization/)
|
89
|
+
|
90
|
+
### Browsing translations in your app
|
91
|
+
|
92
|
+
Simply build and run your app (in the simulator). When in development mode, phraseapp-rubymotion will send all of your localized strings to PhraseApp automatically! Log into your [PhraseApp account](https://phraseapp.com/account/login) and check your newly created translation keys. If you already have your localization files in the correct place, it will transmit translations as well.
|
93
|
+
|
94
|
+
|
95
|
+
## Support
|
96
|
+
|
97
|
+
* [PhraseApp Documentation](https://phraseapp.com/docs)
|
98
|
+
* [PhraseApp Support Channel](https://phraseapp.com/support)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,74 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
class PhraseAppConfig
|
6
|
+
attr_accessor :access_token, :enabled, :project_id
|
7
|
+
|
8
|
+
CONFIG_FILE = './app/phraseapp_config.rb'
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
@enabled = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def access_token=(access_token)
|
16
|
+
@access_token = access_token
|
17
|
+
create_phraseapp_config_file
|
18
|
+
end
|
19
|
+
|
20
|
+
def project_id=(project_id)
|
21
|
+
@project_id = project_id
|
22
|
+
create_phraseapp_config_file
|
23
|
+
end
|
24
|
+
|
25
|
+
def enabled=(enabled)
|
26
|
+
@enabled = enabled
|
27
|
+
create_phraseapp_config_file
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
def create_phraseapp_config_file
|
34
|
+
return unless @access_token
|
35
|
+
|
36
|
+
if !config_file_exists? or config_file_content_outdated?
|
37
|
+
File.open(CONFIG_FILE, 'w') { |f| f.write(config_file_content) }
|
38
|
+
end
|
39
|
+
files = @config.files.flatten
|
40
|
+
files.unshift(CONFIG_FILE) unless files.find { |f| File.expand_path(f) == File.expand_path(CONFIG_FILE) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def config_file_exists?
|
44
|
+
File.exist?(CONFIG_FILE)
|
45
|
+
end
|
46
|
+
|
47
|
+
def config_file_content_outdated?
|
48
|
+
config_file_exists? && File.read(CONFIG_FILE) != config_file_content
|
49
|
+
end
|
50
|
+
|
51
|
+
def config_file_content
|
52
|
+
content = <<EOF
|
53
|
+
# This file is automatically generated. Do not edit.
|
54
|
+
PHRASEAPP_ENABLED = #{enabled}
|
55
|
+
PHRASEAPP_ACCESS_TOKEN = "#{access_token}"
|
56
|
+
PHRASEAPP_PROJECT_ID = "#{project_id}"
|
57
|
+
EOF
|
58
|
+
content
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Motion
|
63
|
+
module Project
|
64
|
+
class Config
|
65
|
+
variable :phraseapp
|
66
|
+
|
67
|
+
def phraseapp
|
68
|
+
@phraseapp ||= PhraseAppConfig.new(self)
|
69
|
+
yield @phraseapp if block_given?
|
70
|
+
@phraseapp
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
require "motion/project/phrase"
|
6
|
+
require "motion-cocoapods"
|
7
|
+
require "phraseapp-ruby"
|
8
|
+
|
9
|
+
Motion::Project::App.setup do |app|
|
10
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'phraseapp-rubymotion/**/*.rb')).each do |file|
|
11
|
+
app.files.unshift(file)
|
12
|
+
end
|
13
|
+
|
14
|
+
app.files.unshift("./app/phraseapp_config.rb")
|
15
|
+
|
16
|
+
app.pods do
|
17
|
+
pod 'AFNetworking', '>= 2.5.0'
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module MotionPhrase
|
2
|
+
class ApiClient
|
3
|
+
API_CLIENT_IDENTIFIER = "PhraseApp RubyMotion " + MotionPhrase::VERSION
|
4
|
+
API_BASE_URI = "https://api.phraseapp.com/v2/"
|
5
|
+
|
6
|
+
def self.sharedClient
|
7
|
+
Dispatch.once { @instance ||= new }
|
8
|
+
@instance
|
9
|
+
end
|
10
|
+
|
11
|
+
def store(keyName, content, fallbackContent, currentLocale)
|
12
|
+
return unless access_token_present? && project_id_present?
|
13
|
+
content ||= fallbackContent
|
14
|
+
client.GET("projects/#{project_id}/locales", parameters:{}, success:lambda {|task, responseObject|
|
15
|
+
responseObject.each do |x|
|
16
|
+
if x["default"]
|
17
|
+
locale_id = x["id"]
|
18
|
+
storeKey({name: keyName}, locale_id, content, keyName)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
}, failure:lambda {|task, error|
|
22
|
+
log "Failed to get locales"
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def storeKey(data, locale_id, content, keyName)
|
27
|
+
client.POST("projects/#{project_id}/keys", parameters:data, success:lambda {|task, responseObject|
|
28
|
+
log "Key stored [#{data.inspect}]"
|
29
|
+
|
30
|
+
client.POST("projects/#{project_id}/keys/search", parameters:{q: "name:#{keyName}"}, success:lambda {|task, responseObject|
|
31
|
+
storeTranslation(content, locale_id, responseObject[0]["id"])
|
32
|
+
}, failure:lambda {|task, error|
|
33
|
+
log "Failed to get KeyID [#{data.inspect}]"
|
34
|
+
})
|
35
|
+
}, failure:lambda {|task, error|
|
36
|
+
if error.userInfo['com.alamofire.serialization.response.error.data'].to_s.include?('has already been taken')
|
37
|
+
log "Key [#{data.inspect}] is already stored"
|
38
|
+
|
39
|
+
client.POST("projects/#{project_id}/keys/search", parameters:{q: "name:#{keyName}"}, success:lambda {|task, responseObject|
|
40
|
+
storeTranslation(content, locale_id, responseObject[0]["id"])
|
41
|
+
}, failure:lambda {|task, error|
|
42
|
+
log "Failed to get KeyID [#{data.inspect}]"
|
43
|
+
})
|
44
|
+
else
|
45
|
+
log "Error while storing Key [#{data.inspect}]"
|
46
|
+
log error.localizedDescription
|
47
|
+
end
|
48
|
+
})
|
49
|
+
end
|
50
|
+
|
51
|
+
def storeTranslation(content, locale_id, key_id)
|
52
|
+
data = {
|
53
|
+
content: content,
|
54
|
+
locale_id: locale_id,
|
55
|
+
key_id: key_id
|
56
|
+
}
|
57
|
+
client.POST("projects/#{project_id}/translations", parameters:data, success:lambda {|task, responseObject|
|
58
|
+
log "Translation stored [#{data.inspect}]"
|
59
|
+
}, failure:lambda {|task, error|
|
60
|
+
if error.userInfo['com.alamofire.serialization.response.error.data'].to_s.include?('has already been taken')
|
61
|
+
log "Translation is already stored [#{data.inspect}] "
|
62
|
+
else
|
63
|
+
log "Error while storing Translation [#{data.inspect}]"
|
64
|
+
log error.localizedDescription
|
65
|
+
end
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def client
|
71
|
+
Dispatch.once do
|
72
|
+
@client = begin
|
73
|
+
_client = AFHTTPSessionManager.alloc.initWithBaseURL(NSURL.URLWithString(API_BASE_URI))
|
74
|
+
_client.requestSerializer.setValue("token #{access_token}", forHTTPHeaderField: "Authorization")
|
75
|
+
_client
|
76
|
+
end
|
77
|
+
end
|
78
|
+
@client
|
79
|
+
end
|
80
|
+
|
81
|
+
def log(msg="")
|
82
|
+
$stdout.puts "PHRASEAPP: #{msg}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def access_token
|
86
|
+
if defined?(PHRASEAPP_ACCESS_TOKEN)
|
87
|
+
PHRASEAPP_ACCESS_TOKEN
|
88
|
+
else
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def access_token_present?
|
94
|
+
!access_token.nil? && access_token != ""
|
95
|
+
end
|
96
|
+
|
97
|
+
def project_id
|
98
|
+
if defined?(PHRASEAPP_PROJECT_ID)
|
99
|
+
PHRASEAPP_PROJECT_ID
|
100
|
+
else
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def project_id_present?
|
106
|
+
!project_id.nil? && project_id != ""
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class NSString
|
2
|
+
def _localized(value=nil, table=nil)
|
3
|
+
@localized = NSBundle.mainBundle.localizedStringForKey(self, value:value, table:table)
|
4
|
+
store(self, @localized, value, table) if phraseEnabled?
|
5
|
+
@localized
|
6
|
+
end
|
7
|
+
alias __ _localized
|
8
|
+
|
9
|
+
private
|
10
|
+
def store(key, localized, defaultValue=nil, table=nil)
|
11
|
+
@client = MotionPhrase::ApiClient.sharedClient
|
12
|
+
@client.store(key, localized, defaultValue, currentLocaleName)
|
13
|
+
end
|
14
|
+
|
15
|
+
def phraseEnabled?
|
16
|
+
PHRASEAPP_ENABLED == true && development?
|
17
|
+
end
|
18
|
+
|
19
|
+
def currentLocaleName
|
20
|
+
currentLocale.localeIdentifier
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [NSLocale] locale of user settings
|
24
|
+
def currentLocale
|
25
|
+
languages = NSLocale.preferredLanguages
|
26
|
+
if languages.count > 0
|
27
|
+
return NSLocale.alloc.initWithLocaleIdentifier(languages.first)
|
28
|
+
else
|
29
|
+
return NSLocale.currentLocale
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def environment
|
34
|
+
RUBYMOTION_ENV
|
35
|
+
end
|
36
|
+
|
37
|
+
def development?
|
38
|
+
environment == 'development'
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'phraseapp-rubymotion/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "phraseapp-rubymotion"
|
8
|
+
gem.version = MotionPhrase::VERSION
|
9
|
+
gem.authors = ["PhraseApp"]
|
10
|
+
gem.email = ["info@phraseapp.com"]
|
11
|
+
gem.description = "RubyMotion library for PhraseApp"
|
12
|
+
gem.summary = "Connect your RubyMotion application to PhraseApp for the best i18n experience"
|
13
|
+
gem.homepage = "https://github.com/phrase/phraseapp-rubymotion"
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.add_dependency 'phraseapp-ruby'
|
19
|
+
gem.add_dependency 'motion-cocoapods'
|
20
|
+
gem.add_development_dependency 'rake'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: phraseapp-rubymotion
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- PhraseApp
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: phraseapp-ruby
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: motion-cocoapods
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: RubyMotion library for PhraseApp
|
56
|
+
email:
|
57
|
+
- info@phraseapp.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- LICENSE.txt
|
65
|
+
- README.md
|
66
|
+
- Rakefile
|
67
|
+
- lib/motion/project/phrase.rb
|
68
|
+
- lib/phraseapp-rubymotion.rb
|
69
|
+
- lib/phraseapp-rubymotion/api_client.rb
|
70
|
+
- lib/phraseapp-rubymotion/nsstring.rb
|
71
|
+
- lib/phraseapp-rubymotion/version.rb
|
72
|
+
- phraseapp-rubymotion.gemspec
|
73
|
+
homepage: https://github.com/phrase/phraseapp-rubymotion
|
74
|
+
licenses: []
|
75
|
+
metadata: {}
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options: []
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
requirements: []
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 2.4.7
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Connect your RubyMotion application to PhraseApp for the best i18n experience
|
96
|
+
test_files: []
|