active_storage_validations 1.0.4 → 3.0.2

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +785 -245
  3. data/config/locales/da.yml +63 -0
  4. data/config/locales/de.yml +60 -19
  5. data/config/locales/en-GB.yml +63 -0
  6. data/config/locales/en.yml +60 -20
  7. data/config/locales/es.yml +60 -19
  8. data/config/locales/fr.yml +60 -19
  9. data/config/locales/it.yml +60 -19
  10. data/config/locales/ja.yml +60 -19
  11. data/config/locales/nl.yml +60 -19
  12. data/config/locales/pl.yml +60 -19
  13. data/config/locales/pt-BR.yml +60 -19
  14. data/config/locales/ru.yml +60 -19
  15. data/config/locales/sv.yml +63 -0
  16. data/config/locales/tr.yml +60 -19
  17. data/config/locales/uk.yml +60 -19
  18. data/config/locales/vi.yml +60 -19
  19. data/config/locales/zh-CN.yml +60 -19
  20. data/lib/active_storage_validations/analyzer/audio_analyzer.rb +58 -0
  21. data/lib/active_storage_validations/analyzer/content_type_analyzer.rb +60 -0
  22. data/lib/active_storage_validations/analyzer/image_analyzer/image_magick.rb +46 -0
  23. data/lib/active_storage_validations/analyzer/image_analyzer/vips.rb +56 -0
  24. data/lib/active_storage_validations/analyzer/image_analyzer.rb +49 -0
  25. data/lib/active_storage_validations/analyzer/null_analyzer.rb +18 -0
  26. data/lib/active_storage_validations/analyzer/pdf_analyzer.rb +89 -0
  27. data/lib/active_storage_validations/analyzer/shared/asv_ff_probable.rb +61 -0
  28. data/lib/active_storage_validations/analyzer/video_analyzer.rb +130 -0
  29. data/lib/active_storage_validations/analyzer.rb +88 -0
  30. data/lib/active_storage_validations/aspect_ratio_validator.rb +157 -97
  31. data/lib/active_storage_validations/attached_validator.rb +22 -5
  32. data/lib/active_storage_validations/base_comparison_validator.rb +83 -0
  33. data/lib/active_storage_validations/content_type_validator.rb +219 -31
  34. data/lib/active_storage_validations/dimension_validator.rb +187 -97
  35. data/lib/active_storage_validations/duration_validator.rb +70 -0
  36. data/lib/active_storage_validations/extensors/asv_blob_metadatable.rb +56 -0
  37. data/lib/active_storage_validations/extensors/asv_marcelable.rb +12 -0
  38. data/lib/active_storage_validations/limit_validator.rb +76 -9
  39. data/lib/active_storage_validations/matchers/aspect_ratio_validator_matcher.rb +119 -0
  40. data/lib/active_storage_validations/matchers/attached_validator_matcher.rb +48 -25
  41. data/lib/active_storage_validations/matchers/base_comparison_validator_matcher.rb +150 -0
  42. data/lib/active_storage_validations/matchers/content_type_validator_matcher.rb +98 -39
  43. data/lib/active_storage_validations/matchers/dimension_validator_matcher.rb +93 -55
  44. data/lib/active_storage_validations/matchers/duration_validator_matcher.rb +39 -0
  45. data/lib/active_storage_validations/matchers/limit_validator_matcher.rb +127 -0
  46. data/lib/active_storage_validations/matchers/pages_validator_matcher.rb +39 -0
  47. data/lib/active_storage_validations/matchers/processable_file_validator_matcher.rb +78 -0
  48. data/lib/active_storage_validations/matchers/shared/asv_active_storageable.rb +19 -0
  49. data/lib/active_storage_validations/matchers/shared/asv_allow_blankable.rb +28 -0
  50. data/lib/active_storage_validations/matchers/shared/asv_attachable.rb +72 -0
  51. data/lib/active_storage_validations/matchers/shared/asv_contextable.rb +57 -0
  52. data/lib/active_storage_validations/matchers/shared/asv_messageable.rb +28 -0
  53. data/lib/active_storage_validations/matchers/shared/asv_rspecable.rb +27 -0
  54. data/lib/active_storage_validations/matchers/shared/asv_validatable.rb +56 -0
  55. data/lib/active_storage_validations/matchers/size_validator_matcher.rb +17 -71
  56. data/lib/active_storage_validations/matchers/total_size_validator_matcher.rb +47 -0
  57. data/lib/active_storage_validations/matchers.rb +17 -21
  58. data/lib/active_storage_validations/pages_validator.rb +61 -0
  59. data/lib/active_storage_validations/processable_file_validator.rb +37 -0
  60. data/lib/active_storage_validations/railtie.rb +14 -0
  61. data/lib/active_storage_validations/shared/asv_active_storageable.rb +30 -0
  62. data/lib/active_storage_validations/shared/asv_analyzable.rb +89 -0
  63. data/lib/active_storage_validations/shared/asv_attachable.rb +236 -0
  64. data/lib/active_storage_validations/shared/asv_errorable.rb +64 -0
  65. data/lib/active_storage_validations/shared/asv_loggable.rb +11 -0
  66. data/lib/active_storage_validations/shared/asv_optionable.rb +29 -0
  67. data/lib/active_storage_validations/shared/asv_symbolizable.rb +14 -0
  68. data/lib/active_storage_validations/size_validator.rb +24 -41
  69. data/lib/active_storage_validations/total_size_validator.rb +52 -0
  70. data/lib/active_storage_validations/version.rb +1 -1
  71. data/lib/active_storage_validations.rb +27 -13
  72. metadata +113 -31
  73. data/lib/active_storage_validations/metadata.rb +0 -151
  74. data/lib/active_storage_validations/option_proc_unfolding.rb +0 -16
  75. data/lib/active_storage_validations/processable_image_validator.rb +0 -43
@@ -1,22 +1,63 @@
1
1
  tr:
2
2
  errors:
3
3
  messages:
4
- content_type_invalid: "geçersiz dosya tipine sahip"
5
- file_size_out_of_range: "dosya boyutu %{file_size} gerekli aralık dışında"
6
- limit_out_of_range: "toplam miktar aralık dışında"
7
- image_metadata_missing: "geçerli bir imaj değil"
8
- dimension_min_inclusion: "%{width} x %{height} piksele eşit ya da büyük olmalı"
9
- dimension_max_inclusion: "%{width} x %{height} piksele eşit ya da küçük olmalı"
10
- dimension_width_inclusion: "en %{min} ve %{max} piksel aralığı dışında"
11
- dimension_height_inclusion: "boy %{min} ve %{max} piksel aralığı dışında"
12
- dimension_width_greater_than_or_equal_to: "en %{length} piksele eşit ya da büyük olmalı"
13
- dimension_height_greater_than_or_equal_to: "boy %{length} piksele eşit ya da büyük olmalı"
14
- dimension_width_less_than_or_equal_to: "en %{length} piksele eşit ya da küçük olmalı"
15
- dimension_height_less_than_or_equal_to: "boy %{length} piksele eşit ya da küçük olmalı"
16
- dimension_width_equal_to: "en %{length} piksele eşit olmalı"
17
- dimension_height_equal_to: "boy %{length} piksele eşit olmalı"
18
- aspect_ratio_not_square: "kare bir imaj olmalı"
19
- aspect_ratio_not_portrait: "dikey bir imaj olmalı"
20
- aspect_ratio_not_landscape: "yatay bir imaj olmalı"
21
- aspect_ratio_is_not: "%{aspect_ratio} en boy oranına sahip olmalı"
22
- aspect_ratio_unknown: "bilinmeyen en boy oranı"
4
+ content_type_invalid:
5
+ one: "geçersiz içerik türüne sahip (yetkili içerik türü %{authorized_human_content_types})"
6
+ other: "geçersiz içerik türüne sahip (yetkili içerik türleri %{authorized_human_content_types})"
7
+ content_type_spoofed:
8
+ one: "içeriği aracılığıyla algılanan içerik türüne eşdeğer olmayan bir içerik türüne sahiptir (yetkili içerik türü %{authorized_human_content_types})"
9
+ other: "içeriği aracılığıyla algılanan içerik türüne eşdeğer olmayan bir içerik türüne sahiptir (yetkili içerik türleri %{authorized_human_content_types})"
10
+ file_size_not_less_than: "dosya boyutu %{max} boyutundan küçük olmalıdır (geçerli boyut %{file_size}'dir)"
11
+ file_size_not_less_than_or_equal_to: "dosya boyutu %{max} değerinden küçük veya ona eşit olmalıdır (geçerli boyut %{file_size}'dir)"
12
+ file_size_not_greater_than: "dosya boyutu %{min} boyutundan büyük olmalıdır (geçerli boyut %{file_size}'dir)"
13
+ file_size_not_greater_than_or_equal_to: "dosya boyutu %{min} değerinden büyük veya eşit olmalıdır (geçerli boyut %{file_size}'dir)"
14
+ file_size_not_between: "dosya boyutu %{min} ile %{max} arasında olmalıdır (geçerli boyut %{file_size}'dir)"
15
+ file_size_not_equal_to: "dosya boyutu %{exact} değerine eşit olmalıdır (geçerli boyut %{file_size}'dir)"
16
+ total_file_size_not_less_than: "toplam dosya boyutu %{max} boyutundan küçük olmalıdır (geçerli boyut %{total_file_size}'dir)"
17
+ total_file_size_not_less_than_or_equal_to: "toplam dosya boyutu %{max} değerinden küçük veya ona eşit olmalıdır (geçerli boyut %{total_file_size}'dir)"
18
+ total_file_size_not_greater_than: "toplam dosya boyutu %{min} boyutundan büyük olmalıdır (geçerli boyut %{total_file_size}'dir)"
19
+ total_file_size_not_greater_than_or_equal_to: "toplam dosya boyutu %{min} değerinden büyük veya eşit olmalıdır (geçerli boyut %{total_file_size}'dir)"
20
+ total_file_size_not_between: "toplam dosya boyutu %{min} ile %{max} arasında olmalıdır (geçerli boyut %{total_file_size}'dir)"
21
+ total_file_size_not_equal_to: "toplam dosya boyutu %{exact} değerine eşit olmalıdır (geçerli boyut %{total_file_size}'dir)"
22
+ duration_not_less_than: "süre %{max} değerinden az olmalıdır (geçerli süre %{duration})"
23
+ duration_not_less_than_or_equal_to: "süre %{max} değerine eşit veya daha düşük olmalıdır (geçerli süre %{duration})"
24
+ duration_not_greater_than: "süre %{min} değerinden büyük olmalıdır (geçerli süre %{duration})"
25
+ duration_not_greater_than_or_equal_to: "süre %{min} değerine eşit veya daha büyük olmalıdır (geçerli süre %{duration})"
26
+ duration_not_between: "süre %{min} ile %{max} arasında olmalıdır (geçerli süre %{duration})"
27
+ duration_not_equal_to: "süre %{exact} değerine eşit olmalıdır (geçerli süre %{duration})"
28
+ limit_out_of_range:
29
+ zero: "dosya eklenmedi ( %{min} ve %{max} dosyaları arasında olmalıdır)"
30
+ one: "yalnızca 1 dosya eklenmiş ( %{min} ve %{max} dosyaları arasında olmalıdır)"
31
+ other: "toplam dosya sayısı %{min} ve %{max} dosyaları arasında olmalıdır ( %{count} dosyaları ektedir)"
32
+ limit_min_not_reached:
33
+ zero: "dosya eklenmedi (en az %{min} dosyaları olmalıdır)"
34
+ one: "yalnızca 1 dosya eklenmiş (en az %{min} dosyalarına sahip olmalıdır)"
35
+ other: "%{count} dosyaları eklenmiş (en az %{min} dosyaları olmalıdır)"
36
+ limit_max_exceeded:
37
+ zero: "dosya eklenmedi (maksimum %{max} dosyaları)"
38
+ one: "çok fazla dosya eklendi (maksimum %{max} dosyaları, %{count})"
39
+ other: "çok fazla dosya eklendi (maksimum %{max} dosyaları, %{count} var)"
40
+ attachment_missing: "ekli dosya yok"
41
+ media_metadata_missing: "geçerli bir medya dosyası değil"
42
+ dimension_min_not_included_in: "%{width} x %{height} piksele eşit ya da büyük olmalı"
43
+ dimension_max_not_included_in: "%{width} x %{height} piksele eşit ya da küçük olmalı"
44
+ dimension_width_not_included_in: "en %{min} ve %{max} piksel aralığı dışında"
45
+ dimension_height_not_included_in: "boy %{min} ve %{max} piksel aralığı dışında"
46
+ dimension_width_not_greater_than_or_equal_to: "en %{length} piksele eşit ya da büyük olmalı"
47
+ dimension_height_not_greater_than_or_equal_to: "boy %{length} piksele eşit ya da büyük olmalı"
48
+ dimension_width_not_less_than_or_equal_to: "en %{length} piksele eşit ya da küçük olmalı"
49
+ dimension_height_not_less_than_or_equal_to: "boy %{length} piksele eşit ya da küçük olmalı"
50
+ dimension_width_not_equal_to: "en %{length} piksele eşit olmalı"
51
+ dimension_height_not_equal_to: "boy %{length} piksele eşit olmalı"
52
+ aspect_ratio_not_square: "kare olmalı (geçerli dosya %{width}x%{height}px)"
53
+ aspect_ratio_not_portrait: "portre olmalı (geçerli dosya %{width}x%{height}px)"
54
+ aspect_ratio_not_landscape: "yatay olmalıdır (geçerli dosya %{width}x%{height}px)"
55
+ aspect_ratio_not_x_y: "%{authorized_aspect_ratios} olmalıdır (geçerli dosya %{width}x%{height}px)"
56
+ aspect_ratio_invalid: "geçersiz bir en boy oranına sahiptir (geçerli en boy oranları %{authorized_aspect_ratios})"
57
+ file_not_processable: "geçerli bir medya dosyası olarak tanımlanmadı"
58
+ pages_not_less_than: "sayfa sayısı %{max} değerinden az olmalıdır (geçerli sayfa sayısı %{pages})"
59
+ pages_not_less_than_or_equal_to: "sayfa sayısı %{max} değerinden az veya eşit olmalıdır (geçerli sayfa sayısı %{pages})"
60
+ pages_not_greater_than: "sayfa sayısı %{min} değerinden fazla olmalıdır (geçerli sayfa sayısı %{pages})"
61
+ pages_not_greater_than_or_equal_to: "sayfa sayısı %{min} değerinden fazla veya eşit olmalıdır (geçerli sayfa sayısı %{pages})"
62
+ pages_not_between: "sayfa sayısı %{min} ile %{max} arasında olmalıdır (geçerli sayfa sayısı %{pages})"
63
+ pages_not_equal_to: "sayfa sayısı %{exact} değerine eşit olmalıdır (geçerli sayfa sayısı %{pages})"
@@ -1,22 +1,63 @@
1
1
  uk:
2
2
  errors:
3
3
  messages:
4
- content_type_invalid: "має неприпустимий тип вмісту"
5
- file_size_out_of_range: "розмір %{file_size} більше необхідного"
6
- limit_out_of_range: "кількість файлів більше необхідного"
7
- image_metadata_missing: "не є допустимим зображенням"
8
- dimension_min_inclusion: "мусить бути більше або дорівнювати %{width} x %{height} пікселям"
9
- dimension_max_inclusion: "мусить бути менше або дорівнювати %{width} x %{height} пікселям"
10
- dimension_width_inclusion: "ширина не включена між %{min} і %{max} пікселям"
11
- dimension_height_inclusion: "висота не включена між %{min} і %{max} пікселям"
12
- dimension_width_greater_than_or_equal_to: "ширина мусить бути більше або дорівнювати %{length} пікселям"
13
- dimension_height_greater_than_or_equal_to: "висота мусить бути більше або дорівнювати %{length} пікселям"
14
- dimension_width_less_than_or_equal_to: "ширина мусить бути менше або дорівнювати %{length} пікселям"
15
- dimension_height_less_than_or_equal_to: "висота мусить бути менше або дорівнювати %{length} пікселям"
16
- dimension_width_equal_to: "ширина мусить дорівнювати %{length} пікселям"
17
- dimension_height_equal_to: "висота мусить дорівнювати %{length} пікселям"
18
- aspect_ratio_not_square: "мусить бути квадратне зображення"
19
- aspect_ratio_not_portrait: "мусить бути портретне зображення"
20
- aspect_ratio_not_landscape: "мусить бути пейзажне зображення"
21
- aspect_ratio_is_not: "мусить мати співвідношення сторін %{aspect_ratio}"
22
- aspect_ratio_unknown: "має невідоме співвідношення сторін"
4
+ content_type_invalid:
5
+ one: "має недійсний тип вмісту (уповноважений тип вмісту становить %{autorized_human_content_types})"
6
+ other: "має недійсний тип вмісту (дозволені типи вмісту %{autorized_human_content_types})"
7
+ content_type_spoofed:
8
+ one: "має тип вмісту, який не еквівалентний тому, який виявляється через його вміст (уповноважений тип вмісту становить %{autorized_human_content_types})"
9
+ other: "має тип вмісту, який не еквівалентний тому, який виявляється через його вміст (дозволені типи вмісту %{autorized_human_content_types})"
10
+ file_size_not_less_than: "розмір файлу має бути менше %{max} (поточний розмір %{file_size})"
11
+ file_size_not_less_than_or_equal_to: "розмір файлу має бути меншим або дорівнювати %{max} (поточний розмір %{file_size})"
12
+ file_size_not_greater_than: "розмір файлу має бути більшим ніж %{min} (поточний розмір %{file_size})"
13
+ file_size_not_greater_than_or_equal_to: "розмір файлу має бути більшим або дорівнювати %{min} (поточний розмір %{file_size})"
14
+ file_size_not_between: "розмір файлу має бути від %{min} до %{max} (поточний розмір %{file_size})"
15
+ file_size_not_equal_to: "розмір файлу має бути рівний %{exact} (поточний розмір %{file_size})"
16
+ total_file_size_not_less_than: "загальний розмір файлу має бути менше %{max} (поточний розмір %{total_file_size})"
17
+ total_file_size_not_less_than_or_equal_to: "загальний розмір файлу має бути меншим або дорівнювати %{max} (поточний розмір %{total_file_size})"
18
+ total_file_size_not_greater_than: "загальний розмір файлу має бути більшим ніж %{min} (поточний розмір %{total_file_size})"
19
+ total_file_size_not_greater_than_or_equal_to: "загальний розмір файлу має бути більшим або дорівнювати %{min} (поточний розмір %{total_file_size})"
20
+ total_file_size_not_between: "загальний розмір файлу має бути від %{min} до %{max} (поточний розмір %{total_file_size})"
21
+ total_file_size_not_equal_to: "загальний розмір файлу має бути рівний %{exact} (поточний розмір %{total_file_size})"
22
+ duration_not_less_than: "тривалість повинна бути меншою ніж %{max} (поточна тривалість становить %{duration})"
23
+ duration_not_less_than_or_equal_to: "тривалість повинна бути меншою або дорівнює %{max} (поточна тривалість становить %{duration})"
24
+ duration_not_greater_than: "тривалість повинна бути більше %{min} (поточна тривалість становить %{duration})"
25
+ duration_not_greater_than_or_equal_to: "тривалість повинна бути більшою або дорівнює %{min} (поточна тривалість становить %{duration})"
26
+ duration_not_between: "тривалість повинна бути між %{min} і %{max} (поточна тривалість становить %{duration})"
27
+ duration_not_equal_to: "тривалість повинна бути рівна %{exact} (поточна тривалість становить %{duration})"
28
+ limit_out_of_range:
29
+ zero: "немає доданих файлів (повинно мати між %{min} і %{max} файли)"
30
+ one: "додається лише 1 файл (повинен мати між %{min} і %{max} файли)"
31
+ other: "загальна кількість файлів повинна бути між %{min} і %{max} файлами (є %{count} файли)"
32
+ limit_min_not_reached:
33
+ zero: "немає доданих файлів (повинен мати принаймні %{min} файлів)"
34
+ one: "додається лише 1 файл (повинен мати принаймні %{min} файли)"
35
+ other: "%{count} додані файли (повинні мати принаймні %{min} файли)"
36
+ limit_max_exceeded:
37
+ zero: "не додано файлів (максимум -%{max} файли)"
38
+ one: "занадто багато доданих файлів (максимум -%{max} файлів, отримав %{count})"
39
+ other: "занадто багато доданих файлів (максимум -%{max} файлів, отримав %{count})"
40
+ attachment_missing: "не має доданого файлу"
41
+ media_metadata_missing: "не є допустимим зображенням"
42
+ dimension_min_not_included_in: "мусить бути більше або дорівнювати %{width} x %{height} пікселям"
43
+ dimension_max_not_included_in: "мусить бути менше або дорівнювати %{width} x %{height} пікселям"
44
+ dimension_width_not_included_in: "ширина не включена між %{min} і %{max} пікселям"
45
+ dimension_height_not_included_in: "висота не включена між %{min} і %{max} пікселям"
46
+ dimension_width_not_greater_than_or_equal_to: "ширина мусить бути більше або дорівнювати %{length} пікселям"
47
+ dimension_height_not_greater_than_or_equal_to: "висота мусить бути більше або дорівнювати %{length} пікселям"
48
+ dimension_width_not_less_than_or_equal_to: "ширина мусить бути менше або дорівнювати %{length} пікселям"
49
+ dimension_height_not_less_than_or_equal_to: "висота мусить бути менше або дорівнювати %{length} пікселям"
50
+ dimension_width_not_equal_to: "ширина мусить дорівнювати %{length} пікселям"
51
+ dimension_height_not_equal_to: "висота мусить дорівнювати %{length} пікселям"
52
+ aspect_ratio_not_square: "повинен бути квадратним (поточний файл %{width}x%{height} пікселям)"
53
+ aspect_ratio_not_portrait: "повинен бути портретним (поточний файл %{width}x%{height} пікселям)"
54
+ aspect_ratio_not_landscape: "повинен бути пейзажним (поточний файл %{width}x%{height} пікселям)"
55
+ aspect_ratio_not_x_y: "повинен бути %{authorized_aspect_ratios} (поточний файл становить %{width}x%{height} пікселям)"
56
+ aspect_ratio_invalid: "має недійсне співвідношення сторін (дійсні співвідношення сторін %{authorized_aspect_ratios})"
57
+ file_not_processable: "не ідентифікується як дійсний медіа-файл"
58
+ pages_not_less_than: "кількість сторінок має бути менше %{max} (поточна кількість сторінок %{pages})"
59
+ pages_not_less_than_or_equal_to: "кількість сторінок має бути меншою або дорівнювати %{max} (поточна кількість сторінок становить %{pages})"
60
+ pages_not_greater_than: "кількість сторінок має бути більшою за %{min} (поточна кількість сторінок становить %{pages})"
61
+ pages_not_greater_than_or_equal_to: "кількість сторінок має бути більшою або дорівнювати %{min} (поточна кількість сторінок становить %{pages})"
62
+ pages_not_between: "кількість сторінок має бути від %{min} до %{max} (поточна кількість сторінок становить %{pages})"
63
+ pages_not_equal_to: "кількість сторінок має дорівнювати %{exact} (поточна кількість сторінок - %{pages})"
@@ -1,22 +1,63 @@
1
1
  vi:
2
2
  errors:
3
3
  messages:
4
- content_type_invalid: "tệp không hợp lệ"
5
- file_size_out_of_range: "kích thước %{file_size} vượt giới hạn"
6
- limit_out_of_range: "tổng số tệp vượt giới hạn"
7
- image_metadata_missing: "không phải là ảnh"
8
- dimension_min_inclusion: "phải lớn hơn hoặc bằng %{width} x %{height} pixel"
9
- dimension_max_inclusion: "phải nhỏ hơn hoặc bằng %{width} x %{height} pixel"
10
- dimension_width_inclusion: "chiều rộng không nằm trong %{min} %{max} pixel"
11
- dimension_height_inclusion: "chiều cao không nằm trong %{min} %{max} pixel"
12
- dimension_width_greater_than_or_equal_to: "chiều rộng phải lớn hơn hoặc bằng %{length} pixel"
13
- dimension_height_greater_than_or_equal_to: "chiều cao phải lớn hơn hoặc bằng %{length} pixel"
14
- dimension_width_less_than_or_equal_to: "chiều rộng phải nhỏ hơn hoặc bằng %{length} pixel"
15
- dimension_height_less_than_or_equal_to: "chiều cao phải nhỏ hơn hoặc bằng %{length} pixel"
16
- dimension_width_equal_to: "chiều rộng phải bằng %{length} pixel"
17
- dimension_height_equal_to: "chiều cao phải bằng %{length} pixel"
18
- aspect_ratio_not_square: "phải ảnh hình vuông"
19
- aspect_ratio_not_portrait: "phải là ảnh đứng"
20
- aspect_ratio_not_landscape: "phải là ảnh ngang"
21
- aspect_ratio_is_not: "phải tỉ lệ ảnh %{aspect_ratio}"
22
- aspect_ratio_unknown: "tỉ lệ ảnh không xác định"
4
+ content_type_invalid:
5
+ one: " loại nội dung không hợp lệ (loại nội dung được ủy quyền là %{autorized_human_content_types})"
6
+ other: " loại nội dung không hợp lệ (các loại nội dung được ủy quyền là %{autorized_human_content_types})"
7
+ content_type_spoofed:
8
+ one: " một loại nội dung không tương đương với loại được phát hiện thông qua nội dung của nó (loại nội dung được ủy quyền là %{autorized_human_content_types})"
9
+ other: " một loại nội dung không tương đương với loại được phát hiện thông qua nội dung của nó (các loại nội dung được ủy quyền là %{autorized_human_content_types})"
10
+ file_size_not_less_than: "kích thước tệp phải nhỏ hơn %{max} (kích thước hiện tại là %{file_size})"
11
+ file_size_not_less_than_or_equal_to: "kích thước tệp phải nhỏ hơn hoặc bằng %{max} (kích thước hiện tại là %{file_size})"
12
+ file_size_not_greater_than: "kích thước tệp phải lớn hơn %{min} (kích thước hiện tại là %{file_size})"
13
+ file_size_not_greater_than_or_equal_to: "kích thước tệp phải lớn hơn hoặc bằng %{min} (kích thước hiện tại là %{file_size})"
14
+ file_size_not_between: "kích thước tệp phải nằm trong khoảng từ %{min} đến %{max} (kích thước hiện tại là %{file_size})"
15
+ file_size_not_equal_to: "kích thước tệp phải bằng %{exact} (kích thước hiện tại là %{file_size})"
16
+ total_file_size_not_less_than: "tổng kích thước tệp phải nhỏ hơn %{max} (kích thước hiện tại là %{total_file_size})"
17
+ total_file_size_not_less_than_or_equal_to: "tổng kích thước tệp phải nhỏ hơn hoặc bằng %{max} (kích thước hiện tại là %{total_file_size})"
18
+ total_file_size_not_greater_than: "tổng kích thước tệp phải lớn hơn %{min} (kích thước hiện tại là %{total_file_size})"
19
+ total_file_size_not_greater_than_or_equal_to: "tổng kích thước tệp phải lớn hơn hoặc bằng %{min} (kích thước hiện tại %{total_file_size})"
20
+ total_file_size_not_between: "tổng kích thước tệp phải nằm trong khoảng từ %{min} đến %{max} (kích thước hiện tại %{total_file_size})"
21
+ total_file_size_not_equal_to: "tổng kích thước tệp phải bằng %{exact} (kích thước hiện tại là %{total_file_size})"
22
+ duration_not_less_than: "thời lượng phải nhỏ hơn %{max} (thời lượng hiện tại là %{duration})"
23
+ duration_not_less_than_or_equal_to: "thời lượng phải nhỏ hơn hoặc bằng %{max} (thời lượng hiện tại là %{duration})"
24
+ duration_not_greater_than: "thời lượng phải lớn hơn %{min} (thời lượng hiện tại là %{duration})"
25
+ duration_not_greater_than_or_equal_to: "thời lượng phải lớn hơn hoặc bằng %{min} (thời lượng hiện tại là %{duration})"
26
+ duration_not_between: "thời lượng phải nằm trong khoảng từ %{min} và %{max} (thời lượng hiện tại là %{duration})"
27
+ duration_not_equal_to: "thời lượng phải bằng %{exact} (thời lượng hiện tại là %{duration})"
28
+ limit_out_of_range:
29
+ zero: "không có tệp nào được đính kèm (phải có giữa các tệp %{min} và %{max})"
30
+ one: "chỉ có 1 tệp được đính kèm (phải có giữa các tệp %{min} và %{max})"
31
+ other: "tổng số tệp phải nằm trong khoảng từ %{min} và %{max} tệp (có các tệp %{count} được đính kèm)"
32
+ limit_min_not_reached:
33
+ zero: "không có tệp nào được đính kèm (phải có ít nhất %{min} tệp)"
34
+ one: "chỉ có 1 tệp được đính kèm (phải có ít nhất %{min} tệp)"
35
+ other: "các tệp %{count} được đính kèm (phải có ít nhất %{min} tệp)"
36
+ limit_max_exceeded:
37
+ zero: "không có tệp nào được đính kèm (tối đa là các tệp %{max})"
38
+ one: "quá nhiều tệp được đính kèm (tối đa là các tệp %{max}, có %{count})"
39
+ other: "quá nhiều tệp được đính kèm (tối đa là các tệp %{max}, có %{count})"
40
+ attachment_missing: "không có tập tin đính kèm"
41
+ media_metadata_missing: "không phải là ảnh"
42
+ dimension_min_not_included_in: "phải lớn hơn hoặc bằng %{width} x %{height} pixel"
43
+ dimension_max_not_included_in: "phải nhỏ hơn hoặc bằng %{width} x %{height} pixel"
44
+ dimension_width_not_included_in: "chiều rộng không nằm trong %{min} và %{max} pixel"
45
+ dimension_height_not_included_in: "chiều cao không nằm trong %{min} và %{max} pixel"
46
+ dimension_width_not_greater_than_or_equal_to: "chiều rộng phải lớn hơn hoặc bằng %{length} pixel"
47
+ dimension_height_not_greater_than_or_equal_to: "chiều cao phải lớn hơn hoặc bằng %{length} pixel"
48
+ dimension_width_not_less_than_or_equal_to: "chiều rộng phải nhỏ hơn hoặc bằng %{length} pixel"
49
+ dimension_height_not_less_than_or_equal_to: "chiều cao phải nhỏ hơn hoặc bằng %{length} pixel"
50
+ dimension_width_not_equal_to: "chiều rộng phải bằng %{length} pixel"
51
+ dimension_height_not_equal_to: "chiều cao phải bằng %{length} pixel"
52
+ aspect_ratio_not_square: "phải là hình vuông (tệp hiện tại là %{width}x%{height}px)"
53
+ aspect_ratio_not_portrait: "phải là chân dung (tệp hiện tại là %{width}x%{height}px)"
54
+ aspect_ratio_not_landscape: "phải là ngang (tệp hiện tại là %{width}x%{height}px)"
55
+ aspect_ratio_not_x_y: "phải là %{authorized_aspect_ratios} (tệp hiện tại là %{width}x%{height}px)"
56
+ aspect_ratio_invalid: "có tỷ lệ khung hình không hợp lệ (tỷ lệ khung hình hợp lệ là %{authorized_aspect_ratios})"
57
+ file_not_processable: "không được xác định là tệp phương tiện hợp lệ"
58
+ pages_not_less_than: "số trang phải nhỏ hơn %{max} (số trang hiện tại là %{pages})"
59
+ pages_not_less_than_or_equal_to: "số trang phải nhỏ hơn hoặc bằng %{max} (số trang hiện tại là %{pages})"
60
+ pages_not_greater_than: "số trang phải lớn hơn %{min} (số trang hiện tại là %{pages})"
61
+ pages_not_greater_than_or_equal_to: "số trang phải lớn hơn hoặc bằng %{min} (số trang hiện tại là %{pages})"
62
+ pages_not_between: "số trang phải nằm trong khoảng từ %{min} đến %{max} (số trang hiện tại là %{pages})"
63
+ pages_not_equal_to: "số trang phải bằng %{exact} (số trang hiện tại là %{pages})"
@@ -1,22 +1,63 @@
1
1
  zh-CN:
2
2
  errors:
3
3
  messages:
4
- content_type_invalid: "文件类型错误"
5
- file_size_out_of_range: "文件大小 %{file_size} 超出限定范围"
6
- limit_out_of_range: "文件数超出限定范围"
7
- image_metadata_missing: "不是有效的图像"
8
- dimension_min_inclusion: "必须大于或等于 %{width} x %{height} 像素"
9
- dimension_max_inclusion: "必须小于或等于 %{width} x %{height} 像素"
10
- dimension_width_inclusion: "宽度不在 %{min} %{max} 像素之间"
11
- dimension_height_inclusion: "高度不在 %{min} %{max} 像素之间"
12
- dimension_width_greater_than_or_equal_to: "宽度必须大于或等于 %{length} 像素"
13
- dimension_height_greater_than_or_equal_to: "高度必须大于或等于 %{length} 像素"
14
- dimension_width_less_than_or_equal_to: "宽度必须小于或等于 %{length} 像素"
15
- dimension_height_less_than_or_equal_to: "高度必须小于或等于 %{length} 像素"
16
- dimension_width_equal_to: "宽度必须等于 %{length} 像素"
17
- dimension_height_equal_to: "高度必须等于 %{length} 像素"
18
- aspect_ratio_not_square: "必须是方形图片"
19
- aspect_ratio_not_portrait: "必须是竖屏图片"
20
- aspect_ratio_not_landscape: "必须是横屏图片"
21
- aspect_ratio_is_not: "纵横比必须是 %{aspect_ratio}"
22
- aspect_ratio_unknown: "未知的纵横比"
4
+ content_type_invalid:
5
+ one: "具有无效的内容类型(授权的内容类型为%{authorized_human_content_types})"
6
+ other: "具有无效的内容类型(授权的内容类型为%{authorized_human_content_types})"
7
+ content_type_spoofed:
8
+ one: "其内容类型不等于通过其内容检测到的内容类型(授权内容类型为%{authorized_human_content_types})"
9
+ other: "其内容类型与通过其内容检测到的内容类型不等效(授权内容类型为%{authorized_human_content_types})"
10
+ file_size_not_less_than: "文件大小必须小于 %{max}(当前大小为 %{file_size})"
11
+ file_size_not_less_than_or_equal_to: "文件大小必须小于或等于 %{max}(当前大小为 %{file_size})"
12
+ file_size_not_greater_than: "文件大小必须大于 %{min}(当前大小为 %{file_size})"
13
+ file_size_not_greater_than_or_equal_to: "文件大小必须大于或等于 %{min}(当前大小为 %{file_size})"
14
+ file_size_not_between: "文件大小必须介于 %{min} 和 %{max} 之间(当前大小为 %{file_size})"
15
+ file_size_not_equal_to: "文件大小必须等于 %{exact}(当前大小为 %{file_size})"
16
+ total_file_size_not_less_than: "总文件大小必须小于 %{max}(当前大小为 %{total_file_size})"
17
+ total_file_size_not_less_than_or_equal_to: "文件总大小必须小于或等于 %{max}(当前大小为 %{total_file_size})"
18
+ total_file_size_not_greater_than: "总文件大小必须大于 %{min}(当前大小为 %{total_file_size})"
19
+ total_file_size_not_greater_than_or_equal_to: "文件总大小必须大于或等于 %{min}(当前大小为 %{total_file_size})"
20
+ total_file_size_not_between: "总文件大小必须介于 %{min} 和 %{max} 之间(当前大小为 %{total_file_size})"
21
+ total_file_size_not_equal_to: "总文件大小必须等于 %{exact}(当前大小为 %{total_file_size})"
22
+ duration_not_less_than: "持续时间必须小于%{max}(当前持续时间为%{duration})"
23
+ duration_not_less_than_or_equal_to: "持续时间必须小于或等于%{max}(当前持续时间为%{duration})"
24
+ duration_not_greater_than: "持续时间必须大于%{min}(当前持续时间为%{duration})"
25
+ duration_not_greater_than_or_equal_to: "持续时间必须大于或等于%{min}(当前持续时间为%{duration})"
26
+ duration_not_between: "持续时间必须在%{min}和%{max}之间(当前持续时间为%{duration})"
27
+ duration_not_equal_to: "持续时间必须等于%{exact}(当前持续时间为%{duration})"
28
+ limit_out_of_range:
29
+ zero: "未附加文件(必须具有%{min}和%{max}文件之间)"
30
+ one: "仅附加1个文件(必须具有%{min}和%{max}文件之间)"
31
+ other: "文件总数必须在%{min}和%{max}文件之间(已连接%{count}文件)"
32
+ limit_min_not_reached:
33
+ zero: "未附加文件(必须至少具有%{min}文件)"
34
+ one: "仅附加1个文件(必须至少具有%{min}文件)"
35
+ other: "%{count}文件已连接(必须至少具有%{min}文件)"
36
+ limit_max_exceeded:
37
+ zero: "未附加文件(最大为%{max}文件)"
38
+ one: "附加的文件太多(最大为%{max}文件,得到%{count})"
39
+ other: "附加的文件太多(最大为%{max}文件,得到%{count})"
40
+ attachment_missing: "没有附件"
41
+ media_metadata_missing: "不是有效的媒体文件"
42
+ dimension_min_not_included_in: "必须大于或等于 %{width} x %{height} 像素"
43
+ dimension_max_not_included_in: "必须小于或等于 %{width} x %{height} 像素"
44
+ dimension_width_not_included_in: "宽度不在 %{min} 和 %{max} 像素之间"
45
+ dimension_height_not_included_in: "高度不在 %{min} 和 %{max} 像素之间"
46
+ dimension_width_not_greater_than_or_equal_to: "宽度必须大于或等于 %{length} 像素"
47
+ dimension_height_not_greater_than_or_equal_to: "高度必须大于或等于 %{length} 像素"
48
+ dimension_width_not_less_than_or_equal_to: "宽度必须小于或等于 %{length} 像素"
49
+ dimension_height_not_less_than_or_equal_to: "高度必须小于或等于 %{length} 像素"
50
+ dimension_width_not_equal_to: "宽度必须等于 %{length} 像素"
51
+ dimension_height_not_equal_to: "高度必须等于 %{length} 像素"
52
+ aspect_ratio_not_square: "必须为正方形(当前文件为 %{width} x%{height} 像素)"
53
+ aspect_ratio_not_portrait: "必须是纵向的(当前文件为 %{width} x%{height} 像素)"
54
+ aspect_ratio_not_landscape: "必须是横向(当前文件为 %{width} x%{height} 像素)"
55
+ expect_ratio_not_x_y: "必须为 %{authorized_aspect_ratios}(当前文件为 %{width} x%{height} 像素)"
56
+ expect_ratio_not_in_list: "具有无效的长宽比(有效长宽比为 %{authorized_aspect_ratios})"
57
+ file_not_processable: "未标识为有效的媒体文件"
58
+ pages_not_less_than: "页数必须小于 %{max}(当前页数为 %{pages})"
59
+ pages_not_less_than_or_equal_to: "页数必须小于或等于 %{max}(当前页数为 %{pages})"
60
+ pages_not_greater_than: "页数必须大于 %{min}(当前页数为 %{pages})"
61
+ pages_not_greater_than_or_equal_to: "页数必须大于或等于 %{min}(当前页数为 %{pages})"
62
+ pages_not_between: "页数必须介于 %{min} 和 %{max} 之间(当前页数为 %{pages})"
63
+ pages_not_equal_to: "页数必须等于 %{exact}(当前页数为%{pages})"
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+ require_relative "shared/asv_ff_probable"
5
+
6
+ module ActiveStorageValidations
7
+ # = ActiveStorageValidations Audio \Analyzer
8
+ #
9
+ # Extracts the following from an audio attachable:
10
+ #
11
+ # * Duration (seconds)
12
+ # * Bit rate (bits/s)
13
+ # * Sample rate (hertz)
14
+ # * Tags (internal metadata)
15
+ #
16
+ # Example:
17
+ #
18
+ # ActiveStorageValidations::Analyzer::AudioAnalyzer.new(attachable).metadata
19
+ # # => { duration: 5.0, bit_rate: 320340, sample_rate: 44100, tags: { encoder: "Lavc57.64", ... } }
20
+ #
21
+ # This analyzer requires the {FFmpeg}[https://www.ffmpeg.org] system library, which is not provided by \Rails.
22
+ class Analyzer::AudioAnalyzer < Analyzer
23
+ include ASVFFProbable
24
+
25
+ def metadata
26
+ read_media do |media|
27
+ {
28
+ duration: duration,
29
+ bit_rate: bit_rate,
30
+ sample_rate: sample_rate,
31
+ tags: tags
32
+ }.compact
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def duration
39
+ duration = audio_stream["duration"]
40
+ Float(duration).round(1) if duration
41
+ end
42
+
43
+ def bit_rate
44
+ bit_rate = audio_stream["bit_rate"]
45
+ Integer(bit_rate) if bit_rate
46
+ end
47
+
48
+ def sample_rate
49
+ sample_rate = audio_stream["sample_rate"]
50
+ Integer(sample_rate) if sample_rate
51
+ end
52
+
53
+ def tags
54
+ tags = audio_stream["tags"]
55
+ Hash(tags) if tags
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "open3"
4
+
5
+ module ActiveStorageValidations
6
+ # = ActiveStorageValidations ContentType \Analyzer
7
+ #
8
+ # Extracts the content type from an attachable. This is used to prevent content
9
+ # type spoofing.
10
+ #
11
+ # Example:
12
+ #
13
+ # ActiveStorageValidations::Analyzer::ContentTypeAnalyzer.new(attachable).content_type
14
+ # # => { content_type: "image/png" }
15
+ #
16
+ # This analyzer requires the {UNIX file}[https://en.wikipedia.org/wiki/File_(command)] command, which is not provided by \Rails. While it is available on most UNIX distributions, it may need to be installed explicitly on minimal or custom setups.
17
+ class Analyzer::ContentTypeAnalyzer < Analyzer
18
+ class FileCommandLineToolNotInstalledError < StandardError; end
19
+
20
+ def content_type
21
+ read_media do |media|
22
+ {
23
+ content_type: media
24
+ }
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def read_media
31
+ Tempfile.create(binmode: true) do |tempfile|
32
+ begin
33
+ if media(tempfile).present?
34
+ yield media(tempfile)
35
+ else
36
+ logger.info "Skipping file content_type analysis because Linux file command doesn't support the file"
37
+ nil
38
+ end
39
+ ensure
40
+ tempfile.close
41
+ end
42
+ end
43
+ rescue Errno::ENOENT
44
+ raise FileCommandLineToolNotInstalledError, "file command-line tool is not installed"
45
+ end
46
+
47
+ def media_from_path(path)
48
+ instrument("file") do
49
+ stdout, status = Open3.capture2(
50
+ "file",
51
+ "-b",
52
+ "--mime-type",
53
+ path
54
+ )
55
+
56
+ status.success? ? stdout.strip : nil
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorageValidations
4
+ # This analyzer relies on the third-party {MiniMagick}[https://github.com/minimagick/minimagick] gem.
5
+ # MiniMagick requires the {ImageMagick}[http://www.imagemagick.org] system library.
6
+ # This is the default Rails image analyzer.
7
+ class Analyzer::ImageAnalyzer::ImageMagick < Analyzer::ImageAnalyzer
8
+ private
9
+
10
+ def read_media
11
+ Tempfile.create(binmode: true) do |tempfile|
12
+ begin
13
+ if media(tempfile).valid?
14
+ yield media(tempfile)
15
+ else
16
+ logger.info "Skipping image analysis because ImageMagick doesn't support the file"
17
+ {}
18
+ end
19
+ ensure
20
+ tempfile.close
21
+ end
22
+ end
23
+ rescue MiniMagick::Error => error
24
+ logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
25
+ {}
26
+ end
27
+
28
+ def media_from_path(path)
29
+ instrument("mini_magick") do
30
+ MiniMagick::Image.new(path)
31
+ end
32
+ end
33
+
34
+ def rotated_image?(image)
35
+ %w[ RightTop LeftBottom TopRight BottomLeft ].include?(image["%[orientation]"])
36
+ end
37
+
38
+ def supported?
39
+ require "mini_magick"
40
+ true
41
+ rescue LoadError
42
+ logger.info "Skipping image analysis because the mini_magick gem isn't installed"
43
+ false
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveStorageValidations
4
+ # This analyzer relies on the third-party {ruby-vips}[https://github.com/libvips/ruby-vips] gem.
5
+ # Ruby-vips requires the {libvips}[https://libvips.github.io/libvips/] system library.
6
+ class Analyzer::ImageAnalyzer::Vips < Analyzer::ImageAnalyzer
7
+ private
8
+
9
+ def read_media
10
+ Tempfile.create(binmode: true) do |tempfile|
11
+ begin
12
+ if media(tempfile)
13
+ yield media(tempfile)
14
+ else
15
+ logger.info "Skipping image analysis because Vips doesn't support the file"
16
+ {}
17
+ end
18
+ ensure
19
+ tempfile.close
20
+ end
21
+ end
22
+ rescue ::Vips::Error => error
23
+ logger.error "Skipping image analysis due to a Vips error: #{error.message}"
24
+ {}
25
+ end
26
+
27
+ def media_from_path(path)
28
+ instrument("vips") do
29
+ begin
30
+ ::Vips::Image.new_from_file(path, access: :sequential)
31
+ rescue ::Vips::Error
32
+ # Vips throw errors rather than returning false when reading a not
33
+ # supported attachable.
34
+ # We stumbled upon this issue while reading 0 byte size attachable
35
+ # https://github.com/janko/image_processing/issues/97
36
+ nil
37
+ end
38
+ end
39
+ end
40
+
41
+ ROTATIONS = /Right-top|Left-bottom|Top-right|Bottom-left/
42
+ def rotated_image?(image)
43
+ ROTATIONS === image.get("exif-ifd0-Orientation")
44
+ rescue ::Vips::Error
45
+ false
46
+ end
47
+
48
+ def supported?
49
+ require "vips"
50
+ true
51
+ rescue LoadError
52
+ logger.info "Skipping image analysis because the ruby-vips gem isn't installed"
53
+ false
54
+ end
55
+ end
56
+ end