moirai 0.1.0 → 0.3.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +15 -6
  3. data/CHANGELOG.md +21 -0
  4. data/Gemfile +12 -1
  5. data/README.md +63 -27
  6. data/app/assets/config/moirai_manifest.js +0 -1
  7. data/app/assets/javascripts/moirai_translation_controller.js +41 -0
  8. data/app/assets/stylesheets/moirai/application.css +2 -0
  9. data/app/assets/stylesheets/translation_files.css +22 -0
  10. data/app/controllers/moirai/translation_files_controller.rb +66 -18
  11. data/app/controllers/moirai/translations_controller.rb +7 -0
  12. data/app/models/moirai/change.rb +15 -0
  13. data/app/models/moirai/key_finder.rb +55 -0
  14. data/app/models/moirai/translation.rb +9 -5
  15. data/app/models/moirai/translation_dumper.rb +40 -13
  16. data/app/views/layouts/moirai/application.html.erb +28 -1
  17. data/app/views/moirai/translation_files/_form.html.erb +3 -3
  18. data/app/views/moirai/translation_files/index.html.erb +1 -1
  19. data/app/views/moirai/translation_files/show.html.erb +11 -5
  20. data/app/views/moirai/translations/index.html.erb +7 -0
  21. data/bin/check +3 -1
  22. data/config/routes.rb +2 -1
  23. data/lib/generators/moirai/install_generator.rb +27 -2
  24. data/lib/generators/moirai/migration_generator.rb +5 -1
  25. data/lib/generators/moirai/templates/make_moirai_translations_file_path_not_required.rb.erb +5 -0
  26. data/lib/i18n/backend/moirai.rb +1 -53
  27. data/lib/i18n/extensions/i18n.rb +13 -0
  28. data/lib/moirai/engine.rb +8 -6
  29. data/lib/moirai/pull_request_creator.rb +42 -33
  30. data/lib/moirai/version.rb +1 -1
  31. data/lib/moirai.rb +2 -1
  32. data/moirai.gemspec +3 -6
  33. metadata +12 -77
  34. data/app/assets/javascripts/moirai/application.js +0 -2
  35. data/app/assets/javascripts/moirai/controllers/moirai_translation_controller.js +0 -27
  36. data/app/assets/javascripts/moirai/stimulus/init.js +0 -5
  37. /data/lib/generators/moirai/templates/{migration.rb.erb → create_moirai_translations.rb.erb} +0 -0
@@ -1,24 +1,51 @@
1
1
  module Moirai
2
2
  class TranslationDumper
3
+ def initialize
4
+ @key_finder = KeyFinder.new
5
+ end
6
+
7
+ # @return Array[Moirai::Change]
3
8
  def call
4
- project_root = Rails.root.to_s
5
- Moirai::Translation.pluck(:file_path).uniq.map do |file_path|
6
- absolute_file_path = File.expand_path(file_path, project_root)
7
- next unless absolute_file_path.start_with?(project_root)
8
-
9
- updated_file_contents = get_updated_file_contents(file_path)
10
- {
11
- file_path: file_path.sub(project_root, "."),
12
- content: updated_file_contents
13
- }
14
- end.compact
9
+ translations_by_file_path = group_translations_by_file_path
10
+ changes = []
11
+ translations_by_file_path.each do |file_path, translations|
12
+ relative_file_path = Pathname.new(file_path).relative_path_from(Rails.root)
13
+ changes << Change.new(relative_file_path, get_updated_file_contents(file_path, translations))
14
+ end
15
+ changes
16
+ end
17
+
18
+ def best_file_path_for(key, locale)
19
+ file_paths = @key_finder.file_paths_for(key, locale: locale)
20
+ file_paths.filter! { |p| p.start_with?(Rails.root.to_s) }
21
+ if file_paths.any?
22
+ file_paths.first
23
+ elsif key.split(".").size > 1
24
+ parent_key = key.split(".")[0..-2].join(".")
25
+ best_file_path_for(parent_key, locale)
26
+ else
27
+ "./config/locales/#{locale}.yml"
28
+ end
15
29
  end
16
30
 
17
31
  private
18
32
 
19
- def get_updated_file_contents(file_path)
20
- translations = Moirai::Translation.where(file_path: file_path)
33
+ def group_translations_by_file_path
34
+ translations_grouped_by_file_path = {}
35
+ Moirai::Translation.order(created_at: :asc).each do |translation|
36
+ file_path = best_file_path_for(translation.key, translation.locale)
37
+ absolute_file_path = File.expand_path(file_path, Rails.root)
38
+
39
+ # skip file paths that don't belong to the project
40
+ next unless absolute_file_path.to_s.start_with?(Rails.root.to_s)
41
+
42
+ translations_grouped_by_file_path[absolute_file_path] ||= []
43
+ translations_grouped_by_file_path[absolute_file_path] << translation
44
+ end
45
+ translations_grouped_by_file_path
46
+ end
21
47
 
48
+ def get_updated_file_contents(file_path, translations)
22
49
  yaml = YAML.load_file(file_path)
23
50
 
24
51
  translations.each do |translation|
@@ -6,9 +6,36 @@
6
6
  <%= csp_meta_tag %>
7
7
 
8
8
  <%= stylesheet_link_tag "moirai/application", media: "all" %>
9
- <%= javascript_include_tag "moirai/application", "data-turoblinks-track": "reload", type: "module" %>
10
9
  <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
11
10
  <link rel="icon" href="data:image/png;base64,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">
11
+
12
+ <style>
13
+ td {
14
+ height: 100px; /* Ensure the cell has a consistent height */
15
+ width: 200px; /* Set a reasonable width */
16
+ vertical-align: top;
17
+ }
18
+
19
+ form {
20
+ height: 100%;
21
+ display: flex;
22
+ align-items: stretch;
23
+ }
24
+
25
+ textarea {
26
+ flex: 1; /* Allow the textarea to expand */
27
+ width: 100%; /* Ensure it fills the width */
28
+ resize: none; /* Disable manual resizing */
29
+ box-sizing: border-box; /* Account for padding and borders */
30
+ border: 1px solid #ccc; /* Standard input border style */
31
+ border-radius: 4px; /* Match the design */
32
+ padding: 5px; /* Inner padding for text */
33
+ font-family: inherit; /* Use consistent font */
34
+ font-size: inherit; /* Match the font size */
35
+ overflow: hidden; /* Hide overflow before it resizes */
36
+ }
37
+ </style>
38
+
12
39
  </head>
13
40
  <body>
14
41
 
@@ -1,9 +1,9 @@
1
1
  <span
2
2
  contenteditable
3
- data-action="blur->moirai-translation#submit click->moirai-translation#click"
3
+ data-action="blur->moirai-translation#submit click->moirai-translation#click"
4
4
  style="border: 1px dashed #1d9f74; min-width: 30px; display: inline-block;"
5
- data-key="<%= key %>"
6
- data-file-path="<%= file_path %>"
5
+ data-moirai-translation-key-value="<%= key %>"
6
+ data-moirai-translation-locale-value="<%= locale %>"
7
7
  data-controller="moirai-translation">
8
8
  <%= value %>
9
9
  </span>
@@ -2,7 +2,7 @@
2
2
  <h1>Translation files</h1>
3
3
 
4
4
  <% if Moirai::PullRequestCreator.available? %>
5
- <%= button_to "Create or update PR", moirai_open_pr_path %>
5
+ <%= button_to "Create or update Pull Request", moirai_open_pr_path %>
6
6
  <% else %>
7
7
  <p>PR creation is not available. Add the gem octokit to your gemfile to enable this feature</p>
8
8
  <% end %>
@@ -9,11 +9,12 @@
9
9
  <tr>
10
10
  <th>Key</th>
11
11
  <th>Value</th>
12
+ <th>Original Translation</th>
12
13
  </tr>
13
14
  </thead>
14
15
  <tbody>
15
16
  <% @translation_keys.each do |key, value| %>
16
- <% translation = Moirai::Translation.find_by(key: key, file_path: @decoded_path) %>
17
+ <% translation = @translations.find { |t| t.key == key } %>
17
18
 
18
19
  <tr>
19
20
  <td>
@@ -24,13 +25,18 @@
24
25
  <% end %>
25
26
  </td>
26
27
  <td>
27
- <%= form_for Moirai::Translation.new, url: moirai_create_or_update_translation_path do |f| %>
28
- <%= f.hidden_field :key, value: key %>
29
- <%= f.hidden_field :file_path, value: @decoded_path %>
30
- <%= f.text_field :value, value: translation&.value || value %>
28
+ <%= form_for translation&.presence || Moirai::Translation.new(key: key, locale: @locale, value: value),
29
+ url: moirai_create_or_update_translation_path,
30
+ method: :post do |f| %>
31
+ <%= f.hidden_field :key %>
32
+ <%= f.hidden_field :locale %>
33
+ <%= f.text_area :value, class: 'translation-textarea' %>
31
34
  <%= f.submit 'Update', style: 'display: none;' %>
32
35
  <% end %>
33
36
  </td>
37
+ <td>
38
+ <%= I18n.translate_without_moirai(key, @locale) %>
39
+ </td>
34
40
  </tr>
35
41
  <% end %>
36
42
  </tbody>
@@ -0,0 +1,7 @@
1
+ <% @translations.each do |locale, key, value| %>
2
+ <div class="card">
3
+ <p><strong>Locale:</strong> <%=locale %></p>
4
+ <p><strong>Key:</strong> <%=key %></p>
5
+ <p><strong>Value:</strong> <%= value %></p>
6
+ </div>
7
+ <% end %>
data/bin/check CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
+ set -e
4
+
3
5
  bundle exec rails test
4
- #bundle exec rails test:system
6
+ bundle exec rails test:system
data/config/routes.rb CHANGED
@@ -3,7 +3,8 @@
3
3
  Moirai::Engine.routes.draw do
4
4
  root to: "translation_files#index"
5
5
 
6
- resources :translation_files, only: %i[index show], as: "moirai_translation_files"
6
+ resources :translations, only: %i[index]
7
+ resources :translation_files, only: %i[index show], as: "moirai_translation_files", param: :hashed_file_path
7
8
  post "/translation_files/open_pr", to: "translation_files#open_pr", as: "moirai_open_pr"
8
9
  post "/translation_files", to: "translation_files#create_or_update", as: "moirai_create_or_update_translation"
9
10
  end
@@ -10,9 +10,34 @@ module Moirai
10
10
  invoke "moirai:migration"
11
11
  end
12
12
 
13
+ def setup_javascript
14
+ if using_importmap?
15
+ say "Pin moirai"
16
+ string_to_be_added = "pin \"controllers/moirai_translation_controller\", to: \"moirai_translation_controller.js\""
17
+ say %(Appending: #{string_to_be_added})
18
+ append_to_file "config/importmap.rb", %(#{string_to_be_added}\n)
19
+ elsif using_js_bundling?
20
+ append_path = "app/javascript/controllers/moirai_translation_controller.js"
21
+ say "Copying Moirai Stimulus controller in #{append_path}"
22
+ copy_file "../../../../app/assets/javascripts/moirai_translation_controller.js", append_path
23
+ rails_command "stimulus:manifest:update"
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def using_js_bundling?
30
+ Rails.root.join("app/javascript/controllers").exist?
31
+ end
32
+
13
33
  def mount_engine
14
- route 'mount Moirai::Engine => "/moirai", as: "moirai"
15
- '
34
+ route 'mount Moirai::Engine => "/moirai", as: "moirai"'
35
+ end
36
+
37
+ private
38
+
39
+ def using_importmap?
40
+ Rails.root.join("config/importmap.rb").exist?
16
41
  end
17
42
  end
18
43
  end
@@ -11,7 +11,11 @@ module Moirai
11
11
  source_root File.expand_path("templates", __dir__)
12
12
 
13
13
  def create_migration_file
14
- migration_template "migration.rb.erb", "db/migrate/create_moirai_translations.rb", migration_version: migration_version
14
+ migration_template "create_moirai_translations.rb.erb", "db/migrate/create_moirai_translations.rb", migration_version: migration_version
15
+ end
16
+
17
+ def file_path_migration_file
18
+ migration_template "make_moirai_translations_file_path_not_required.rb.erb", "db/migrate/make_moirai_translations_file_path_not_required.rb", migration_version: migration_version
15
19
  end
16
20
 
17
21
  private
@@ -0,0 +1,5 @@
1
+ class MakeMoiraiTranslationsFilePathNotRequired < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ change_column_null :moirai_translations, :file_path, true
4
+ end
5
+ end
@@ -1,6 +1,6 @@
1
1
  module I18n
2
2
  module Backend
3
- class Moirai < I18n::Backend::Simple # TODO: no need to extend the simple one. It does too much
3
+ class Moirai < I18n::Backend::Simple
4
4
  # TODO: mega inefficient. we don't want to perform a SQL query for each key!
5
5
  def translate(locale, key, options = EMPTY_HASH)
6
6
  overridden_translation = ::Moirai::Translation.find_by(locale: locale, key: key)
@@ -8,58 +8,6 @@ module I18n
8
8
  overridden_translation.value
9
9
  end
10
10
  end
11
-
12
- def store_moirai_translations(filename, locale, data, options)
13
- moirai_translations[locale] ||= Concurrent::Hash.new
14
- flatten_data = flatten_hash(filename, data)
15
- flatten_data = Utils.deep_symbolize_keys(flatten_data) unless options.fetch(:skip_symbolize_keys, false)
16
- Utils.deep_merge!(moirai_translations[locale], flatten_data)
17
- end
18
-
19
- def moirai_translations(do_init: false)
20
- @moirai_translations ||= Concurrent::Hash.new do |h, k|
21
- MUTEX.synchronize do
22
- h[k] = Concurrent::Hash.new
23
- end
24
- end
25
- end
26
-
27
- def flatten_hash(filename, hash, parent_key = "", result = {})
28
- hash.each do |key, value|
29
- new_key = parent_key.empty? ? key.to_s : "#{parent_key}.#{key}"
30
- case value
31
- when Hash
32
- flatten_hash(filename, value, new_key, result)
33
- when Array
34
- value.each_with_index do |item, index|
35
- array_key = "#{new_key}.#{index}"
36
- if item.is_a?(Hash)
37
- flatten_hash(filename, item, array_key, result)
38
- else
39
- result[array_key] = filename
40
- end
41
- end
42
- else
43
- result[new_key] = filename
44
- end
45
- end
46
- result
47
- end
48
-
49
- def load_file(filename)
50
- type = File.extname(filename).tr(".", "").downcase
51
- raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
52
- data, keys_symbolized = send(:"load_#{type}", filename)
53
- unless data.is_a?(Hash)
54
- raise InvalidLocaleData.new(filename, "expects it to return a hash, but does not")
55
- end
56
- data.each do |locale, d|
57
- store_translations(locale, d || {}, skip_symbolize_keys: keys_symbolized)
58
- store_moirai_translations(filename, locale, d || {}, skip_symbolize_keys: keys_symbolized)
59
- end
60
-
61
- data
62
- end
63
11
  end
64
12
  end
65
13
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module I18n
4
+ class << self
5
+ attr_accessor :original_backend
6
+ end
7
+
8
+ def self.translate_without_moirai(key, locale, **)
9
+ raise "Original backend is not set" unless original_backend
10
+
11
+ original_backend.translate(locale, key, **)
12
+ end
13
+ end
data/lib/moirai/engine.rb CHANGED
@@ -9,9 +9,12 @@ module Moirai
9
9
  end
10
10
 
11
11
  config.after_initialize do
12
- moirai_backend = I18n::Backend::Moirai.new
13
- moirai_backend.eager_load!
14
- I18n.backend = I18n::Backend::Chain.new(moirai_backend, I18n.backend)
12
+ I18n.original_backend = I18n.backend
13
+ if ActiveRecord::Base.connection.data_source_exists?("moirai_translations") || ENV["RAILS_ENV"] == "test"
14
+ I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Moirai.new, I18n.backend)
15
+ else
16
+ Rails.logger.warn("moirai disabled: tables have not been generated yet.")
17
+ end
15
18
  end
16
19
 
17
20
  # TODO: how to do this without rewriting the entire method?
@@ -25,12 +28,11 @@ module Moirai
25
28
  value = original_translate(key, **options)
26
29
 
27
30
  if moirai_edit_enabled?
28
- moirai_translations = I18n.backend.backends.find { |b| b.respond_to?(:moirai_translations) }.moirai_translations
29
- file_path = moirai_translations[I18n.locale][scope_key_by_partial(key)]
31
+ @key_finder ||= Moirai::KeyFinder.new
30
32
 
31
33
  render(partial: "moirai/translation_files/form",
32
34
  locals: {key: scope_key_by_partial(key),
33
- file_path: file_path,
35
+ locale: I18n.locale,
34
36
  value: value})
35
37
  else
36
38
  value
@@ -1,41 +1,43 @@
1
1
  class Moirai::PullRequestCreator
2
- BRANCH_NAME = "moirai-translations"
3
-
4
2
  def self.available?
5
- defined?(Octokit)
3
+ !!defined?(Octokit)
6
4
  end
7
5
 
6
+ BRANCH_PREFIX = "moirai-translations-"
7
+
8
+ attr_reader :github_repo_name, :github_access_token, :github_client, :github_repository, :branch_name
9
+
8
10
  def initialize
9
11
  @github_repo_name = ENV["MOIRAI_GITHUB_REPO_NAME"] || Rails.application.credentials.dig(:moirai, :github_repo_name)
10
12
  @github_access_token = ENV["MOIRAI_GITHUB_ACCESS_TOKEN"] || Rails.application.credentials.dig(:moirai, :github_access_token)
11
- @client = Octokit::Client.new(
12
- access_token: @github_access_token
13
- )
13
+ @github_client = Octokit::Client.new(access_token: github_access_token)
14
+ @github_repository = github_client.repo(github_repo_name)
14
15
  end
15
16
 
16
- def create_pull_request(translations_array)
17
- repo = @client.repo(@github_repo_name)
18
- default_branch = repo.default_branch
17
+ # @param changes Array[Moirai::Change]
18
+ def create_pull_request(changes)
19
+ @branch_name = "#{BRANCH_PREFIX}#{Time.current.strftime("%F-%H-%M-%S")}-#{rand(1000..9999)}"
20
+ default_branch = github_repository.default_branch
19
21
 
20
- if branch_exists?
21
- puts "Branch #{BRANCH_NAME} already exists - the branch will be updated with the new changes"
22
+ if moirai_branch_exists?
23
+ Rails.logger.debug { "Branch #{branch_name} already exists - the branch will be updated with the new changes" }
22
24
  else
23
- puts "Branch #{BRANCH_NAME} does not exist - creating branch"
24
- default_branch_ref = @client.ref(@github_repo_name, "heads/#{default_branch}")
25
+ Rails.logger.debug { "Branch #{branch_name} does not exist - creating branch" }
26
+ default_branch_ref = @github_client.ref(@github_repo_name, "heads/#{default_branch}")
25
27
  latest_commit_sha = default_branch_ref.object.sha
26
28
 
27
- @client.create_ref(@github_repo_name, "heads/#{BRANCH_NAME}", latest_commit_sha)
29
+ @github_client.create_ref(@github_repo_name, "heads/#{branch_name}", latest_commit_sha)
28
30
  end
29
31
 
30
- translations_array.each do |translation_hash|
31
- update_file(translation_hash[:file_path], translation_hash[:content])
32
+ changes.each do |change|
33
+ update_file(change.file_path, change.content)
32
34
  end
33
35
 
34
- unless pull_request_exists?
35
- pull_request = @client.create_pull_request(
36
+ unless existing_open_pull_request.present?
37
+ pull_request = @github_client.create_pull_request(
36
38
  @github_repo_name,
37
39
  default_branch,
38
- BRANCH_NAME,
40
+ branch_name,
39
41
  "Adding new content by Moirai",
40
42
  "BODY - This is a pull request created by Moirai"
41
43
  )
@@ -44,40 +46,47 @@ class Moirai::PullRequestCreator
44
46
  end
45
47
  end
46
48
 
47
- def branch_exists?
48
- @client.ref(@github_repo_name, "heads/#{BRANCH_NAME}")
49
+ def moirai_branch_exists?
50
+ @github_client.ref(@github_repo_name, "heads/#{branch_name}")
49
51
  true
50
52
  rescue Octokit::NotFound
51
53
  false
52
54
  end
53
55
 
56
+ def existing_open_pull_request
57
+ @github_client.pull_requests(@github_repo_name).find do |pull_request|
58
+ pull_request.head.ref.start_with?(BRANCH_PREFIX) && (pull_request.state == "open")
59
+ end
60
+ end
61
+
62
+ def cleanup
63
+ pr = existing_open_pull_request
64
+ @github_client.close_pull_request(@github_repo_name, pr.number)
65
+ @github_client.delete_branch(@github_repo_name, pr.head.ref)
66
+ end
67
+
68
+ private
69
+
54
70
  def update_file(path, content)
55
71
  # TODO: check what happens if branch exists
56
-
57
- file = @client.contents(@github_repo_name, path: path, ref: BRANCH_NAME)
72
+ file = @github_client.contents(@github_repo_name, path: path, ref: branch_name)
58
73
  file_sha = file.sha
59
74
 
60
- @client.update_contents(
75
+ @github_client.update_contents(
61
76
  @github_repo_name,
62
77
  path,
63
78
  "Updating translations for #{path} by Moirai",
64
79
  file_sha,
65
80
  content,
66
- branch: BRANCH_NAME
81
+ branch: branch_name
67
82
  )
68
83
  rescue Octokit::NotFound
69
- @client.create_contents(
84
+ @github_client.create_contents(
70
85
  @github_repo_name,
71
86
  path,
72
87
  "Creating translations for #{path} by Moirai",
73
88
  content,
74
- branch: BRANCH_NAME
89
+ branch: branch_name
75
90
  )
76
91
  end
77
-
78
- def pull_request_exists?
79
- @client.pull_requests(@github_repo_name).any? do |pull_request|
80
- pull_request.head.ref == BRANCH_NAME
81
- end
82
- end
83
92
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Moirai
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/moirai.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "moirai/version"
4
+ require "i18n/extensions/i18n"
5
+ require "i18n/backend/moirai"
4
6
  require "moirai/engine"
5
7
  require "moirai/pull_request_creator"
6
- require "i18n/backend/moirai"
7
8
 
8
9
  module Moirai
9
10
  # Your code goes here...
data/moirai.gemspec CHANGED
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "lib/moirai/version"
4
+
3
5
  Gem::Specification.new do |spec|
4
6
  spec.name = "moirai"
5
- spec.version = "0.1.0"
7
+ spec.version = Moirai::VERSION
6
8
  spec.authors = ["Alessandro Rodi", "Oliver Anthony", "Daniel Bengl"]
7
9
  spec.email = %w[alessandro.rodi@renuo.ch oliver.anthony@renuo.ch daniel.bengl@renuo.ch]
8
10
 
@@ -25,11 +27,6 @@ Gem::Specification.new do |spec|
25
27
 
26
28
  spec.required_ruby_version = ">= 2.7.0"
27
29
  spec.add_dependency "rails", ">= 6.1"
28
- spec.add_development_dependency "octokit", ">= 4.0"
29
- spec.add_development_dependency "capybara"
30
- spec.add_development_dependency "selenium-webdriver"
31
- spec.add_development_dependency "rails", "~> 7.2.0"
32
- spec.add_development_dependency "dotenv"
33
30
 
34
31
  spec.license = "MIT"
35
32
  spec.metadata["rubygems_mfa_required"] = "true"