eluvia-base 3.37.1 → 3.39.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +79 -0
- data/lib/eluvia/active_record/filtering.rb +16 -6
- data/lib/eluvia/active_record/filters_model.rb +13 -4
- data/lib/eluvia/base/config.rb +20 -0
- data/lib/eluvia/handlers/pagination_handler.rb +90 -9
- data/lib/eluvia/locales/cs.yml +22 -0
- data/lib/eluvia/locales/de.yml +22 -0
- data/lib/eluvia/locales/en.yml +25 -0
- data/lib/eluvia/locales/es.yml +22 -0
- data/lib/eluvia/locales/fr.yml +22 -0
- data/lib/eluvia/locales/it.yml +22 -0
- data/lib/eluvia/locales/ja.yml +22 -0
- data/lib/eluvia/locales/nl.yml +22 -0
- data/lib/eluvia/locales/pl.yml +22 -0
- data/lib/eluvia/locales/pt.yml +22 -0
- data/lib/eluvia/locales/ro.yml +22 -0
- data/lib/eluvia/locales/sk.yml +22 -0
- data/lib/eluvia/locales/uk.yml +22 -0
- data/lib/eluvia-base.rb +3 -0
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 691157713c8474d969d76eaee1106d331696a45b9458ee64a563762391e43ed3
|
|
4
|
+
data.tar.gz: 280074f623f0c865a349edaf49c277875c6eeb28374ab8062b0f2aff5f061d67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e202828e32b3c665d109ec6584c68fe4ff047b46a9af05b3119c68118d692e306ab3deac2534bc46779dcfc3e5a51b5af057e21940f0aea56ee076f6df9c8c9
|
|
7
|
+
data.tar.gz: 6eff59b834d789c738f7499d14770bc89cd2793d38ac337c2c7baf158b166170c94a38f55e7d4a6cad31cee49ba1937f81c1f9e15a9acd6748d711b8eb02356b
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [3.39.0] — 2026-09-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- This changelog, in the format the ci-toolbox release job expects: on release the unreleased
|
|
12
|
+
heading is rewritten to the released version and date, and the section becomes the description
|
|
13
|
+
of the GitLab release.
|
|
14
|
+
- `Eluvia::Base::Config.max_page_limit` — upper bound for the `limit` pagination param on
|
|
15
|
+
`set_pagination` (default `1000`, `nil` disables the check), overridable per controller via
|
|
16
|
+
`pagination_max_limit` or per call via the `max_limit:` keyword.
|
|
17
|
+
- `Eluvia::Base::Config.disable_pagination_errors` and the `disable_errors:` keyword on
|
|
18
|
+
`set_pagination`, to restore the previous silent-fallback behavior for an invalid `limit`
|
|
19
|
+
instead of raising.
|
|
20
|
+
- `allow_meta_only_limit:` keyword on `set_pagination` to reject `limit=0` like any other invalid
|
|
21
|
+
value, for resources that don't support a meta-only request.
|
|
22
|
+
- Translations (`lib/eluvia/locales/*.yml`) for all validation error messages raised by this gem
|
|
23
|
+
(ordering, filtering, fieldset, pagination), in the same languages supported by `habarico`
|
|
24
|
+
(`cs`, `de`, `en`, `es`, `fr`, `it`, `ja`, `nl`, `pl`, `pt`, `ro`, `sk`, `uk`).
|
|
25
|
+
- `Eluvia::PaginationHandler.order_by_param_name` — resolves the `order_by`/`orderBy` query
|
|
26
|
+
parameter name the same way `set_pagination` does, for callers outside this concern (e.g.
|
|
27
|
+
request-level validators run in a `before_action` ahead of it) that need to read the same
|
|
28
|
+
parameter without duplicating the `Config.api_case` check.
|
|
29
|
+
|
|
30
|
+
### Security
|
|
31
|
+
- **BREAKING:** `set_pagination`'s `limit` param is now capped and validated (HAB-946, from the
|
|
32
|
+
HAB-894 audit). A non-numeric, negative, or above-`max_page_limit` `limit` is rejected with a
|
|
33
|
+
`422 Unprocessable Entity` (error detail on the `limit` field) instead of being silently
|
|
34
|
+
truncated or defaulted. `limit=0` no longer raises `ZeroDivisionError` — it's now accepted as a
|
|
35
|
+
deliberate meta-only request (see `allow_meta_only_limit:`), mirroring `ListPagination` in
|
|
36
|
+
`eluvia-base-django`. Only a missing or blank `limit` still falls back to `default_limit`,
|
|
37
|
+
unchanged.
|
|
38
|
+
- **BREAKING:** `set_pagination`'s `order_by` param is now strictly validated (HAB-915, from the
|
|
39
|
+
HAB-894 audit). Each `field:direction` entry must have exactly one `:` separator, a non-blank
|
|
40
|
+
field name, and a lower-case `asc`/`desc` direction; anything else is rejected with a
|
|
41
|
+
`422 Unprocessable Entity` (format errors on `order_by`, direction errors on
|
|
42
|
+
`order_by__<field>`) instead of being silently truncated to two segments or defaulted to `asc`.
|
|
43
|
+
A blank `order_by=` no longer raises `NoMethodError` — it's treated as "not supplied" and falls
|
|
44
|
+
back to `default_order_by`/`fallback_order_by`.
|
data/README.md
CHANGED
|
@@ -82,6 +82,58 @@ class TestRecordsController < ApplicationController
|
|
|
82
82
|
end
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
**BREAKING CHANGE:** the `limit` param is now capped. Requests with a `limit` above the configured ceiling are
|
|
86
|
+
rejected with a `422 Unprocessable Entity` (error detail on the `limit` field) instead of being silently accepted.
|
|
87
|
+
A negative or non-numeric `limit` no longer falls through to Kaminari — it now also raises the same `422`. Only a
|
|
88
|
+
missing or blank `limit` param still falls back to `default_limit`, unchanged. `limit=0` is treated as a deliberate
|
|
89
|
+
meta-only request (see below) rather than an error, mirroring `ListPagination` in eluvia-base-django.
|
|
90
|
+
|
|
91
|
+
The ceiling defaults to `Eluvia::Base::Config.max_page_limit` (`1000` by default, `nil` disables the check):
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
Eluvia::Base::Config.max_page_limit = 500
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
It can be overridden per controller by overriding `pagination_max_limit`, or per call via the `max_limit:` keyword
|
|
98
|
+
(an explicit `max_limit: nil` removes the ceiling for that call only, regardless of `pagination_max_limit`):
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
class TestRecordsController < ApplicationController
|
|
102
|
+
def pagination_max_limit
|
|
103
|
+
50
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
before_action -> { set_pagination(default_limit: 20, default_offset: 0, max_limit: 50) }, only: [:index]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
To restore the pre-validation behavior (invalid or above-ceiling `limit` silently falls back to `default_limit`
|
|
113
|
+
instead of raising `422`), enable `disable_errors` — globally via `Eluvia::Base::Config.disable_pagination_errors =
|
|
114
|
+
true` (default: `false`), or per call via the `disable_errors:` keyword, which takes precedence over the global
|
|
115
|
+
setting:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
before_action -> { set_pagination(default_limit: 20, default_offset: 0, disable_errors: true) }, only: [:index]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`limit=0` is accepted by default as a way to request only pagination metadata without fetching any records — check
|
|
122
|
+
`@limit.zero?` in the action and skip the query:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
def index
|
|
126
|
+
@test_records = @limit.zero? ? TestRecord.none : TestRecord.all.order(@order_by).page(@page).per(@limit).padding(@padding)
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Pass `allow_meta_only_limit: false` (e.g. for a search-backed resource, mirroring
|
|
131
|
+
`AnySearchCursorBasedPagination` in eluvia-base-django) to reject `limit=0` like any other invalid value instead:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
before_action -> { set_pagination(default_limit: 20, default_offset: 0, allow_meta_only_limit: false) }, only: [:index]
|
|
135
|
+
```
|
|
136
|
+
|
|
85
137
|
### 2.3. Params parser
|
|
86
138
|
|
|
87
139
|
You can use `parse_json_param` helper to parse JSON without predefined structure. In case you know the input JSON
|
|
@@ -223,3 +275,30 @@ end
|
|
|
223
275
|
|
|
224
276
|
If `upload_key` is present on the assigned `Eluvia::File` but no finalizer is registered, a
|
|
225
277
|
`Eluvia::Errors::StandardError` is raised.
|
|
278
|
+
|
|
279
|
+
### 2.7. Translations
|
|
280
|
+
|
|
281
|
+
All validation error messages raised by this gem (ordering, filtering, fieldset and pagination errors) go through
|
|
282
|
+
`I18n.t` with an English `default:`, so the gem works out of the box without any locale setup. In addition,
|
|
283
|
+
`lib/eluvia/locales/*.yml` ships ready-made translations — under the `eluvia.errors.*` key namespace — for the
|
|
284
|
+
same set of languages supported by `habarico`: `cs`, `de`, `en`, `es`, `fr`, `it`, `ja`, `nl`, `pl`, `pt`, `ro`,
|
|
285
|
+
`sk`, `uk`. These are appended to `I18n.load_path` automatically when the gem loads; a host application only
|
|
286
|
+
needs to add the relevant locale to its own `I18n.available_locales` and set `I18n.locale` as usual. A host app's
|
|
287
|
+
own `config/locales/*.yml` takes precedence over these if it defines the same key.
|
|
288
|
+
|
|
289
|
+
## 3. Development
|
|
290
|
+
|
|
291
|
+
### 3.1. Versioning and releases
|
|
292
|
+
|
|
293
|
+
The gem version lives in `version.json` and is read at load time by `Eluvia::Base.version`. Releases are
|
|
294
|
+
driven by the `ruby-library` component of the
|
|
295
|
+
[ci-toolbox](https://gitlab.eluvia.dev/gitlab-ci/ci-toolbox) — the release job bumps the version, tags it,
|
|
296
|
+
and the tag pipeline publishes the gem to [geminabox](https://geminabox.eluvia.dev) and to
|
|
297
|
+
[rubygems.org](https://rubygems.org/gems/eluvia-base), and creates a GitLab release.
|
|
298
|
+
|
|
299
|
+
### 3.2. Changelog
|
|
300
|
+
|
|
301
|
+
Notable changes go to [CHANGELOG.md](CHANGELOG.md) under the `## [Unreleased]` heading, in the
|
|
302
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format. The release job rewrites that heading to
|
|
303
|
+
the released version and the release date, and uses the section as the description of the GitLab release —
|
|
304
|
+
so what you write there is what the Releases page shows.
|
|
@@ -365,19 +365,29 @@ module Eluvia
|
|
|
365
365
|
return scope if search_term.blank?
|
|
366
366
|
return scope if filters_model_class.nil?
|
|
367
367
|
|
|
368
|
-
|
|
369
|
-
return scope if
|
|
368
|
+
search_attrs = filters_model_class.search_attrs
|
|
369
|
+
return scope if search_attrs.empty?
|
|
370
370
|
|
|
371
371
|
search_term.split.each do |word|
|
|
372
|
-
sql_parts =
|
|
373
|
-
col =
|
|
374
|
-
"lower(
|
|
372
|
+
sql_parts = search_attrs.map do |attr_name|
|
|
373
|
+
col = attr_name.is_a?(Symbol) ? "#{self.table_name}.#{attr_name}" : attr_name.to_s
|
|
374
|
+
"lower(#{normalize_search_expression(col)}) LIKE ('%' || lower(#{normalize_search_expression('?')}) || '%')"
|
|
375
375
|
end
|
|
376
|
-
scope = scope.where(sql_parts.join(' OR '), *([word] *
|
|
376
|
+
scope = scope.where(sql_parts.join(' OR '), *([word] * search_attrs.size))
|
|
377
377
|
end
|
|
378
378
|
scope
|
|
379
379
|
end
|
|
380
380
|
|
|
381
|
+
# Wraps a search expression in `trim` and, when enabled via config, `unaccent`.
|
|
382
|
+
# `unaccent` requires the PostgreSQL `unaccent` extension to be enabled in the database.
|
|
383
|
+
def normalize_search_expression(expr)
|
|
384
|
+
if Eluvia::Base::Config.search_use_unaccent
|
|
385
|
+
"unaccent(trim(#{expr}))"
|
|
386
|
+
else
|
|
387
|
+
"trim(#{expr})"
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
381
391
|
def apply_filters_for_filter_attrs(scope, params, parent: nil, current_user: nil)
|
|
382
392
|
return scope unless is_filters_model?(filters_model_class)
|
|
383
393
|
filters_model_class.filter_attrs.each do |attr_spec|
|
|
@@ -12,11 +12,20 @@ module Eluvia
|
|
|
12
12
|
|
|
13
13
|
class_methods do
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
# Declares (with arguments) or returns (without arguments) the attributes searched by the
|
|
16
|
+
# generic `search` param. Each attribute is compared with a case-insensitive substring match,
|
|
17
|
+
# OR-combined across all of them.
|
|
18
|
+
#
|
|
19
|
+
# @example
|
|
20
|
+
# class User::Filters
|
|
21
|
+
# include Eluvia::ActiveRecord::FiltersModel
|
|
22
|
+
# search_attrs :first_name, :last_name, :email
|
|
23
|
+
# end
|
|
24
|
+
def search_attrs(*attr_names)
|
|
25
|
+
if attr_names.empty?
|
|
26
|
+
@_search_attrs ||= []
|
|
18
27
|
else
|
|
19
|
-
@
|
|
28
|
+
@_search_attrs = attr_names.flatten
|
|
20
29
|
end
|
|
21
30
|
end
|
|
22
31
|
|
data/lib/eluvia/base/config.rb
CHANGED
|
@@ -33,6 +33,26 @@ module Eluvia
|
|
|
33
33
|
mattr_accessor :uuid_seed
|
|
34
34
|
@@uuid_seed = '12345678-1234-1234-1234-1234567890ab'
|
|
35
35
|
|
|
36
|
+
# Whether the generic `search` param should wrap compared columns in the PostgreSQL `unaccent`
|
|
37
|
+
# function, making the search insensitive to diacritics. Requires the `unaccent` extension to be
|
|
38
|
+
# enabled in the database (`enable_extension 'unaccent'`). When false, search is only
|
|
39
|
+
# case-insensitive. (default: true)
|
|
40
|
+
mattr_accessor :search_use_unaccent
|
|
41
|
+
@@search_use_unaccent = true
|
|
42
|
+
|
|
43
|
+
# Upper bound for the `limit` pagination param on `set_pagination`. Requests with a
|
|
44
|
+
# higher `limit` are rejected with 422 instead of being silently truncated. `nil`
|
|
45
|
+
# disables the check. Mirrors `MAX_PAGE_LIMIT` in eluvia-base-django. (default: 1000)
|
|
46
|
+
mattr_accessor :max_page_limit
|
|
47
|
+
@@max_page_limit = 1000
|
|
48
|
+
|
|
49
|
+
# Whether an invalid `limit` param (non-numeric, negative, above `max_page_limit`, or zero
|
|
50
|
+
# without `allow_meta_only_limit:`) on `set_pagination` silently falls back to
|
|
51
|
+
# `default_limit` instead of being rejected with 422. Mirrors `disable_errors` on
|
|
52
|
+
# `LimitResolutionMixin` in eluvia-base-django. (default: false)
|
|
53
|
+
mattr_accessor :disable_pagination_errors
|
|
54
|
+
@@disable_pagination_errors = false
|
|
55
|
+
|
|
36
56
|
end
|
|
37
57
|
end
|
|
38
58
|
end
|
|
@@ -2,23 +2,104 @@ module Eluvia
|
|
|
2
2
|
module PaginationHandler
|
|
3
3
|
extend ::ActiveSupport::Concern
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# Resolves the query parameter name carrying the `order_by` input according to the configured
|
|
6
|
+
# API case. Exposed so callers outside this concern (e.g. request-level validators run in a
|
|
7
|
+
# `before_action` ahead of `set_pagination`) parse the exact same parameter, instead of
|
|
8
|
+
# duplicating this ternary and risking it drifting out of sync with `Config.api_case`.
|
|
9
|
+
def self.order_by_param_name
|
|
10
|
+
Eluvia::Base::Config.api_case == 'camel_case' ? :orderBy : :order_by
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Sentinel distinguishing an unset `max_limit:` kwarg (defer to `pagination_max_limit`) from
|
|
14
|
+
# an explicit `max_limit: nil` (no ceiling for this call only, regardless of the config/method).
|
|
15
|
+
NOT_SET = Object.new.freeze
|
|
16
|
+
|
|
17
|
+
# Ceiling applied to `limit` for this controller. Override to customize (e.g. a
|
|
18
|
+
# per-resource value pulled from a resource definition). Defaults to the library-wide config.
|
|
19
|
+
def pagination_max_limit
|
|
20
|
+
Eluvia::Base::Config.max_page_limit
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def set_pagination(default_limit: 20, default_offset: 0, default_order_by: 'created_at:asc',
|
|
24
|
+
fallback_order_by: 'created_at:asc', force_order_by: false, max_limit: NOT_SET,
|
|
25
|
+
disable_errors: nil, allow_meta_only_limit: true)
|
|
6
26
|
|
|
7
27
|
# Pagination
|
|
8
|
-
@limit =
|
|
28
|
+
@limit = resolve_pagination_limit(default_limit: default_limit, max_limit: max_limit,
|
|
29
|
+
disable_errors: disable_errors, allow_meta_only_limit: allow_meta_only_limit)
|
|
30
|
+
|
|
9
31
|
@offset = params[:offset] ? params[:offset].to_i : default_offset
|
|
10
|
-
|
|
11
|
-
|
|
32
|
+
if @limit.zero?
|
|
33
|
+
# Meta-only request (see `allow_meta_only_limit:`) - no records to page through.
|
|
34
|
+
@page = 1
|
|
35
|
+
@padding = 0
|
|
36
|
+
else
|
|
37
|
+
@page = (@offset / @limit) + 1
|
|
38
|
+
@padding = @offset % @limit
|
|
39
|
+
end
|
|
12
40
|
|
|
13
41
|
# Order by
|
|
42
|
+
order_by_param = Eluvia::PaginationHandler.order_by_param_name
|
|
43
|
+
user_order_by = params[order_by_param].to_s.strip
|
|
44
|
+
# A blank `order_by` is treated as "not supplied" (falls through to defaults/fallback)
|
|
45
|
+
# rather than as a literal empty ordering, since a Kaminari scope always needs some order.
|
|
46
|
+
order_by = !force_order_by && user_order_by.present? ? user_order_by : default_order_by
|
|
47
|
+
order_by = "#{order_by},#{fallback_order_by}"
|
|
48
|
+
|
|
14
49
|
@order_by = {}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
50
|
+
order_by.split(',').each do |entry|
|
|
51
|
+
entry = entry.strip
|
|
52
|
+
# `-1` keeps a trailing empty segment (e.g. `name:`) instead of Ruby's default of
|
|
53
|
+
# dropping it, so it is caught below as an invalid direction rather than as a bare field.
|
|
54
|
+
parts = entry.split(':', -1)
|
|
55
|
+
field_name, direction = parts
|
|
56
|
+
|
|
57
|
+
if parts.length != 2 || field_name.blank?
|
|
58
|
+
raise Eluvia::Errors::UnprocessableEntity.new({
|
|
59
|
+
'order_by' => I18n.t('eluvia.errors.ordering.invalid_format',
|
|
60
|
+
default: 'Invalid format, expected "field_name:asc" or "field_name:desc".')
|
|
61
|
+
})
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
unless %w[asc desc].include?(direction)
|
|
65
|
+
raise Eluvia::Errors::UnprocessableEntity.new({
|
|
66
|
+
"order_by__#{field_name}" => I18n.t('eluvia.errors.ordering.invalid_direction',
|
|
67
|
+
default: 'Invalid order direction. Allowed values are `asc` and `desc`.')
|
|
68
|
+
})
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
@order_by[field_name] = direction.to_sym
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def resolve_pagination_limit(default_limit:, max_limit:, disable_errors:, allow_meta_only_limit:)
|
|
79
|
+
return default_limit unless params[:limit].present?
|
|
80
|
+
|
|
81
|
+
raw_limit = params[:limit].to_s
|
|
82
|
+
parsed_limit = raw_limit.match?(/\A-?\d+\z/) ? raw_limit.to_i : nil
|
|
83
|
+
errors_disabled = disable_errors.nil? ? Eluvia::Base::Config.disable_pagination_errors : disable_errors
|
|
84
|
+
|
|
85
|
+
if parsed_limit.nil? || parsed_limit.negative? || (parsed_limit.zero? && !allow_meta_only_limit)
|
|
86
|
+
return default_limit if errors_disabled
|
|
87
|
+
|
|
88
|
+
msg = I18n.t('eluvia.errors.pagination.invalid_limit',
|
|
89
|
+
default: 'Limit must be a positive integer, got %<limit>s.', limit: params[:limit])
|
|
90
|
+
raise Eluvia::Errors::UnprocessableEntity.new('limit' => msg)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
ceiling = max_limit == NOT_SET ? pagination_max_limit : max_limit
|
|
94
|
+
if ceiling && parsed_limit > ceiling
|
|
95
|
+
return default_limit if errors_disabled
|
|
96
|
+
|
|
97
|
+
msg = I18n.t('eluvia.errors.pagination.max_limit_exceeded',
|
|
98
|
+
default: 'Limit %<limit>s exceeds the maximum allowed limit of %<max>s.', limit: parsed_limit, max: ceiling)
|
|
99
|
+
raise Eluvia::Errors::UnprocessableEntity.new('limit' => msg)
|
|
20
100
|
end
|
|
21
101
|
|
|
102
|
+
parsed_limit
|
|
22
103
|
end
|
|
23
104
|
|
|
24
105
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
cs:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Neplatný formát, očekává se "field_name:asc" nebo "field_name:desc".'
|
|
6
|
+
invalid_direction: "Neplatný směr řazení. Povolené hodnoty jsou `asc` a `desc`."
|
|
7
|
+
invalid_definition: "Neplatná definice atributu `order by`. Očekává se pouze jeden oddělovač `__`."
|
|
8
|
+
association_not_found: "Asociace nenalezena."
|
|
9
|
+
not_found_on_association: "Na asociaci neexistuje."
|
|
10
|
+
not_found: "Neexistuje."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Neznámý parametr filtru."
|
|
13
|
+
invalid_term: "Neplatný filtrovací výraz."
|
|
14
|
+
invalid_value_format: "Neplatný formát hodnoty."
|
|
15
|
+
invalid_uuid_format: "Neplatný formát UUID."
|
|
16
|
+
invalid_integer_format: "Neplatný formát celého čísla."
|
|
17
|
+
invalid_date_format: "Neplatný formát data."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Neznámé pole."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Limit musí být kladné celé číslo, zadáno %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Limit %<limit>s překračuje maximální povolený limit %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
de:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Ungültiges Format, erwartet wird "field_name:asc" oder "field_name:desc".'
|
|
6
|
+
invalid_direction: "Ungültige Sortierrichtung. Erlaubte Werte sind `asc` und `desc`."
|
|
7
|
+
invalid_definition: "Ungültige Definition für ein `order by`-Attribut. Es wird genau ein `__`-Trennzeichen erwartet."
|
|
8
|
+
association_not_found: "Assoziation nicht gefunden."
|
|
9
|
+
not_found_on_association: "Existiert nicht in der Assoziation."
|
|
10
|
+
not_found: "Existiert nicht."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Unbekannter Filterparameter."
|
|
13
|
+
invalid_term: "Ungültiger Filterbegriff."
|
|
14
|
+
invalid_value_format: "Ungültiges Wertformat."
|
|
15
|
+
invalid_uuid_format: "Ungültiges UUID-Format."
|
|
16
|
+
invalid_integer_format: "Ungültiges Ganzzahlformat."
|
|
17
|
+
invalid_date_format: "Ungültiges Datumsformat."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Unbekanntes Feld."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Limit muss eine positive Ganzzahl sein, erhalten: %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Limit %<limit>s überschreitet das maximal zulässige Limit von %<max>s."
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Translations for the validation error messages raised by eluvia-base (ordering.rb, filtering.rb,
|
|
2
|
+
# fieldset_serializer.rb, pagination_handler.rb). Each key mirrors the `default:` string passed to
|
|
3
|
+
# `I18n.t` at the call site, so a host app without these locale files still gets the same English text.
|
|
4
|
+
en:
|
|
5
|
+
eluvia:
|
|
6
|
+
errors:
|
|
7
|
+
ordering:
|
|
8
|
+
invalid_format: 'Invalid format, expected "field_name:asc" or "field_name:desc".'
|
|
9
|
+
invalid_direction: "Invalid order direction. Allowed values are `asc` and `desc`."
|
|
10
|
+
invalid_definition: "Invalid definition for an `order by` attribute. Expecting only one `__` delimiter."
|
|
11
|
+
association_not_found: "Association not found."
|
|
12
|
+
not_found_on_association: "Does not exist on association."
|
|
13
|
+
not_found: "Does not exist."
|
|
14
|
+
filter:
|
|
15
|
+
unknown_param: "Unknown filter param."
|
|
16
|
+
invalid_term: "Invalid filter term."
|
|
17
|
+
invalid_value_format: "Invalid value format."
|
|
18
|
+
invalid_uuid_format: "Invalid UUID format."
|
|
19
|
+
invalid_integer_format: "Invalid integer format."
|
|
20
|
+
invalid_date_format: "Invalid date format."
|
|
21
|
+
fieldset:
|
|
22
|
+
unknown_field: "Unknown field."
|
|
23
|
+
pagination:
|
|
24
|
+
invalid_limit: "Limit must be a positive integer, got %<limit>s."
|
|
25
|
+
max_limit_exceeded: "Limit %<limit>s exceeds the maximum allowed limit of %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
es:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Formato no válido, se espera "field_name:asc" o "field_name:desc".'
|
|
6
|
+
invalid_direction: "Dirección de ordenación no válida. Los valores permitidos son `asc` y `desc`."
|
|
7
|
+
invalid_definition: "Definición no válida para un atributo `order by`. Se espera solo un delimitador `__`."
|
|
8
|
+
association_not_found: "Asociación no encontrada."
|
|
9
|
+
not_found_on_association: "No existe en la asociación."
|
|
10
|
+
not_found: "No existe."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Parámetro de filtro desconocido."
|
|
13
|
+
invalid_term: "Término de filtro no válido."
|
|
14
|
+
invalid_value_format: "Formato de valor no válido."
|
|
15
|
+
invalid_uuid_format: "Formato de UUID no válido."
|
|
16
|
+
invalid_integer_format: "Formato de número entero no válido."
|
|
17
|
+
invalid_date_format: "Formato de fecha no válido."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Campo desconocido."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "El límite debe ser un número entero positivo, recibido %<limit>s."
|
|
22
|
+
max_limit_exceeded: "El límite %<limit>s supera el límite máximo permitido de %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
fr:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Format invalide, attendu "field_name:asc" ou "field_name:desc".'
|
|
6
|
+
invalid_direction: "Direction de tri invalide. Les valeurs autorisées sont `asc` et `desc`."
|
|
7
|
+
invalid_definition: "Définition invalide pour un attribut `order by`. Un seul délimiteur `__` est attendu."
|
|
8
|
+
association_not_found: "Association introuvable."
|
|
9
|
+
not_found_on_association: "N'existe pas sur l'association."
|
|
10
|
+
not_found: "N'existe pas."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Paramètre de filtre inconnu."
|
|
13
|
+
invalid_term: "Terme de filtre invalide."
|
|
14
|
+
invalid_value_format: "Format de valeur invalide."
|
|
15
|
+
invalid_uuid_format: "Format UUID invalide."
|
|
16
|
+
invalid_integer_format: "Format d'entier invalide."
|
|
17
|
+
invalid_date_format: "Format de date invalide."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Champ inconnu."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "La limite doit être un entier positif, valeur reçue %<limit>s."
|
|
22
|
+
max_limit_exceeded: "La limite %<limit>s dépasse la limite maximale autorisée de %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
it:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Formato non valido, previsto "field_name:asc" oppure "field_name:desc".'
|
|
6
|
+
invalid_direction: "Direzione di ordinamento non valida. I valori consentiti sono `asc` e `desc`."
|
|
7
|
+
invalid_definition: "Definizione non valida per un attributo `order by`. È previsto un solo delimitatore `__`."
|
|
8
|
+
association_not_found: "Associazione non trovata."
|
|
9
|
+
not_found_on_association: "Non esiste nell'associazione."
|
|
10
|
+
not_found: "Non esiste."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Parametro di filtro sconosciuto."
|
|
13
|
+
invalid_term: "Termine di filtro non valido."
|
|
14
|
+
invalid_value_format: "Formato del valore non valido."
|
|
15
|
+
invalid_uuid_format: "Formato UUID non valido."
|
|
16
|
+
invalid_integer_format: "Formato numero intero non valido."
|
|
17
|
+
invalid_date_format: "Formato data non valido."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Campo sconosciuto."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Il limite deve essere un numero intero positivo, ricevuto %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Il limite %<limit>s supera il limite massimo consentito di %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
ja:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: '形式が無効です。"field_name:asc" または "field_name:desc" を指定してください。'
|
|
6
|
+
invalid_direction: "並び順が無効です。使用できる値は `asc` と `desc` です。"
|
|
7
|
+
invalid_definition: "`order by` 属性の定義が無効です。`__` 区切り文字は1つだけ使用できます。"
|
|
8
|
+
association_not_found: "アソシエーションが見つかりません。"
|
|
9
|
+
not_found_on_association: "アソシエーション上に存在しません。"
|
|
10
|
+
not_found: "存在しません。"
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "不明なフィルターパラメータです。"
|
|
13
|
+
invalid_term: "フィルター条件が無効です。"
|
|
14
|
+
invalid_value_format: "値の形式が無効です。"
|
|
15
|
+
invalid_uuid_format: "UUID の形式が無効です。"
|
|
16
|
+
invalid_integer_format: "整数の形式が無効です。"
|
|
17
|
+
invalid_date_format: "日付の形式が無効です。"
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "不明なフィールドです。"
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "limit は正の整数である必要があります(指定値: %<limit>s)。"
|
|
22
|
+
max_limit_exceeded: "limit %<limit>s は許可されている最大値 %<max>s を超えています。"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
nl:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Ongeldig formaat, verwacht wordt "field_name:asc" of "field_name:desc".'
|
|
6
|
+
invalid_direction: "Ongeldige sorteerrichting. Toegestane waarden zijn `asc` en `desc`."
|
|
7
|
+
invalid_definition: "Ongeldige definitie voor een `order by`-attribuut. Er wordt precies één `__`-scheidingsteken verwacht."
|
|
8
|
+
association_not_found: "Associatie niet gevonden."
|
|
9
|
+
not_found_on_association: "Bestaat niet binnen de associatie."
|
|
10
|
+
not_found: "Bestaat niet."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Onbekende filterparameter."
|
|
13
|
+
invalid_term: "Ongeldige filterterm."
|
|
14
|
+
invalid_value_format: "Ongeldig waardeformaat."
|
|
15
|
+
invalid_uuid_format: "Ongeldig UUID-formaat."
|
|
16
|
+
invalid_integer_format: "Ongeldig geheel-getalformaat."
|
|
17
|
+
invalid_date_format: "Ongeldig datumformaat."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Onbekend veld."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Limit moet een positief geheel getal zijn, ontvangen: %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Limit %<limit>s overschrijdt de maximaal toegestane limiet van %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
pl:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Nieprawidłowy format, oczekiwano "field_name:asc" lub "field_name:desc".'
|
|
6
|
+
invalid_direction: "Nieprawidłowy kierunek sortowania. Dozwolone wartości to `asc` i `desc`."
|
|
7
|
+
invalid_definition: "Nieprawidłowa definicja atrybutu `order by`. Oczekiwany jest dokładnie jeden separator `__`."
|
|
8
|
+
association_not_found: "Nie znaleziono powiązania."
|
|
9
|
+
not_found_on_association: "Nie istnieje w powiązaniu."
|
|
10
|
+
not_found: "Nie istnieje."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Nieznany parametr filtra."
|
|
13
|
+
invalid_term: "Nieprawidłowy termin filtra."
|
|
14
|
+
invalid_value_format: "Nieprawidłowy format wartości."
|
|
15
|
+
invalid_uuid_format: "Nieprawidłowy format UUID."
|
|
16
|
+
invalid_integer_format: "Nieprawidłowy format liczby całkowitej."
|
|
17
|
+
invalid_date_format: "Nieprawidłowy format daty."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Nieznane pole."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Limit musi być dodatnią liczbą całkowitą, otrzymano %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Limit %<limit>s przekracza maksymalny dozwolony limit %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
pt:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Formato inválido, esperado "field_name:asc" ou "field_name:desc".'
|
|
6
|
+
invalid_direction: "Direção de ordenação inválida. Os valores permitidos são `asc` e `desc`."
|
|
7
|
+
invalid_definition: "Definição inválida para o atributo `order by`. É esperado apenas um delimitador `__`."
|
|
8
|
+
association_not_found: "Associação não encontrada."
|
|
9
|
+
not_found_on_association: "Não existe na associação."
|
|
10
|
+
not_found: "Não existe."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Parâmetro de filtro desconhecido."
|
|
13
|
+
invalid_term: "Termo de filtro inválido."
|
|
14
|
+
invalid_value_format: "Formato de valor inválido."
|
|
15
|
+
invalid_uuid_format: "Formato de UUID inválido."
|
|
16
|
+
invalid_integer_format: "Formato de número inteiro inválido."
|
|
17
|
+
invalid_date_format: "Formato de data inválido."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Campo desconhecido."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "O limite deve ser um número inteiro positivo, recebido %<limit>s."
|
|
22
|
+
max_limit_exceeded: "O limite %<limit>s excede o limite máximo permitido de %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
ro:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Format invalid, se așteaptă "field_name:asc" sau "field_name:desc".'
|
|
6
|
+
invalid_direction: "Direcție de sortare invalidă. Valorile permise sunt `asc` și `desc`."
|
|
7
|
+
invalid_definition: "Definiție invalidă pentru atributul `order by`. Este permis un singur delimitator `__`."
|
|
8
|
+
association_not_found: "Asocierea nu a fost găsită."
|
|
9
|
+
not_found_on_association: "Nu există în asociere."
|
|
10
|
+
not_found: "Nu există."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Parametru de filtrare necunoscut."
|
|
13
|
+
invalid_term: "Termen de filtrare invalid."
|
|
14
|
+
invalid_value_format: "Format de valoare invalid."
|
|
15
|
+
invalid_uuid_format: "Format UUID invalid."
|
|
16
|
+
invalid_integer_format: "Format de număr întreg invalid."
|
|
17
|
+
invalid_date_format: "Format de dată invalid."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Câmp necunoscut."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Limita trebuie să fie un număr întreg pozitiv, valoare primită %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Limita %<limit>s depășește limita maximă permisă de %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
sk:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Neplatný formát, očakáva sa "field_name:asc" alebo "field_name:desc".'
|
|
6
|
+
invalid_direction: "Neplatný smer radenia. Povolené hodnoty sú `asc` a `desc`."
|
|
7
|
+
invalid_definition: "Neplatná definícia atribútu `order by`. Očakáva sa iba jeden oddeľovač `__`."
|
|
8
|
+
association_not_found: "Asociácia nebola nájdená."
|
|
9
|
+
not_found_on_association: "Na asociácii neexistuje."
|
|
10
|
+
not_found: "Neexistuje."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Neznámy parameter filtra."
|
|
13
|
+
invalid_term: "Neplatný filtrovací výraz."
|
|
14
|
+
invalid_value_format: "Neplatný formát hodnoty."
|
|
15
|
+
invalid_uuid_format: "Neplatný formát UUID."
|
|
16
|
+
invalid_integer_format: "Neplatný formát celého čísla."
|
|
17
|
+
invalid_date_format: "Neplatný formát dátumu."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Neznáme pole."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Limit musí byť kladné celé číslo, zadané %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Limit %<limit>s prekračuje maximálny povolený limit %<max>s."
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
uk:
|
|
2
|
+
eluvia:
|
|
3
|
+
errors:
|
|
4
|
+
ordering:
|
|
5
|
+
invalid_format: 'Недійсний формат, очікується "field_name:asc" або "field_name:desc".'
|
|
6
|
+
invalid_direction: "Недійсний напрямок сортування. Дозволені значення: `asc` і `desc`."
|
|
7
|
+
invalid_definition: "Недійсне визначення атрибута `order by`. Очікується рівно один роздільник `__`."
|
|
8
|
+
association_not_found: "Асоціацію не знайдено."
|
|
9
|
+
not_found_on_association: "Не існує в асоціації."
|
|
10
|
+
not_found: "Не існує."
|
|
11
|
+
filter:
|
|
12
|
+
unknown_param: "Невідомий параметр фільтра."
|
|
13
|
+
invalid_term: "Недійсний термін фільтра."
|
|
14
|
+
invalid_value_format: "Недійсний формат значення."
|
|
15
|
+
invalid_uuid_format: "Недійсний формат UUID."
|
|
16
|
+
invalid_integer_format: "Недійсний формат цілого числа."
|
|
17
|
+
invalid_date_format: "Недійсний формат дати."
|
|
18
|
+
fieldset:
|
|
19
|
+
unknown_field: "Невідоме поле."
|
|
20
|
+
pagination:
|
|
21
|
+
invalid_limit: "Ліміт має бути додатним цілим числом, отримано %<limit>s."
|
|
22
|
+
max_limit_exceeded: "Ліміт %<limit>s перевищує максимально допустимий ліміт %<max>s."
|
data/lib/eluvia-base.rb
CHANGED
|
@@ -4,6 +4,9 @@ require 'eluvia/base/config'
|
|
|
4
4
|
# Version
|
|
5
5
|
require 'eluvia/base/version'
|
|
6
6
|
|
|
7
|
+
# Locales (translations for the validation error messages raised across this gem)
|
|
8
|
+
I18n.load_path += Dir[File.expand_path('eluvia/locales/*.yml', __dir__)]
|
|
9
|
+
|
|
7
10
|
# Uploads
|
|
8
11
|
require 'eluvia/uploads'
|
|
9
12
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: eluvia-base
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.39.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matěj Outlý
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rest-client
|
|
@@ -117,6 +117,7 @@ executables: []
|
|
|
117
117
|
extensions: []
|
|
118
118
|
extra_rdoc_files: []
|
|
119
119
|
files:
|
|
120
|
+
- CHANGELOG.md
|
|
120
121
|
- LICENSE
|
|
121
122
|
- README.md
|
|
122
123
|
- lib/eluvia-base.rb
|
|
@@ -149,6 +150,19 @@ files:
|
|
|
149
150
|
- lib/eluvia/handlers/params_handler.rb
|
|
150
151
|
- lib/eluvia/helpers/attachment_helper.rb
|
|
151
152
|
- lib/eluvia/integrations/eluvia_integration.rb
|
|
153
|
+
- lib/eluvia/locales/cs.yml
|
|
154
|
+
- lib/eluvia/locales/de.yml
|
|
155
|
+
- lib/eluvia/locales/en.yml
|
|
156
|
+
- lib/eluvia/locales/es.yml
|
|
157
|
+
- lib/eluvia/locales/fr.yml
|
|
158
|
+
- lib/eluvia/locales/it.yml
|
|
159
|
+
- lib/eluvia/locales/ja.yml
|
|
160
|
+
- lib/eluvia/locales/nl.yml
|
|
161
|
+
- lib/eluvia/locales/pl.yml
|
|
162
|
+
- lib/eluvia/locales/pt.yml
|
|
163
|
+
- lib/eluvia/locales/ro.yml
|
|
164
|
+
- lib/eluvia/locales/sk.yml
|
|
165
|
+
- lib/eluvia/locales/uk.yml
|
|
152
166
|
- lib/eluvia/models/file.rb
|
|
153
167
|
- lib/eluvia/models/file_wrapper.rb
|
|
154
168
|
- lib/eluvia/models/image_wrapper.rb
|