phrase-ota-i18n 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2f9c7981adbdad2b7ccda60036861f500c4855dc3793cb536d3282845af6197e
4
+ data.tar.gz: 7a41b105cf56b98f410faefd85b938a83988f7d0d82e79e7fd8d374bea52aabc
5
+ SHA512:
6
+ metadata.gz: c622e6fbf7ed2b806ed4d6466ba6e48c0917e1c184dfcd39e7af0d01aee6fa02a02947f0c4873f8da394d72a0a2e36c76164e335f79317469da834c98a263e2c
7
+ data.tar.gz: 4c14fe8da857858018ff49d457657d361224d3c42af94578b1caed6090357f452ce774081a87241436daf3c66de153a2f610103cf33cbca1971e50c836cd8263
@@ -0,0 +1,20 @@
1
+ name: "Check PR title"
2
+
3
+ on:
4
+ pull_request_target:
5
+ types:
6
+ - opened
7
+ - edited
8
+ - synchronize
9
+
10
+ permissions:
11
+ pull-requests: read
12
+
13
+ jobs:
14
+ main:
15
+ name: Validate PR title
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: amannn/action-semantic-pull-request@c3cd5d1ea3580753008872425915e343e351ab54 # pin@5.2.0
19
+ env:
20
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,15 @@
1
+ name: Lint
2
+ on: [push]
3
+ jobs:
4
+ standard:
5
+ name: standard
6
+ runs-on: ubuntu-latest
7
+ steps:
8
+ - name: Checkout
9
+ uses: actions/checkout@v3
10
+ - name: Install Ruby
11
+ uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf
12
+ with:
13
+ bundler-cache: true
14
+ - name: standard
15
+ run: bundle exec standardrb --no-fix
@@ -0,0 +1,36 @@
1
+ name: Release
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+
7
+ jobs:
8
+ release-please:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: GoogleCloudPlatform/release-please-action@ca6063f4ed81b55db15b8c42d1b6f7925866342d # pin@3.7.11
12
+ with:
13
+ release-type: ruby
14
+ package-name: phrase-ota-i18n
15
+ version-file: "lib/phrase/ota/version.rb"
16
+ - uses: actions/checkout@v3
17
+ if: ${{ steps.release.outputs.release_created }}
18
+ - uses: ruby/setup-ruby@250fcd6a742febb1123a77a841497ccaa8b9e939 #pin@v1.152.0
19
+ with:
20
+ ruby-version: 3.2.2
21
+ if: ${{ steps.release.outputs.release_created }}
22
+ - run: bundle install
23
+ if: ${{ steps.release.outputs.release_created }}
24
+ - name: publish gem
25
+ run: |
26
+ mkdir -p $HOME/.gem
27
+ touch $HOME/.gem/credentials
28
+ chmod 0600 $HOME/.gem/credentials
29
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
30
+ gem build phrase-ota-i18n.gemspec
31
+ gem push *.gem
32
+ env:
33
+ GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_TOKEN}}"
34
+ if: ${{ steps.release.outputs.release_created }}
35
+
36
+
@@ -0,0 +1,17 @@
1
+ name: Test
2
+ on: [push]
3
+ jobs:
4
+ rspec:
5
+ name: RSpec
6
+ runs-on: ubuntu-latest
7
+ env:
8
+ RAILS_ENV: test
9
+ steps:
10
+ - name: Checkout
11
+ uses: actions/checkout@v3
12
+ - name: Install Ruby
13
+ uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf
14
+ with:
15
+ bundler-cache: true
16
+ - name: RSpec
17
+ run: bundle exec rspec spec/
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.2.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2023-08-07)
4
+
5
+
6
+ ### Features
7
+
8
+ * add debug flag ([ae741b7](https://github.com/phrase/phrase-ota-i18n/commit/ae741b79a8eadc75603e23b70d55c435ea7de26a))
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in phrase-ota-i18n.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "standard"
8
+ gem "debug"
9
+ gem "rspec"
10
+ gem "webmock"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Phrase GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ # phrase-ota-i18n
2
+
3
+ Backend for the [I18n](https://github.com/ruby-i18n/i18n) gem to update translations over-the-air from [Phrase Strings](https://phrase.com)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'phrase-ota-i18n'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install phrase-ota-i18n
20
+
21
+ ## Usage
22
+
23
+ Generate config:
24
+
25
+ bundle exec rails generate phrase_ota_rails:install --distribution-id <DISTRIBUTION_ID> --secret-token <SECRET>
26
+
27
+
28
+ ## Development
29
+
30
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
31
+
32
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
33
+
34
+ ## Contributing
35
+
36
+ This project relies on [conventional commits](https://www.conventionalcommits.org) used by [release-please](https://github.com/googleapis/release-please) to generate proper changelogs and increment versions of the generated client libraries affected by the PR. Please use [appropriate prefixes](https://kapeli.com/cheat_sheets/Conventional_Commits.docset/Contents/Resources/Documents/index) when giving titles to your PRs as they decide whether there will be a version bump and changelog entry.
37
+
38
+
39
+ ## License
40
+
41
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "phrase/ota"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,19 @@
1
+ require "rails/generators"
2
+
3
+ module PhraseOta
4
+ class InstallGenerator < Rails::Generators::Base
5
+ source_root File.expand_path("../templates", __FILE__)
6
+
7
+ desc "Creates a Phrase OTA initializer for your Rails application."
8
+ class_option :distribution_id, type: :string, desc: "Your Phrase OTA distribution ID", required: true
9
+ class_option :secret_token, type: :string, desc: "Your Phrase OTA secret token", required: true
10
+
11
+ def copy_initializer
12
+ template "phrase_ota.rb", "config/initializers/phrase_ota.rb"
13
+ end
14
+
15
+ def show_readme
16
+ readme "README.md" if behavior == :invoke
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ Welcome to Phrase OTA!
2
+
3
+ Phrase OTA lets you update the translations of your app on the fly, without restarting or deploying anything.
4
+
5
+ Happy internationalizing!
@@ -0,0 +1,25 @@
1
+ require "phrase/ota"
2
+
3
+ fallback_backend = I18n::Backend::Simple.new
4
+
5
+ Phrase::Ota.configure do |config|
6
+ # Possible datacenter values are "eu" and "us". The distribution_id and secret_token need to match the datacenter
7
+ config.datacenter = "eu"
8
+
9
+ # Phrase OTA Distribution ID
10
+ config.distribution_id = "<%= options[:distribution_id] %>"
11
+
12
+ # Your Phrase OTA secret token (either development or production)
13
+ config.secret_token = "<%= options[:secret_token] %>"
14
+
15
+ # Logger
16
+ config.logger = Rails.logger
17
+
18
+ # App version, set to nil if you do not want to use app version restriction
19
+ config.app_version = nil
20
+
21
+ # Available locales that will be updated over-the-air
22
+ config.available_locales = fallback_backend.available_locales
23
+ end
24
+
25
+ I18n.backend = I18n::Backend::Chain.new(Phrase::Ota::Backend.new, fallback_backend)
@@ -0,0 +1,68 @@
1
+ require "faraday"
2
+ require "faraday_middleware"
3
+ require "i18n"
4
+
5
+ module Phrase
6
+ module Ota
7
+ class Backend < I18n::Backend::Simple
8
+ def initialize
9
+ @current_version = nil
10
+ start_polling
11
+ end
12
+
13
+ def available_locales
14
+ Phrase::Ota.config.available_locales
15
+ end
16
+
17
+ def init_translations
18
+ @translations = {}
19
+ @initialized = true
20
+ end
21
+
22
+ protected
23
+
24
+ def start_polling
25
+ Thread.new do
26
+ loop do
27
+ sleep(Phrase::Ota.config.poll_interval_seconds)
28
+ update_translations
29
+ end
30
+ end
31
+ end
32
+
33
+ def update_translations
34
+ log("Phrase: Updating translations...")
35
+
36
+ available_locales.each do |locale|
37
+ url = "#{Phrase::Ota.config.base_url}/#{Phrase::Ota.config.distribution_id}/#{Phrase::Ota.config.secret_token}/#{locale}/yml"
38
+ params = {
39
+ app_version: Phrase::Ota.config.app_version,
40
+ client: "ruby",
41
+ sdk_version: Phrase::Ota::VERSION
42
+ }
43
+ params[:current_version] = @current_version unless @current_version.nil?
44
+
45
+ connection = Faraday.new do |faraday|
46
+ faraday.use FaradayMiddleware::FollowRedirects
47
+ faraday.adapter Faraday.default_adapter
48
+ end
49
+
50
+ log("Phrase: Fetching URL: #{url}")
51
+
52
+ response = connection.get(url, params, {"User-Agent" => "phrase-ota-i18n #{Phrase::Ota::VERSION}"})
53
+ next unless response.status == 200
54
+
55
+ @current_version = CGI.parse(URI(response.env.url).query)["version"].first.to_i
56
+ yaml = YAML.safe_load(response.body)
57
+ yaml.each do |yaml_locale, tree|
58
+ store_translations(yaml_locale, tree || {})
59
+ end
60
+ end
61
+ end
62
+
63
+ def log(message)
64
+ Phrase::Ota.config.logger.info(message) if Phrase::Ota.config.debug
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,48 @@
1
+ require "logger"
2
+
3
+ module Phrase
4
+ module Ota
5
+ class UnknownDatacenterException < StandardError; end
6
+
7
+ class Configuration
8
+ attr_accessor :distribution_id
9
+ attr_accessor :secret_token
10
+ attr_accessor :logger
11
+ attr_accessor :app_version
12
+ attr_accessor :poll_interval_seconds
13
+ attr_accessor :datacenter
14
+ attr_accessor :available_locales
15
+ attr_accessor :debug
16
+ attr_writer :base_url
17
+
18
+ def initialize
19
+ @distribution_id = nil
20
+ @secret_token = nil
21
+ @logger = Logger.new($stdout)
22
+ @app_version = nil
23
+ @poll_interval_seconds = 60
24
+ @datacenter = "eu"
25
+ @available_locales = []
26
+ @base_url = nil
27
+ @debug = false
28
+ end
29
+
30
+ def base_url
31
+ @base_url || datacenter_url
32
+ end
33
+
34
+ private
35
+
36
+ def datacenter_url
37
+ case @datacenter.downcase
38
+ when "eu"
39
+ "https://ota.eu.phrase.com"
40
+ when "us"
41
+ "https://ota.us.phrase.com"
42
+ else
43
+ raise UnknownDatacenterException
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ module Phrase
2
+ module Ota
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
data/lib/phrase/ota.rb ADDED
@@ -0,0 +1,15 @@
1
+ require "phrase/ota/version"
2
+ require "phrase/ota/configuration"
3
+ require "phrase/ota/backend"
4
+
5
+ module Phrase
6
+ module Ota
7
+ def self.configure
8
+ yield(config) if block_given?
9
+ end
10
+
11
+ def self.config
12
+ @config ||= Phrase::Ota::Configuration.new
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ require_relative "lib/phrase/ota/version"
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "phrase-ota-i18n"
5
+ spec.version = Phrase::Ota::VERSION
6
+ spec.authors = ["Phrase"]
7
+ spec.email = ["support@phrase.com"]
8
+
9
+ spec.summary = "Phrase OTA for Rails i18n"
10
+ spec.description = "Phrase OTA for Rails i18n"
11
+ spec.homepage = "https://github.com/phrase/phrase-ota-i18n"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
14
+
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency "i18n"
27
+ spec.add_dependency "faraday"
28
+ spec.add_dependency "faraday_middleware"
29
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: phrase-ota-i18n
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Phrase
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: i18n
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: faraday
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: faraday_middleware
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Phrase OTA for Rails i18n
56
+ email:
57
+ - support@phrase.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".github/workflows/check_pr_title.yml"
63
+ - ".github/workflows/lint.yml"
64
+ - ".github/workflows/release.yml"
65
+ - ".github/workflows/test.yml"
66
+ - ".gitignore"
67
+ - ".rspec"
68
+ - ".tool-versions"
69
+ - CHANGELOG.md
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - bin/console
75
+ - bin/setup
76
+ - lib/generators/phrase_ota/install_generator.rb
77
+ - lib/generators/phrase_ota/templates/README.md
78
+ - lib/generators/phrase_ota/templates/phrase_ota.rb
79
+ - lib/phrase/ota.rb
80
+ - lib/phrase/ota/backend.rb
81
+ - lib/phrase/ota/configuration.rb
82
+ - lib/phrase/ota/version.rb
83
+ - phrase-ota-i18n.gemspec
84
+ homepage: https://github.com/phrase/phrase-ota-i18n
85
+ licenses:
86
+ - MIT
87
+ metadata:
88
+ homepage_uri: https://github.com/phrase/phrase-ota-i18n
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 3.0.0
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 3.4.10
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Phrase OTA for Rails i18n
108
+ test_files: []