moirai 0.2.0 → 0.3.1

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: 5cd2eae769961645bc1baa4295ed58bf261beb38a48e934c1d3d38dd083f033a
4
- data.tar.gz: fd3dddd2520c7f06987d814fec2986c5e02ac113748d39a1117315296cc0aaf3
3
+ metadata.gz: ecb41a395f21cd347b67e6e0233bd776a80493be4bf98d423077b7fd7cbe2005
4
+ data.tar.gz: 1335f5ca28ab8804459172894841f71cb8ac88740ce0b94d21096bc3a1713386
5
5
  SHA512:
6
- metadata.gz: 5ae7c1af2f697ea2f7fad123f4c2451e3fa9ba86ffb048ae0b6846c2002bc532e50f762ecf000e32d76f6631d62ebd9f211288b4dca081e61e9d1bbcb05fd6ef
7
- data.tar.gz: f113aa608adfe9b5fae4a073f2d23936bb30090b3fe9d544dfc7d9421663244a78e3350b7218f988fa9c413fe6aef6a6ab154dd79cb5d0160dd026205bdac30d
6
+ metadata.gz: 927bd40a31ce569fca7b6d6a68194106db7616bf3a733009dd84669a387450a4808bc650aeff8f7f1d6aefe630d859db0c0486972008189e183f957247fada80
7
+ data.tar.gz: c8a831cd233bf06ff6160acd096346afb3ab8b1209b3bda7a5a4c7ccbecffe263fadaffd4829508d5f13cb3f4201fdf3658ef46ddcb1ae14c16d46ca4c85c324
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.1
@@ -0,0 +1,18 @@
1
+ version: v1.0
2
+ name: main-deploy
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu2004
7
+
8
+ blocks:
9
+ - name: main-deploy
10
+ task:
11
+ secrets:
12
+ - name: rubygems-deploy
13
+ jobs:
14
+ - name: main-deploy
15
+ commands:
16
+ - checkout --use-cache
17
+ - gem build moirai
18
+ - gem push moirai-*.gem
@@ -0,0 +1,50 @@
1
+ version: "v1.0"
2
+ name: moirai
3
+ agent:
4
+ machine:
5
+ type: e1-standard-2
6
+ os_image: ubuntu2004
7
+ auto_cancel:
8
+ running:
9
+ when: "true"
10
+
11
+ blocks:
12
+ - name: tests
13
+ execution_time_limit:
14
+ minutes: 10
15
+ task:
16
+ secrets:
17
+ - name: moirai
18
+ prologue:
19
+ commands:
20
+ - checkout --use-cache
21
+ - cache restore
22
+ - bundle config set path 'vendor/bundle'
23
+ - bundle install -j 4
24
+ - cache store
25
+ jobs:
26
+ - name: linter
27
+ commands:
28
+ - bundle exec standardrb
29
+ - name: tests sqlite
30
+ env_vars:
31
+ - name: TARGET_DB
32
+ value: sqlite
33
+ - name: RAILS_ENV
34
+ value: test
35
+ commands:
36
+ - bin/rails db:create db:schema:load
37
+ - bin/check
38
+ - name: tests postgres
39
+ env_vars:
40
+ - name: TARGET_DB
41
+ value: postgres
42
+ - name: RAILS_ENV
43
+ value: test
44
+ commands:
45
+ - sem-service start postgres 14 --username=semaphore
46
+ - bin/rails db:create db:schema:load
47
+ - bin/check
48
+ promotions:
49
+ - name: main
50
+ pipeline_file: main-deploy.yml
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
- ## Unreleased
1
+ ## 0.3.1
2
2
 
3
+ * Fixes a problem when running a rake command and no database exists yet using postgres. ([@coorasse][])
4
+
5
+ ## 0.3.0
6
+
7
+ * Added a method `I18n.translate_without_moirai` ([@oliveranthony17][])
8
+ * Simplified stimulus setup ([@coorasse][])
9
+ * Fixed some setup issues in test environments ([@oliveranthony17][])
10
+ * Show original translation when deleting the whole inline editing content. ([@CuddlyBunion341][])
11
+
12
+ * Support for html translations ([@CuddlyBunion341][])
13
+ =======
3
14
  ## 0.2.0
4
15
 
5
16
  * Support for strings coming from gems ([@coorasse][])
data/Gemfile CHANGED
@@ -12,6 +12,7 @@ gem "stimulus-rails"
12
12
  group :development, :test do
13
13
  gem "puma"
14
14
  gem "sqlite3"
15
+ gem "pg"
15
16
  gem "rake"
16
17
  gem "dotenv"
17
18
  gem "minitest"
data/README.md CHANGED
@@ -5,12 +5,13 @@
5
5
  ### Manage translation strings in real time
6
6
 
7
7
  - Let your non-developer team members finally manage translations (yes, even Karen from marketing...).
8
- - See those translations live in your app, so you can make sure “Submit” isn’t overlapping the button where “**Do not press this button EVER” should be.
9
- - Automatically create Pull Requests based on these changes, saving your developers from yet another “small tweakemail request.
8
+ - See those translations live in your app, so you can make sure “Submit” isn’t overlapping the button where “**Do not
9
+ press this button EVERshould be.
10
+ - Automatically create Pull Requests based on these changes, saving your developers from yet another “small tweak” email
11
+ request.
10
12
 
11
13
  > Let the world be translated, one typo at a time.
12
14
 
13
-
14
15
  ## Installation
15
16
 
16
17
  Add this line to your application's Gemfile:
@@ -20,11 +21,13 @@ gem "moirai"
20
21
  ```
21
22
 
22
23
  And then execute:
24
+
23
25
  ```bash
24
26
  bundle
25
27
  ```
26
28
 
27
- Next, you need to run the generator which will create the necessary files including the database migration, as well as inserting the engine in the `routes.rb` file:
29
+ Next, you need to run the generator which will create the necessary files including the database migration,
30
+ as well as inserting the engine in the `routes.rb` file, and importing the necessary javascript files:
28
31
 
29
32
  ```bash
30
33
  bin/rails g moirai:install
@@ -40,40 +43,51 @@ bin/rails db:migrate
40
43
 
41
44
  ### How to change translations
42
45
 
43
- If you mounted Moirai under "/moirai", head there and you will find a list of all the files containing texts that can be translated.
44
- Open a file, change the value of translations, and press ENTER to update the translation and see it immediately changed on the application.
46
+ If you mounted Moirai under "/moirai", head there and you will find a list of all the files containing texts that can be
47
+ translated.
48
+ Open a file, change the value of translations, and press ENTER to update the translation and see it immediately changed
49
+ on the application.
45
50
 
46
51
  ### Inline editing
47
52
 
48
53
  By default, inline editing is disabled. To enable it, set the `moirai=true` query parameter in the URL.
49
54
 
50
- If you want to only allow specific users to perform inline editing, you can override the `moirai_edit_enabled?` method in your application helper.
55
+ If you want to only allow specific users to perform inline editing, you can override the `moirai_edit_enabled?` method
56
+ in your application helper.
51
57
 
52
58
  ```ruby
59
+
53
60
  module ApplicationHelper
54
61
  def moirai_edit_enabled?
55
- params[:moirai] == "true" || current_user&.admin?
62
+ params[:moirai] == "true" && current_user&.admin?
56
63
  end
57
64
  end
58
65
  ```
59
66
 
60
67
  You also need to have the moirai_translations_controller.js Stimulus Controller initialized.
61
68
 
62
- If you use importmaps:
69
+ #### Importmap
63
70
 
64
- Pin the controller in `config/importmap.rb`
71
+ The command `bin/rails g moirai:install` should have already pinned the necessary controller for you in importmap.rb, so
72
+ no further steps are needed.
65
73
 
66
- ```ruby
67
- pin "controllers/moirai_translation_controller", to: "moirai_translation_controller.js"
68
- ```
74
+ #### jsbulding
69
75
 
70
- If you’re unsure about all the possible configuration options, you can simply copy and paste the stimulus controller into your app as a fallback.
76
+ The command `bin/rails g moirai:install` should have already copied the necessary controller for you in
77
+ `app/javascripts/controllers`, so no further steps are needed.
78
+
79
+ #### More?
80
+
81
+ If you’re unsure about all the possible configuration options, you can simply copy and paste the stimulus controller
82
+ into your app as a fallback.
71
83
 
72
84
  ### Automatic PR creation with Octokit (**optional**)
73
85
 
74
- If you would like Moirai to automatically create a pull request on GitHub to keep translations synchronized with the codebase,
86
+ If you would like Moirai to automatically create a pull request on GitHub to keep translations synchronized with the
87
+ codebase,
75
88
  you need to set up [Octokit](https://github.com/octokit/octokit.rb).
76
- You will also need to create a **Personal Access Token** on GitHub, and configure the access in the appropriate **environment variables** (this is explained below).
89
+ You will also need to create a **Personal Access Token** on GitHub, and configure the access in the appropriate *
90
+ *environment variables** (this is explained below).
77
91
 
78
92
  #### 1. Add Octokit to Your Gemfile
79
93
 
@@ -87,22 +101,23 @@ Then run `bundle install`.
87
101
 
88
102
  #### 2. Create a Personal Access Token (PAT) on GitHub
89
103
 
90
- You will need a Personal Access Token (PAT) with the `Content - Write` permission to allow Octokit to create branches and pull requests.
104
+ You will need a Personal Access Token (PAT) with the `Content - Write` permission to allow Octokit to create branches
105
+ and pull requests.
91
106
 
92
- - Go to GitHub Token Settings.
93
- - Click Generate New Token.
94
- - Give your token a name (e.g., “Moirai”).
95
- - Under Scopes, select:
96
- - repo (for full control of private repositories, including writing content).
97
- - content (for read/write access to code, commit statuses, and pull requests).
98
- - Generate the token and copy it immediately as it will be shown only once.
107
+ - Go to GitHub Token Settings.
108
+ - Click Generate New Token.
109
+ - Give your token a name (e.g., “Moirai”).
110
+ - Under Scopes, select:
111
+ - repo (for full control of private repositories, including writing content).
112
+ - content (for read/write access to code, commit statuses, and pull requests).
113
+ - Generate the token and copy it immediately as it will be shown only once.
99
114
 
100
115
  #### 3. Set Up Environment Variables
101
116
 
102
117
  You need to configure the following environment variables in your application:
103
118
 
104
- - `MOIRAI_GITHUB_REPO_NAME`: The name of the repository where the pull request will be created.
105
- - `MOIRAI_GITHUB_ACCESS_TOKEN`: The Personal Access Token (PAT) you created earlier.
119
+ - `MOIRAI_GITHUB_REPO_NAME`: The name of the repository where the pull request will be created.
120
+ - `MOIRAI_GITHUB_ACCESS_TOKEN`: The Personal Access Token (PAT) you created earlier.
106
121
 
107
122
  For example, in your `.env` file:
108
123
 
@@ -111,7 +126,8 @@ MOIRAI_GITHUB_REPO_NAME=your-organization/your-repo
111
126
  MOIRAI_GITHUB_ACCESS_TOKEN=your-generated-token
112
127
  ```
113
128
 
114
- We also support Rails credentials. The environment variables need to be stored in a slightly different way to adhere to convention. For example:
129
+ We also support Rails credentials. The environment variables need to be stored in a slightly different way to adhere to
130
+ convention. For example:
115
131
 
116
132
  ```env
117
133
  moirai:
@@ -121,13 +137,14 @@ moirai:
121
137
 
122
138
  #### 4. Triggering the pull request creation
123
139
 
124
- Moirai will now be able to use this Personal Access Token to create a pull request on GitHub when a translation is updated.
140
+ Moirai will now be able to use this Personal Access Token to create a pull request on GitHub when a translation is
141
+ updated.
125
142
 
126
143
  To trigger this, you can press the `Create or update PR` button once you have made your changes.
127
144
 
128
145
  ### Authentication
129
146
 
130
- Moirai allows you to use basic HTTP authentication to protect the engine.
147
+ Moirai allows you to use basic HTTP authentication to protect the engine.
131
148
  To enable this, you need to set the following environment variables:
132
149
 
133
150
  ```env
@@ -137,11 +154,11 @@ MOIRAI_BASICAUTH_PASSWORD=moirai
137
154
 
138
155
  > ⚠️ Remember to protect Moirai. You don't want to give everyone the possibility to change strings in the application.
139
156
 
140
- If you have authenticated users, you can leverage the Rails Routes protection mechanism to protect the engine.
157
+ If you have authenticated users, you can leverage the Rails Routes protection mechanism to protect the engine.
141
158
  See the following example:
142
159
 
143
160
  ```ruby
144
- authenticated :user, lambda {|u| u.role == "admin"} do
161
+ authenticated :user, lambda { |u| u.role == "admin" } do
145
162
  mount Moirai::Engine => '/moirai', as: 'moirai'
146
163
  end
147
164
  ```
@@ -166,12 +183,12 @@ end
166
183
 
167
184
  4. Set your environment variables using the newly created `.env` file.
168
185
 
169
- You will need a repository to test against and a token. Generate a new Fine-GRained Personal access token and give the necessary permissions to your repository.
186
+ You will need a repository to test against and a token. Generate a new Fine-GRained Personal access token and give the
187
+ necessary permissions to your repository.
170
188
  See the image below as an example:
171
189
 
172
190
  ![](docs/github_settings.png)
173
191
 
174
-
175
192
  5. Run the tests:
176
193
  ```bash
177
194
  bin/check
@@ -191,6 +208,7 @@ See the image below as an example:
191
208
  * Support for fallbacks: it should detect when a fallback string is in use and prevent attempts to override its value.
192
209
 
193
210
  ## License
211
+
194
212
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
195
213
 
196
214
  ## Copyright
@@ -27,6 +27,15 @@ export default class MoiraiTranslationController extends Controller {
27
27
  value: event.target.innerText
28
28
  }
29
29
  })
30
+ })
31
+ .then(response => response.json())
32
+ .then(data => {
33
+ if (data?.fallback_translation) {
34
+ event.target.innerText = data.fallback_translation
35
+ }
36
+ })
37
+ .catch(error => {
38
+ console.error('Error:', error);
30
39
  });
31
40
  }
32
41
  }
@@ -12,4 +12,6 @@
12
12
  *
13
13
  *= require_tree .
14
14
  *= require_self
15
+ *= require translation_files
16
+
15
17
  */
@@ -0,0 +1,22 @@
1
+ td {
2
+ height: 100px;
3
+ width: 200px;
4
+ vertical-align: top;
5
+ }
6
+
7
+ form {
8
+ height: 100%;
9
+ display: flex;
10
+ align-items: stretch;
11
+ }
12
+
13
+ textarea.translation-textarea {
14
+ width: 100%;
15
+ height: auto;
16
+ resize: vertical;
17
+ min-height: 3em;
18
+ overflow: hidden;
19
+ margin-bottom: 0;
20
+ }
21
+
22
+ /*# TODO: this isn't coming through */
@@ -39,8 +39,17 @@ module Moirai
39
39
  def handle_update(translation)
40
40
  if translation_params[:value].blank? || translation_same_as_current?
41
41
  translation.destroy
42
- flash.notice = "Translation #{translation.key} was successfully deleted."
43
- redirect_to_translation_file(translation.file_path)
42
+ respond_to do |format|
43
+ format.json do
44
+ render json: {
45
+ fallback_translation: get_fallback_translation
46
+ }
47
+ end
48
+ format.html do
49
+ flash.notice = "Translation #{translation.key} was successfully deleted."
50
+ redirect_to_translation_file(translation.file_path)
51
+ end
52
+ end
44
53
  return
45
54
  end
46
55
 
@@ -60,6 +69,10 @@ module Moirai
60
69
  return
61
70
  end
62
71
 
72
+ if translation_params[:value].blank? && request.format.json?
73
+ return render json: {fallback_translation: get_fallback_translation}
74
+ end
75
+
63
76
  translation = Translation.new(translation_params)
64
77
 
65
78
  if translation.save
@@ -74,6 +87,7 @@ module Moirai
74
87
  def success_response(translation)
75
88
  respond_to do |format|
76
89
  format.json do
90
+ flash.discard
77
91
  render json: {}
78
92
  end
79
93
  format.all do
@@ -114,5 +128,14 @@ module Moirai
114
128
 
115
129
  translation_params[:value] == @file_handler.parse_file(file_paths.first)[translation_params[:key]]
116
130
  end
131
+
132
+ def get_fallback_translation
133
+ file_paths = KeyFinder.new.file_paths_for(translation_params[:key], locale: translation_params[:locale])
134
+
135
+ return "" if file_paths.empty?
136
+ return "" unless file_paths.all? { |file_path| File.exist?(file_path) }
137
+
138
+ @file_handler.parse_file(file_paths.first)[translation_params[:key]]
139
+ end
117
140
  end
118
141
  end
@@ -8,6 +8,34 @@
8
8
  <%= stylesheet_link_tag "moirai/application", media: "all" %>
9
9
  <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
10
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
+
11
39
  </head>
12
40
  <body>
13
41
 
@@ -1,9 +1,9 @@
1
1
  <span
2
- contenteditable
2
+ contenteditable
3
3
  data-action="blur->moirai-translation#submit click->moirai-translation#click"
4
- style="border: 1px dashed #1d9f74; min-width: 30px; display: inline-block;"
4
+ style="outline: 1px solid #1d9f74; min-width: 30px; display: inline-block; <%= 'color: red;' if is_missing_translation %>"
5
5
  data-moirai-translation-key-value="<%= key %>"
6
6
  data-moirai-translation-locale-value="<%= locale %>"
7
7
  data-controller="moirai-translation">
8
- <%= value %>
8
+ <%= value.to_s.gsub("<", "&lt;").gsub(">", "&gt;").html_safe %>
9
9
  </span>
@@ -9,6 +9,7 @@
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>
@@ -24,13 +25,17 @@
24
25
  <% end %>
25
26
  </td>
26
27
  <td>
27
- <%= form_for translation&.presence || Moirai::Translation.new(key: key, locale: @locale, value: value), url: moirai_create_or_update_translation_path, method: :post do |f| %>
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| %>
28
31
  <%= f.hidden_field :key %>
29
32
  <%= f.hidden_field :locale %>
30
- <%= f.text_field :value %>
31
- <%= f.submit 'Update', style: 'display: none;' %>
33
+ <%= f.text_field :value, class: 'translation-textarea' %>
32
34
  <% end %>
33
35
  </td>
36
+ <td>
37
+ <%= I18n.translate_without_moirai(key, @locale) %>
38
+ </td>
34
39
  </tr>
35
40
  <% end %>
36
41
  </tbody>
@@ -10,9 +10,35 @@ 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
34
  route 'mount Moirai::Engine => "/moirai", as: "moirai"'
15
35
  end
36
+
37
+ private
38
+
39
+ def using_importmap?
40
+ Rails.root.join("config/importmap.rb").exist?
41
+ end
16
42
  end
17
43
  end
18
44
  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,7 +9,20 @@ module Moirai
9
9
  end
10
10
 
11
11
  config.after_initialize do
12
- I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Moirai.new, I18n.backend)
12
+ I18n.original_backend = I18n.backend
13
+ table_created =
14
+ begin
15
+ (defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter) &&
16
+ ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)) ||
17
+ ActiveRecord::Base.connection.table_exists?("moirai_translations")
18
+ rescue ActiveRecord::NoDatabaseError
19
+ false
20
+ end
21
+ if table_created
22
+ I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Moirai.new, I18n.backend)
23
+ else
24
+ Rails.logger.warn("moirai disabled: tables have not been generated yet.")
25
+ end
13
26
  end
14
27
 
15
28
  # TODO: how to do this without rewriting the entire method?
@@ -22,12 +35,18 @@ module Moirai
22
35
  def translate(key, **options)
23
36
  value = original_translate(key, **options)
24
37
 
38
+ is_missing_translation = value.include?('class="translation_missing"')
39
+ if value.is_a?(String) && is_missing_translation
40
+ value = extract_inner_content(value)
41
+ end
42
+
25
43
  if moirai_edit_enabled?
26
44
  @key_finder ||= Moirai::KeyFinder.new
27
45
 
28
46
  render(partial: "moirai/translation_files/form",
29
47
  locals: {key: scope_key_by_partial(key),
30
48
  locale: I18n.locale,
49
+ is_missing_translation: is_missing_translation,
31
50
  value: value})
32
51
  else
33
52
  value
@@ -39,6 +58,13 @@ module Moirai
39
58
  def moirai_edit_enabled?
40
59
  params[:moirai] == "true"
41
60
  end
61
+
62
+ private
63
+
64
+ def extract_inner_content(html)
65
+ match = html.match(/<[^>]+>([^<]*)<\/[^>]+>/)
66
+ match ? match[1] : nil
67
+ end
42
68
  end
43
69
  end
44
70
  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.1"
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.2.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
 
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moirai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi
8
8
  - Oliver Anthony
9
9
  - Daniel Bengl
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2024-11-06 00:00:00.000000000 Z
13
+ date: 2024-11-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -38,8 +38,10 @@ extensions: []
38
38
  extra_rdoc_files: []
39
39
  files:
40
40
  - ".github/CODEOWNERS"
41
- - ".github/workflows/test.yml"
42
41
  - ".gitignore"
42
+ - ".ruby-version"
43
+ - ".semaphore/main-deploy.yml"
44
+ - ".semaphore/semaphore.yml"
43
45
  - Appraisals
44
46
  - CHANGELOG.md
45
47
  - Gemfile
@@ -49,6 +51,7 @@ files:
49
51
  - app/assets/images/moirai/.keep
50
52
  - app/assets/javascripts/moirai_translation_controller.js
51
53
  - app/assets/stylesheets/moirai/application.css
54
+ - app/assets/stylesheets/translation_files.css
52
55
  - app/controllers/concerns/.keep
53
56
  - app/controllers/moirai/application_controller.rb
54
57
  - app/controllers/moirai/translation_files_controller.rb
@@ -78,6 +81,7 @@ files:
78
81
  - lib/generators/moirai/templates/create_moirai_translations.rb.erb
79
82
  - lib/generators/moirai/templates/make_moirai_translations_file_path_not_required.rb.erb
80
83
  - lib/i18n/backend/moirai.rb
84
+ - lib/i18n/extensions/i18n.rb
81
85
  - lib/moirai.rb
82
86
  - lib/moirai/engine.rb
83
87
  - lib/moirai/pull_request_creator.rb
@@ -92,7 +96,7 @@ metadata:
92
96
  changelog_uri: https://github.com/renuo/moirai/CHANGELOG.md
93
97
  steep_types: sig
94
98
  rubygems_mfa_required: 'true'
95
- post_install_message:
99
+ post_install_message:
96
100
  rdoc_options: []
97
101
  require_paths:
98
102
  - lib
@@ -107,8 +111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
111
  - !ruby/object:Gem::Version
108
112
  version: '0'
109
113
  requirements: []
110
- rubygems_version: 3.4.20
111
- signing_key:
114
+ rubygems_version: 3.4.7
115
+ signing_key:
112
116
  specification_version: 4
113
117
  summary: Manage translation strings in real time
114
118
  test_files: []
@@ -1,60 +0,0 @@
1
- name: Test & lint
2
- on: [push]
3
-
4
- env:
5
- RAILS_ENV: test
6
- PGHOST: localhost
7
- PGUSER: postgres
8
- MOIRAI_GITHUB_REPO_NAME: ${{ secrets.MOIRAI_GITHUB_REPO_NAME }}
9
- MOIRAI_GITHUB_ACCESS_TOKEN: ${{ secrets.MOIRAI_GITHUB_ACCESS_TOKEN }}
10
- jobs:
11
- tests:
12
- name: Test
13
-
14
- strategy:
15
- fail-fast: false
16
- matrix:
17
- os: [ubuntu-latest]
18
- ruby: [3.3]
19
-
20
- runs-on: ${{ matrix.os }}
21
-
22
- steps:
23
- - name: Checkout code
24
- uses: actions/checkout@v4
25
-
26
- - name: Set up Ruby
27
- uses: ruby/setup-ruby@v1
28
- with:
29
- ruby-version: ${{ matrix.ruby }}
30
- bundler-cache: true
31
-
32
- - name: Install dependencies
33
- run: bundle install --jobs 4 --retry 3
34
-
35
- - name: Run tests
36
- run: bundle exec rails test
37
-
38
- - name: Run system tests
39
- run: bundle exec rails test:system
40
-
41
-
42
- lint:
43
- name: Lint
44
- runs-on: ubuntu-latest
45
-
46
- steps:
47
- - name: Checkout code
48
- uses: actions/checkout@v2
49
-
50
- - name: Set up Ruby
51
- uses: ruby/setup-ruby@v1
52
- with:
53
- ruby-version: 3.3
54
- bundler-cache: true
55
-
56
- - name: Install dependencies
57
- run: bundle install --jobs 4 --retry 3
58
-
59
- - name: Run linters
60
- run: bin/fastcheck