shimmer 0.0.1 → 0.0.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36dcc714d5d4ddff50af58d02889b9c193754c8a8c8a48b38e989f898805adc5
4
- data.tar.gz: 3a3d6e7b848df467c7aa6ceb2f51071cd325f06da912dbc2926f0f7b7d986193
3
+ metadata.gz: f4c44b134bb61f78f82008a1907c738d358b48147ad6518211b7ffcef9fa4aab
4
+ data.tar.gz: 4b7eb93d01ed55818f0845498e3b33a531352dde7d72b491addded5a77f81ce5
5
5
  SHA512:
6
- metadata.gz: 7716f31b96c8d62da7c94151b59a6006ef12ddd918314aceb3026094cfb414634285e583979e0bc6b0932e16d36e95b69199d0e83c03933148ceaaf3002eac0d
7
- data.tar.gz: 64803d66f26ed93da2265b453493bfe768344273cabb9e0c077678d7c881d73eebdee1701801767adef198da8cda100cc72f5486687c56df2fdb8de865f84dac
6
+ metadata.gz: 49e8e4866c5d8bafc59d5ccbcac324afd214d2e83f31845a3ff207400059f25061629261ab494fbaf2d2ce1f8be575f978938f11b347d7e751606724e48b666d
7
+ data.tar.gz: 1e0892571dc244cd238be164c61d4c1b5480e38a994dc266c1d8e8652102a89efcf4ffa8686dd7d8d439dad8aad5080b2faadaa6b3b426f933567a36e16e7b7e
data/.editorconfig ADDED
@@ -0,0 +1,12 @@
1
+ ; EditorConfig is awesome: http://EditorConfig.org
2
+
3
+ ; top-most EditorConfig file
4
+ root = true
5
+
6
+ ; Unix-style newlines with a newline ending every file
7
+ [*]
8
+ indent_style = spaces
9
+ end_of_line = lf
10
+ insert_final_newline = true
11
+ trim_trailing_whitespace = true
12
+ indent_size = 2
data/.eslintrc.js ADDED
@@ -0,0 +1,25 @@
1
+ module.exports = {
2
+ env: {
3
+ browser: true,
4
+ es6: true,
5
+ },
6
+ parser: "@typescript-eslint/parser",
7
+ extends: [
8
+ "plugin:@typescript-eslint/recommended",
9
+ "plugin:prettier/recommended",
10
+ ],
11
+ parserOptions: {
12
+ ecmaVersion: 2018,
13
+ sourceType: "module",
14
+ },
15
+ plugins: ["@typescript-eslint"],
16
+ rules: {
17
+ "no-console": 2,
18
+ "@typescript-eslint/explicit-function-return-type": [
19
+ "error",
20
+ {
21
+ allowExpressions: true,
22
+ },
23
+ ],
24
+ },
25
+ };
data/.prettierrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "trailingComma": "es5"
3
+ }
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.3
data/.solargraph.yml ADDED
@@ -0,0 +1,4 @@
1
+ plugins:
2
+ - solargraph-standardrb
3
+ reporters:
4
+ - standardrb
@@ -0,0 +1,3 @@
1
+ {
2
+ "solargraph.useBundler": true
3
+ }
data/Gemfile CHANGED
@@ -6,3 +6,5 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
+ gem "standard"
10
+ gem "solargraph-standardrb"
data/Gemfile.lock ADDED
@@ -0,0 +1,87 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ shimmer (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ backport (1.2.0)
11
+ benchmark (0.2.0)
12
+ diff-lcs (1.4.4)
13
+ e2mmap (0.1.0)
14
+ jaro_winkler (1.5.4)
15
+ kramdown (2.3.1)
16
+ rexml
17
+ kramdown-parser-gfm (1.1.0)
18
+ kramdown (~> 2.0)
19
+ nokogiri (1.12.5-x86_64-darwin)
20
+ racc (~> 1.4)
21
+ nokogiri (1.12.5-x86_64-linux)
22
+ racc (~> 1.4)
23
+ parallel (1.21.0)
24
+ parser (3.0.3.2)
25
+ ast (~> 2.4.1)
26
+ racc (1.6.0)
27
+ rainbow (3.0.0)
28
+ rake (13.0.6)
29
+ regexp_parser (2.2.0)
30
+ reverse_markdown (2.1.1)
31
+ nokogiri
32
+ rexml (3.2.5)
33
+ rubocop (1.23.0)
34
+ parallel (~> 1.10)
35
+ parser (>= 3.0.0.0)
36
+ rainbow (>= 2.2.2, < 4.0)
37
+ regexp_parser (>= 1.8, < 3.0)
38
+ rexml
39
+ rubocop-ast (>= 1.12.0, < 2.0)
40
+ ruby-progressbar (~> 1.7)
41
+ unicode-display_width (>= 1.4.0, < 3.0)
42
+ rubocop-ast (1.15.0)
43
+ parser (>= 3.0.1.1)
44
+ rubocop-performance (1.12.0)
45
+ rubocop (>= 1.7.0, < 2.0)
46
+ rubocop-ast (>= 0.4.0)
47
+ ruby-progressbar (1.11.0)
48
+ solargraph (0.44.2)
49
+ backport (~> 1.2)
50
+ benchmark
51
+ bundler (>= 1.17.2)
52
+ diff-lcs (~> 1.4)
53
+ e2mmap
54
+ jaro_winkler (~> 1.5)
55
+ kramdown (~> 2.3)
56
+ kramdown-parser-gfm (~> 1.1)
57
+ parser (~> 3.0)
58
+ reverse_markdown (>= 1.0.5, < 3)
59
+ rubocop (>= 0.52)
60
+ thor (~> 1.0)
61
+ tilt (~> 2.0)
62
+ yard (~> 0.9, >= 0.9.24)
63
+ solargraph-standardrb (0.0.4)
64
+ solargraph (>= 0.39.1)
65
+ standard (>= 0.4.1)
66
+ standard (1.5.0)
67
+ rubocop (= 1.23.0)
68
+ rubocop-performance (= 1.12.0)
69
+ thor (1.1.0)
70
+ tilt (2.0.10)
71
+ unicode-display_width (2.1.0)
72
+ webrick (1.7.0)
73
+ yard (0.9.27)
74
+ webrick (~> 1.7.0)
75
+
76
+ PLATFORMS
77
+ x86_64-darwin-21
78
+ x86_64-linux
79
+
80
+ DEPENDENCIES
81
+ rake (~> 13.0)
82
+ shimmer!
83
+ solargraph-standardrb
84
+ standard
85
+
86
+ BUNDLED WITH
87
+ 2.2.32
data/README.md CHANGED
@@ -1,38 +1,196 @@
1
- # Shimmer
1
+ # Shimmer - Because Ruby could be more shiny!
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/shimmer`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Shimmer is a collection of Rails extensions that bring advanced UI features into your app and make your life easier as a developer.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ## Features
6
+
7
+ ### Static File Serving
8
+
9
+ `ActiveStorage` is great, but serving of files, especially behind a CDN, can be complicated to get right. This can be fixed easily:
10
+
11
+ ```ruby
12
+ # use an image tag
13
+ image_tag user.avatar, width: 300
14
+ ```
15
+
16
+ This extension overrides `image_tag` and also supplies a matching `image_file_url` that automatically resizes your image and creates a static, cacheable url.
17
+
18
+ ### Modals
19
+
20
+ Modals are the designer's best friend, but developers usually hate them for their complexity. Fear no more: Shimmer has you covered.
21
+
22
+ ```slim
23
+ a href=modal_path(new_post_path) Create a new Post
24
+ ```
25
+
26
+ This will open a modal on click and then asynchronously request the modal content from the controller. Modals can also be controlled via JavaScript via the global `ui` variable:
27
+
28
+ ```js
29
+ ui.modal.open({ url: "/posts/new" });
30
+ ui.modal.close();
31
+ ```
32
+
33
+ ### Popovers
34
+
35
+ When modals are annoying to implement, popovers are even worse. Thankfully, Shimmer comes to the rescue:
36
+
37
+ ```slim
38
+ a href=popover_path(new_post_path, placement: :left)
39
+ ```
40
+
41
+ This will request `new_post_path` and display it left of the anchor thanks to PopperJS.
42
+
43
+ ### Remote Navigation
44
+
45
+ Remote navigation takes Hotwire to the next level with built-in navigation actions, integrated with modals and popovers.
46
+
47
+ ```ruby
48
+ def create
49
+ @post = current_user.posts.create! post_params
50
+ ui.navigate_to @post
51
+ end
52
+ ```
53
+
54
+ This will automatically close the current modal or popover and navigate via Turbo Drive to the post's url - no redirects necessary.
55
+
56
+ The `ui` helper comes with several built-in functions:
57
+
58
+ ```ruby
59
+ # run any kind of javascript upon request completion
60
+ ui.run_javascript("alert('hello world')")
61
+
62
+ # open or replace a modal's content (dependent on its ID)
63
+ ui.open_modal(new_post_path, size: :small)
64
+
65
+ # close an open modal
66
+ ui.close_modal
67
+
68
+ # same methods also available for popovers
69
+ ui.open_popover(new_post_path, selector: "#user-profile", placement: :left)
70
+ ui.close_popover
71
+
72
+ # navigate via Turbo Drive
73
+ ui.navigate_to(@post)
74
+
75
+ # manipulate the page's content
76
+ ui.append(@post, with: "comments/comment", comment: @comment)
77
+ ui.prepend("#user-profile", with: "users/extra")
78
+ ui.replace(@post)
79
+ ui.remove(@post)
80
+ ```
81
+
82
+ ### Sitemaps
83
+
84
+ Want to implement sitemaps, but the ephemeral filesystem of Heroku hates you? Here's a simple way to upload sitemaps:
85
+
86
+ - install the sitemap gem and configure the `sitemap.rb` as usual
87
+ - use the shimmer adapter to automatically upload your sitemap to your configured ActiveStorage adapter
88
+ - use the shimmer controller to display the sitemap in your app
89
+ - (optional) tell sidekiq scheduler to regularly update your sitemap
90
+
91
+ ```ruby
92
+ # sitemap.rb
93
+ SitemapGenerator::Sitemap.adapter = Shimmer::SitemapAdapter.new
94
+
95
+ # routes.rb
96
+ get "sitemaps/*path", to: "shimmer/sitemaps#show"
97
+
98
+ # sidekiq.yml
99
+ :schedule:
100
+ sitemap:
101
+ cron: '0 0 12 * * * Europe/Berlin' # every day at 16:00, Berlin time
102
+ class: Shimmer::SitemapJob
103
+ ```
104
+
105
+ ### Cloudflare Support
106
+
107
+ As you might have noticed, Cloudflare SSL will cause some issues with your Rails app if you're not using SSL strict mode (https://github.com/rails/rails/issues/22965). If you can't switch to strict mode, go for the standard flexible mode instead and add this middleware to your stack:
108
+
109
+ ```ruby
110
+ # application.rb
111
+ config.middleware.use Shimmer::CloudflareProxy
112
+ ```
113
+
114
+ ### Heroku Database Helpers
115
+
116
+ Can't reproduce an issue with your local test data and just want the production or staging data on your development machine? Here you go:
117
+
118
+ ```bash
119
+ rails db:pull
120
+ ```
121
+
122
+ This will drop your local database and pull in the database of your connected Heroku app (make sure you executed `heroku git:remote -a your_app` before to have the git remote). But what about assets you might ask? Easy - assets are pulled from S3 as well via the AWS CLI automatically (make sure your environment variables in Heroku are correctly named as `AWS_REGION`, `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`) and the database is updated to use your local filesystem instead.
123
+
124
+ If you don't want the asset support, you can also only pull the database or only the assets:
125
+
126
+ ```bash
127
+ rails db:pull_data
128
+ rails db:pull_assets
129
+ ```
130
+
131
+ ### Localizable Routes with Browser Locale Support
132
+
133
+ To localize a page via urls, this will help you tremendously.
134
+
135
+ ```ruby
136
+ # routes.rb
137
+ Rails.application.routes.draw do
138
+ scope "/(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
139
+ get "login", to: "sessions#new"
140
+ end
141
+ end
142
+ ```
143
+
144
+ From now on you can prefix your routes with a locale like `/de/login` or `/en/login` and `I18n.locale` will automatically be set. If there is no locale in the url (it's optional), this will automatically use the browser's locale.
145
+
146
+ You want to redirect from unlocalized paths? Add a before action to your controller:
147
+
148
+ ```ruby
149
+ before_action :check_locale
150
+ ```
151
+
152
+ Trying to figure out which key a certain translation on the page has? Append `?debug` to the url and `I18n.debug?` will be set - which leads to keys being printed on the page.
6
153
 
7
154
  ## Installation
8
155
 
9
156
  Add this line to your application's Gemfile:
10
157
 
11
158
  ```ruby
12
- gem 'shimmer'
159
+ gem "shimmer"
13
160
  ```
14
161
 
15
162
  And then execute:
16
163
 
17
- $ bundle install
164
+ ```bash
165
+ $ bundle install
166
+ ```
18
167
 
19
- Or install it yourself as:
168
+ Add some configuration to your project:
20
169
 
21
- $ gem install shimmer
170
+ ```ruby
171
+ # routes.rb
22
172
 
23
- ## Usage
173
+ resources :files, only: :show, controller: "shimmer/files"
24
174
 
25
- TODO: Write usage instructions here
175
+ # application_controller.rb
176
+ class ApplicationController < ActionController::Base
177
+ include Shimmer::Localizable
178
+ include Shimmer::RemoteNavigation
179
+ end
180
+ ```
26
181
 
27
- ## Development
182
+ ```ts
183
+ // application.ts
28
184
 
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
185
+ import { start } from "@nerdgeschoss/shimmer";
186
+ import { application } from "controllers/application";
30
187
 
31
- 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
188
+ start({ application });
189
+ ```
32
190
 
33
191
  ## Contributing
34
192
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/shimmer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/shimmer/blob/master/CODE_OF_CONDUCT.md).
193
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nerdgeschoss/shimmer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/nerdgeschoss/shimmer/blob/master/CODE_OF_CONDUCT.md).
36
194
 
37
195
  ## License
38
196
 
@@ -40,4 +198,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
198
 
41
199
  ## Code of Conduct
42
200
 
43
- Everyone interacting in the Shimmer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/shimmer/blob/master/CODE_OF_CONDUCT.md).
201
+ Everyone interacting in the Shimmer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/nerdgeschoss/shimmer/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ class FilesController < ActionController::Base
5
+ def show
6
+ expires_in 1.year, public: true
7
+ request.session_options[:skip] = true # prevents a session cookie from being set (would prevent caching on CDNs)
8
+ proxy = FileProxy.restore(params.require(:id))
9
+ send_data proxy.file,
10
+ filename: proxy.filename.to_s,
11
+ type: proxy.content_type,
12
+ disposition: "inline"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ class SitemapsController < ActionController::Base
5
+ def show
6
+ path = "sitemaps/#{params.require(:path)}.gz"
7
+ send_data ActiveStorage::Blob.service.download(path)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ class SitemapJob < ActiveJob::Base
5
+ def perform
6
+ SitemapGenerator::Interpreter.run
7
+ SitemapGenerator::Sitemap.ping_search_engines
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://github.com/rails/rails/issues/22965
4
+ module Shimmer
5
+ class CloudflareProxy
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ return @app.call(env) unless env["HTTP_CF_VISITOR"]
12
+
13
+ env["HTTP_X_FORWARDED_PROTO"] = JSON.parse(env["HTTP_CF_VISITOR"])["scheme"]
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ module Shimmer
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ path = File.expand_path(__dir__)
5
+ Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :db do
4
+ desc "Downloads the app database from heroku to local db"
5
+ task pull_data: :environment do
6
+ config = ActiveRecord::Base.connection_db_config.config
7
+ # binding.pry
8
+ ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"] = "1"
9
+ Rake::Task["db:drop"].invoke
10
+ ENV["PGUSER"] = config["username"]
11
+ ENV["PGHOST"] = config["host"]
12
+ ENV["PGPORT"] = config["port"].to_s
13
+ sh "heroku pg:pull DATABASE_URL #{config["database"]} --app thefetishtraveller"
14
+ sh "rails db:environment:set"
15
+ sh "RAILS_ENV=test rails db:create"
16
+ end
17
+
18
+ task pull_assets: :environment do
19
+ config = JSON.parse(`heroku config --json`)
20
+ ENV["AWS_DEFAULT_REGION"] = config.fetch("AWS_REGION")
21
+ bucket = config.fetch("AWS_BUCKET")
22
+ ENV["AWS_ACCESS_KEY_ID"] = config.fetch("AWS_ACCESS_KEY_ID")
23
+ ENV["AWS_SECRET_ACCESS_KEY"] = config.fetch("AWS_SECRET_ACCESS_KEY")
24
+ storage_folder = Rails.root.join("storage")
25
+ download_folder = storage_folder.join("downloads")
26
+ FileUtils.mkdir_p download_folder
27
+ sh "aws s3 sync s3://#{bucket} #{storage_folder}/downloads"
28
+ download_folder.each_child do |file|
29
+ next if file.directory?
30
+
31
+ new_path = storage_folder.join file.basename.to_s.then { |e| [e[0..1], e[2..3], e] }.join("/")
32
+ FileUtils.mkdir_p(new_path.dirname)
33
+ FileUtils.cp(file, new_path)
34
+ end
35
+ # purge variants
36
+ ActiveStorage::VariantRecord.delete_all
37
+ ActiveStorage::Blob.update_all(service_name: :local)
38
+ end
39
+
40
+ desc "Download all app data, including assets"
41
+ task pull: [:pull_data, :pull_assets]
42
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Executes all linters and tests"
4
+ task :lint do
5
+ sh "bundle exec standardrb --fix"
6
+ sh "yarn lint"
7
+ sh "i18n-tasks health"
8
+ sh "bin/rspec"
9
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ module FileHelper
5
+ def image_tag(source, **options)
6
+ return nil if source.blank?
7
+
8
+ if source.is_a?(ActiveStorage::Variant) || source.is_a?(ActiveStorage::Attached) || source.is_a?(ActiveStorage::Attachment) || source.is_a?(ActionText::Attachment)
9
+ attachment = source
10
+ width = options[:width]
11
+ height = options[:height]
12
+ source = image_file_url(source, width: width, height: height)
13
+ options[:loading] = :lazy
14
+ options[:srcset] = "#{source} 1x, #{image_file_url(attachment, width: width.to_i * 2, height: height ? height.to_i * 2 : nil)} 2x" if options[:width].present?
15
+ end
16
+ super source, options
17
+ end
18
+
19
+ def image_file_url(source, width: nil, height: nil)
20
+ return if source.blank?
21
+ return source if source.is_a?(String)
22
+
23
+ blob = source.try(:blob) || source
24
+ Shimmer::FileProxy.new(blob_id: blob.id, width: width, height: height).url
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ class FileProxy
5
+ attr_reader :blob_id, :resize
6
+
7
+ delegate :message_verifier, to: :class
8
+ delegate :content_type, :filename, to: :blob
9
+
10
+ class << self
11
+ def restore(id)
12
+ blob_id, resize = message_verifier.verified(id)
13
+ new blob_id: blob_id, resize: resize
14
+ end
15
+ end
16
+
17
+ def initialize(blob_id:, resize: nil, width: nil, height: nil)
18
+ @blob_id = blob_id
19
+ if !resize && width
20
+ resize = if height
21
+ "#{width}x#{height}>"
22
+ else
23
+ "#{width}x"
24
+ end
25
+ end
26
+ @resize = resize
27
+ end
28
+
29
+ class << self
30
+ def message_verifier
31
+ @message_verifier ||= ApplicationRecord.signed_id_verifier
32
+ end
33
+ end
34
+
35
+ def path
36
+ Rails.application.routes.url_helpers.file_path(id, locale: nil)
37
+ end
38
+
39
+ def url(protocol: Rails.env.production? ? :https : :http)
40
+ Rails.application.routes.url_helpers.file_url(id, locale: nil, protocol: protocol)
41
+ end
42
+
43
+ def blob
44
+ @blob ||= ActiveStorage::Blob.find(blob_id)
45
+ end
46
+
47
+ def resizeable
48
+ resize.present? && !blob.content_type.include?("svg")
49
+ end
50
+
51
+ def variant
52
+ @variantvariant ||= resizeable ? blob.representation(resize: resize).processed : blob
53
+ end
54
+
55
+ def file
56
+ @file ||= blob.service.download(variant.key)
57
+ end
58
+
59
+ private
60
+
61
+ def id
62
+ @id ||= message_verifier.generate([blob_id, resize])
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Shimmer
4
+ module Localizable
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_action :set_locale
9
+
10
+ def default_url_options(options = {})
11
+ options = {locale: I18n.locale}.merge options
12
+ options[:debug] = true if I18n.debug?
13
+ options
14
+ end
15
+
16
+ def request_locale
17
+ request.env["HTTP_ACCEPT_LANGUAGE"].to_s[0..1].downcase.presence&.then { |e| e if I18n.available_locales.include?(e.to_sym) }
18
+ end
19
+
20
+ def set_locale
21
+ I18n.locale = url_locale || request_locale || I18n.default_locale
22
+ I18n.debug = params.key?(:debug)
23
+ end
24
+
25
+ def check_locale
26
+ redirect_to url_for(locale: I18n.locale) if params[:locale].blank? && request.get? && request.format.html?
27
+ end
28
+
29
+ def url_locale
30
+ params[:locale]
31
+ end
32
+
33
+ I18n.class_eval do
34
+ thread_mattr_accessor :debug
35
+
36
+ class << self
37
+ alias_method :old_translate, :translate
38
+ def translate(key, options = {})
39
+ untranslated_scopes = ["number", "transliterate", "date", "datetime", "errors", "helpers", "support", "time", "faker"].map { |k| "#{k}." }
40
+ key = key.to_s.downcase
41
+ untranslated = untranslated_scopes.any? { |e| key.include? e }
42
+ key_name = [options[:scope], key].flatten.compact.join(".")
43
+ option_names = options.except(:count, :default, :raise, :scope).map { |k, v| "#{k}=#{v}" }.join(", ")
44
+ return "#{key_name} #{option_names}" if I18n.debug && !untranslated
45
+
46
+ options.reverse_merge!(default: old_translate(key, **options.merge(locale: :de))) if untranslated
47
+ old_translate(key, **options)
48
+ end
49
+ alias_method :t, :translate
50
+
51
+ def debug?
52
+ debug
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end