Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c54105c
added i18n gem
brauzik123 Oct 25, 2026
18c2b9d
added locale switching
brauzik123 Oct 27, 2026
996b39d
added js i18n helpers
brauzik123 Oct 27, 2026
3f765db
translated shared helpers and flash messages
brauzik123 Oct 27, 2026
e3d742a
translated shared partials
brauzik123 Oct 27, 2026
21cec38
translated story groups
brauzik123 Oct 27, 2026
e4f0c9a
translated layout and navigation
brauzik123 Oct 27, 2026
7d5d0bc
translated sign-in and login email
brauzik123 Oct 27, 2026
49685ac
translated home page and notifications
brauzik123 Oct 27, 2026
2eb83d5
translated ranking
brauzik123 Oct 27, 2026
714313c
translated students
brauzik123 Oct 27, 2026
50df516
translated student badges
brauzik123 Oct 27, 2026
8104ed0
translated currency adjustments
brauzik123 Oct 27, 2026
12e8990
translated currency history
brauzik123 Oct 27, 2026
73acc20
translated student items
brauzik123 Oct 27, 2026
1f5f1a2
translated badges
brauzik123 Oct 27, 2026
9fc9093
translated ranks
brauzik123 Oct 27, 2026
6d98713
translated items
brauzik123 Oct 27, 2026
08b11c5
translated shop
brauzik123 Oct 27, 2026
3b269ac
translated invites
brauzik123 Oct 27, 2026
9decad2
translated joining a group
brauzik123 Oct 27, 2026
5203f61
translated membership settings
brauzik123 Oct 27, 2026
750f0b2
translated teachers
brauzik123 Oct 27, 2026
e8891dd
translated sheet templates
brauzik123 Oct 27, 2026
08c61a1
translated grade sheets
brauzik123 Oct 27, 2026
9ae46fe
translated grading
brauzik123 Oct 27, 2026
253a95c
removed polish plural helper
brauzik123 Oct 27, 2026
d54a7f3
fixed deleting students and groups with notifications
brauzik123 Oct 27, 2026
9319f0c
added translations test
brauzik123 Oct 27, 2026
b971f29
fixed flaky dashboard test
brauzik123 Oct 27, 2026
4b78482
Merge branch 'main' into feature/add-translations
cub8 Oct 28, 2026
b104bab
Adjustments
cub8 Oct 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ gem 'omniauth-oauth', '~> 1.2' # OAuth 1.0
gem 'omniauth-rails_csrf_protection', '~> 2.0' # OAuth CSRF compatibility
gem 'pundit', '~> 2.5.2' # For roles managements
gem 'rack-attack', '~> 6.8.0' # For throttling incoming request in authentication
gem 'rails-i18n', '~> 8.0' # For internationalization [https://github.com/svenfuchs/rails-i18n]
gem 'rondo_form', '~> 1.0' # For nested forms
gem 'rqrcode', '~> 3.0' # For generating QR codes
gem 'tzinfo-data', '~> 1', platforms: %i[windows jruby] # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ GEM
rails-html-sanitizer (1.7.1)
loofah (~> 2.25, >= 2.25.2)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
rails-i18n (8.1.0)
i18n (>= 0.7, < 2)
railties (>= 8.0.0, < 9)
railties (8.1.3.1)
actionpack (= 8.1.3.1)
activesupport (= 8.1.3.1)
Expand Down Expand Up @@ -478,6 +481,7 @@ DEPENDENCIES
pundit (~> 2.5.2)
rack-attack (~> 6.8.0)
rails (~> 8.1.3.1)
rails-i18n (~> 8.0)
rondo_form (~> 1.0)
rqrcode (~> 3.0)
rubocop (~> 1.84)
Expand Down Expand Up @@ -615,6 +619,7 @@ CHECKSUMS
rails (8.1.3.1) sha256=ccd11a36bfc171bf9c66d585d14c0ece91c0c9dde840aae60c0118d6f5c9c52a
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
rails-html-sanitizer (1.7.1) sha256=e797a7c9b01e567307e317c576b49ab4168017e63eea4dba9ce3cb587e2f22c2
rails-i18n (8.1.0) sha256=52d5fd6c0abef28d84223cc05647f6ae0fd552637a1ede92deee9545755b6cf3
railties (8.1.3.1) sha256=2388a232579a00cefea4487de66c8553c3408c1300abdc6cf1799d86ffb04487
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
Expand Down
16 changes: 8 additions & 8 deletions app/components/shared/header_component.html.haml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
%header.gh-topbar
= link_to home_path, class: 'gh-topbar-logo', 'aria-label': 'Gamification Hub, start' do
= link_to home_path, class: 'gh-topbar-logo', 'aria-label': t('layouts.header.home') do
= image_tag 'logo.png', alt: ''
%span.gh-topbar-logo-word Gamification Hub

- if group_chrome
%button.gh-group-switcher{ type: 'button',
data: { action: 'menu#open', menu_id_param: 'gh-group-switcher' },
'aria-label': "Grupa #{group_chrome.name}, zmień grupę" }
'aria-label': t('layouts.header.switch_group', name: group_chrome.name) }
= render 'layouts/group_thumb', story_group: group_chrome.story_group, size: nil
%span.gh-group-switcher-name= group_chrome.name
%i.fa-solid.fa-chevron-down{ 'aria-hidden': 'true' }
Expand All @@ -17,21 +17,21 @@
- purse = group_chrome.student_membership
= link_to story_group_student_currency_transactions_path(group_chrome.story_group, purse),
class: 'gh-balance-button',
title: "#{purse.current_currency} do wydania, #{purse.total_currency} zebrane łącznie",
'aria-label': "Masz #{purse.current_currency} do wydania, pokaż historię waluty" do
title: t('layouts.header.balance_title', balance: purse.current_currency, total: purse.total_currency),
'aria-label': t('layouts.header.balance_label', balance: purse.current_currency) do
= render 'layouts/currency_token', story_group: group_chrome.story_group, size: 32
%span
%b= purse.current_currency
%small do wydania
%small= t('layouts.header.to_spend')

= link_to new_join_path, class: 'gh-btn gh-btn--secondary gh-btn--small gh-topbar-join-link',
data: { turbo_frame: 'modal' } do
%i.fa-solid.fa-plus
%span Dołącz do grupy
%span= t('layouts.header.join')

%button.gh-icon-button.gh-topbar-theme-toggle{ type: 'button',
data: { action: 'theme#toggle' },
'aria-label': 'Przełącz motyw' }
'aria-label': t('layouts.theme.toggle') }
%i.fa-solid.fa-moon.gh-theme-icon-moon
%i.fa-solid.fa-sun.gh-theme-icon-sun

Expand All @@ -44,6 +44,6 @@

%button.gh-avatar-button{ type: 'button',
data: { action: 'menu#open', menu_id_param: 'gh-account-menu' },
'aria-label': "Konto: #{user.full_name}" }
'aria-label': t('layouts.header.account', name: user.full_name) }
%span.gh-avatar.gh-octagon-clip{ 'data-gh-h': helpers.gh_avatar_hue(user.full_name), 'aria-hidden': 'true' }
= helpers.gh_initials(user.full_name)
4 changes: 2 additions & 2 deletions app/components/shared/header_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def unread_count
end

def bell_label
return 'Powiadomienia' if unread_count.zero?
return t('layouts.header.notifications') if unread_count.zero?

"Powiadomienia, #{unread_count} #{helpers.gh_plural(unread_count, 'nowe', 'nowe', 'nowych')}"
t('layouts.header.notifications_unread', count: unread_count)
end
end
4 changes: 2 additions & 2 deletions app/components/shared/sidebar_component.html.haml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
%aside.gh-sidebar{ class: ('gh-sidebar--collapsed' if collapsed),
data: { sidebar_target: 'sidebar' } }
%nav.gh-sidebar-nav.gh-sidebar-nav--primary{ 'aria-label': 'Główna' }
%nav.gh-sidebar-nav.gh-sidebar-nav--primary{ 'aria-label': t('layouts.sidebar.main') }
- nav_items.each do |item|
= link_to item.path, class: "gh-sidebar-link #{'gh-sidebar-link--active' if current?(item.path)}",
title: item.label, 'aria-current': ('page' if current?(item.path)) do
Expand All @@ -10,7 +10,7 @@
- if group_chrome
= render 'layouts/deck', chrome: group_chrome, current_path: current_path
- elsif groups.any?
%p.gh-sidebar-section-label Twoje grupy
%p.gh-sidebar-section-label= t('layouts.sidebar.your_groups')
.gh-sidebar-group-list
- groups.each do |story_group|
= link_to story_group_path(story_group), class: 'gh-sidebar-group-list-item', title: story_group.name do
Expand Down
4 changes: 2 additions & 2 deletions app/components/shared/sidebar_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def groups
end

def role_label(story_group)
StoryGroupsListing::ROLE_LABELS[role_for(story_group)]
t("story_groups.listing.roles.#{role_for(story_group)}")
end

def role_for(story_group)
Expand All @@ -44,7 +44,7 @@ def current?(path)
end

def toggle_label
collapsed ? 'Rozwiń' : 'Zwiń panel'
collapsed ? t('layouts.sidebar.expand') : t('layouts.sidebar.collapse')
end

def toggle_icon
Expand Down
4 changes: 2 additions & 2 deletions app/components/shared/tab_bar_component.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
%nav.gh-mobile-tabbar{ 'aria-label': 'Nawigacja' }
%nav.gh-mobile-tabbar{ 'aria-label': t('layouts.tab_bar.label') }
- items.each do |item|
- on = item.current?(current_path)
= link_to item.path, class: "gh-mobile-tab #{'gh-mobile-tab--active' if on}",
Expand All @@ -10,4 +10,4 @@
%button.gh-mobile-tab{ type: 'button',
data: { action: 'menu#open', menu_id_param: 'gh-more-sheet' } }
%i.fa-solid.fa-ellipsis
%span Więcej
%span= t('shared.actions.more')
2 changes: 1 addition & 1 deletion app/controllers/account_setups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def update
@current_user.first_login = false

if @current_user.save(context: :account_setup)
redirect_to home_path, notice: 'Pomyślnie skonfigurowano konto.'
redirect_to home_path, notice: t('account_setups.flash.done')
else
@current_user.first_login = true
render :edit, status: :unprocessable_content
Expand Down
11 changes: 7 additions & 4 deletions app/controllers/activity_group_templates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ class ActivityGroupTemplatesController < ApplicationController
def new
@activity_group_template = @story_group.activity_group_templates.build

@activity_group_template.categories.build(didactic_description: 'Obecność', reward: 2, position: 0)
@activity_group_template.categories.build(didactic_description: t('activity_group_templates.default_category'),
reward: 2,
position: 0,)
@activity_group_template.categories.build(reward: 1, position: 1)
end

Expand All @@ -28,7 +30,8 @@ def create

if @activity_group_template.save(context: :settings)
redirect_to story_group_activity_groups_path(@story_group),
notice: "Utworzono szablon „#{@activity_group_template.base_name}”.", status: :see_other
notice: t('activity_group_templates.flash.created', name: @activity_group_template.base_name),
status: :see_other
else
render :new, status: :unprocessable_content
end
Expand All @@ -39,7 +42,7 @@ def update

if @activity_group_template.save(context: :settings)
redirect_to story_group_activity_groups_path(@story_group),
notice: 'Zapisano szablon. Nowe arkusze dostaną te kategorie.', status: :see_other
notice: t('activity_group_templates.flash.updated'), status: :see_other
else
@sheet_names = sheet_names_for(@activity_group_template)
render :edit, status: :unprocessable_content
Expand All @@ -51,7 +54,7 @@ def destroy
@activity_group_template.soft_delete!

redirect_outside_turbo_frame story_group_activity_groups_path(@story_group),
notice: "Usunięto szablon „#{name}”. Utworzone z niego arkusze zostają."
notice: t('activity_group_templates.flash.destroyed', name: name)
end

private
Expand Down
9 changes: 4 additions & 5 deletions app/controllers/activity_groups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def update

if @activity_group.save(context: :settings)
redirect_to story_group_activity_groups_path(@story_group),
notice: "Zapisano ustawienia arkusza #{@activity_group.name}.", status: :see_other
notice: t('activity_groups.flash.updated', name: @activity_group.name), status: :see_other
else
render :edit, status: :unprocessable_content
end
Expand All @@ -54,8 +54,7 @@ def destroy
@activity_group.soft_delete!

redirect_outside_turbo_frame story_group_activity_groups_path(@story_group),
notice: "Usunięto arkusz #{name}. " \
'Przyznane nagrody zostają w historii studentów.'
notice: t('activity_groups.flash.destroyed', name: name)
end

private
Expand Down Expand Up @@ -87,9 +86,9 @@ def bulk_count
end

def created_notice(sheets)
return "Utworzono: #{sheets.first.name}." if sheets.one?
return t('activity_groups.flash.created_one', name: sheets.first.name) if sheets.one?

"Utworzono: #{sheets.first.name} – #{sheets.last.name}."
t('activity_groups.flash.created_many', first: sheets.first.name, last: sheets.last.name)
end

def columns_changed?
Expand Down
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

class ApplicationController < ActionController::Base
include Pundit::Authorization
include Localization
include Authentication
include Sidebar
include StatusRedirects
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/auth/passwordless_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def verify
token = params.expect(:token)
login_token = LoginToken.find_by_token(token)

return redirect_to login_path, alert: 'Nieprawidłowy token' if login_token.nil? || login_token.expired?
return redirect_to login_path, alert: t('auth.flash.invalid_token') if login_token.nil? || login_token.expired?

user = login_token.user
user.consume_login_token!
Expand Down Expand Up @@ -61,7 +61,7 @@ def create
session[:pending_login_email] = email
session[:pending_login_sent_at] = Time.current.to_i

notice = 'Wysłaliśmy nowy link. Poprzedni już nie działa.' if resend
notice = t('auth.flash.resent') if resend
redirect_to auth_passwordless_inbox_path, notice: notice
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/auth/usos_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ def create

sign_in_and_redirect(user)
rescue InvalidProviderError
redirect_to root_path, alert: 'Nieprawidłowy dostawca logowania.'
redirect_to root_path, alert: t('auth.flash.invalid_provider')
rescue Providers::InvalidAuthError
redirect_to root_path, alert: 'Nieprawidłowa próba autoryzacji.'
redirect_to root_path, alert: t('auth.flash.invalid_auth')
end

private
Expand Down
7 changes: 3 additions & 4 deletions app/controllers/badges_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def create
@badge = @story_group.badges.build(badge_params)

if @badge.save
redirect_to story_group_badges_path(@story_group), notice: "Dodano odznakę „#{@badge.name}”."
redirect_to story_group_badges_path(@story_group), notice: t('badges.flash.created', name: @badge.name)
else
set_shelf
render :new, status: :unprocessable_content
Expand All @@ -41,7 +41,7 @@ def create

def update
if @badge.update(badge_params)
redirect_to story_group_badges_path(@story_group), notice: "Zapisano odznakę „#{@badge.name}”."
redirect_to story_group_badges_path(@story_group), notice: t('badges.flash.updated', name: @badge.name)
else
set_shelf
render :edit, status: :unprocessable_content
Expand All @@ -53,8 +53,7 @@ def destroy
@badge.soft_delete!

redirect_outside_turbo_frame story_group_badges_path(@story_group),
notice: "Usunięto odznakę „#{name}”. Studenci, " \
'którzy ją mają, zachowują ją w historii.'
notice: t('badges.flash.destroyed', name: name)
end

private
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/concerns/auth/sign_in.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def sign_in_and_redirect(user)
reset_session
session[:user_id] = user.id

redirect_to after_login_path(return_to), notice: 'Zalogowano pomyślnie.'
redirect_to after_login_path(return_to), notice: t('auth.flash.signed_in')
end

def after_login_path(path)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def authenticate!
return if @current_user

store_return_path
redirect_to login_path, alert: 'Zaloguj się, aby kontynuować.'
redirect_to login_path, alert: t('application.flash.log_in_first')
end

def store_return_path
Expand Down
33 changes: 33 additions & 0 deletions app/controllers/concerns/localization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Localization
extend ActiveSupport::Concern

LOCALE_COOKIE = :locale

included do
around_action :switch_locale
end

protected

# A block keeps the locale from leaking into the next request served by the same thread.
def switch_locale(&)
I18n.with_locale(requested_locale, &)
end

def requested_locale
[cookies[LOCALE_COOKIE], browser_locale].find { |locale| available_locale?(locale) } || I18n.default_locale
end

# "en-US,en;q=0.9,pl;q=0.8" -> "en". Browsers list languages in order of preference.
def browser_locale
request.headers['Accept-Language'].to_s.split(',')
.map { |entry| entry.strip.first(2).downcase }
.find { |locale| available_locale?(locale) }
end

def available_locale?(locale)
I18n.available_locales.map(&:to_s).include?(locale.to_s)
end
end
2 changes: 1 addition & 1 deletion app/controllers/concerns/logged_user_redirector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module LoggedUserRedirector
def redirect_logged_user
redirect_to root_path, alert: 'Jesteś już zalogowany.' if @current_user
redirect_to root_path, alert: t('application.flash.already_signed_in') if @current_user
end
end
4 changes: 2 additions & 2 deletions app/controllers/concerns/status_redirects.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module StatusRedirects
protected

def record_not_found
redirect_to root_path, alert: 'Nie znaleziono.'
redirect_to root_path, alert: t('application.flash.not_found')
end

def not_authorized
redirect_to root_path, alert: 'Nie znaleziono.'
redirect_to root_path, alert: t('application.flash.not_found')
end
end
4 changes: 2 additions & 2 deletions app/controllers/currency_adjustments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def set_presentation
end

def notice_for(form)
verb = form.positive? ? 'Dodano' : 'Odjęto'
key = form.positive? ? 'added' : 'taken'

"#{verb} #{form.value}. Saldo: #{@student.reload.current_currency}."
t("currency_adjustments.flash.#{key}", value: form.value, balance: @student.reload.current_currency)
end
end
2 changes: 1 addition & 1 deletion app/controllers/currency_transactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def set_student
end

def ledger_kind
kinds = CurrencyLedger::KINDS.map(&:first).compact
kinds = CurrencyLedger::KINDS.compact
kinds.include?(params[:kind]) ? params[:kind] : nil
end
end
Loading
Loading