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.
@@ -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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .rvmrc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in motion-phrase.gemspec
4
+ gemspec
@@ -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.
@@ -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)
@@ -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,3 @@
1
+ module MotionPhrase
2
+ VERSION = "1.0.0"
3
+ 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: []