rocket_cms 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +2 -0
  6. data/.travis.yml +19 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +36 -0
  10. data/Rakefile +1 -0
  11. data/app/assets/javascripts/head.load.js +707 -0
  12. data/app/assets/javascripts/jquery.placeholder.js +157 -0
  13. data/app/assets/javascripts/rocket_cms.js.coffee +10 -0
  14. data/app/assets/javascripts/rocket_cms/flash.js.coffee +3 -0
  15. data/app/assets/javascripts/rocket_cms/map.js.coffee +22 -0
  16. data/app/assets/stylesheets/rocket_cms.css.sass +2 -0
  17. data/app/assets/stylesheets/rocket_cms/flash.css.sass +66 -0
  18. data/app/assets/stylesheets/rocket_cms/normalize.css.scss +406 -0
  19. data/app/controllers/concerns/no_cache.rb +12 -0
  20. data/app/controllers/concerns/rs_errors.rb +58 -0
  21. data/app/controllers/concerns/rs_menu.rb +45 -0
  22. data/app/controllers/concerns/rs_pages.rb +41 -0
  23. data/app/controllers/contacts_controller.rb +29 -0
  24. data/app/controllers/news_controller.rb +22 -0
  25. data/app/controllers/pages_controller.rb +12 -0
  26. data/app/controllers/search_controller.rb +25 -0
  27. data/app/mailers/contact_mailer.rb +15 -0
  28. data/app/models/ckeditor/asset.rb +5 -0
  29. data/app/models/ckeditor/attachment_file.rb +15 -0
  30. data/app/models/ckeditor/picture.rb +16 -0
  31. data/app/models/concerns/boolean_field.rb +9 -0
  32. data/app/models/concerns/enableable.rb +8 -0
  33. data/app/models/concerns/geocodeable.rb +4 -0
  34. data/app/models/concerns/manual_slug.rb +38 -0
  35. data/app/models/concerns/mappable.rb +77 -0
  36. data/app/models/concerns/seoable.rb +35 -0
  37. data/app/models/concerns/sort_field.rb +12 -0
  38. data/app/models/concerns/sortable.rb +8 -0
  39. data/app/models/concerns/trackable.rb +8 -0
  40. data/app/models/contact_message.rb +6 -0
  41. data/app/models/menu.rb +6 -0
  42. data/app/models/news.rb +5 -0
  43. data/app/models/page.rb +6 -0
  44. data/app/views/contact_mailer/new_message_email.html.haml +15 -0
  45. data/app/views/contacts/new.html.haml +10 -0
  46. data/app/views/contacts/sent.html.haml +4 -0
  47. data/app/views/errors/_base.html.haml +3 -0
  48. data/app/views/errors/error_403.html.haml +1 -0
  49. data/app/views/errors/error_404.html.haml +1 -0
  50. data/app/views/errors/error_500.html.haml +1 -0
  51. data/app/views/news/index.html.haml +8 -0
  52. data/app/views/news/show.html.haml +8 -0
  53. data/app/views/pages/show.html.haml +1 -0
  54. data/app/views/rails_admin/main/_check_boxes.html.haml +27 -0
  55. data/app/views/rails_admin/main/_form_raw.html.haml +1 -0
  56. data/app/views/search/index.html.haml +19 -0
  57. data/app/views/shared/_admin_link.html.haml +3 -0
  58. data/app/views/shared/_messages.html.haml +7 -0
  59. data/app/views/shared/_meta.html.haml +6 -0
  60. data/app/views/shared/_obj.html.haml +14 -0
  61. data/app/views/shared/_og.html.haml +4 -0
  62. data/config/locales/en.rocket_admin.yml +6 -0
  63. data/config/locales/en.rs.yml +17 -0
  64. data/config/locales/ru.cancan.yml +4 -0
  65. data/config/locales/ru.devise.yml +65 -0
  66. data/config/locales/ru.kaminari.yml +17 -0
  67. data/config/locales/ru.models.yml +78 -0
  68. data/config/locales/ru.mongoid.yml +450 -0
  69. data/config/locales/ru.rails_admin.yml +147 -0
  70. data/config/locales/ru.rocket_admin.yml +6 -0
  71. data/config/locales/ru.rs.yml +17 -0
  72. data/config/locales/ru.simple_captcha.yml +3 -0
  73. data/config/locales/ru.simple_form.yml +9 -0
  74. data/lib/filename_to_slug.rb +32 -0
  75. data/lib/generators/rocket_cms/admin_generator.rb +20 -0
  76. data/lib/generators/rocket_cms/templates/ability.erb +17 -0
  77. data/lib/generators/rocket_cms/templates/admin.erb +71 -0
  78. data/lib/generators/rocket_cms/utils.rb +22 -0
  79. data/lib/history_tracker.rb +4 -0
  80. data/lib/rails_admin/custom_show_in_app.rb +39 -0
  81. data/lib/rocket_cms.rb +57 -0
  82. data/lib/rocket_cms/admin.rb +128 -0
  83. data/lib/rocket_cms/configuration.rb +54 -0
  84. data/lib/rocket_cms/controller.rb +24 -0
  85. data/lib/rocket_cms/elastic_search.rb +32 -0
  86. data/lib/rocket_cms/engine.rb +4 -0
  87. data/lib/rocket_cms/model.rb +16 -0
  88. data/lib/rocket_cms/models/contact_message.rb +37 -0
  89. data/lib/rocket_cms/models/menu.rb +16 -0
  90. data/lib/rocket_cms/models/news.rb +61 -0
  91. data/lib/rocket_cms/models/page.rb +86 -0
  92. data/lib/rocket_cms/patch.rb +58 -0
  93. data/lib/rocket_cms/rails_admin_menu.rb +137 -0
  94. data/lib/rocket_cms/railtie.rb +39 -0
  95. data/lib/rocket_cms/tasks.rb +14 -0
  96. data/lib/rocket_cms/version.rb +3 -0
  97. data/lib/smart_excerpt.rb +98 -0
  98. data/rocket_cms.gemspec +50 -0
  99. metadata +533 -0
@@ -0,0 +1,35 @@
1
+ module Seoable
2
+ extend ActiveSupport::Concern
3
+ include Mongoid::Paperclip
4
+
5
+ included do
6
+ field :name, type: String
7
+ field :h1, type: String
8
+
9
+ field :title, type: String
10
+ field :keywords, type: String
11
+ field :description, type: String
12
+ field :robots, type: String
13
+
14
+ field :og_title, type: String
15
+ has_mongoid_attached_file :og_image, styles: {thumb: "800x600>"}
16
+ end
17
+
18
+ def page_title
19
+ title.blank? ? name : title
20
+ end
21
+
22
+ def get_og_title
23
+ og_title.blank? ? name : og_title
24
+ end
25
+
26
+ def self.admin
27
+ RocketCMS.seo_config
28
+ end
29
+
30
+ # deprecated
31
+ def self.seo_config
32
+ RocketCMS.seo_config
33
+ end
34
+ end
35
+
@@ -0,0 +1,12 @@
1
+ module SortField
2
+ extend ActiveSupport::Concern
3
+
4
+ module ClassMethods
5
+ def sort_field(prefix = '')
6
+ prefix = "#{prefix}_" unless prefix == ''
7
+
8
+ field "#{prefix}sort".to_sym, type: Integer
9
+ scope "#{prefix}sorted".to_sym, -> { asc("#{prefix}sort".to_sym) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Sortable
2
+ extend ActiveSupport::Concern
3
+ include SortField
4
+
5
+ included do
6
+ sort_field
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Trackable
2
+ extend ActiveSupport::Concern
3
+ include Mongoid::Audit::Trackable
4
+ included do
5
+ track_history track_create: true, track_destroy: true
6
+ end
7
+ end
8
+
@@ -0,0 +1,6 @@
1
+ class ContactMessage
2
+ include RocketCMS::Models::ContactMessage
3
+ RocketCMS.apply_patches self
4
+ rails_admin &RocketCMS.contact_message_config
5
+ end
6
+
@@ -0,0 +1,6 @@
1
+ class Menu
2
+ include RocketCMS::Models::Menu
3
+ RocketCMS.apply_patches self
4
+ rails_admin &RocketCMS.menu_config
5
+ end
6
+
@@ -0,0 +1,5 @@
1
+ class News
2
+ include RocketCMS::Models::News
3
+ RocketCMS.apply_patches self
4
+ rails_admin &RocketCMS.news_config
5
+ end
@@ -0,0 +1,6 @@
1
+ class Page
2
+ include RocketCMS::Models::Page
3
+ RocketCMS.apply_patches self
4
+ rails_admin &RocketCMS.page_config
5
+ end
6
+
@@ -0,0 +1,15 @@
1
+
2
+ - excluded_column_names = %w[id created_at updated_at _id _type enabled attachment c_at u_at captcha captcha_key version modifier modifier_id]
3
+
4
+ %h3 Сообщение из формы связи:
5
+
6
+ %table
7
+ %tr
8
+ %th(style='padding: 2px 3px') Поле
9
+ %th(style='padding: 2px 3px') Значение
10
+ - ContactMessage.fields.keys.reject{|c| excluded_column_names.include?(c) }.each do |c|
11
+ %tr
12
+ %td(style='padding: 2px 3px')
13
+ = ContactMessage.human_attribute_name(c)
14
+ %td(style='padding: 2px 3px')
15
+ = @message.send(c.to_sym)
@@ -0,0 +1,10 @@
1
+ = render 'shared/obj', obj: @seo_page
2
+
3
+ #rocket_cms_contact_form
4
+ = simple_form_for @contact_message do |f|
5
+ = f.input :name
6
+ = f.input :email
7
+ = f.input :phone
8
+ = f.input :content
9
+ = f.input :captcha
10
+ = f.submit t('rs.send')
@@ -0,0 +1,4 @@
1
+ #rocket_cms_contact_sent
2
+ %h1 Обратная связь
3
+ %h2 Ваше сообщение отправлено
4
+ %div Если оно требует ответа, мы постараемся ответить в ближайшее время
@@ -0,0 +1,3 @@
1
+ #rocket_cms_error{class: "error-#{code}"}
2
+ %h1 Ошибка #{code}
3
+ %p #{text}
@@ -0,0 +1 @@
1
+ = render 'errors/base', code: 403, text: 'Доступ запрещен'
@@ -0,0 +1 @@
1
+ = render 'errors/base', code: 404, text: 'Запрашиваемая страница была удалена, или введён некорректный адрес'
@@ -0,0 +1 @@
1
+ = render 'errors/base', code: 500, text: 'Внутренняя ошибка сервера'
@@ -0,0 +1,8 @@
1
+ .rs-news-index
2
+ %h1= t('rs.news')
3
+ - @news.each do |news|
4
+ .rs-news-date= news.time.strftime('%Y-%m-%d')
5
+ - unless RocketCMS.configuration.news_image_styles.nil?
6
+ .rs-news-image= image_tag news.image.url(:full)
7
+ .rs-news-excerpt = news.excerpt
8
+ = paginate @news
@@ -0,0 +1,8 @@
1
+ .rs-news-show
2
+ %h1.rs-news-title= @news.name
3
+ .rs-news-date= @news.time.strftime('%Y-%m-%d')
4
+ .rs-news-text = @news.excerpt
5
+ - unless RocketCMS.configuration.news_image_styles.nil?
6
+ .rs-news-image= image_tag @news.image.url(:full)
7
+ .rs-news-content
8
+ = render 'shared/obj', obj: @news
@@ -0,0 +1 @@
1
+ = render 'shared/obj', obj: @seo_page
@@ -0,0 +1,27 @@
1
+ - if params[:associations].nil?
2
+ = form.collection_check_boxes field.method_name, form.object.class.send(field.method_name).values.map { |v| [t("enumerize.#{form.object.class.name.downcase}.#{field.method_name}.#{v}"), v] }, :last, :first, {}, {} { |i| i.label( class: 'checkbox' ) { i.check_box + i.text } }
3
+ - else
4
+ :ruby
5
+ related_id = params[:associations] && params[:associations][field.name.to_s]
6
+ config = field.associated_model_config
7
+ source_abstract_model = RailsAdmin.config(form.object.class).abstract_model
8
+
9
+ if form.object.new_record? && related_id.present? && related_id != 'new'
10
+ selected = [config.abstract_model.get(related_id)]
11
+ else
12
+ selected = form.object.send(field.name)
13
+ end
14
+ selected_ids = selected.map{|s| s.send(field.associated_primary_key)}
15
+
16
+ current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update'
17
+
18
+ xhr = !field.associated_collection_cache_all
19
+
20
+ collection = if xhr
21
+ selected.map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
22
+ else
23
+ i = 0
24
+ controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
25
+ end
26
+
27
+ = form.collection_check_boxes field.method_name, collection, :last, :first, {}, {} { |i| i.label( class: 'checkbox' ) { i.check_box + i.text } }
@@ -0,0 +1 @@
1
+ = field.pretty_value
@@ -0,0 +1,19 @@
1
+ .rs-search-results
2
+ %h1 Результаты поиска
3
+ = form_tag search_path, method: :get, class: 'nav_search' do
4
+ = text_field_tag 'query', params[:query], placeholder: "Поиск"
5
+ = submit_tag 'Найти'
6
+ %ol
7
+ - any = false
8
+ - @results.each do |r|
9
+ - any = true
10
+ %li
11
+ .title= link_to (r._highlight.nil? || r._highlight['name'].nil?) ? r.name : r._highlight['name'].join(' ... ').html_safe, url_for(r)
12
+ .text
13
+ = raw (r._highlight.nil? || r._highlight['content'].nil?) ? (r.content.blank? ? '' : SmartExcerpt.truncate(r.content)) : r._highlight['content'].join(' ... ')
14
+ %span.more= link_to '', url_for(r)
15
+
16
+ - unless any
17
+ .rs-search-no-results К сожалению, ничего не найдено
18
+
19
+ = paginate @results if any
@@ -0,0 +1,3 @@
1
+ - if user_signed_in? && respond_to?(:can?) && can?(:access, :rails_admin) && can?(:edit, obj)
2
+ %div.admin_link
3
+ = link_to t('rs.edit'), rails_admin.edit_path(obj.class.model_name.i18n_key.to_s.gsub('/', '~'), obj.id), 'data-no-turbolink' => true
@@ -0,0 +1,7 @@
1
+ - unless flash.empty?
2
+ .flash
3
+ - flash.each do |type, message|
4
+ - next if message.blank?
5
+ %div{class: "message #{type}"}
6
+ %a.close_flash ×
7
+ = simple_format(message.strip)
@@ -0,0 +1,6 @@
1
+ - unless !obj.respond_to?(:keywords) || obj.keywords.blank?
2
+ %meta{name: "keywords", content: obj.keywords}/
3
+ - unless !obj.respond_to?(:description) || obj.description.blank?
4
+ %meta{name: "description", content: obj.description}/
5
+ - unless !obj.respond_to?(:robots) || obj.robots.blank?
6
+ %meta{name: "robots", content: obj.robots}/
@@ -0,0 +1,14 @@
1
+ - unless obj.nil?
2
+ .text_content
3
+ - unless obj.h1.blank?
4
+ %h1= obj.h1
5
+ - if obj.content.blank?
6
+ = raw @seo_page.page_content unless @seo_page.nil?
7
+ = render 'shared/admin_link', obj: @seo_page
8
+ - else
9
+ = raw obj.content
10
+ = render 'shared/admin_link', obj: obj
11
+
12
+ - content_for :meta do
13
+ = render 'shared/meta', obj: obj
14
+ = render 'shared/og', title: obj.get_og_title, image: obj.og_image
@@ -0,0 +1,4 @@
1
+ - if defined?(title) && !title.blank?
2
+ %meta{property: 'og:title', content: title}
3
+ - if defined?(image) && !image.blank?
4
+ %meta{property: 'og:image', content: "http://#{request.host}#{image}"}
@@ -0,0 +1,6 @@
1
+ en:
2
+ admin:
3
+ actions:
4
+ custom_show_in_app:
5
+ title: 'Show in app'
6
+ menu: "Show in app"
@@ -0,0 +1,17 @@
1
+ en:
2
+ rs:
3
+ cms: "CMS"
4
+ menu: "Menu"
5
+ settings: 'Settings'
6
+ news: 'News'
7
+ with_final_slash: "should begin with a slash"
8
+ page_url_regex: "Regular expression to check if page is current"
9
+ final_in_menu: "This link is also displayed in menu"
10
+ no_contact_info: "Please enter your phone or email so we could contact you."
11
+ map: 'Map'
12
+ edit: Edit
13
+ m:
14
+ enabled: 'added to menu "%{menu}"'
15
+ disabled: 'deleted from menu "%{menu}"'
16
+ error: "Error: %{err}"
17
+ no_id: "No ID"
@@ -0,0 +1,4 @@
1
+ en:
2
+ unauthorized:
3
+ manage:
4
+ all: "У вас нет прав на действие %{action} над %{subject}."
@@ -0,0 +1,65 @@
1
+ ru:
2
+ devise:
3
+ confirmations:
4
+ confirmed: Ваша учётная запись подтверждена. Теперь вы вошли в систему.
5
+ send_instructions: В течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи.
6
+ send_paranoid_instructions: Если ваш адрес e-mail есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по подтверждению вашей учётной записи.
7
+ failure:
8
+ already_authenticated: Вы уже вошли в систему.
9
+ inactive: Ваша учётная запись ещё не активирована.
10
+ invalid: Неверный адрес e-mail или пароль.
11
+ invalid_token: Неверный ключ аутентификации.
12
+ locked: Ваша учётная запись заблокирована.
13
+ not_found_in_database:
14
+ timeout: Ваш сеанс закончился. Пожалуйста, войдите в систему снова.
15
+ unauthenticated: Вам необходимо войти в систему или зарегистрироваться.
16
+ unconfirmed: Вы должны подтвердить вашу учётную запись.
17
+ mailer:
18
+ confirmation_instructions:
19
+ subject: Инструкции по подтверждению учётной записи
20
+ reset_password_instructions:
21
+ subject: Инструкции по восстановлению пароля
22
+ unlock_instructions:
23
+ subject: Инструкции по разблокировке учётной записи
24
+ omniauth_callbacks:
25
+ failure: Вы не можете войти в систему с учётной записью из %{kind}, т.к. "%{reason}".
26
+ success: Вход в систему выполнен с учётной записью из %{kind}.
27
+ passwords:
28
+ no_token: Доступ к этой странице возможен только по ссылке из письма о восстановлении пароля. Если Вы пришли по такой ссылке, пожалуйста убедитесь что Вы скопировали всю ссылку целиком.
29
+ send_instructions: В течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля.
30
+ send_paranoid_instructions: Если ваш адрес e-mail есть в нашей базе данных, то в течение нескольких минут вы получите письмо с инструкциями по восстановлению вашего пароля.
31
+ updated: Ваш пароль изменён. Теперь вы вошли в систему.
32
+ updated_not_active: Ваш пароль изменен.
33
+ registrations:
34
+ destroyed: До свидания! Ваша учётная запись удалена. Надеемся снова увидеть вас.
35
+ signed_up: Добро пожаловать! Вы успешно зарегистрировались.
36
+ signed_up_but_inactive: Вы успешно зарегистрированы. Однако, вы не можете войти в систему, потому что ваша учетная запись не активирована.
37
+ signed_up_but_locked: Вы успешно зарегистрированы. Однако, вы не можете войти в систему, потому что ваша учетная запись заблокирована.
38
+ signed_up_but_unconfirmed: Письмо со ссылкой для подтверждения было отправлено на ваш e-mail. Пожалуйста, перейдите по ссылке, чтобы подтвердить вашу учетную запись.
39
+ update_needs_confirmation: Вы успешно обновили данные вашей учетной записи, но нам нужно проверить ваш новый адрес e-mail. Пожалуйста, проверьте ваш почтовый ящик и перейдите по ссылке, чтобы закончить процедуру проверки вашего нового адреса e-mail.
40
+ updated: Ваша учётная запись изменена.
41
+ sessions:
42
+ signed_in: Вход в систему выполнен.
43
+ signed_out: Выход из системы выполнен.
44
+ unlocks:
45
+ send_instructions: В течение нескольких минут вы получите письмо с инструкциями по разблокировке вашей учётной записи.
46
+ send_paranoid_instructions: Если ваша учётная запись существует, то в течение нескольких минут вы получите письмо с инструкциями по её разблокировке.
47
+ unlocked: Ваша учётная запись разблокирована. Теперь вы можете войти в систему.
48
+ failure:
49
+ user:
50
+ not_found_in_database: Пользователь не найден в базе
51
+ invalid: Неверный пароль
52
+ unauthenticated: Необходимо авторизоваться
53
+ unconfirmed: 'Необходимо подтвердить адрес электронной почты'
54
+ errors:
55
+ messages:
56
+ already_confirmed: уже подтверждена. Пожалуйста, попробуйте войти в систему
57
+ confirmation_period_expired:
58
+ expired: устарела. Пожалуйста, запросите новую
59
+ not_found: не найдена
60
+ not_locked: не заблокирована
61
+ not_saved:
62
+ few: ! '%{resource}: сохранение не удалось из-за %{count} ошибок'
63
+ many: ! '%{resource}: сохранение не удалось из-за %{count} ошибок'
64
+ one: ! '%{resource}: сохранение не удалось из-за %{count} ошибки'
65
+ other: ! '%{resource}: сохранение не удалось из-за %{count} ошибки'
@@ -0,0 +1,17 @@
1
+ ru:
2
+ views:
3
+ pagination:
4
+ first: "« Начало"
5
+ last: "Конец »"
6
+ previous: "‹ Предыдущая"
7
+ next: "Следующая ›"
8
+ truncate: "…"
9
+ helpers:
10
+ page_entries_info:
11
+ one_page:
12
+ display_entries:
13
+ zero: "%{entry_name} не найдены"
14
+ one: "Показано <b>1</b> %{entry_name}"
15
+ other: "Показаны <b>все %{count}</b> %{entry_name}"
16
+ more_pages:
17
+ display_entries: "Показаны %{entry_name} <b>%{first}&nbsp;-&nbsp;%{last}</b> из <b>%{total}</b>"
@@ -0,0 +1,78 @@
1
+ ru:
2
+ attributes:
3
+ user: Пользователь
4
+ name: Название
5
+ category: Раздел
6
+ file: Файл
7
+ short: Короткое описание
8
+ text: Текст
9
+ desc: Описание
10
+ image: Картинка
11
+ href: Ссылка
12
+ enabled: Включено
13
+ slug: URL код
14
+ text_slug: URL код
15
+ c_at: Создано
16
+ u_at: Обновлено
17
+ id: ID
18
+ content: Содержимое
19
+ time: Время
20
+ excerpt: Превью
21
+ sort: Сортировка
22
+ link: Ссылка
23
+ url: URL
24
+ address: Адрес
25
+ map_address: Адрес для карты
26
+ map_hint: Подсказка для карты
27
+ coordinates: Координаты из геокодирования
28
+ lat: Широта (вручную)
29
+ lon: Долгота (вручную)
30
+ description: SEO Description
31
+ email: Email
32
+ keywords: SEO Keywords
33
+ modifier_id: Кто правил
34
+ og_title: Og title
35
+ robots: Robots
36
+ title: Title
37
+ version: Version
38
+
39
+ mongoid:
40
+ models:
41
+ user: Пользователь
42
+ menu: Меню
43
+ page: Страница
44
+ contact_message: Сообщение
45
+ news: Новость
46
+
47
+ attributes:
48
+ user:
49
+ email: E-mail
50
+ old_password: Текущий пароль
51
+ password: Пароль
52
+ password_confirmation: Подтвердите пароль
53
+ remember_me: Запомнить
54
+ c_at: Создан
55
+ current_sign_in_ip: Текущий IP
56
+ last_sign_in_ip: Прошлый IP
57
+ first_name: Имя
58
+ last_name: Фамилия
59
+ phone: Телефон
60
+
61
+ page:
62
+ fullpath: URL
63
+ regexp: Подсветка меню
64
+ redirect: Редирект
65
+ image: Картинка
66
+ hidden: Скрытая
67
+ menus: Меню
68
+ contact_message:
69
+ name: Ваше имя
70
+ email: Ваш е-мейл
71
+ phone: Ваш телефон
72
+ content: Ваше сообщение
73
+
74
+ activemodel:
75
+ errors:
76
+ messages:
77
+ invalid_email_address: Неверный e-mail
78
+