i18n_proofreading 0.12.1 → 1.0.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 +4 -4
- data/AGENTS.md +6 -1
- data/CHANGELOG.md +35 -2
- data/README.md +40 -3
- data/SECURITY.md +38 -0
- data/app/controllers/concerns/i18n_proofreading/request_context.rb +20 -0
- data/app/controllers/i18n_proofreading/submissions_controller.rb +11 -1
- data/{app/helpers → lib}/i18n_proofreading/tag_helper.rb +5 -3
- data/lib/i18n_proofreading/version.rb +1 -1
- data/lib/i18n_proofreading.rb +1 -0
- metadata +11 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1018fa5f4f5be802e224bfc1a8bf5e93b1cff5c9122e854327792a9ffc89c0eb
|
|
4
|
+
data.tar.gz: 48b4c23cef0d8aac0ba47f996be007b259d3354fffa6065a1fea5f820b4802eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb442c1774c324987f44e8a347f74f061cd7ee64388df006f77b4a7d94ff6b6e57844303190f9fce36d7f556d7391160a1ef611e2424fe9a2a090d78638f16df
|
|
7
|
+
data.tar.gz: 3094f3c4160701c912116a499be621486b1f718168450b8030956bb43d3b1864576e7a278a95e948552444969c45835b150f7a05cd50106408bd9b3dfa381587
|
data/AGENTS.md
CHANGED
|
@@ -5,7 +5,7 @@ Instructions for coding agents. Two audiences:
|
|
|
5
5
|
- **[Installing i18n_proofreading into a Rails app](#installing-into-a-rails-app)** — you are working in a host app and were asked to add in-context translation review or a way for someone to suggest better wording.
|
|
6
6
|
- **[Working on the gem itself](#working-on-the-gem-itself)** — you are working in this repository.
|
|
7
7
|
|
|
8
|
-
Requirements: Ruby >= 3.2, Rails >= 7.1. The widget needs the CSRF token from `csrf_meta_tags`, which a standard Rails layout already has.
|
|
8
|
+
Requirements: Ruby >= 3.2, Rails >= 7.1 and < 9. The widget needs the CSRF token from `csrf_meta_tags`, which a standard Rails layout already has.
|
|
9
9
|
|
|
10
10
|
**Read this first: the gem never writes to your locale files, and it is not a production tool.** Both are deliberate, and both are covered below.
|
|
11
11
|
|
|
@@ -137,6 +137,11 @@ The tool's own UI ships in 26 languages, RTL mirrored, and follows system light/
|
|
|
137
137
|
|
|
138
138
|
## Working on the gem itself
|
|
139
139
|
|
|
140
|
+
The development toolchain is pinned to Ruby 4.0.5 in `mise.toml`. Do not use
|
|
141
|
+
macOS's `/usr/bin/ruby`. In shells, hooks, or automation where mise activation
|
|
142
|
+
is uncertain, explicitly prepend the configured Ruby, for example
|
|
143
|
+
`PATH="$(mise where ruby)/bin:$PATH" bundle exec rake test`.
|
|
144
|
+
|
|
140
145
|
```bash
|
|
141
146
|
bundle exec rake test # minitest, dummy app under test/dummy
|
|
142
147
|
bundle exec rubocop # must be clean
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [1.0.1] - 2026-08-11
|
|
6
|
+
|
|
7
|
+
- **A failing `on_submit` hook no longer turns a saved suggestion into a 500.**
|
|
8
|
+
The failure is logged after persistence, so host notifications cannot make
|
|
9
|
+
the review submission appear lost.
|
|
10
|
+
- **Stored page context is now privacy-filtered.** Only bounded HTTP(S) URLs
|
|
11
|
+
without credentials, query strings, or fragments are retained.
|
|
12
|
+
|
|
13
|
+
## [1.0.0] - 2026-08-11
|
|
14
|
+
|
|
15
|
+
- **The documented integration surface is now the stable 1.x contract.**
|
|
16
|
+
`I18nProofreading.configure`, every generated configuration option,
|
|
17
|
+
`mount_i18n_proofreading`, `i18n_proofreading_tag`, the toggle parameter,
|
|
18
|
+
`I18nProofreading::Suggestion`'s documented fields/status helpers/scopes, and
|
|
19
|
+
the `on_submit` callback will follow semantic versioning. Engine controllers,
|
|
20
|
+
partials, CSS classes and widget internals remain private implementation.
|
|
21
|
+
- **Hosts that load Action View from an initializer boot normally.** `TagHelper`
|
|
22
|
+
is required from `lib` before the engine registers its Action View load hook,
|
|
23
|
+
rather than relying on an `app/helpers` autoload that Rails may not have set
|
|
24
|
+
up yet. A dummy-host initializer now reproduces that early load on every test
|
|
25
|
+
boot. The helper constant and `i18n_proofreading_tag` API are unchanged.
|
|
26
|
+
- Supported combinations are Ruby 3.2 through 4.0 and Rails 7.1 through 8.1.
|
|
27
|
+
Rails now has a `< 9` upper bound: future Rails majors must pass the suite
|
|
28
|
+
before Bundler treats them as supported.
|
|
29
|
+
- Added a security policy and documented the data a suggestion stores, the
|
|
30
|
+
production-off default, private vulnerability reporting, and host-owned
|
|
31
|
+
retention/deletion. Upgrading from 0.12.1 requires no migration or config
|
|
32
|
+
change.
|
|
33
|
+
- Release validation now runs the normal and browser suites, RuboCop, the
|
|
34
|
+
widget syntax check and gem build on Ruby 4.0; it verifies the published
|
|
35
|
+
version and creates the GitHub Release. Generator tests now write only under
|
|
36
|
+
ignored root `tmp/`, so running the suite no longer rewrites tracked fixtures.
|
|
37
|
+
|
|
3
38
|
## 0.12.1
|
|
4
39
|
|
|
5
40
|
- **The demo suggestions now teach the review contract.** Pending explains the
|
|
@@ -72,8 +107,6 @@
|
|
|
72
107
|
does, so a uuid-keyed host gets a uuid table.
|
|
73
108
|
- A `BackboneTest` now fails the build on any of the above regressing.
|
|
74
109
|
|
|
75
|
-
## [Unreleased]
|
|
76
|
-
|
|
77
110
|
## [0.10.6]
|
|
78
111
|
|
|
79
112
|
- Added `AGENTS.md`: install and integration instructions written for coding
|
data/README.md
CHANGED
|
@@ -46,8 +46,8 @@ No layout change needed — the widget injects itself into HTML responses.
|
|
|
46
46
|
> `%w[development staging]`, and the review dashboard defaults to development
|
|
47
47
|
> only. This is not a production tool.
|
|
48
48
|
|
|
49
|
-
Ruby
|
|
50
|
-
a standard Rails layout.
|
|
49
|
+
Ruby 3.2–4.0 · Rails 7.1–8.1 · CSRF token comes from `csrf_meta_tags`, already
|
|
50
|
+
in a standard Rails layout.
|
|
51
51
|
|
|
52
52
|
Installing with a coding agent? Point it at [AGENTS.md](AGENTS.md) — the same
|
|
53
53
|
steps in the order an agent needs them, the gates it tends to get wrong, and the
|
|
@@ -273,6 +273,36 @@ to use the localized `i18n_proofreading.pill` key.
|
|
|
273
273
|
|
|
274
274
|
</details>
|
|
275
275
|
|
|
276
|
+
## Compatibility and public API
|
|
277
|
+
|
|
278
|
+
Starting with 1.0, these documented integration points follow semantic
|
|
279
|
+
versioning: incompatible changes wait for a new major version, while a
|
|
280
|
+
deprecation normally ships in a preceding minor release.
|
|
281
|
+
|
|
282
|
+
- `I18nProofreading.configure` and the configuration options listed above.
|
|
283
|
+
- `mount_i18n_proofreading at:` and the mounted dashboard root.
|
|
284
|
+
- `i18n_proofreading_tag` for hosts that disable automatic injection.
|
|
285
|
+
- The configured toggle parameter and its `true` / `false` behavior.
|
|
286
|
+
- `I18nProofreading::Suggestion` fields documented under Reviewing
|
|
287
|
+
suggestions, `STATUSES`, prefixed status helpers/scopes, and `newest_first`.
|
|
288
|
+
- `on_submit`, called with the saved suggestion.
|
|
289
|
+
|
|
290
|
+
Engine controllers, view partials, CSS classes, generated HTML structure, and
|
|
291
|
+
the JavaScript object behind the widget are implementation details. Integrate
|
|
292
|
+
through the APIs above rather than reopening or linking to those internals.
|
|
293
|
+
|
|
294
|
+
Supported versions are Ruby 3.2 through 4.0 and Rails 7.1 through 8.1. The gem
|
|
295
|
+
depends on Rails `< 9`; support for a future Rails major is released after that
|
|
296
|
+
major passes the compatibility and browser suites.
|
|
297
|
+
|
|
298
|
+
### Upgrading from 0.12.1
|
|
299
|
+
|
|
300
|
+
Change the version requirement and run `bundle update i18n_proofreading`. No
|
|
301
|
+
database migration, generator, initializer change, or data rewrite is needed.
|
|
302
|
+
The `I18nProofreading::TagHelper` constant and `i18n_proofreading_tag` behavior
|
|
303
|
+
are unchanged; only the helper's internal load location moved so hosts that
|
|
304
|
+
configure Action View during initialization can boot reliably.
|
|
305
|
+
|
|
276
306
|
## Security
|
|
277
307
|
|
|
278
308
|
- **Gated on the server** for every marker, endpoint, and injection. Setting
|
|
@@ -286,6 +316,12 @@ to use the localized `i18n_proofreading.pill` key.
|
|
|
286
316
|
survives Turbo visits.
|
|
287
317
|
- **Rate-limited per IP** on the submission endpoint (30/min by default,
|
|
288
318
|
Rails 7.2+).
|
|
319
|
+
- **Host-owned review data.** A row may contain translated text, proposed text,
|
|
320
|
+
a comment, page URL, and optional author fields. The host controls access,
|
|
321
|
+
backups, retention, and deletion.
|
|
322
|
+
|
|
323
|
+
Report vulnerabilities privately through the process in
|
|
324
|
+
[SECURITY.md](SECURITY.md), not through a public issue.
|
|
289
325
|
|
|
290
326
|
## Development
|
|
291
327
|
|
|
@@ -296,7 +332,8 @@ bundle exec rake test:system # browser tests (headless Chrome)
|
|
|
296
332
|
bundle exec rubocop
|
|
297
333
|
```
|
|
298
334
|
|
|
299
|
-
Tests run against a dummy Rails app in `test/dummy`.
|
|
335
|
+
Tests run against a dummy Rails app in `test/dummy`. CI covers Ruby 3.2–4.0
|
|
336
|
+
against Rails 7.1–8.1, plus the real browser flow on Ruby 4.0.
|
|
300
337
|
|
|
301
338
|
## One family
|
|
302
339
|
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Security fixes are released for the latest 1.x version. If a report also
|
|
6
|
+
affects the newest 0.x release, a backport may be published when the fix is
|
|
7
|
+
small and the affected application cannot upgrade immediately.
|
|
8
|
+
|
|
9
|
+
## Reporting a vulnerability
|
|
10
|
+
|
|
11
|
+
Please do not open a public issue for a vulnerability. Use
|
|
12
|
+
[GitHub private vulnerability reporting](https://github.com/yshmarov/i18n_proofreading/security/advisories/new)
|
|
13
|
+
and include the affected version, a minimal reproduction, impact, and any known
|
|
14
|
+
workaround. Credentials, session cookies, private application URLs, customer
|
|
15
|
+
text, and production database contents should not be included.
|
|
16
|
+
|
|
17
|
+
Public disclosure should wait until a fixed version is available and affected
|
|
18
|
+
users have had a reasonable opportunity to upgrade.
|
|
19
|
+
|
|
20
|
+
## Data and deployment boundary
|
|
21
|
+
|
|
22
|
+
The proofreading widget is enabled only in development and staging by default.
|
|
23
|
+
Adding production to `enabled_environments` is unsupported: key marking changes
|
|
24
|
+
rendered application text and the suggestion endpoint is intended for trusted
|
|
25
|
+
review environments.
|
|
26
|
+
|
|
27
|
+
A suggestion can store its translation key, locale, current and proposed text,
|
|
28
|
+
comment, page URL, status, timestamps, and optional host-provided author id and
|
|
29
|
+
label. Host applications own that data, its backups, retention period, access
|
|
30
|
+
controls, and deletion. Delete a suggestion with ordinary Active Record when a
|
|
31
|
+
reviewer or application policy requires erasure:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
I18nProofreading::Suggestion.find(id).destroy!
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The mounted dashboard is independently protected by `authorize_admin`. Outside
|
|
38
|
+
development it fails closed until the host explicitly grants access.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
3
5
|
module I18nProofreading
|
|
4
6
|
# Who is asking, and the gates that answer it.
|
|
5
7
|
#
|
|
@@ -37,5 +39,23 @@ module I18nProofreading
|
|
|
37
39
|
|
|
38
40
|
@current_author = I18nProofreading.config.current_user.call(request)
|
|
39
41
|
end
|
|
42
|
+
|
|
43
|
+
# Browser URLs can carry password-reset tokens, signed ids, and campaign
|
|
44
|
+
# details in their query or fragment. Store only a bounded HTTP(S) location
|
|
45
|
+
# without credentials before it reaches the suggestion table.
|
|
46
|
+
def clean_page_url(value)
|
|
47
|
+
raw = value.to_s
|
|
48
|
+
return if raw.blank? || raw.length > 2_048
|
|
49
|
+
|
|
50
|
+
uri = URI.parse(raw)
|
|
51
|
+
return unless %w[http https].include?(uri.scheme&.downcase)
|
|
52
|
+
return if uri.host.blank? || uri.userinfo.present?
|
|
53
|
+
|
|
54
|
+
uri.query = nil
|
|
55
|
+
uri.fragment = nil
|
|
56
|
+
uri.to_s.first(255)
|
|
57
|
+
rescue URI::InvalidURIError
|
|
58
|
+
nil
|
|
59
|
+
end
|
|
40
60
|
end
|
|
41
61
|
end
|
|
@@ -37,10 +37,11 @@ module I18nProofreading
|
|
|
37
37
|
|
|
38
38
|
def create
|
|
39
39
|
suggestion = Suggestion.new(suggestion_params)
|
|
40
|
+
suggestion.page_url = clean_page_url(suggestion.page_url)
|
|
40
41
|
attribute_author(suggestion)
|
|
41
42
|
|
|
42
43
|
if suggestion.save
|
|
43
|
-
|
|
44
|
+
notify_host(suggestion)
|
|
44
45
|
head :created
|
|
45
46
|
else
|
|
46
47
|
render json: { errors: suggestion.errors.full_messages }, status: :unprocessable_entity
|
|
@@ -49,6 +50,15 @@ module I18nProofreading
|
|
|
49
50
|
|
|
50
51
|
private
|
|
51
52
|
|
|
53
|
+
# The host's hook must never turn a saved suggestion into a 500 — the
|
|
54
|
+
# suggestion is in the database; notification failures are the host's
|
|
55
|
+
# logs' problem.
|
|
56
|
+
def notify_host(suggestion)
|
|
57
|
+
I18nProofreading.config.on_submit.call(suggestion)
|
|
58
|
+
rescue StandardError => e
|
|
59
|
+
Rails.logger.error("i18n_proofreading: on_submit hook raised #{e.class}: #{e.message}")
|
|
60
|
+
end
|
|
61
|
+
|
|
52
62
|
def attribute_author(suggestion)
|
|
53
63
|
author = current_author
|
|
54
64
|
return unless author
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module I18nProofreading
|
|
4
|
-
# Lets a host place the widget explicitly (`<%= i18n_proofreading_tag %>` at
|
|
5
|
-
# of a layout) instead of relying on auto-injection.
|
|
6
|
-
#
|
|
4
|
+
# Lets a host place the widget explicitly (`<%= i18n_proofreading_tag %>` at
|
|
5
|
+
# the end of a layout) instead of relying on auto-injection. This lives under
|
|
6
|
+
# lib and is required before the engine registers its Action View load hook:
|
|
7
|
+
# a host initializer may load Action View before Rails sets up application
|
|
8
|
+
# autoloaders, when an app/helpers constant cannot be resolved yet.
|
|
7
9
|
module TagHelper
|
|
8
10
|
def i18n_proofreading_tag
|
|
9
11
|
return ''.html_safe unless I18nProofreading.available?(request)
|
data/lib/i18n_proofreading.rb
CHANGED
|
@@ -4,6 +4,7 @@ require 'i18n_proofreading/version'
|
|
|
4
4
|
require 'i18n_proofreading/configuration'
|
|
5
5
|
require 'i18n_proofreading/marking'
|
|
6
6
|
require 'i18n_proofreading/widget'
|
|
7
|
+
require 'i18n_proofreading/tag_helper'
|
|
7
8
|
require 'i18n_proofreading/middleware'
|
|
8
9
|
require 'i18n_proofreading/seeds'
|
|
9
10
|
require 'i18n_proofreading/engine'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: i18n_proofreading
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yaroslav Shmarov
|
|
@@ -16,6 +16,9 @@ dependencies:
|
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '7.1'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '9'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -23,6 +26,9 @@ dependencies:
|
|
|
23
26
|
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
28
|
version: '7.1'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '9'
|
|
26
32
|
description: |
|
|
27
33
|
A mountable Rails engine that renders each translation alongside its i18n key
|
|
28
34
|
in development and staging, lets reviewers click any string in the running app
|
|
@@ -39,13 +45,13 @@ files:
|
|
|
39
45
|
- MIT-LICENSE
|
|
40
46
|
- README.md
|
|
41
47
|
- Rakefile
|
|
48
|
+
- SECURITY.md
|
|
42
49
|
- app/controllers/concerns/i18n_proofreading/request_context.rb
|
|
43
50
|
- app/controllers/i18n_proofreading/application_controller.rb
|
|
44
51
|
- app/controllers/i18n_proofreading/dashboard_controller.rb
|
|
45
52
|
- app/controllers/i18n_proofreading/submissions_controller.rb
|
|
46
53
|
- app/controllers/i18n_proofreading/suggestions_controller.rb
|
|
47
54
|
- app/controllers/i18n_proofreading/widgets_controller.rb
|
|
48
|
-
- app/helpers/i18n_proofreading/tag_helper.rb
|
|
49
55
|
- app/models/i18n_proofreading/application_record.rb
|
|
50
56
|
- app/models/i18n_proofreading/suggestion.rb
|
|
51
57
|
- app/views/i18n_proofreading/shared/_dashboard.html.erb
|
|
@@ -91,6 +97,7 @@ files:
|
|
|
91
97
|
- lib/i18n_proofreading/marking.rb
|
|
92
98
|
- lib/i18n_proofreading/middleware.rb
|
|
93
99
|
- lib/i18n_proofreading/seeds.rb
|
|
100
|
+
- lib/i18n_proofreading/tag_helper.rb
|
|
94
101
|
- lib/i18n_proofreading/version.rb
|
|
95
102
|
- lib/i18n_proofreading/widget.js
|
|
96
103
|
- lib/i18n_proofreading/widget.rb
|
|
@@ -101,6 +108,7 @@ licenses:
|
|
|
101
108
|
metadata:
|
|
102
109
|
source_code_uri: https://github.com/yshmarov/i18n_proofreading
|
|
103
110
|
changelog_uri: https://github.com/yshmarov/i18n_proofreading/blob/main/CHANGELOG.md
|
|
111
|
+
bug_tracker_uri: https://github.com/yshmarov/i18n_proofreading/issues
|
|
104
112
|
rubygems_mfa_required: 'true'
|
|
105
113
|
rdoc_options: []
|
|
106
114
|
require_paths:
|
|
@@ -116,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
116
124
|
- !ruby/object:Gem::Version
|
|
117
125
|
version: '0'
|
|
118
126
|
requirements: []
|
|
119
|
-
rubygems_version: 4.0.
|
|
127
|
+
rubygems_version: 4.0.16
|
|
120
128
|
specification_version: 4
|
|
121
129
|
summary: 'In-context i18n proofreading for Rails: click any translated string and
|
|
122
130
|
suggest a fix.'
|