diff --git a/Gemfile b/Gemfile index 2d95ba7..9e7c4f6 100644 --- a/Gemfile +++ b/Gemfile @@ -65,6 +65,8 @@ gem 'rspec-rails' gem 'factory_bot_rails', '~> 6.4', '>= 6.4.3' gem 'faker' + +gem 'i18n' # Use Redis adapter to run Action Cable in production # gem "redis", ">= 4.0.1" diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f18faa7..da30af8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,16 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base + before_action :set_locale + + def set_locale + I18n.locale = params[:locale] || I18n.default_locale + end + + def default_url_options + { locale: I18n.locale } + end + def index @images = Image.take(5) end diff --git a/app/javascript/application.js b/app/javascript/application.js index 84859d1..b1671ba 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -1,11 +1,7 @@ -import "bootstrap" import "@hotwired/turbo-rails" -window.process = { env: { NODE_ENV: 'production' } }; import '@popperjs/core' import "popper" +import "bootstrap" import "controllers" import "./upload.js" import "./modal.js" -// import "./rails_admin.js" -// import 'rails_admin/dist/rails_admin.js'; - diff --git a/app/views/application/index.html.slim b/app/views/application/index.html.slim index b6eb9c8..2d38723 100644 --- a/app/views/application/index.html.slim +++ b/app/views/application/index.html.slim @@ -1,7 +1,9 @@ div .container-welcome - h1.title WELCOME SMOG - p.text Smog is a new platform to store and share images with everyone. You can comment or like some pictures, but for that you have to sign up. + h1.title + = t('home.welcome_title') + p.text + = t('home.welcome_description') div.carousel-container diff --git a/app/views/categories/index.html.slim b/app/views/categories/index.html.slim index 6ac0769..d6c30a4 100644 --- a/app/views/categories/index.html.slim +++ b/app/views/categories/index.html.slim @@ -9,8 +9,8 @@ div.category-container = category[:name] - if user_signed_in? - if category.subscriptions.empty? - = button_to "Subscribe", category_subscriptions_path(category), data: { turbo_method: :post }, method: :post, class: "category-btn" + = button_to t('categories.subscribe_button'), category_subscriptions_path(category), data: { turbo_method: :post }, method: :post, class: "category-btn" - else - = button_to "Unsubscribe", category_subscription_path(category, category.subscriptions[0]), data: { turbo_method: :delete }, method: :delete, class: "category-btn" + = button_to t('categories.unsubscribe_button'), category_subscription_path(category, category.subscriptions[0]), data: { turbo_method: :delete }, method: :delete, class: "category-btn" - else - = button_to "Subscribe", new_user_session_path, data: { turbo: false }, method: :get, class: "category-btn" + = button_to t('categories.subscribe_button'), new_user_session_path, data: { turbo: false }, method: :get, class: "category-btn" diff --git a/app/views/images/_modal.html.slim b/app/views/images/_modal.html.slim index 49ba608..2cb1760 100644 --- a/app/views/images/_modal.html.slim +++ b/app/views/images/_modal.html.slim @@ -8,22 +8,29 @@ = image_tag image.image.url(:thumb), id: "modalImage", class: "fixed-dimensions" .like-section p - | Likes: #{image.likes.size} + | #{t('image_info.likes_title')}: #{image.likes.size} = button_to category_image_likes_path(category.slug, image), method: :post, class: "btn btn-link" do = image_tag "like.svg", class: "like-image" .comments-container - h5 Comments + h5 + = t('image_info.likes_title') .comment-form = form_with model: [category, image, Comment.new], local: true, html: { id: 'commentForm', data: { image_id: image.id } } do |f| .form-group = recaptcha_tags .form-group - = f.label :caption + = f.label t('image_info.caption') = f.text_area :caption, class: "form-control", rows: 3 .form-group - = f.submit 'Add Comment', class: "btn btn-primary" + = f.submit t('image_info.add_comment'), class: "btn btn-primary" .comments-list = render partial: 'comments/comments_list', locals: { comments: image.comments } .modal-footer - = link_to 'Close', category_path(category.slug), class: "btn btn-secondary" + = link_to t('image_info.close_image'), category_path(category.slug), class: "btn btn-secondary" .modal-backdrop.fade.show +/ image_info: +/ comments_title: 'Коментарі' +/ caption: 'Опис' +/ add_comment: 'Додати коментар' +/ close_image: 'Закрити' +/ likes_title: 'Сподобалося' \ No newline at end of file diff --git a/app/views/images/new.html.slim b/app/views/images/new.html.slim index 166c136..481d2c4 100644 --- a/app/views/images/new.html.slim +++ b/app/views/images/new.html.slim @@ -3,7 +3,7 @@ .col-md-6 = form_with model: @image, local: true, html: { multipart: true } do |f| .form-group - = f.label :category_name, "Category Name" + = f.label :category_name, t('app_pin_page.category_input_label') = f.text_field :category_name, class: "form-control" .image-preview.hidden .form-group.upload-container @@ -11,8 +11,9 @@ label for="file-upload" span.icon i class="fas fa-arrow-up" - span.text Select a file or drag it here + span.text + = t('app_pin_page.category_recommend_text') .upload-info - | We recommend using high quality .jpg files (less than 20MB in size) + = t('app_pin_page.image_upload_info') .form-group - = f.submit 'Upload', class: 'signup-button', disabled: true + = f.submit t('app_pin_page.submit_image'), class: 'signup-button', disabled: true diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index f537e02..51a9c6a 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -9,31 +9,40 @@ html body nav.navbar.navbar-expand-lg.bg-body-tertiary .container-fluid - = link_to "SMOG", root_path, class: "navbar-brand order-0" button.navbar-toggler.order-1 type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation" span.navbar-toggler-icon #navbarText.collapse.navbar-collapse.order-2 - ul.navbar-nav.ms-auto.mb-2.mb-lg-0 + ul.navbar-nav.me-auto.mb-2.mb-lg-0 li.nav-item - = link_to "Home", root_path, class: "nav-link #{'active' if current_page?(root_path)}", aria: { current: "page" }, data: { turbo: false } + = link_to t('navigator.home'), root_path, class: "nav-link #{'active' if current_page?(root_path)}", aria: { current: "page" }, data: { turbo: false } li.nav-item - = link_to "Explore", images_path, class: "nav-link #{'active' if current_page?(images_path)}", data: { turbo: false } + = link_to t('navigator.explore'), images_path, class: "nav-link #{'active' if current_page?(images_path)}", data: { turbo: false } - if user_signed_in? li.nav-item - = link_to "Add pin", new_image_path, class: "nav-link #{'active' if current_page?(new_image_path)}", data: { turbo: false } - li.nav-item - = link_to "Categories", categories_path, class: "nav-link #{'active' if current_page?(categories_path)}", data: { turbo: false } - li.nav-item - = link_to "Profile", edit_user_registration_path, class: "nav-link #{'active' if current_page?(edit_user_registration_path)}", data: { turbo: false } + = link_to t('navigator.add_pin'), new_image_path, class: "nav-link #{'active' if current_page?(new_image_path)}", data: { turbo: false } + li.nav-item + = link_to t('navigator.category'), categories_path, class: "nav-link #{'active' if current_page?(categories_path)}", data: { turbo: false } + li.nav-item + = link_to t('navigator.profile'), edit_user_registration_path, class: "nav-link #{'active' if current_page?(edit_user_registration_path)}", data: { turbo: false } + li.nav-item.dropdown + a.nav-link.dropdown-toggle href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false" + = t('language') + ul.dropdown-menu aria-labelledby="languageDropdown" + li + = link_to "English", url_for(locale: 'en'), class: "dropdown-item" + li + = link_to "Українська", url_for(locale: 'ua'), class: "dropdown-item" + ul.navbar-nav.ms-auto li.nav-item - if user_signed_in? - = link_to "Log out", destroy_user_session_path, data: { turbo_method: :delete }, class: "btn-signup" + = link_to t('navigator.log_out'), destroy_user_session_path, data: { turbo_method: :delete }, class: "btn-signup" - else - = link_to "Sign up", new_user_registration_path, class: "btn-signup" + = link_to t('navigator.sign_up'), new_user_registration_path, class: "btn-signup" + div = yield footer.footer .footer-content - | Smog developed by + = t('footer.developed_by') a href="https://github.com/kkkiikkk" target="_blank" kkkiikkk diff --git a/config/application.rb b/config/application.rb index 094d0f4..ef03a91 100644 --- a/config/application.rb +++ b/config/application.rb @@ -23,6 +23,10 @@ class Application < Rails::Application config.active_job.queue_adapter = :resque config.action_dispatch.cookies_same_site_protection = :none config.action_controller.default_protect_from_forgery = false if ENV['RAILS_ENV'] == 'development' + config.i18n.default_locale = :ua + config.i18n.available_locales = [:en, :ua] + config.i18n.fallbacks = true + # Configuration for the application, engines, and railties goes here. # diff --git a/config/locales/devise.ua.yml b/config/locales/devise.ua.yml new file mode 100644 index 0000000..4137eba --- /dev/null +++ b/config/locales/devise.ua.yml @@ -0,0 +1,63 @@ +ua: + devise: + confirmations: + confirmed: "Ваша електронна адреса успішно підтверджена." + send_instructions: "Ви отримаєте лист із інструкціями, як підтвердити вашу електронну адресу, через кілька хвилин." + send_paranoid_instructions: "Якщо ваша електронна адреса існує в нашій базі даних, ви отримаєте лист із інструкціями щодо підтвердження вашої електронної адреси через кілька хвилин." + failure: + already_authenticated: "Ви вже увійшли в систему." + inactive: "Ваш акаунт ще не активовано." + invalid: "Невірний %{authentication_keys} або пароль." + locked: "Ваш акаунт заблоковано." + last_attempt: "У вас залишилась одна спроба перед блокуванням акаунту." + not_found_in_database: "Невірний %{authentication_keys} або пароль." + timeout: "Сеанс закінчився. Будь ласка, увійдіть знову, щоб продовжити." + unauthenticated: "Ви повинні увійти або зареєструватися перед продовженням." + unconfirmed: "Ви повинні підтвердити свою електронну адресу перед продовженням." + mailer: + confirmation_instructions: + subject: "Інструкції щодо підтвердження" + reset_password_instructions: + subject: "Інструкції щодо скидання пароля" + unlock_instructions: + subject: "Інструкції щодо розблокування" + email_changed: + subject: "Електронна адреса змінена" + password_change: + subject: "Пароль змінено" + omniauth_callbacks: + failure: "Не вдалося автентифікувати вас через %{kind}, тому що \"%{reason}\"." + success: "Успішно автентифіковано через обліковий запис %{kind}." + passwords: + no_token: "Ви не можете отримати доступ до цієї сторінки без посилання на скидання пароля. Якщо ви прийшли з листа про скидання пароля, переконайтеся, що ви використали повний URL, наданий у листі." + send_instructions: "Ви отримаєте лист із інструкціями щодо скидання пароля через кілька хвилин." + send_paranoid_instructions: "Якщо ваша електронна адреса існує в нашій базі даних, ви отримаєте посилання на відновлення пароля на свою електронну адресу через кілька хвилин." + updated: "Ваш пароль успішно змінено. Ви тепер увійшли в систему." + updated_not_active: "Ваш пароль успішно змінено." + registrations: + destroyed: "До побачення! Ваш акаунт успішно скасовано. Сподіваємося побачити вас знову незабаром." + signed_up: "Ласкаво просимо! Ви успішно зареєструвалися." + signed_up_but_inactive: "Ви успішно зареєструвалися. Однак ми не змогли вас увійти, оскільки ваш акаунт ще не активовано." + signed_up_but_locked: "Ви успішно зареєструвалися. Однак ми не змогли вас увійти, оскільки ваш акаунт заблоковано." + signed_up_but_unconfirmed: "Повідомлення з посиланням на підтвердження було надіслано на вашу електронну адресу. Будь ласка, перейдіть за посиланням, щоб активувати свій акаунт." + update_needs_confirmation: "Ви успішно оновили свій акаунт, але нам потрібно підтвердити вашу нову електронну адресу. Будь ласка, перевірте свою електронну пошту та перейдіть за посиланням для підтвердження нової електронної адреси." + updated: "Ваш акаунт успішно оновлено." + updated_but_not_signed_in: "Ваш акаунт успішно оновлено, але оскільки ваш пароль був змінений, вам потрібно увійти знову." + sessions: + signed_in: "Ви успішно увійшли в систему." + signed_out: "Ви успішно вийшли з системи." + already_signed_out: "Ви успішно вийшли з системи." + unlocks: + send_instructions: "Ви отримаєте лист із інструкціями, як розблокувати ваш акаунт, через кілька хвилин." + send_paranoid_instructions: "Якщо ваш акаунт існує, ви отримаєте лист із інструкціями, як розблокувати його через кілька хвилин." + unlocked: "Ваш акаунт успішно розблоковано. Будь ласка, увійдіть, щоб продовжити." + errors: + messages: + already_confirmed: "вже було підтверджено, будь ласка, спробуйте увійти в систему" + confirmation_period_expired: "потрібно підтвердити протягом %{period}, будь ласка, запросіть новий" + expired: "закінчився, будь ласка, запросіть новий" + not_found: "не знайдено" + not_locked: "не було заблоковано" + not_saved: + one: "1 помилка завадила збереженню цього %{resource}:" + other: "%{count} помилок завадили збереженню цього %{resource}:" diff --git a/config/locales/en.yml b/config/locales/en.yml index 6c349ae..fba490a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,31 +1,29 @@ -# Files in the config/locales directory are used for internationalization and -# are automatically loaded by Rails. If you want to use locales other than -# English, add the necessary files in this directory. -# -# To use the locales, use `I18n.t`: -# -# I18n.t "hello" -# -# In views, this is aliased to just `t`: -# -# <%= t("hello") %> -# -# To use a different locale, set it with `I18n.locale`: -# -# I18n.locale = :es -# -# This would use the information in config/locales/es.yml. -# -# To learn more about the API, please read the Rails Internationalization guide -# at https://guides.rubyonrails.org/i18n.html. -# -# Be aware that YAML interprets the following case-insensitive strings as -# booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings -# must be quoted to be interpreted as strings. For example: -# -# en: -# "yes": yup -# enabled: "ON" - -en: - hello: "Hello world" +en: + language: 'Language' + home: + welcome_title: 'Welcome to SMOG' + welcome_description: 'Smog is a new platform for storing and sharing images with everyone. You can comment on or like some photos, but you need to register to do so.' + navigator: + category: 'Categories' + home: 'Home' + explore: 'Explore' + profile: 'My Profile' + add_pin: 'Add Pin' + log_out: 'Log Out' + sign_up: 'Create New Account' + footer: + developed_by: 'Developed by ' + app_pin_page: + category_input_label: 'Category Name' + category_recommend_text: 'Select a file or drag it here' + image_upload_info: 'We recommend using high-quality .jpg files (size less than 20MB)' + submit_image: 'Upload' + categories: + subscribe_button: 'Subscribe' + unsubscribe_button: 'Unsubscribe' + image_info: + comments_title: 'Comments' + caption: 'Caption' + add_comment: 'Add Comment' + close_image: 'Close' + likes_title: 'Likes' diff --git a/config/locales/ua.yml b/config/locales/ua.yml new file mode 100644 index 0000000..a3b4894 --- /dev/null +++ b/config/locales/ua.yml @@ -0,0 +1,29 @@ +ua: + language: 'Мова' + home: + welcome_title: 'Вітаємо у SMOG' + welcome_description: 'Smog – це нова платформа для зберігання та обміну зображеннями з усіма. Ви можете коментувати або лайкати деякі фотографії, але для цього вам потрібно зареєструватися.' + navigator: + category: 'Категорії' + home: 'Головна' + explore: 'Досліджувати' + profile: 'Мій профіль' + add_pin: 'Додати нову картинку' + log_out: 'Вийти' + sign_up: 'Створити новий акаунт' + footer: + developed_by: 'Створено розробником ' + app_pin_page: + category_input_label: 'Назва категорії' + category_recommend_text: 'Виберіть файл або перетягніть його' + image_upload_info: 'Ми рекомендуємо використовувати файли високої якості .jpg (розмір менше 20 МБ)' + submit_image: 'Завантажити' + categories: + subscribe_button: 'Підписатись' + unsubscribe_button: 'Відписатись' + image_info: + comments_title: 'Коментарі' + caption: 'Опис' + add_comment: 'Додати коментар' + close_image: 'Закрити' + likes_title: 'Сподобалося' \ No newline at end of file