From d3a7f14a143e177f4febb757516079a02cb2a799 Mon Sep 17 00:00:00 2001 From: Yanick Minder <79108296+kcinay055679@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:29:14 +0200 Subject: [PATCH] Feature/728 language clean up (#743) * create language selector dropdown * translate languages * change position of selector * add translations check * add attr translation for object * update translations for people profile and add cancel form button * add translations for people_skills and language select * fix human_attribute_name method * use instance for translations * add translation for sv_export * Update translate and action_link helper * update translations * add more action_link helper * update translations till _cv.html * Fix translations for people * update translations for people_skills * translate all person_relations * update translations for admin panel * update skills translations * add custom rubocop * finish translations * update translations * add missing translations for everything * start adding custom scanner * update i18n-tasks config * normalize translation files * add missing tranlatins * Fix failing tests * fix complex tests * try to fix people skills * add translations and fix tests * add french tranlatiions * fix search * fix tests * make rubocop happy * fix language selector and belive * language gets persistend after changing person * fix i18n tests * fix all failing tests * improve person routing behavior * improve translations * fix i18n-tasks * fix topbar * add translations via url path * Fix bug related to the new way to set locale * update locale files * fix rspec locale bug * fix failing tests * normalize locale files * clean up * normalize locale files * Make rubocop happy * Implement feedback * fix translation of adminpanel and fix export icon * use tabbar partial for main navbar and improve tabbar * works * fix translations of cv search * clean up language files * update translations * simplify routing logic * simplify i18n helper logic * regenerate language files * clean up translations * start fixing cv search * fix translations * translate people skills search * fix people_skills search * reimplement placeholder in skills_search * fix translations * fix all tests * normalize files * add routing and tabbar specs * readd instant login for keycloak * Fix controller specs * use options_for_select in people_search * clean up people search * add tests to check lanugage selection * fix routing and tabbar specs * add translation for tabbar * add more model translations * change name of cancel.svg and use correct language to display language * Return languages capitalized for language dropdown --------- Co-authored-by: Robin Steiner --- .rubocop.yml | 4 + Gemfile | 1 + Gemfile.lock | 14 + app/assets/images/{x.svg => cancel.svg} | 0 app/assets/stylesheets/crud.scss | 3 + app/assets/stylesheets/styles.scss | 10 + app/controllers/application_controller.rb | 16 +- app/controllers/people_controller.rb | 5 +- .../people_skills/filter_params.rb | 2 +- app/domain/people_search.rb | 3 +- app/exporters/odt/cv.rb | 2 +- app/helpers/actions_helper.rb | 22 +- app/helpers/auth_helper.rb | 9 + app/helpers/cv_search_helper.rb | 5 +- app/helpers/date_helper.rb | 2 +- app/helpers/dry_crud/form/builder.rb | 2 +- app/helpers/i18n_helper.rb | 5 +- app/helpers/person_helper.rb | 8 + app/helpers/select_helper.rb | 10 +- app/helpers/tab_helper.rb | 29 +- .../controllers/dropdown_controller.js | 5 +- app/javascript/controllers/index.js | 3 - .../controllers/profile_tab_controller.js | 20 - app/models/concerns/daterange_model.rb | 2 +- app/models/language_skill.rb | 2 +- app/models/person.rb | 2 +- app/models/person_role.rb | 2 +- app/views/activities/_form.html.haml | 4 +- app/views/admin/companies/index.html.haml | 2 +- app/views/admin/departments/index.html.haml | 2 +- app/views/admin/roles/index.html.haml | 2 +- app/views/advanced_trainings/_form.html.haml | 2 +- .../application/_daterange_picker.html.haml | 10 +- .../_edit_interest_stars.html.haml | 2 +- .../application/_error_banners.html.haml | 9 +- .../_show_interest_stars.html.haml | 2 +- app/views/application/_tabbar.html.haml | 8 +- app/views/crud/show.html.haml | 2 - app/views/cv_search/index.html.haml | 17 +- app/views/devise/sessions/new.html.haml | 8 +- app/views/educations/_form.html.haml | 4 +- app/views/layouts/application.html.haml | 26 +- app/views/layouts/person.html.haml | 6 +- app/views/people/_core_competences.html.haml | 5 +- app/views/people/_cv.html.haml | 8 +- app/views/people/_form.html.haml | 63 ++-- .../people/_language_skill_fields.html.haml | 11 +- .../people/_person_role_fields.html.haml | 4 +- app/views/people/_profile.html.haml | 53 ++- app/views/people/_scroll_to_menu.html.haml | 5 +- app/views/people/_search.html.haml | 10 +- app/views/people/_skills.html.haml | 5 - .../people/competence_notes/_show.html.haml | 3 +- .../people/competence_notes/edit.html.haml | 4 +- .../people/export_cv/_export_form.html.haml | 17 +- app/views/people/index.html.haml | 8 +- app/views/people/new.html.haml | 2 +- .../people/people_skills/_edit_form.html.haml | 12 +- .../people/people_skills/_form.html.haml | 15 +- .../people/people_skills/_overview.html.haml | 9 +- .../people/people_skills/index.html.haml | 13 +- app/views/people/people_skills/new.html.haml | 2 +- .../people/person_relations/_form.html.haml | 6 +- .../people/person_relations/_index.html.haml | 4 +- .../people_skills/_person_skill.html.haml | 6 +- .../people_skills/_search_form.html.haml | 8 +- .../people_skills/filter_form/index.html.haml | 9 +- app/views/people_skills/index.html.haml | 13 +- app/views/projects/_form.html.haml | 8 +- app/views/projects/_project.html.haml | 6 +- app/views/shared/_error_messages.html.haml | 6 - app/views/skills/_header.html.haml | 17 +- app/views/skills/_row.html.haml | 5 +- app/views/skills/edit.html.haml | 6 +- app/views/skills/index.html.haml | 22 +- app/views/skills/new.html.haml | 2 +- app/views/skills/show.html.haml | 13 +- config/application.rb | 1 + config/environments/test.rb | 2 +- config/i18n-tasks.yml | 186 ++++++++++ config/initializers/skills_form_builder.rb | 23 ++ config/locales/crud.de.yml | 84 ++--- config/locales/crud.en.yml | 84 ++--- config/locales/crud.fr.yml | 48 +++ config/locales/crud.it.yml | 84 ++--- config/locales/de.yml | 343 ++++++++++++------ config/locales/devise.de.yml | 11 +- config/locales/devise.en.yml | 125 ++++--- config/locales/devise.fr.yml | 42 +++ config/locales/devise.it.yml | 42 +++ config/locales/en.yml | 318 +++++++++++----- config/locales/fr.yml | 255 +++++++++++++ config/locales/it.yml | 255 +++++++++++++ config/routes.rb | 97 ++--- lib/custom_cops/translated_haml_files.rb | 23 ++ .../api/people/picture_controller_spec.rb | 4 +- .../api/people/search_controller_spec.rb | 2 +- .../people/picture_controller_spec.rb | 6 +- .../people_skills_controller_spec.rb | 2 +- spec/domain/people_search_spec.rb | 4 +- spec/features/activities_spec.rb | 4 +- spec/features/advanced_trainings_spec.rb | 8 +- spec/features/auth_spec.rb | 2 +- spec/features/core_competences_spec.rb | 23 +- spec/features/cv_search_spec.rb | 34 +- spec/features/edit_people_skills_spec.rb | 6 +- spec/features/people_skill_search_spec.rb | 8 +- spec/features/people_spec.rb | 38 +- spec/features/projects_spec.rb | 4 +- spec/features/routing_spec.rb | 44 +++ spec/features/skills_controller_spec.rb | 7 +- spec/features/tabbar_spec.rb | 81 +++++ spec/i18n_spec.rb | 36 ++ spec/models/activity_spec.rb | 2 +- spec/models/advanced_training_spec.rb | 2 +- spec/models/education_spec.rb | 2 +- spec/models/language_skill_spec.rb | 2 +- spec/models/people_role_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/rails_helper.rb | 11 + spec/serializer/error_serializer_spec.rb | 2 +- spec/support/default_params.rb | 25 ++ spec/support/people_skills_helper.rb | 2 +- spec/support/utilities_helpers.rb | 5 + 124 files changed, 2261 insertions(+), 806 deletions(-) rename app/assets/images/{x.svg => cancel.svg} (100%) delete mode 100644 app/javascript/controllers/profile_tab_controller.js delete mode 100644 app/views/people/_skills.html.haml delete mode 100644 app/views/shared/_error_messages.html.haml create mode 100644 config/i18n-tasks.yml create mode 100644 config/initializers/skills_form_builder.rb create mode 100644 config/locales/crud.fr.yml create mode 100644 config/locales/devise.fr.yml create mode 100644 config/locales/devise.it.yml create mode 100644 config/locales/fr.yml create mode 100644 config/locales/it.yml create mode 100644 lib/custom_cops/translated_haml_files.rb create mode 100644 spec/features/routing_spec.rb create mode 100644 spec/features/tabbar_spec.rb create mode 100644 spec/i18n_spec.rb create mode 100644 spec/support/default_params.rb create mode 100644 spec/support/utilities_helpers.rb diff --git a/.rubocop.yml b/.rubocop.yml index 0ac9954f0..9996a534e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,6 +3,7 @@ require: - rubocop-rspec - rubocop-capybara - rubocop-rspec_rails + - ./lib/custom_cops/translated_haml_files AllCops: NewCops: enable @@ -177,3 +178,6 @@ Style/FrozenStringLiteralComment: Style/Attr: Enabled: false + +CustomCops/TranslatedHamlFiles: + Enabled: true \ No newline at end of file diff --git a/Gemfile b/Gemfile index 3c1141a4e..e42c550c0 100644 --- a/Gemfile +++ b/Gemfile @@ -56,6 +56,7 @@ group :development, :test do # Call 'byebug' anywhere in the code # to stop execution and get a debugger console gem 'byebug', platform: :mri + gem 'i18n-tasks', '~> 1.0.14' gem 'pry' gem 'pry-byebug' gem 'rspec-rails' diff --git a/Gemfile.lock b/Gemfile.lock index d0acd4e66..bc69ba0ed 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -167,11 +167,22 @@ GEM rubocop (>= 1.0) sysexits (~> 1.1) hashie (5.0.0) + highline (3.0.1) http-accept (1.7.0) http-cookie (1.0.5) domain_name (~> 0.5) i18n (1.14.5) concurrent-ruby (~> 1.0) + i18n-tasks (1.0.14) + activesupport (>= 4.0.2) + ast (>= 2.1.0) + erubi + highline (>= 2.0.0) + i18n + parser (>= 3.2.2.1) + rails-i18n + rainbow (>= 2.2.2, < 4.0) + terminal-table (>= 1.5.1) i18n_data (0.17.1) simple_po_parser (~> 1.1) image_processing (1.12.2) @@ -428,6 +439,8 @@ GEM strscan (3.1.0) sysexits (1.2.0) temple (0.10.3) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) thor (1.3.1) tilt (2.3.0) timeout (0.4.1) @@ -475,6 +488,7 @@ DEPENDENCIES faker haml-rails haml_lint + i18n-tasks (~> 1.0.14) i18n_data jsbundling-rails language_list diff --git a/app/assets/images/x.svg b/app/assets/images/cancel.svg similarity index 100% rename from app/assets/images/x.svg rename to app/assets/images/cancel.svg diff --git a/app/assets/stylesheets/crud.scss b/app/assets/stylesheets/crud.scss index e9436c96d..7587b432e 100644 --- a/app/assets/stylesheets/crud.scss +++ b/app/assets/stylesheets/crud.scss @@ -48,6 +48,7 @@ footer { height: 16px; display: inline-block; background: no-repeat; + background-position: center; vertical-align: top; } @@ -56,3 +57,5 @@ footer { .icon-pencil { background-image: url('assets/pencil-square.svg'); } .icon-list { background-image: url('assets/list.png'); } .icon-zoom-in { background-image: url('assets/search.svg'); } +.icon-export { background-image: url('assets/export.svg'); } +.icon-close { background-image: url('assets/cancel.svg'); } diff --git a/app/assets/stylesheets/styles.scss b/app/assets/stylesheets/styles.scss index b9950c658..93771ffb9 100644 --- a/app/assets/stylesheets/styles.scss +++ b/app/assets/stylesheets/styles.scss @@ -25,6 +25,16 @@ $skills-dark-blue: #1e5a96; cursor: pointer; } +.skills-navbar{ + .nav-link { + color: white; + @extend .px-2; + &.active { + background-color: $skills-dark-blue; + } + } +} + .navbar { flex-direction: row; list-style-type: none; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 190a52559..19a4a35ea 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,8 +2,14 @@ class ApplicationController < ActionController::Base before_action :authenticate_auth_user! - before_action :set_first_path! + around_action :switch_locale + default_form_builder SkillsFormBuilder + + def switch_locale(&) + locale = params[:locale] || I18n.default_locale + I18n.with_locale(locale, &) + end def authenticate_auth_user! return super if helpers.devise? @@ -14,10 +20,6 @@ def authenticate_auth_user! request.env['warden'].set_user(admin, :scope => :auth_user) end - def set_first_path! - @first_path = Pathname(request.path).each_filename.to_a.map { |e| "/#{e}" }.first - end - def render_unauthorized_not_admin render_unauthorized(helpers.admin?) end @@ -39,4 +41,8 @@ def render_error(title_key, body_key, status = :bad_request) body: translate("devise.failure.#{body_key}") }, :status => status end + + def default_url_options + { locale: I18n.locale } + end end diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index 6d1fed1b8..34a5c9266 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -8,8 +8,6 @@ class PeopleController < CrudController self.permitted_attrs = [:birthdate, :location, :marital_status, :updated_by, :name, :nationality, :nationality2, :title, :competence_notes, :company_id, :email, :department_id, :shortname, :picture, :picture_cache, - { person_roles_attributes: [:role_id, :person_role_level_id, - :percent, :id, :_destroy] }, { person_roles_attributes: [:role_id, :person_role_level_id, :percent, :id, :_destroy] }, { language_skills_attributes: @@ -17,7 +15,7 @@ class PeopleController < CrudController layout 'person', only: [:show] def index - return flash[:alert] = I18n.t('errors.profile-not-found') if params[:alert].present? + return flash[:alert] = I18n.t('errors.messages.profile-not-found') if params[:alert].present? super end @@ -60,6 +58,7 @@ def export disposition: content_disposition('attachment', filename) end + private def fetch_entries diff --git a/app/controllers/people_skills/filter_params.rb b/app/controllers/people_skills/filter_params.rb index 13b8c66af..ce5a4d971 100644 --- a/app/controllers/people_skills/filter_params.rb +++ b/app/controllers/people_skills/filter_params.rb @@ -40,7 +40,7 @@ def interest_of_row(row_id) end def skill_of_row(row_id) - skill_ids.nil? ? nil : skill_ids[row_id].to_i + skill_ids[row_id]&.to_i end def query_params diff --git a/app/domain/people_search.rb b/app/domain/people_search.rb index e2b062588..209ac227a 100644 --- a/app/domain/people_search.rb +++ b/app/domain/people_search.rb @@ -21,7 +21,8 @@ def search_result people.map do |p| found_in(p).each do |result| - results.push({ person: { id: p.id, name: p.name }, found_in: result }) + translated_attr = Person.human_attribute_name(result, count: 2) + results.push({ person: { id: p.id, name: p.name }, found_in: translated_attr }) end end results diff --git a/app/exporters/odt/cv.rb b/app/exporters/odt/cv.rb index 3f8da86d5..858bc56ce 100644 --- a/app/exporters/odt/cv.rb +++ b/app/exporters/odt/cv.rb @@ -175,7 +175,7 @@ def insert_core_competences(report) # rubocop:enable Metrics/MethodLength def skills_by_level(level_value) - person.people_skills.where('level >= ?', level_value) + person.people_skills.where(level: level_value..) end def competence_notes_list diff --git a/app/helpers/actions_helper.rb b/app/helpers/actions_helper.rb index e29918854..c1c9f0395 100644 --- a/app/helpers/actions_helper.rb +++ b/app/helpers/actions_helper.rb @@ -53,10 +53,28 @@ def index_action_link(path = nil, url_options = { returning: true }) # Standard add action to given path. # Uses the current +model_class+ if no path is given. - def add_action_link(path = nil, url_options = {}) + def add_action_link(path = nil, url_options = {}, html_options = {}) path ||= path_args(model_class) path = new_polymorphic_path(path, url_options) unless path.is_a?(String) - action_link(ti('link.add'), 'plus', path) + action_link(ti('link.add'), 'plus', path, html_options) end + def add_action_link_modal(path = nil, url_options = {}) + path ||= path_args(model_class) + path = new_polymorphic_path(path, url_options) unless path.is_a?(String) + options = { data: { turbo_frame: 'remote_modal' } } + action_link(ti('link.add'), 'plus', path, options) + end + + def export_action_link(path, options = {}) + action_link(ti('link.export'), 'export', path, options) + end + + def close_action_link(path, options = {}) + action_link('', 'close', path, options) + end + + def cancel_action_link(path, options = {}) + action_link(ti('link.cancel'), '', path, options) + end end diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 2d98e159f..4de63080c 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module AuthHelper + def session_path(_scope) new_auth_user_session_path end @@ -21,4 +22,12 @@ def find_person_by_auth_user def devise? AuthConfig.keycloak? || Rails.env.test? end + + def language_selector + languages = I18n.available_locales.map { |e| e.to_s }.map do |lang_code| + language = I18nData.languages(lang_code)[lang_code.upcase] + [language.capitalize, url_for(locale: lang_code)] + end + options_for_select(languages, url_for(locale: I18n.locale)) + end end diff --git a/app/helpers/cv_search_helper.rb b/app/helpers/cv_search_helper.rb index ff69c808a..9c3f2eab5 100644 --- a/app/helpers/cv_search_helper.rb +++ b/app/helpers/cv_search_helper.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true module CvSearchHelper - def translate_found_in(result) - I18n.t("cv_search.#{result[:found_in].underscore}") - end def found_in_skills?(result) - result[:found_in].include?('skills') + result[:found_in].include?('Skills') end end diff --git a/app/helpers/date_helper.rb b/app/helpers/date_helper.rb index 259902ecd..4f9bf098b 100644 --- a/app/helpers/date_helper.rb +++ b/app/helpers/date_helper.rb @@ -12,7 +12,7 @@ def months def date_range_end_label(model_with_dates) if model_with_dates&.till_today? - return "- #{t('date_range_picker.today')}" + return "- #{ti('date.today')}" elsif !(model_with_dates.same_year? && model_with_dates.same_month?) return "- #{months[model_with_dates&.month_to || 0]} #{model_with_dates&.year_to}" end diff --git a/app/helpers/dry_crud/form/builder.rb b/app/helpers/dry_crud/form/builder.rb index 05b57cd98..8a3d71baa 100644 --- a/app/helpers/dry_crud/form/builder.rb +++ b/app/helpers/dry_crud/form/builder.rb @@ -150,7 +150,7 @@ def has_many_field(attr, html_options = {}) # Render the error messages for the current form. def error_messages - @template.render('shared/error_messages', + @template.render('application/error_banners', errors: @object.errors, object: @object) end diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index bd256f2ab..b2d82bd1d 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -12,11 +12,12 @@ module I18nHelper # - {parent_controller}.global.{key} # - ... # - global.{key} - def translate_inheritable(key, variables = {}) + def translate_inheritable(key, variables = {}) # rubocop:disable Metrics/CyclomaticComplexity partial = defined?(@virtual_path) ? @virtual_path.gsub(/.*\/_?/, '') : nil defaults = inheritable_translation_defaults(key, partial) variables[:default] ||= defaults - t(defaults.shift, **variables) + variables[:model] ||= model_class&.model_name&.human if respond_to?(:model_class) + t(defaults.shift, **variables).upcase_first end alias ti translate_inheritable diff --git a/app/helpers/person_helper.rb b/app/helpers/person_helper.rb index 6d2bcd6b3..61b6ccca9 100644 --- a/app/helpers/person_helper.rb +++ b/app/helpers/person_helper.rb @@ -76,4 +76,12 @@ def not_rated_default_skills(person) certificate: false, core_competence: false }) end end + + def sorted_people + people_for_select.sort_by { |e| e.first.downcase } + end + + def people_for_select + Person.all.map { |p| [p.name, person_path(p)] } + end end diff --git a/app/helpers/select_helper.rb b/app/helpers/select_helper.rb index fa69b73b2..ea71548fb 100644 --- a/app/helpers/select_helper.rb +++ b/app/helpers/select_helper.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module SelectHelper - def select_when_availabale(obj) - selected = obj ? obj.id : '' - prompt = obj ? false : true + def select_when_available(obj) + selected = obj || '' + prompt = selected.blank? { selected: selected, prompt: prompt, disabled: '' } end @@ -15,4 +15,8 @@ def skills_dropdown_options skills = Skill.list.map { |s| [s.title, s.id, { 'data-category-id': s.category.id }] } add_default_option(skills, { 'data-placeholder': true }) end + + def model_path_or_nil(model) + polymorphic_path(model) if model + end end diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb index 2b76198f1..2d217cc7f 100644 --- a/app/helpers/tab_helper.rb +++ b/app/helpers/tab_helper.rb @@ -1,10 +1,35 @@ # frozen_string_literal: true module TabHelper + LOCALE_REGEX = /(\/(?:#{I18n.available_locales.join('|')}))/ + GLOBAL_NAVBAR_REGEX = /^#{LOCALE_REGEX}?(\/[^\/]+)(?:\/|$)/ + PERSON_NAVBAR_REGEX = /^(.*)/ + def person_tabs(person) [ - { title: 'CV', path: person_path(person) }, - { title: 'Skills', path: person_people_skills_path(person) } + { title: ti('tabbar.cv'), path: person_path(person) }, + { title: ti('tabbar.skills'), path: person_people_skills_path(person) } + ] + end + + def global_tabs + [ + { title: ti('navbar.profile'), path: people_path }, + { title: ti('navbar.skill_search'), path: people_skills_path }, + { title: ti('navbar.cv_search'), path: cv_search_index_path }, + { title: ti('navbar.skillset'), path: skills_path } ] end + + def extract_path(regex) + request.path.match(regex)&.captures&.join + end + + def global_navbar_path + extract_path(GLOBAL_NAVBAR_REGEX) + end + + def person_navbar_path + extract_path(PERSON_NAVBAR_REGEX) + end end diff --git a/app/javascript/controllers/dropdown_controller.js b/app/javascript/controllers/dropdown_controller.js index 5639ce0ac..5861a498b 100644 --- a/app/javascript/controllers/dropdown_controller.js +++ b/app/javascript/controllers/dropdown_controller.js @@ -5,12 +5,15 @@ import SlimSelect from 'slim-select'; export default class extends Controller { static targets = [ "dropdown" ] connect() { + if (!this.hasDropdownTarget) + return; + new SlimSelect({ select: this.dropdownTarget }); } handleChange(event) { - window.location.href = event.target.dataset.value + event.target.value; + window.location.href = event.target.value; } } diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index a9e868934..b49a8d73a 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -40,9 +40,6 @@ application.register("people-skills", PeopleSkillsController) import PeopleSkillsFilterController from "./people_skills_filter_controller" application.register("people-skills-filter", PeopleSkillsFilterController) -import ProfileTabController from "./profile_tab_controller" -application.register("profile-tab", ProfileTabController) - import RemoteModalController from "./remote_modal_controller" application.register("remote-modal", RemoteModalController) diff --git a/app/javascript/controllers/profile_tab_controller.js b/app/javascript/controllers/profile_tab_controller.js deleted file mode 100644 index d0cfeda04..000000000 --- a/app/javascript/controllers/profile_tab_controller.js +++ /dev/null @@ -1,20 +0,0 @@ -import {Controller} from "@hotwired/stimulus" - -export default class extends Controller { - static targets = ['tab'] - - connect() { - this.setCurrentTab() - } - - setCurrentTab() { - this.tabTargets.forEach((element) => element.classList.remove('active')) - this.tabTargets.forEach((element) => this.isCorrectTab(element) ? element.classList.add('active') : null) - } - - isCorrectTab(currentTab) { - const currentTabPath = currentTab.parentElement.getAttribute('href'); - const currentPath = window.location.pathname - return currentTabPath === currentPath - } -} \ No newline at end of file diff --git a/app/models/concerns/daterange_model.rb b/app/models/concerns/daterange_model.rb index b97a7a2cc..4b282624b 100644 --- a/app/models/concerns/daterange_model.rb +++ b/app/models/concerns/daterange_model.rb @@ -41,6 +41,6 @@ def start_at_before_finish_at formatted_month_to = month_to || 12 start_at = Date.new(year_from, formatted_month_from) finish_at = Date.new(year_to, formatted_month_to) - errors.add(:year_from, 'muss vor "Datum bis" sein') if start_at > finish_at + errors.add(:year_from, :invalid_date_range) if start_at > finish_at end end diff --git a/app/models/language_skill.rb b/app/models/language_skill.rb index dbb0f07b1..4585087d3 100644 --- a/app/models/language_skill.rb +++ b/app/models/language_skill.rb @@ -29,7 +29,7 @@ class LanguageSkill < ApplicationRecord def language_is_not_obligatory return unless %w(DE EN FR).include?(language) - errors.add(:language, 'darf nicht gelöscht werden') + errors.add(:language, :cannot_remove) throw(:abort) end end diff --git a/app/models/person.rb b/app/models/person.rb index 071c49c0e..2659f951a 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -105,6 +105,6 @@ def to_s def picture_size return if picture.nil? || picture.size < 10.megabytes - errors.add(:picture, 'grösse kann maximal 10MB sein') + errors.add(:picture, :max_size_10MB) end end diff --git a/app/models/person_role.rb b/app/models/person_role.rb index 66f053bdf..32954cbdf 100644 --- a/app/models/person_role.rb +++ b/app/models/person_role.rb @@ -26,6 +26,6 @@ class PersonRole < ApplicationRecord def percent_must_be_a_number return if percent.nil? || percent.between?(0, 200) - errors.add(:percent, 'muss zwischen 0 und 200 sein') + errors.add(:percent, :valid_percent_range) end end diff --git a/app/views/activities/_form.html.haml b/app/views/activities/_form.html.haml index 57e9a9b80..f6744e55f 100644 --- a/app/views/activities/_form.html.haml +++ b/app/views/activities/_form.html.haml @@ -1,7 +1,7 @@ = form_with model: ([entry.person, entry]) do |f| = render('people/person_relations/form', form: f) do - content_for :input do - = t "activerecord.attributes.activity.role" + = f.label :role = f.text_area :role, placeholder: "Rolle", class: "form-control w-100" - = t "activerecord.attributes.activity.description" + = f.label :description = f.text_area :description, placeholder: "Beschreibung", class: "form-control w-100" \ No newline at end of file diff --git a/app/views/admin/companies/index.html.haml b/app/views/admin/companies/index.html.haml index 706117f13..2c4efae58 100644 --- a/app/views/admin/companies/index.html.haml +++ b/app/views/admin/companies/index.html.haml @@ -1,3 +1,3 @@ -= link_to t("admin.panel.title"), admin_index_path += index_action_link admin_index_path = render 'list' = render 'actions_index' \ No newline at end of file diff --git a/app/views/admin/departments/index.html.haml b/app/views/admin/departments/index.html.haml index 706117f13..2c4efae58 100644 --- a/app/views/admin/departments/index.html.haml +++ b/app/views/admin/departments/index.html.haml @@ -1,3 +1,3 @@ -= link_to t("admin.panel.title"), admin_index_path += index_action_link admin_index_path = render 'list' = render 'actions_index' \ No newline at end of file diff --git a/app/views/admin/roles/index.html.haml b/app/views/admin/roles/index.html.haml index 706117f13..2c4efae58 100644 --- a/app/views/admin/roles/index.html.haml +++ b/app/views/admin/roles/index.html.haml @@ -1,3 +1,3 @@ -= link_to t("admin.panel.title"), admin_index_path += index_action_link admin_index_path = render 'list' = render 'actions_index' \ No newline at end of file diff --git a/app/views/advanced_trainings/_form.html.haml b/app/views/advanced_trainings/_form.html.haml index 8c0533c2f..3111158a0 100644 --- a/app/views/advanced_trainings/_form.html.haml +++ b/app/views/advanced_trainings/_form.html.haml @@ -1,5 +1,5 @@ = form_with model: ([entry.person, entry]) do |f| = render('people/person_relations/form', form: f) do - content_for :input do - = t "activerecord.attributes.advanced_training.description" + = f.label :description = f.text_area :description, placeholder: "Description", class: "form-control w-100" diff --git a/app/views/application/_daterange_picker.html.haml b/app/views/application/_daterange_picker.html.haml index 0df2f4e0d..479351d8f 100644 --- a/app/views/application/_daterange_picker.html.haml +++ b/app/views/application/_daterange_picker.html.haml @@ -10,7 +10,7 @@ %hr.my-1 %div.d-flex.row.align-items-center %span.fw-bold.col-2 - = "#{t('date_range_picker.from')}:" + = "#{ti('date.from')}:" %span.col-5 = form.select :month_from, add_default_option(months_with_nil, { text: '-' }), {}, class: "form-select" %span.col-5 @@ -18,7 +18,7 @@ %div{"data-date-picker-target": "hideable", hidden: end_date, id: "end_date_picker"} %div.d-flex.row.align-items-center %span.fw-bold.col-2 - = "#{t('date_range_picker.to')}:" + = "#{ti('date.to')}:" %span.col-5 = form.select :month_to, add_default_option(months_with_nil, { text: '-' }), {}, class: "form-select" %span.col-5 @@ -26,12 +26,12 @@ %div{"data-date-picker-target": "hideable", hidden: !end_date} %div.d-flex.justify-content-end %span.d-flex.justify-content-center.fw-bold.py-2.col-10 - = t("date_range_picker.till_today") + = ti("date.till_today") %div.d-flex.row.justify-content-end %span.col-10 %button{"data-action": "date-picker#toggleTargets", class: "btn btn-primary w-100", type: "button"} %span{"data-date-picker-target": "hideable", hidden: end_date} - = t("date_range_picker.till_today") + = ti("date.till_today") %span{"data-date-picker-target": "hideable", hidden: !end_date} - = t("date_range_picker.with_enddate") + = ti("date.with_enddate") diff --git a/app/views/application/_edit_interest_stars.html.haml b/app/views/application/_edit_interest_stars.html.haml index f9bef0763..7ec345f81 100644 --- a/app/views/application/_edit_interest_stars.html.haml +++ b/app/views/application/_edit_interest_stars.html.haml @@ -1,4 +1,4 @@ -%label.form-label.text-gray= t "people-skills.interest" +%label.form-label.text-gray= ti "people_skills.interest" .rate = ff.radio_button :interest, 5, { checked: ff.object.interest == 5, id: "star5#{ff.object.skill.id}", "data-action": "change->people-skills#rateSkill" } %label{for: "star5#{ff.object.skill.id}", title: "text", id: "star-label5#{ff.object.skill.id}", class: "star5"} 5 stars diff --git a/app/views/application/_error_banners.html.haml b/app/views/application/_error_banners.html.haml index b7a47e3fe..3317377c7 100644 --- a/app/views/application/_error_banners.html.haml +++ b/app/views/application/_error_banners.html.haml @@ -1,5 +1,6 @@ - if errors.any? - .alert.alert-danger - %ul.mb-0 - - errors.full_messages.each do |error| - %li= error \ No newline at end of file + #error_explanation.alert.alert-danger + %h2= ti(:"errors.header", count: errors.count, model: (defined?(object) && object&.to_s) || "Error") + %ul + - errors.full_messages.each do |msg| + %li= msg diff --git a/app/views/application/_show_interest_stars.html.haml b/app/views/application/_show_interest_stars.html.haml index 7e5315b3e..b557fd6ad 100644 --- a/app/views/application/_show_interest_stars.html.haml +++ b/app/views/application/_show_interest_stars.html.haml @@ -1,4 +1,4 @@ -%label.form-label.text-gray= t "people-skills.interest" +%label.form-label.text-gray= ti "people_skills.interest" .rate.rate-show %input{type: "radio", value: 5, id: "star5#{person_skill.id}", checked: person_skill.interest == 5, disabled: true}/ diff --git a/app/views/application/_tabbar.html.haml b/app/views/application/_tabbar.html.haml index 2141ae10f..475861cc3 100644 --- a/app/views/application/_tabbar.html.haml +++ b/app/views/application/_tabbar.html.haml @@ -1,8 +1,8 @@ -%ul.nav.nav-tabs.d-flex.flex-row.mt-2.justify-content-between.mb-3 +%div.d-flex.flex-row.justify-content-between{class: "#{bar_class}"} %div.d-flex.flex-row - tabs.each do |tab| - = link_to tab[:path], class: "btn text-primary p-0", "data-action": "click->profile-tab#setCurrentTab" do - %div.nav-link{ "data-profile-tab-target": "tab"} + = link_to tab[:path], class: "btn text-primary p-0 d-flex align-items-center" do + %div{class: "nav-link h-100 d-flex align-items-center #{'active' if active_path == tab[:path]}"} = tab[:title] %div - = yield \ No newline at end of file + = yield if defined?(do_yield) && do_yield|| false diff --git a/app/views/crud/show.html.haml b/app/views/crud/show.html.haml index 8fec97cd5..67033e6d4 100644 --- a/app/views/crud/show.html.haml +++ b/app/views/crud/show.html.haml @@ -3,5 +3,3 @@ - content_for(:actions, render('actions_show')) = render 'attrs' - - diff --git a/app/views/cv_search/index.html.haml b/app/views/cv_search/index.html.haml index 1341b024d..59b6845fb 100644 --- a/app/views/cv_search/index.html.haml +++ b/app/views/cv_search/index.html.haml @@ -1,19 +1,24 @@ %div.mt-2 %form.d-flex.align-items-center{data: {"turbo-frame": "search-results", "turbo-action": "advance"}, "data-controller": "search"} - %input{class: 'form-control w-75', placeholder: 'CVs durchsuchen...', name: 'q', "data-action": "search#submitWithTimeout", id: "cv_search_field"} + %input{class: 'form-control w-75', placeholder: ti("search_placeholder"), name: 'q', "data-action": "search#submitWithTimeout", id: "cv_search_field"} %div.ms-5 %input{type: "checkbox", name: 'search_skills', id: 'search_skills_checkbox', onchange: 'this.form.requestSubmit();'} - = t('cv_search.search_skills') + = ti('search_skills') %div.profile-header.mw-100.border-bottom.mt-2.mb-2 - Suchresultate + = ti "search.search_results" %turbo-frame{id: "search-results"} - if @cv_search_results.blank? - Keine Resultate + = ti "search.no_results" - else - @cv_search_results.each do |result| %div.w-50.d-flex = link_to result[:person][:name], person_path(result[:person][:id]), {class: "bg-skills-green w-50 text-decoration-none text-white ps-1 p-2 rounded-1", "data-turbo": "false"} %div.w-50.d-flex.justify-content-end.align-items-center - %div.me-1 gefunden in: - = link_to translate_found_in(result), found_in_skills?(result) ? person_people_skills_path(result[:person][:id], q: params[:q], rating: 1) : person_path(result[:person][:id], q: params[:q]), {class: "bg-skills-search-result-blue w-50 text-decoration-none text-white ps-1 p-2 rounded-1 text-center", "data-turbo": "false"} + %div.me-1 + = ti("search.found_in") + - url_params = {q: params[:q], rating: found_in_skills?(result)? 1: nil} + - person_id = result[:person][:id] + - path = person_path(person_id, url_params) + - path = person_people_skills_path(person_id, url_params) if found_in_skills?(result) + = link_to result[:found_in], path, {class: "bg-skills-search-result-blue w-50 text-decoration-none text-white ps-1 p-2 rounded-1 text-center", "data-turbo": "false"} %br \ No newline at end of file diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 41e72be4b..da0ab90b6 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,6 +1,8 @@ -%h2 Log in +%h2 + = ti("devise.sign_in") - if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| - = button_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), {data: { turbo: false }, class: "btn btn-primary"} + = + = button_to ti("sign_in_with", provider: provider.to_s.titleize), omniauth_authorize_path(resource_name, provider), {data: { turbo: false }, class: "btn btn-primary"} - else - An error %occured, no Omniauth providers are available, please contact the administrator. \ No newline at end of file + = ti("devise.no_omniauth_providers") \ No newline at end of file diff --git a/app/views/educations/_form.html.haml b/app/views/educations/_form.html.haml index 9daf46859..dceb4d551 100644 --- a/app/views/educations/_form.html.haml +++ b/app/views/educations/_form.html.haml @@ -1,7 +1,7 @@ = form_with model: ([entry.person, entry]) do |f| = render('people/person_relations/form', form: f) do - content_for :input do - = t "activerecord.attributes.education.title" + = f.label :title = f.text_area :title, placeholder: "Description", class: "form-control w-100" - = t "activerecord.attributes.education.location" + = f.label :location = f.text_area :location, placeholder: "Ein Ausbildungsort", class: "form-control w-100" diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index a78dd8e78..af5a0ddd1 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -24,18 +24,21 @@ %img{:src=> "/assets/logo.svg",:height=>"32"} %text.d-flex.align-items-end.ms-2.small= "5.0.0" %ul.navbar.text-gray + -# Language selector + %li.d-flex.align-items-center.cursor-pointer.border-start.border-end.h-100.ps-2.pe-2{"data-controller": "dropdown"} + = select :i18n, :language, language_selector, {}, class: "form-control", data:{action: "change->dropdown#handleChange"} -# Devise/Mockdata - if Rails.env.development? %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100 %span#username - if devise? - Devise + = ti("devise.devise") - else - Mockdata + = ti("devise.mockdata") -# Admin panel - if conf_admin? %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100 - = link_to "Admin panel", admin_index_path + = link_to ti("devise.admin_panel"), admin_index_path -# Username - if auth_user_signed_in? %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.border-end.h-100 @@ -46,14 +49,14 @@ - else = link_to find_person_by_auth_user.name, person_path(find_person_by_auth_user) - if admin? - (Admin) + = ti "devise.admin" -# Login/Logout - if devise? %li.d-flex.align-items-center.cursor-pointer.border-start.border-end.h-100.ps-2.pe-2 - if auth_user_signed_in? - =link_to "Logout", destroy_auth_user_session_path, data: { "turbo-method": :delete}, class: "btn btn-link" + =link_to ti("devise.sign_out"), destroy_auth_user_session_path, data: { "turbo-method": :delete}, class: "btn btn-link" - elsif devise_mapping.omniauthable? - =button_to "Login", omniauth_authorize_path(resource_name, resource_class.omniauth_providers.first), {data: { "turbo": false, controller: "instant-click"}, class: "btn btn-link"} + =button_to ti("devise.sign_in"), omniauth_authorize_path(resource_name, resource_class.omniauth_providers.first), {data: { "turbo": false, controller: "instant-click" }, class: "btn btn-link"} -# Help %li.d-flex.align-items-center.cursor-pointer.ps-2.pe-2.border-start.h-100 %a.d-flex.align-items-center{:href => "https://github.com/puzzle/skills/issues"} @@ -61,15 +64,7 @@ %li.d-flex.align-items-center.cursor-pointer.border-start.border-end.h-100.ps-2.pe-2{"data-action": "click->skills-empty-space#goCrazy"} %div.puzzle-header %div.d-flex.h-100 - %ul.navbar.h-100 - %li.bg-skills-blue.h-100.d-flex.align-items-center{class: "#{'highlighted' if @first_path == people_path}"} - %a.nav-link.cursor-pointer.ps-2.pe-2{href: people_path} Profil - %li.bg-skills-blue.h-100.d-flex.align-items-center{class: "#{'highlighted' if @first_path == people_skills_path}"} - %a.nav-link.cursor-pointer.ps-2.pe-2{href: people_skills_path} Skill Suche - %li.bg-skills-blue.h-100.d-flex.align-items-center{class: "#{'highlighted' if @first_path == cv_search_index_path}"} - %a.nav-link.cursor-pointer.ps-2.pe-2{href: cv_search_index_path} CV Suche - %li.bg-skills-blue.h-100.d-flex.align-items-center{class: "#{'highlighted' if @first_path == skills_path}"} - %a.nav-link.cursor-pointer.ps-2.pe-2{href: skills_path} Skillset + = render "application/tabbar", tabs: global_tabs, bar_class: "skills-navbar", active_path: global_navbar_path %div.container-fluid %div.row.d-flex.justify-content-center = render partial: 'layouts/flash', collection: [:notice, :alert], as: :level @@ -77,4 +72,5 @@ %span = yield :actions = content_for?(:content) ? yield(:content) : yield + = turbo_frame_tag "remote_modal", target: "_top" \ No newline at end of file diff --git a/app/views/layouts/person.html.haml b/app/views/layouts/person.html.haml index a7b6dbb4b..69e0de73b 100644 --- a/app/views/layouts/person.html.haml +++ b/app/views/layouts/person.html.haml @@ -2,13 +2,13 @@ %div.profile-header-and-tabs.pt-2 %div =render partial:"people/search", :locals => {person: @person} - %div{"data-controller": "profile-tab highlight"} - = render "application/tabbar", tabs: person_tabs(@person) do + %div{"data-controller": "highlight"} + = render "application/tabbar", tabs: person_tabs(@person), bar_class: "mb-3 mt-2 nav nav-tabs", active_path: person_navbar_path, do_yield: true do %div.dropdown = button_tag ti(:more_actions), class: "btn dropdown-toggle", data: { "bs-toggle": "dropdown" } %ul.dropdown-menu %li - = link_to image_tag("export.svg")+ "Export", export_cv_person_path(@person), class: "btn text-primary", data: { turbo_frame: "remote_modal" } + = export_action_link export_cv_person_path(@person), data: { turbo_frame: "remote_modal" } %li.text-nowrap = destroy_action_link %turbo-frame#tab-content.d-flex.gap-3{"data-controller": "scroll"} diff --git a/app/views/people/_core_competences.html.haml b/app/views/people/_core_competences.html.haml index 9b046f5be..bf1055ebc 100644 --- a/app/views/people/_core_competences.html.haml +++ b/app/views/people/_core_competences.html.haml @@ -1,6 +1,6 @@ %div.border.border-secondary-subtle.border-1.d-flex.flex-column.mb-3#core-competences{"data-scroll-target": "scrollItem"} %div.profile-header.mw-100.border-bottom - Kernkompetenzen + = t "people.profile.core_competences" %div.d-flex.flex-column.ms-5.mt-3.mb-3 - group_person_skills_by_category(@person).each do |parent_skill, children_skills| %div.d-flex.flex-row.align-items-center.border-bottom.border-1.pb-3.pt-3.core-competence @@ -10,6 +10,7 @@ - if person_skill != children_skills.last %div.circle-divider.ms-2.me-2 %div.d-flex.flex-row.border-bottom.border-1.pb-3.pt-3 - %span.text-gray.w-25 Notizen Member + %span.text-gray.w-25 + = Person.human_attribute_name(:competence_notes) %span.w-75.d-flex.align-items-center = render('people/competence_notes/show') \ No newline at end of file diff --git a/app/views/people/_cv.html.haml b/app/views/people/_cv.html.haml index 51749a010..f341e3ec2 100644 --- a/app/views/people/_cv.html.haml +++ b/app/views/people/_cv.html.haml @@ -1,11 +1,11 @@ -= render 'scroll_to_menu', items: %w[personal-data core-competences educations advanced-trainings activities projects], translate: true do - = link_to image_tag("export.svg") + "Export", export_cv_person_path(@person), data: { turbo_frame: "remote_modal" } += render 'scroll_to_menu', items: %w[personal-data core-competences educations advanced-trainings activities projects] do + = export_action_link export_cv_person_path(@person), data: { turbo_frame: "remote_modal" } %div.w-100{data: { "scroll-target": "parent"}} - if @person.people_skills.count == 0 %span{"data-controller": "people", "data-people-target": "message"} %p.alert.alert-info.d-flex.justify-content-between - = t('profile.no_skills_rated_msg') - = image_tag("x.svg", "data-action": "click->people#remove", class: "x-img") + = t('.no_skills_rated_msg') + = close_action_link "#", data: {action: "click->people#remove"} = render('profile') = render('core_competences') = render('people/person_relations/index', list: @person.educations.list, id: "educations") diff --git a/app/views/people/_form.html.haml b/app/views/people/_form.html.haml index 12e2164d6..40c3001d6 100644 --- a/app/views/people/_form.html.haml +++ b/app/views/people/_form.html.haml @@ -8,74 +8,87 @@ - else %img.rounded-circle#avatar{src: "#{@person.id}/picture?#{Time.now.to_f}", width: '141', height: '141'} %br - - if @person.id.nil? - %label.btn.btn-link{for: "avatar-uploader"} Bild hochladen - - else - %label.btn.btn-link{for: "avatar-uploader"} Bild ändern + %label.btn.btn-link{for: "avatar-uploader"} + - if @person.id.nil? + = t "people.profile.upload_image" + - else + = t "people.profile.change_image" %div.visually-hidden{"data-controller"=>"image-upload"}= form.file_field :picture, { accept: "image/", "data-action" => "image-upload#changeImage", id: "avatar-uploader" } = form.hidden_field :picture_cache %div.pe-5.col-xl-3.col-12 %table.w-100 %tbody - %th.fw-normal Name + %th.fw-normal + = form.label :name %tr %td= form.text_field :name, class: "mw-100 form-control" - %th.fw-normal Email + %th.fw-normal + = form.label :email %tr %td= form.text_field :email, class: "mw-100 form-control" - %th.fw-normal Abschluss + %th.fw-normal + = form.label :title %tr %td= form.text_field :title, class: "mw-100 form-control" - %th.fw-normal Funktionen + %th.fw-normal + = form.label :person_roles %div = form.fields_for :person_roles do |person_role| %tr %td= render "person_role_fields", f: person_role %tr %td{"data-controller"=>"dynamic-fields"} - = link_to_add_field "Neue Funktion", form, :person_roles - %th.fw-normal Organisationseinheit + = link_to_add_field t("people.profile.add_function"), form, :person_roles + + %th.fw-normal + = form.label :department %tr %td= form.collection_select :department_id, Department.order(:name), :id, :name, {}, class: "form-select mw-100" - %th.fw-normal Firma + %th.fw-normal + = form.label :company %tr %td= form.collection_select :company_id, Company.order(:name), :id, :name, {}, class: "form-select mw-100" - %th.fw-normal Wohnort (Stadt) + %th.fw-normal + = form.label :location %tr %td= form.text_field :location, class: "form-control mw-100" %div.pe-5.col-xl-3.col-12 %table.w-100 %tbody - %th.fw-normal Geburtsdatum + %th.fw-normal + = form.label :birthdate %tr %td= form.date_field :birthdate, class: "form-control mw-100" - %th.fw-normal Doppelbürger + %th.fw-normal + = form.label :dual_citizen %tr %td{"data-controller"=>"nationality-two"}= check_box :has_nationality2, "checked", {"checked" => @person.nationality2?, "data-action" => "nationality-two#nationalityTwoVisible", "id" => "nat-two-checkbox"} - %th.fw-normal Erste Nationalität + %th.fw-normal + = form.label :nationality %tr %td= form.collection_select :nationality, country_alpha2_translation_map, :first, :last, {}, class: "form-select mw-100" - %th.fw-normal.nationality-two Zweite Nationalität + %th.fw-normal.nationality-two + = form.label :nationality2 %tr.nationality-two %td= form.collection_select :nationality2, country_alpha2_translation_map, :first, :last, {}, class: "form-select mw-100" - %th.fw-normal Zivilstand + %th.fw-normal + = form.label :marital_status %tr %td= form.collection_select :marital_status, marital_status_translation_map, :first, :last, { selected: @person.marital_status }, class: "form-select mw-100" - %th.fw-normal Kürzel + %th.fw-normal + = form.label :shortname %tr %td= form.text_field :shortname, class: "mw-100 form-control" %div.col-xl-3.col-12{"data-controller"=>"lang-selection"} - %div.fw-normal Sprachen + %div.fw-normal + = form.label :language_skills %div.border.border-dark-subtle.mt-1.p-2.rounded.w-100 = form.fields_for :language_skills, sort_languages(@person.language_skills) do |language_skill| = render "language_skill_fields", f: language_skill %div{"data-controller"=>"dynamic-fields"} - = link_to_add_field "Add Language", form, :language_skills + = link_to_add_field t("people.profile.add_language"), form, :language_skills %div.mt-3 - = form.submit :Speichern, { class: "btn btn-primary me-3 bg-skills-blue", id: "save-button" } - - if @person.id.nil? - = link_to "Abbrechen", people_path, { id: "cancel-button" } - - else - = link_to "Abbrechen", person_path(@person), { id: "cancel-button" } \ No newline at end of file + = form.submit class: "btn btn-primary me-3 bg-skills-blue", id: "save-button" + = form.cancel \ No newline at end of file diff --git a/app/views/people/_language_skill_fields.html.haml b/app/views/people/_language_skill_fields.html.haml index 4fd1a91cc..85347f5f4 100644 --- a/app/views/people/_language_skill_fields.html.haml +++ b/app/views/people/_language_skill_fields.html.haml @@ -6,10 +6,11 @@ %div.visually-hidden= f.collection_select :language, common_languages_translated, :first, :last, { selected: f.object.language } %div.d-flex %div.w-25.me-2 - %div Level - %div= f.collection_select :level, language_skill_levels, :itself, :itself, {}, class: "form-select mw-100 language-level-select" + = f.label :level + = f.collection_select :level, language_skill_levels, :itself, :itself, {}, class: "form-select mw-100 language-level-select" %div.w-75 - %div Zertifikat - %div= f.text_field :certificate, class: "mw-100 form-control language-certificate-input" + = f.label :certificate + = f.text_field :certificate, class: "mw-100 form-control language-certificate-input" - unless uneditable_language?(f.object.language) - %div{"data-controller"=>"dynamic-fields"}= link_to "Remove", "#", { class: "remove_fields", 'data-action' => 'dynamic-fields#removeField lang-selection#setOptionState' } \ No newline at end of file + %div{"data-controller"=>"dynamic-fields"} + = link_to ti("link.remove"), "#", { class: "remove_fields", 'data-action' => 'dynamic-fields#removeField lang-selection#setOptionState' } \ No newline at end of file diff --git a/app/views/people/_person_role_fields.html.haml b/app/views/people/_person_role_fields.html.haml index 149bc546d..1d68eb7fa 100644 --- a/app/views/people/_person_role_fields.html.haml +++ b/app/views/people/_person_role_fields.html.haml @@ -1,9 +1,9 @@ %div.border.border-dark-subtle.rounded.p-1.fw-light.nested-fields = f.hidden_field :_destroy - Rolle + = f.label :role = f.collection_select :role_id, Role.order(:name), :id, :name, {}, class: "form-select w-100 role-select" %div - Stufe + = f.label :person_role_level %div.d-flex.fw-light = f.collection_select :person_role_level_id, PersonRoleLevel.order(:level), :id, :level, {}, class: "form-select w-50 me-1 role-level-select" = f.number_field :percent, in: 0..200, step: 1, class: "form-control w-50 person-role-percent" diff --git a/app/views/people/_profile.html.haml b/app/views/people/_profile.html.haml index 5146af558..bd2048907 100644 --- a/app/views/people/_profile.html.haml +++ b/app/views/people/_profile.html.haml @@ -1,25 +1,30 @@ %div.mb-3#personal-data{"data-scroll-target": "scrollItem"} %div.profile-header.mw-100.border-bottom - Personalien + = t "people.profile.personals" %div.mt-4 %turbo-frame{id: "#{dom_id @person}"} %div.d-flex.flex-xl-row.flex-column %div.col-xl-3.col-12 - %img.rounded-circle{src: "/people/#{@person.id}/picture?#{Time.now.to_f}", width: '141', height: '141'} - %div.mt-3= link_to "Bearbeiten", edit_person_path, id: "edit-button" + %img.rounded-circle{src: picture_person_path(Person.first, timestamp:Time.now.to_f), width: '141', height: '141'} + %div.mt-3 + = edit_action_link %div.pe-5.col-xl-3.col-12 %table.fixed-table %tbody - %th.fw-normal.text-gray Name + %th.fw-normal.text-gray + = Person.human_attribute_name(:name) %tr %td.text-break.pb-1= @person.name - %th.fw-normal.text-gray Email + %th.fw-normal.text-gray + = Person.human_attribute_name(:email) %tr %td.text-break.pb-1= @person.email - %th.fw-normal.text-gray Abschluss + %th.fw-normal.text-gray + = Person.human_attribute_name(:title) %tr %td.text-break.pb-1= @person.title - %th.fw-normal.text-gray Funktion + %th.fw-normal.text-gray + = Person.human_attribute_name(:person_roles, count: @person.person_roles.count) - unless @person.person_roles.empty? - @person.person_roles.each do |person_role| %tr @@ -27,33 +32,43 @@ - else %tr %td - - %th.fw-normal.text-gray Organisationseinheit + %th.fw-normal.text-gray + = Person.human_attribute_name(:department) %tr - %td.pb-1= @person.department.nil? ? '-' : @person.department.name - %th.fw-normal.text-gray Firma + %td.pb-1= @person.department.name || "-" + %th.fw-normal.text-gray + = Person.human_attribute_name(:company) %tr %td= @person.company.name %div.pe-5.col-xl-3.col-12 %table.fixed-table %tbody - %th.fw-normal.text-gray Geburtsdatum + %th.fw-normal.text-gray + = Person.human_attribute_name(:birthdate) %tr - %td.pb-1= @person.birthdate.to_date.strftime('%d.%m.%Y') - %th.fw-normal.text-gray Nationalität + %td.pb-1 + = @person.birthdate.to_date.strftime('%d.%m.%Y') + %th.fw-normal.text-gray + = Person.human_attribute_name(:nationality) %tr - %td.text-break.pb-1= nationality_string(@person.nationality, @person.nationality2) - %th.fw-normal.text-gray Wohnort (Stadt) + %td.text-break.pb-1 + = nationality_string(@person.nationality, @person.nationality2) + %th.fw-normal.text-gray + = Person.human_attribute_name(:location) %tr %td.text-break.pb-1= @person.location - %th.fw-normal.text-gray Zivilstand + %th.fw-normal.text-gray + = Person.human_attribute_name(:marital_status) %tr %td.pb-1= t("marital_statuses.#{@person.marital_status}") - %th.fw-normal.text-gray Kürzel + %th.fw-normal.text-gray + = Person.human_attribute_name(:shortname) %tr - %td= @person.shortname.blank? ? '-' : @person.shortname + %td= @person.shortname || "-" %div.col-xl-3.col-12 - %div.fw-normal.text-gray Sprachen + %div.fw-normal.text-gray + = Person.human_attribute_name(:language_skills, count: @person.language_skills.count) %div.border.border-dark-subtle.mt-1.p-2.rounded.w-min-content %table %tbody diff --git a/app/views/people/_scroll_to_menu.html.haml b/app/views/people/_scroll_to_menu.html.haml index bff14cc1b..d2422c638 100644 --- a/app/views/people/_scroll_to_menu.html.haml +++ b/app/views/people/_scroll_to_menu.html.haml @@ -4,10 +4,7 @@ %div.sidebar-item.w-100{data: {"scroll-target": "listItem", "action": "click->scroll#scrollToElement", "scroll-id-param": item.parameterize}} %span - - if translate - = t "profile.#{item}" - - else - = item + = t(".#{item}", default: item) %div.sidebar-extras = yield \ No newline at end of file diff --git a/app/views/people/_search.html.haml b/app/views/people/_search.html.haml index be4edee70..f2e06a0ed 100644 --- a/app/views/people/_search.html.haml +++ b/app/views/people/_search.html.haml @@ -1,9 +1,9 @@ %div.d-flex.align-items-center.justify-content-between %div.d-flex.col-9.gap-3 %span.col-6{"data-controller": "dropdown"} - = collection_select :person_id, :person, Person.all.sort_by {|p| p.name.downcase }, :id, :name, select_when_availabale(person), {data:{"dropdown-target": "dropdown" , action: "change->dropdown#handleChange", value: "/people/"}} + - selected_path = model_path_or_nil(person) + = select :person_id, :person, options_for_select(sorted_people, select_when_available(selected_path)), {prompt: person.nil?}, {data:{"dropdown-target": "dropdown" , action: "change->dropdown#handleChange"}} %div.d-flex.align-items-center.text-gray - = "#{t 'profile.updated_at'}: #{@person&.last_updated_at.strftime("%d.%m.%Y")}" if @person&.last_updated_at - %a.d-flex.justify-content-between#new-person-button{href: "/people/new"} - %img.pe-1{src: "/assets/plus-lg.svg"} - Neues Profil \ No newline at end of file + = "#{t '.updated_at'}: #{@person&.last_updated_at.strftime("%d.%m.%Y")}" if @person&.last_updated_at + %a.d-flex.justify-content-between#new-person-button + = add_action_link new_person_path \ No newline at end of file diff --git a/app/views/people/_skills.html.haml b/app/views/people/_skills.html.haml deleted file mode 100644 index f1da945dd..000000000 --- a/app/views/people/_skills.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -%div.profile-header.mw-100.border-bottom - %p.d-flex.align-items-center - Skills - =link_to image_tag("pencil-square.svg") + "Skills bearbeiten", people_skills_path, class: "btn d-flex align-items-center text-primary" - = render "people_skills/form", person: @person \ No newline at end of file diff --git a/app/views/people/competence_notes/_show.html.haml b/app/views/people/competence_notes/_show.html.haml index f4151033d..3287505ad 100644 --- a/app/views/people/competence_notes/_show.html.haml +++ b/app/views/people/competence_notes/_show.html.haml @@ -2,5 +2,4 @@ %div.d-flex %div.persisted-line-breaks= @person.competence_notes %div.d-flex.flex-row - = link_to image_tag("pencil-square.svg")+ "Bearbeiten", - competence_notes_person_path(@person), class: "d-flex align-items-center", id: "edit-link" \ No newline at end of file + = edit_action_link competence_notes_person_path(@person) \ No newline at end of file diff --git a/app/views/people/competence_notes/edit.html.haml b/app/views/people/competence_notes/edit.html.haml index ebe31510a..81f42dd6a 100644 --- a/app/views/people/competence_notes/edit.html.haml +++ b/app/views/people/competence_notes/edit.html.haml @@ -4,5 +4,5 @@ = f.text_area :competence_notes, class: "form-control w-75", value: @person.competence_notes, rows: computed_size .mb-1.mt-4 - = f.button "Speichern", class:"btn btn-primary","aria-label":"Close", id: 'save' - = link_to "Abbrechen", person_path(@person), class: "btn btn-outline-secondary", id: 'cancel' \ No newline at end of file + = f.submit + = f.cancel \ No newline at end of file diff --git a/app/views/people/export_cv/_export_form.html.haml b/app/views/people/export_cv/_export_form.html.haml index 110ef56e0..b55145199 100644 --- a/app/views/people/export_cv/_export_form.html.haml +++ b/app/views/people/export_cv/_export_form.html.haml @@ -1,19 +1,20 @@ = form_with(url: person_path(format: 'odt'), method: 'get', data: {controller: "skills-filter"}) do |f| .mb-2.w-100 - = f.label 'Niederlassung (für Footer):', class: "form-label w-100" - = f.collection_select :location, BranchAdress.all, :id, :short_name, {selected: BranchAdress.find_by(default_branch_adress: true).id}, class: "form-select w-100" + = f.label :location, class: "form-label w-100" + = f.collection_select :location, BranchAdress.all, :id, :short_name, {selected: (BranchAdress.find_by(default_branch_adress: true) || BranchAdress.first).id}, class: "form-select w-100" .mb-2.w-100.form-check.form-switch = f.check_box :includeCS, class: "form-check-input" - = f.label 'Kernkompetenzen - Skills', class: "form-check-label w-100" + = f.label t(".competences_skills"), class: "form-check-label w-100" .mb-2.w-100.form-check.form-switch = f.check_box :skillsByLevel, class: "form-check-input", "data-action": "click->skills-filter#toggleSwitch" - = f.label "Skills nach Level", class: "form-check-label w-100" + = f.label t(".skills_by_level"), class: "form-check-label w-100" + %div{"data-skills-filter-target": "container"} - = f.label "trainee", "data-skills-filter-target": "label", class: "w-100" + = f.label t("global.people_skills.levels.trainee"), "data-skills-filter-target": "label", class: "w-100" = f.range_field :levelValue, min: 1, max: 5, value: 1, class: "form-range w-25", "data-action": "change->skills-filter#toggleLevel", "data-skills-filter-target": "switch" .mb-2.w-100.form-check.form-switch = f.check_box :anon, class: "form-check-input" - = f.label "Anonymisierter CV", class: "form-check-label w-100" + = f.label t(".anonymised_cv"), class: "form-check-label w-100" .mb-1.mt-4 - = f.button "Herunterladen", class:"btn btn-primary","aria-label":"Close" - = link_to "Cancel", skills_path, class: "btn btn-outline-secondary", "data-bs-dismiss":"modal" + = f.submit ti("link.download") + = f.cancel person_path, "data-bs-dismiss":"modal" diff --git a/app/views/people/index.html.haml b/app/views/people/index.html.haml index 0efa0ea37..76db259d4 100644 --- a/app/views/people/index.html.haml +++ b/app/views/people/index.html.haml @@ -5,6 +5,10 @@ .alert.alert-danger.mt-3 = msg %div.mt-3 - %h1.d-inline-block.me-3.banner-text Willkommen bei + %h1.d-inline-block.me-3.banner-text + = ti("welcome") =image_tag('logo.svg', width: '340', class: 'align-baseline test') - %h4.banner-sub-text.mt-3 Wähle eine Person aus oder erfasse ein neues Profil + %h4.banner-sub-text.mt-3 + = ti("choose_create_person") + + diff --git a/app/views/people/new.html.haml b/app/views/people/new.html.haml index 98a3789b2..867fc0003 100644 --- a/app/views/people/new.html.haml +++ b/app/views/people/new.html.haml @@ -2,6 +2,6 @@ =render partial:"people/search", :locals => { person: nil } %div.mt-2 %div.profile-header.mw-100.border-bottom.mb-3 - Personalien + = ti("personals") %div{id: "#{dom_id Person.new}"} = render partial: "form", locals: {person: @person} diff --git a/app/views/people/people_skills/_edit_form.html.haml b/app/views/people/people_skills/_edit_form.html.haml index ebfef9910..d3df14d42 100644 --- a/app/views/people/people_skills/_edit_form.html.haml +++ b/app/views/people/people_skills/_edit_form.html.haml @@ -6,8 +6,8 @@ = ff.hidden_field :unrated, value: false, id: "unrated-field-#{ff.object.skill.id}" %div.col-2 %div.d-flex.flex-column.align-items-center - %label.form-label.text-gray= t "people-skills.levels.level" - %label.form-label.text-gray{"data-people-skills-target": "label"}= t "people-skills.levels.#{ExpertiseTopicSkillValue.skill_levels.key(ff.object.level - 1)}" + = ff.label :level + = ff.label(ti("people_skills.levels.#{ExpertiseTopicSkillValue.skill_levels.key(ff.object.level - 1)}"), {"data-people-skills-target": "label"}) - range_min = (ff.object.id.nil? || ff.object.level != 0) ? 1 : 0 = ff.range_field :level, min: range_min, max: 5, class: "form-range w-75", "data-action": "change->people-skills#displayLevelLabel people-skills#rateSkill", @@ -18,14 +18,14 @@ %div.col-2 %div.d-flex.flex-row.form-check = ff.check_box :certificate, { class: "form-check-input me-2", "data-action": "change->people-skills#rateSkill" } - %label.form-label.text-gray= t "people-skills.certificate" + = ff.label :certificate %div.col-2 %div.d-flex.flex-row.form-check = ff.check_box :core_competence, { class: "form-check-input me-2", "data-action": "change->people-skills#rateSkill" } - %label.form-label.text-gray= t "people-skills.core-competence" + = ff.label :core_competence = ff.hidden_field :skill_id %div.col-2 - if ff.object.id.nil? - = ff.submit "Bewerten", { class: "btn btn-link" } + = ff.submit ti("rate"), { class: "btn btn-link" } - unless ff.object.unrated - = ff.submit "Nicht bewerten", { class: "btn btn-link", "data-action": "people-skills#unrateSkill"} + = ff.submit ti("unrate"), { class: "btn btn-link", "data-action": "people-skills#unrateSkill"} diff --git a/app/views/people/people_skills/_form.html.haml b/app/views/people/people_skills/_form.html.haml index c8ab55a75..18ba96324 100644 --- a/app/views/people/people_skills/_form.html.haml +++ b/app/views/people/people_skills/_form.html.haml @@ -1,7 +1,7 @@ = form_with(model: pskill, url: person_people_skills_path(person)) do |f| %div.d-flex.flex-column{data: {controller: "people-skills"}} = f.hidden_field :person_id - %label.form-label.text-gray= t "people-skills.skill" + = f.label :skill = f.fields_for :skill do |sf| = sf.select :id, options_for_select(skills_dropdown_options, disabled: person.skills.pluck(:id)), {}, {data: {"people-skills-target": "skillsDropdown"}} @@ -11,24 +11,21 @@ = sf.hidden_field :portfolio, value: Settings.portfolio[1] %div - %label.form-label.text-gray{hidden:@category_hidden}= t "people-skills.category" + = sf.label :category, {hidden:@category_hidden} = sf.collection_select :category_id, Category.where.not(parent_id: nil), :id, :name_with_parent, {}, class: "form-select", hidden: @category_hidden, data: {"people-skills-target": "categoriesDropdown"} - %label.form-label.text-gray= t "people-skills.levels.level" + = f.label :level %div.d-flex.gap-2 = f.range_field :level, min: 1, max: 5, value: 1, class: "form-range w-25", data: { "action": "change->people-skills#displayLevelLabel", "people-skills-target": "switch" } - %label.form-label.text-gray#skill-level-label{"data-people-skills-target": "label"} - %div = render partial: "edit_interest_stars", locals: { ff: f } - %div = f.check_box :certificate, class: "form-check-input me-2" - %label.form-label.text-gray= t "people-skills.certificate" + = f.label :certificate %div = f.check_box :core_competence, class: "form-check-input me-2" - %label.form-label.text-gray= t "people-skills.core-competence" - = f.submit class: "btn btn-primary", "aria-label":"Close" + = f.label :core_competence + = f.submit \ No newline at end of file diff --git a/app/views/people/people_skills/_overview.html.haml b/app/views/people/people_skills/_overview.html.haml index a8d10d5c9..365c40b8f 100644 --- a/app/views/people/people_skills/_overview.html.haml +++ b/app/views/people/people_skills/_overview.html.haml @@ -1,6 +1,5 @@ %p.d-flex.align-items-center.profile-header - Skills - ="(#{@person.people_skills.count})" + = "#{PeopleSkill.model_name.human(count: @person.people_skills.count)} (#{@person.people_skills.count})" %div.ms-3 = form_with(url: person_people_skills_path(@person), method: :get, data: {controller: "filter", turbo_frame: "people-skills"}) do |f| @@ -8,15 +7,15 @@ - rating = request.query_parameters[:rating] = f.radio_button :rating, 1, class: "btn-check", checked: rating == "1", onClick: "this.form.requestSubmit()", data: {action: "change->filter#submit"} - = f.label :rating, t("people-skills.filter.all"), value: 1, class: "btn btn-outline-primary" + = f.label :rating, ti("filter.all"), value: 1, class: "btn btn-outline-primary" = f.radio_button :rating, 0, class: "btn-check", checked: rating == "0", onClick: "this.form.requestSubmit()", data: {action: "change->filter#submit"} - = f.label :rating, t("people-skills.filter.rated"), value: 0, class: "btn btn-outline-primary" + = f.label :rating, ti("filter.rated"), value: 0, class: "btn btn-outline-primary" = f.radio_button :rating, -1, class: "btn-check", checked: rating == "-1", onClick: "this.form.requestSubmit()", data: {action: "change->filter#submit"} - = f.label :rating, t("people-skills.filter.unrated"), value: -1, class: "btn btn-outline-primary" + = f.label :rating, ti("filter.unrated"), value: -1, class: "btn btn-outline-primary" = turbo_frame_tag 'people-skills' do - Category.all_parents.each do |category| diff --git a/app/views/people/people_skills/index.html.haml b/app/views/people/people_skills/index.html.haml index 3c32ab06b..366a19c0f 100644 --- a/app/views/people/people_skills/index.html.haml +++ b/app/views/people/people_skills/index.html.haml @@ -1,22 +1,21 @@ %turbo-frame#people-skill-form.d-flex.gap-3.col-12 - = render('people/scroll_to_menu', items: Category.all_parents.pluck(:title), translate: false) do - = link_to image_tag("plus-lg.svg") + t("helpers.submit.add", model: Skill), new_person_people_skill_path(@person), - data: { turbo_frame: "remote_modal"} + = render('people/scroll_to_menu', items: Category.all_parents.pluck(:title)) do + = add_action_link_modal %div.w-100{data: { "scroll-target": "parent"}} - if not_rated_default_skills(@person).count > 0 && !params.key?("no_default_skill_prompt") %div.border.border-1.mb-2.p-3.border-black#default-skills %div#default-skill-errors %div.d-flex.align-items-center.profile-header.justify-content-between.mb-2 %div - Neue Skills zur Bewertung + = ti("new_skills_to_rate") = "(#{not_rated_default_skills(@person).count})" - = link_to person_people_skills_path(@person, no_default_skill_prompt: "") do - =image_tag("x.svg", alt: "Default-skill-form cancel button", width: 25, height: 25, id: "x-button") + + = close_action_link person_people_skills_path(@person, no_default_skill_prompt: "") - not_rated_default_skills(@person).each do |skill| = form_with model: @person, url: people_skills_person_path(@person, rating: params["rating"]) do |form| = form.fields_for :people_skills, skill do |ff| = render "people/people_skills/edit_form", ff: ff %div.align-items-center.mt-3 - = link_to "Abbrechen", person_people_skills_path(@person, no_default_skill_prompt: "") + = cancel_action_link person_people_skills_path(@person, no_default_skill_prompt: "") %div#person-skill-overview = render "people/people_skills/overview" diff --git a/app/views/people/people_skills/new.html.haml b/app/views/people/people_skills/new.html.haml index 59a830949..77a33fa87 100644 --- a/app/views/people/people_skills/new.html.haml +++ b/app/views/people/people_skills/new.html.haml @@ -1,2 +1,2 @@ -= render "remote_modal", title: "Neuer Skill" do += render "remote_modal", title: ti("link.add") do = render "form", pskill: @people_skill, person: @people_skill.person diff --git a/app/views/people/person_relations/_form.html.haml b/app/views/people/person_relations/_form.html.haml index 5da50514e..a4b24b944 100644 --- a/app/views/people/person_relations/_form.html.haml +++ b/app/views/people/person_relations/_form.html.haml @@ -8,7 +8,7 @@ %div.col-3.d-flex.flex-column = form.button(name: :"save", class:"btn btn-primary") - if entry.persisted? - = link_to t("helpers.submit.delete"),polymorphic_path([entry.person, entry]), data: { turbo_method: :delete, turbo_frame: dom_id(entry)}, class: "btn btn-link" + = destroy_action_link - else - = form.button(t("helpers.submit.save-and-new"), name: :"render_new_after_save", class:"btn btn-link", data: { turbo_frame: dom_id(entry.class.new)}) - = link_to t("helpers.submit.cancel"), polymorphic_path(entry.person), data: { turbo_frame: dom_id(entry.persisted? ? entry : entry.class.new)}, method: :get, class: "btn btn-link" \ No newline at end of file + = form.button(ti("link.save_new"), name: :"render_new_after_save", class:"btn btn-link", data: { turbo_frame: dom_id(entry.class.new)}) + = cancel_action_link polymorphic_path(entry.person) \ No newline at end of file diff --git a/app/views/people/person_relations/_index.html.haml b/app/views/people/person_relations/_index.html.haml index 3b1ba3662..fc9f605da 100644 --- a/app/views/people/person_relations/_index.html.haml +++ b/app/views/people/person_relations/_index.html.haml @@ -1,8 +1,8 @@ %div.border.border-secondary-subtle.border-1.d-flex.flex-column.mb-3{id: id, "data-scroll-target": "scrollItem"} %div.profile-header.mw-100.border-bottom - = "#{t "activerecord.models.#{name_of_obj(list)}"} (#{list.count})" + = "#{list.model_name.human(count: list.count)} (#{list.count})" %div.d-flex.flex-column.ms-5.mt-3.mb-3 - = link_to "#{t "activerecord.models.#{name_of_obj(list)}"} hinzufügen", new_polymorphic_path([entry, name_of_obj(list).to_sym]), data: { turbo_frame: dom_id(list.model.new)}, method: :get + = add_action_link new_polymorphic_path([entry, name_of_obj(list).to_sym]), {}, data: { turbo_frame: dom_id(list.model.new)} %div.border.rounded.border %turbo-frame{id: dom_id(list.model.new)} %turbo-frame{id: name_of_obj(list)} diff --git a/app/views/people_skills/_person_skill.html.haml b/app/views/people_skills/_person_skill.html.haml index 0557b1e04..bf8ee8490 100644 --- a/app/views/people_skills/_person_skill.html.haml +++ b/app/views/people_skills/_person_skill.html.haml @@ -1,15 +1,15 @@ %div.d-flex.align-items-center.col-2.people-skill-title = person_skill.skill.title %div.d-flex.flex-column.align-items-center.col-2 - %label.form-label.text-gray#skill-level-label= t "people-skills.levels.#{ExpertiseTopicSkillValue.skill_levels.key(person_skill.level - 1)}" + %label.form-label.text-gray#skill-level-label= ti "people_skills.levels.#{ExpertiseTopicSkillValue.skill_levels.key(person_skill.level - 1)}" %input#people_skill_level{value: person_skill.level, class: "form-range w-75", type: "range", min: 1, max: 5, disabled: true} %div.d-flex.flex-column.align-items-center.col-3 = render partial: "show_interest_stars", locals: { person_skill: person_skill } %div.d-flex.align-items-center.col-2 %div.d-flex.flex-row.form-check %input.check_box#certificate-checkbox{type: "checkbox", class: "form-check-input me-2 ", checked: person_skill.certificate, disabled: true} - %label.form-label.text-gray= t "people-skills.certificate" + %label.form-label.text-gray= PeopleSkill.human_attribute_name(:certificate) %div.d-flex.align-items-center %div.d-flex.flex-row.form-check.col-2 %input.check_box#core-competence-checkbox{type: "checkbox", class: "form-check-input me-2", checked: person_skill.core_competence, disabled: true} - %label.form-label.text-gray= t "people-skills.core-competence" \ No newline at end of file + %label.form-label.text-gray= PeopleSkill.human_attribute_name(:core_competence) diff --git a/app/views/people_skills/_search_form.html.haml b/app/views/people_skills/_search_form.html.haml index 9baf5a2c9..d8db19a8d 100644 --- a/app/views/people_skills/_search_form.html.haml +++ b/app/views/people_skills/_search_form.html.haml @@ -1,13 +1,15 @@ %div.w-100.d-flex.flex-row.justify-content-start{data: {controller: "skills-level"}} %div.w-50.mt-3{"data-controller": "dropdown"} - = form.collection_select "skill_id[]", Skill.all.order(:title), :id, :title, {include_blank: "Select option", selected: filter_params.skill_of_row(row_number)}, data:{"dropdown-target": "dropdown"}, onchange: "this.form.submit()" + - config = select_when_available(filter_params.skill_of_row(row_number)) + = form.collection_select "skill_id[]", Skill.all.order(:title), :id, :title, config, data:{"dropdown-target": "dropdown"}, onchange: "this.form.submit()" %div.w-25.d-flex.flex-column.align-items-center - %label.form-label.text-gray.fs-6{"data-skills-level-target": "label"}= t ExpertiseTopicSkillValue.skill_levels.key(filter_params.level_of_row(row_number)-1) + %label.form-label.text-gray.fs-6{"data-skills-level-target": "label"}= ti "people_skills.levels.#{ExpertiseTopicSkillValue.skill_levels.key(filter_params.level_of_row(row_number)-1)}" = form.range_field "level[]", min: 1, max: 5, value: filter_params.level_of_row(row_number), class: "form-range w-75", "data-action": "change->skills-level#toggleLevel", "data-skills-level-target": "switch", onchange: "this.form.submit()" %div.w-25.d-flex.flex-column.align-items-center - %label.form-label.text-gray.fs-6.mb-0.mt-0 Interesse + %span.fs-6.text-gray + = ti "people_skills.interest" .rate - 5.downto(1) do |index| = form.radio_button "interest[#{row_number}]", index, id: "row#{row_number}_star#{index}", checked: index == filter_params.interest_of_row(row_number), onClick: "this.form.submit()" diff --git a/app/views/people_skills/filter_form/index.html.haml b/app/views/people_skills/filter_form/index.html.haml index 7722713d2..70a0e849c 100644 --- a/app/views/people_skills/filter_form/index.html.haml +++ b/app/views/people_skills/filter_form/index.html.haml @@ -7,10 +7,7 @@ %div.d-flex.flex-row.align-items-center{"data-people-skills-filter-target": "filter", id: "filter-row-#{i+ 1}"} %div.filter-container.me-1 = render("people_skills/search_form", form: form, row_number: i + 1) - = image_tag("x.svg", class: "text-primary pointer", - "data-action": "click->people-skills-filter#remove", "data-people-skills-filter-id-param": i, id: "remove-row-#{i+1}") + = close_action_link "#", {data: {action: "click->people-skills-filter#remove", "people-skills-filter-id-param": i}, id: "remove-row-#{i+1}"} - if filter_params.rows < 4 - = link_to image_tag("plus-lg.svg") + "Skill hinzufügen (max. 5)", - filter_form_people_skills_path + "?rows=#{filter_params.rows + 1}&#{filter_params.query_params}", - class: "btn d-flex align-items-center text-primary w-75", data: {"turbo-frame": "search-filters"}, - id: "add-row-button" \ No newline at end of file + - path = filter_form_people_skills_path(rows: filter_params.rows + 1) + "&#{filter_params.query_params}" + = add_action_link path, {}, {data: {"turbo-frame": "search-filters"}, id: "add-row-button"} \ No newline at end of file diff --git a/app/views/people_skills/index.html.haml b/app/views/people_skills/index.html.haml index a7579aa54..4784390af 100644 --- a/app/views/people_skills/index.html.haml +++ b/app/views/people_skills/index.html.haml @@ -6,18 +6,17 @@ %div.filter-container.me-1 = render("search_form", form: form, row_number: i, filter_params: filter_params) - if i != 0 - = image_tag("x.svg", class: "text-primary pointer", "data-action": "click->people-skills-filter#remove", - "data-people-skills-filter-id-param": i, id: "remove-row-#{i}") + = close_action_link "#", {data: {action: "click->people-skills-filter#remove", "people-skills-filter-id-param": i}, id: "remove-row-#{i+1}"} - if filter_params.rows_count < 5 - = link_to image_tag("plus-lg.svg") + "Skill hinzufügen (max. 5)", - filter_form_people_skills_path + "?rows=#{filter_params.rows_count}&#{filter_params.query_params}", class: "btn d-flex align-items-center text-primary w-75", - data: {"turbo-frame": "search-filters"}, id: "add-row-button" + - path = filter_form_people_skills_path(rows: filter_params.rows_count) + "&#{filter_params.query_params}" + = add_action_link path, {}, {data: {"turbo-frame": "search-filters"}, id: "add-row-button"} + %div.profile-header.mw-100.border-bottom.mt-4.fw-normal - Suchresultate + = ti "search.search_results" %turbo-frame{id: "search-results"} %div.border.p-3.rounded-bottom.search-results - if entries.size == 0 - Keine Resultate + = ti "search.no_results" - else - entries.each do | filtered_entry | %div.d-flex.flex-row.w-100.border-bottom diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index a2c323a6c..0cf487b7c 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -1,11 +1,11 @@ = form_with model: ([entry.person, entry]) do |f| = render('people/person_relations/form', form: f) do - content_for :input do - = t "activerecord.attributes.project.title" + = f.label :title = f.text_field :title, placeholder: "Title", class: "form-control w-100" - = t "activerecord.attributes.project.description" + = f.label :description = f.text_area :description, placeholder: "Description", class: "form-control w-100" - = t "activerecord.attributes.project.technology" + = f.label :technology = f.text_area :technology, placeholder: "Description", class: "form-control w-100" - = t "activerecord.attributes.project.role" + = f.label :role = f.text_area :role, placeholder: "Description", class: "form-control w-100" diff --git a/app/views/projects/_project.html.haml b/app/views/projects/_project.html.haml index 4abe51b13..62cbf2b9d 100644 --- a/app/views/projects/_project.html.haml +++ b/app/views/projects/_project.html.haml @@ -8,16 +8,16 @@ %div.d-flex.gap-1.flex-column %div.row %span.fw-bold.col-12.col-lg-2 - = t "activerecord.attributes.project.description" + = Project.human_attribute_name(:description) %span.col = project.description %div.row %span.fw-bold.col-12.col-lg-2 - = t "activerecord.attributes.project.role" + = Project.human_attribute_name(:role) %span.col = project.role %div.row %span.fw-bold.col-12.col-lg-2 - = t "activerecord.attributes.project.technology" + = Project.human_attribute_name(:technology) %span.col = project.technology diff --git a/app/views/shared/_error_messages.html.haml b/app/views/shared/_error_messages.html.haml deleted file mode 100644 index 879953e25..000000000 --- a/app/views/shared/_error_messages.html.haml +++ /dev/null @@ -1,6 +0,0 @@ -- if errors.any? - #error_explanation.alert.alert-danger - %h2= ti(:"errors.header", count: errors.count, model: object.to_s) - %ul - - errors.full_messages.each do |msg| - %li= msg diff --git a/app/views/skills/_header.html.haml b/app/views/skills/_header.html.haml index f1e5be87e..d356c413f 100644 --- a/app/views/skills/_header.html.haml +++ b/app/views/skills/_header.html.haml @@ -1,7 +1,7 @@ %div.d-flex.flex-column.bg-white{"data-controller": "skillset-selected"} = form_with(url: skills_path, method: :get, data: { turbo_frame: 'skills' }) do |form| %div.d-flex.flex-row.mt-2 - = form.text_field :title, class: "form-control skills-search-field rounded-end-0", placeholder: "#{t('skills.header.search')}", oninput: "this.form.requestSubmit()", include_blank: true + = form.text_field :title, class: "form-control skills-search-field rounded-end-0", placeholder: "#{ti('filter.search', target: Skill.model_name.human)}", oninput: "this.form.requestSubmit()", include_blank: true %div.border.d-flex.rounded-end.bg-white %img.pointer.p-2{src: "/assets/search.svg"} %div.d-flex.flex-row.mt-3.flex-wrap.gap-2 @@ -9,19 +9,18 @@ %label.btn.btn-outline-primary{"data-skillset-selected-target": "selectButton", "data-action": "click->skillset-selected#selectButton", "data-skillset-selected-id-param": 0} = form.radio_button :defaultSet, false, onClick: "this.form.requestSubmit()", class: "d-none" - = t('skills.header.all') + = ti('filter.all') %label.btn.btn-outline-primary{"data-skillset-selected-target": "selectButton", "data-action": "click->skillset-selected#selectButton", "data-skillset-selected-id-param": 1} = form.radio_button :defaultSet, "new", onClick: "this.form.requestSubmit()", class: "d-none" - = t('skills.header.new') + = ti('filter.new') %label.btn.btn-outline-primary{"data-skillset-selected-target": "selectButton", "data-action": "click->skillset-selected#selectButton", "data-skillset-selected-id-param": 2} = form.radio_button :defaultSet, true, onClick: "this.form.requestSubmit()", class: "d-none" - = t('skills.header.default') + = ti('filter.default') %span.d-flex.align-items-center.flex-wrap %span.text-gray.me-1 - = "#{t('skills.header.category')}:" - = form.collection_select :category, Category.all_parents.order(:title), :id, :title, {include_blank: "Select a category"}, class: "form-select fit-content", onchange: 'this.form.requestSubmit();' - =link_to image_tag("download.svg")+ "Export", export_skills_path, class: "btn text-primary d-flex p-0 center-xy" - =link_to image_tag("plus-lg.svg")+ "Neuer Skill", - new_skill_path, class: "btn text-primary p-0 d-flex center-xy", data: { turbo_frame: "remote_modal" } + = "#{Category.model_name.human}:" + = form.collection_select :category, Category.all_parents.order(:title), :id, :title, {prompt: true}, class: "form-select fit-content", onchange: 'this.form.requestSubmit();' + = export_action_link export_skills_path + = add_action_link_modal diff --git a/app/views/skills/_row.html.haml b/app/views/skills/_row.html.haml index 93359830b..c9acf0d12 100644 --- a/app/views/skills/_row.html.haml +++ b/app/views/skills/_row.html.haml @@ -15,7 +15,6 @@ .col-1.d-flex.align-items-center = f.select :portfolio, Settings.portfolio, {:selected => entry.portfolio}, class: "form-select portfolio-select" .col-1 - %div.h-100.d-flex.justify-content-center.align-items-center + %div.h-100.d-flex.justify-content-center.align-items-center.gap-3 = image_submit_tag("/assets/floppy2-fill.svg") - = link_to skills_path, class: "ms-3" do - %img.pointer{:src=> "/assets/x.svg",:height=>"16"} \ No newline at end of file + = close_action_link skills_path \ No newline at end of file diff --git a/app/views/skills/edit.html.haml b/app/views/skills/edit.html.haml index 21b209d33..157e989f8 100644 --- a/app/views/skills/edit.html.haml +++ b/app/views/skills/edit.html.haml @@ -1,4 +1,2 @@ -%div - %h1.font-bold.text-2xl.mb-3 Editing Skill - %turbo-frame{id: "#{dom_id @skill}"} - = render "skills/row", skill: @skill \ No newline at end of file +%turbo-frame{id: "#{dom_id @skill}"} + = render "skills/row", skill: @skill \ No newline at end of file diff --git a/app/views/skills/index.html.haml b/app/views/skills/index.html.haml index bb5da0140..b91e7666b 100644 --- a/app/views/skills/index.html.haml +++ b/app/views/skills/index.html.haml @@ -3,26 +3,26 @@ %div.w-100.margin-header.mt-4 .row.bg-light-subtle.border.border-top.border-5.border-secondary.border-top-0.border-start-0.border-end-0 .col-2.d-flex.align-items-center - %strong= t "skills.table.skill" + %strong= ti "table.skill" .col-1.bg-secondary-subtle.d-flex.align-items-center - %strong= t "skills.table.members" + %strong= ti "table.members" .col-3.d-flex.align-items-center - %strong= t "skills.table.category" + %strong= ti "table.category" .col-2.bg-secondary-subtle.d-flex.align-items-center - %strong= t "skills.table.subcategory" + %strong= ti "table.subcategory" .col-1.d-flex.align-items-center - %strong= t "skills.table.default_set" + %strong= ti "table.default_set" .col-1.bg-secondary-subtle.d-flex.align-items-center - %strong= t "skills.table.radar" + %strong= ti "table.radar" .col-1.d-flex.align-items-center - %strong= t "skills.table.portfolio" + %strong= ti "table.portfolio" .col-1.bg-secondary-subtle.d-flex.align-items-center - %strong= t "skills.table.modify" + %strong= ti "table.modify" %div %turbo-frame{id: "skills"} - @skills.each do |skill| %turbo-frame{id: "#{dom_id skill}"} - .row.border.border-top.table-light.tableform-hover.table-row + .row.border.border-top.table-light.tableform-hover.table-row.py-2 .col-2.d-flex.align-items-center.text-break = link_to skill.title, skill_path(skill), data: { turbo_frame: "remote_modal" } .col-1.bg-light.d-flex.align-items-center @@ -39,5 +39,5 @@ =skill.portfolio .col-1.bg-light %div.h-100.d-flex.justify-content-center.align-items-center - =link_to edit_skill_path(skill), class: "btn bg-gray-100" do - %img.pointer.edit-button{:src=> "/assets/pencil-square.svg",:height=>"16"} \ No newline at end of file + =action_link("", "pencil", edit_skill_path(skill)) + \ No newline at end of file diff --git a/app/views/skills/new.html.haml b/app/views/skills/new.html.haml index 3fbfcbf7a..d0c71c24f 100644 --- a/app/views/skills/new.html.haml +++ b/app/views/skills/new.html.haml @@ -1,2 +1,2 @@ -= render "remote_modal", title: "New Skill" do += render "remote_modal", title: ti("link.add") do = render "form", skill: @entry diff --git a/app/views/skills/show.html.haml b/app/views/skills/show.html.haml index 7c9d300a7..04167f67d 100644 --- a/app/views/skills/show.html.haml +++ b/app/views/skills/show.html.haml @@ -1,4 +1,4 @@ -= render "remote_modal", title: "Skill: #{@skill.title} (#{filter_by_rated(@skill).count } Members)" do += render "remote_modal", title: ti("title", title: @skill.title, amount: filter_by_rated(@skill).count) do %div.d-flex.flex-column - filter_by_rated(@skill).each do |person_skill| - if person_skill.level @@ -9,7 +9,7 @@ %p.m-0= @skill.title %div.col-2 %div.d-flex.flex-column - %label.form-label.text-gray= t ExpertiseTopicSkillValue.skill_levels.key(person_skill.level - 1) + %label.form-label.text-gray= ti "people_skills.levels.#{ExpertiseTopicSkillValue.skill_levels.key(person_skill.level - 1)}" %input.form-range.w-75.level{type: "range", min: 1, max: 5, value: person_skill.level, tabindex: -1} %div.col-2 %div.d-flex.flex-column @@ -17,11 +17,11 @@ %div.col-2 %div.d-flex.flex-row.form-check %input.form-check-input.me-2.certificate{type: "checkbox", checked: person_skill.certificate, disabled: true} - %label.form-label.text-gray= t "people-skills.certificate" + %label.form-label.text-gray= Skill.human_attribute_name(:certificate) %div.col-2 %div.d-flex.flex-row.form-check %input.form-check-input.me-2.core-competence{type: "checkbox", checked: person_skill.core_competence, disabled: true} - %label.form-label.text-gray= t "people-skills.core-competence" + %label.form-label.text-gray= Skill.human_attribute_name(:core_competence) %turbo-frame{id: "#{dom_id @skill}"} .row.border.border-top.table-light.tableform-hover.table-row .col-2.d-flex.align-items-center @@ -33,12 +33,11 @@ .col-2.bg-light.d-flex.align-items-center =@skill.category.title .col-1.d-flex.align-items-center - =@skill.default_set.nil? ? "Neu" : (@skill.default_set? ? "Ja" : "Nein") + =@skill.default_set.nil? ? ti("new") : (@skill.default_set? ? ti("yes") : ti("no")) .col-1.bg-light.d-flex.align-items-center =@skill.radar .col-1.bg-light.d-flex.align-items-center =@skill.portfolio .col-1 %div.h-100.d-flex.justify-content-center.align-items-center - =link_to edit_skill_path(@skill), class: "btn bg-gray-100" do - %img.pointer.edit-button{:src=> "/assets/pencil-square.svg",:height=>"16"} \ No newline at end of file + =action_link("", "pencil", edit_skill_path) \ No newline at end of file diff --git a/config/application.rb b/config/application.rb index dee2a1781..a4e4dac67 100644 --- a/config/application.rb +++ b/config/application.rb @@ -26,6 +26,7 @@ class Application < Rails::Application # Skip views, helpers and assets when generating a new resource. config.autoload_paths += %W( #{config.root}/app/uploaders) # config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')] + I18n.available_locales = [:de, :en, :fr, :it] config.i18n.default_locale = :de config.active_record.verify_foreign_keys_for_fixtures = false diff --git a/config/environments/test.rb b/config/environments/test.rb index 7509a2f58..f74fe3ae1 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -47,7 +47,7 @@ config.active_support.deprecation = :stderr # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true + config.i18n.raise_on_missing_translations = true # config.after_initialize do Bullet.enable = true diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml new file mode 100644 index 000000000..67209a83c --- /dev/null +++ b/config/i18n-tasks.yml @@ -0,0 +1,186 @@ +# i18n-tasks finds and manages missing and unused translations: https://github.com/glebm/i18n-tasks +# The "main" locale. +base_locale: de +## All available locales are inferred from the data by default. Alternatively, specify them explicitly: +# locales: [es, fr] +## Reporting locale, default: en. Available: en, ru. +# internal_locale: en + +# Read and write translations. +data: + ## Translations are read from the file system. Supported format: YAML, JSON. + ## Provide a custom adapter: + # adapter: I18n::Tasks::Data::FileSystem + + # Locale files or `Dir.glob` patterns where translations are read from: + read: + ## Default: + - config/locales/%{locale}.yml + - config/locales/*.%{locale}.yml + ## More files: + # - config/locales/**/*.%{locale}.yml + + # Locale files to write new keys to, based on a list of key pattern => file rules. Matched from top to bottom: + # `i18n-tasks normalize -p` will force move the keys according to these rules + write: + ## For example, write devise and simple form keys to their respective files: + - ['{devise, crud}.*', 'config/locales/\1.%{locale}.yml'] + ## Catch-all default: + - config/locales/%{locale}.yml + + # External locale data (e.g. gems). + # This data is not considered unused and is never written to. + external: + ## Example (replace %#= with %=): + # - "<%#= %x[bundle info vagrant --path].chomp %>/templates/locales/%{locale}.yml" + + ## Specify the router (see Readme for details). Valid values: conservative_router, pattern_router, or a custom class. + # router: conservative_router + + yaml: + write: + # do not wrap lines at 80 characters + line_width: -1 + + ## Pretty-print JSON: + # json: + # write: + # indent: ' ' + # space: ' ' + # object_nl: "\n" + # array_nl: "\n" + +# Find translate calls +search: + ## Paths or `Find.find` patterns to search in: + # paths: + # - app/ + + ## Root directories for relative keys resolution. + # relative_roots: + # - app/controllers + # - app/helpers + # - app/mailers + # - app/presenters + # - app/views + + ## Directories where method names which should not be part of a relative key resolution. + # By default, if a relative translation is used inside a method, the name of the method will be considered part of the resolved key. + # Directories listed here will not consider the name of the method part of the resolved key + # + # relative_exclude_method_name_paths: + # - + + ## Files or `File.fnmatch` patterns to exclude from search. Some files are always excluded regardless of this setting: + ## *.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss *.less + ## *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus *.webp *.map *.xlsx + exclude: + - app/assets/images + - app/assets/fonts + - app/assets/videos + - app/assets/builds + + ## Alternatively, the only files or `File.fnmatch patterns` to search in `paths`: + ## If specified, this settings takes priority over `exclude`, but `exclude` still applies. + # only: ["*.rb", "*.html.slim"] + + ## If `strict` is `false`, guess usages such as t("categories.#{category}.title"). The default is `true`. + # strict: true + + ## Allows adding ast_matchers for finding translations using the AST-scanners + ## The available matchers are: + # - RailsModelMatcher + ## Matches ActiveRecord translations like + ## User.human_attribute_name(:email) and User.model_name.human + ## - DefaultI18nSubjectMatcher + ## Matches ActionMailer's default_i18n_subject method + ## + ## To implement your own, please see `I18n::Tasks::Scanners::AstMatchers::BaseMatcher`. + ast_matchers: + - 'I18n::Tasks::Scanners::AstMatchers::RailsModelMatcher' + # - 'CustomTranslationMatchers::DryCrudTiScanner' + # - 'I18n::Tasks::Scanners::AstMatchers::DefaultI18nSubjectMatcher' + + ## Multiple scanners can be used. Their results are merged. + ## The options specified above are passed down to each scanner. Per-scanner options can be specified as well. + ## See this example of a custom scanner: https://github.com/glebm/i18n-tasks/wiki/A-custom-scanner-example + +## Translation Services +translation: +# # Google Translate +# # Get an API key and set billing info at https://code.google.com/apis/console to use Google Translate +# google_translate_api_key: "AbC-dEf5" +# # DeepL Pro Translate +# # Get an API key and subscription at https://www.deepl.com/pro to use DeepL Pro + deepl_api_key: "xxx" + deepl_host: "https://api-free.deepl.com" + deepl_version: "v2" +# deepl_api_key: "48E92789-57A3-466A-9959-1A1A1A1A1A1A" +# # deepl_host: "https://api.deepl.com" +# # deepl_version: "v2" +# # deepl_glossary_ids: +# # - f28106eb-0e06-489e-82c6-8215d6f95089 +# # - 2c6415be-1852-4f54-9e1b-d800463496b4 +# # add additional options to the DeepL.translate call: https://www.deepl.com/docs-api/translate-text/translate-text/ +# deepl_options: +# formality: prefer_less +# # OpenAI +# openai_api_key: "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +# # openai_model: "gpt-3.5-turbo" # see https://platform.openai.com/docs/models +# # may contain `%{from}` and `%{to}`, which will be replaced by source and target locale codes, respectively (using `Kernel.format`) +# # openai_system_prompt: >- +# # You are a professional translator that translates content from the %{from} locale +# # to the %{to} locale in an i18n locale array. +# # +# # The array has a structured format and contains multiple strings. Your task is to translate +# # each of these strings and create a new array with the translated strings. +# # +# # HTML markups (enclosed in < and > characters) must not be changed under any circumstance. +# # Variables (starting with %%{ and ending with }) must not be changed under any circumstance. +# # +# # Keep in mind the context of all the strings for a more accurate translation. + +## Do not consider these keys missing: +ignore_missing: +# - 'errors.messages.{accepted,blank,invalid,too_short,too_long}' + - '{devise,simple_form}.*' + - 'datetime.prompts.{month,year}' + - 'number.format.{delimiter, precision}' + - 'helpers.select.prompt' + - 'date.month_names' + +## Consider these keys used: +# ignore_unused: +# - 'activerecord.attributes.*' +# - '{devise,kaminari,will_paginate}.*' +# - 'simple_form.{yes,no}' +# - 'simple_form.{placeholders,hints,labels}.*' +# - 'simple_form.{error_notification,required}.:' + +## Exclude these keys from the `i18n-tasks eq-base' report: +# ignore_eq_base: +# all: +# - common.ok +# fr,es: +# - common.brand + +## Exclude these keys from the `i18n-tasks check-consistent-interpolations` report: +# ignore_inconsistent_interpolations: +# - 'activerecord.attributes.*' + +## Ignore these keys completely: +# ignore: +# - kaminari.* + +## Sometimes, it isn't possible for i18n-tasks to match the key correctly, +## e.g. in case of a relative key defined in a helper method. +## In these cases you can use the built-in PatternMapper to map patterns to keys, e.g.: +# +# <%# I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper', +# only: %w(*.html.haml *.html.slim), +# patterns: [['= title\b', '.page_title']] %> +# +# The PatternMapper can also match key literals via a special %{key} interpolation, e.g.: +# +# <%# I18n::Tasks.add_scanner 'I18n::Tasks::Scanners::PatternMapper', +# patterns: [['\bSpree\.t[( ]\s*%{key}', 'spree.%{key}']] %> diff --git a/config/initializers/skills_form_builder.rb b/config/initializers/skills_form_builder.rb new file mode 100644 index 000000000..79e088dee --- /dev/null +++ b/config/initializers/skills_form_builder.rb @@ -0,0 +1,23 @@ +class SkillsFormBuilder < ActionView::Helpers::FormBuilder + + def cancel(value= nil, options = {}) + value, options = nil, value if value.is_a?(Hash) + options[:class] ||= "btn btn-outline-secondary" + options[:id] ||= "cancel-button" + path ||= value || @template.polymorphic_path(self.object) + button_text = options.delete(:text) || I18n.t('helpers.cancel') + @template.link_to(button_text, path, options) + end + + def label(method, text = nil, options = {}, &block) + options[:class] ||= "form-label text-gray" + super + end + + def submit(value = nil, options = {}) + value, options = nil, value if value.is_a?(Hash) + value ||= submit_default_value + options[:class] ||= "btn btn-primary" + @template.submit_tag(value, options) + end +end diff --git a/config/locales/crud.de.yml b/config/locales/crud.de.yml index ccc652268..13783d622 100644 --- a/config/locales/crud.de.yml +++ b/config/locales/crud.de.yml @@ -1,64 +1,48 @@ -# Translations of all crud strings. -# See also I18nHelper#translate_inheritable and #translate_association. - +--- de: - # global scope + crud: + create: + flash: + success: "%{model} wurde erfolgreich erstellt." + destroy: + flash: + failure: "%{model} konnte nicht gelöscht werden." + success: "%{model} wurde erfolgreich gelöscht." + edit: + title: "%{model} bearbeiten" + new: + title: "%{model} erstellen" + show: + title: "%{model}" + update: + flash: + success: "%{model} wurde erfolgreich aktualisiert." global: - "yes": "ja" - "no": "nein" - no_list_entries: Keine Einträge gefunden. - confirm_delete: Wollen Sie diesen Eintrag wirklich löschen? - associations: - # association keys may be customized per model with the prefix - # 'activerecord.associations.{model}.' or even per actual association with - # 'activerecord.associations.models.{holder_model}.{assoc_name}.' - no_entry: (keine) - none_available: (keine verfügbar) + no_entry: "(keine)" + none_available: "(keine verfügbar)" please_select: Bitte auswählen - button: - save: Speichern cancel: Abbrechen + save: Speichern search: Suchen - + confirm_delete: Willst du diesen Eintrag wirklich löschen? + errors: + header: + one: 'Ein Fehler verhinderte das Speichern dieses Eintrages:' + other: "%{count} Fehler verhinderten das Speichern dieses Eintrages:" link: - show: Anzeigen - edit: Bearbeiten add: Erstellen delete: Löschen + edit: Bearbeiten list: Liste - - errors: - header: - one: "Ein Fehler verhinderte das Speichern dieses Eintrages:" - other: "%{count} Fehler verhinderten das Speichern dieses Eintrages:" - - # formats - time: - formats: - time: "%H:%M" - - # list controller + show: Anzeigen + 'no': nein + no_list_entries: Keine Einträge gefunden. + 'yes': ja list: index: title: "%{models}" - - # crud controller - crud: - show: - title: "%{model}" - new: - title: "%{model} erstellen" - edit: - title: "%{model} bearbeiten" - create: - flash: - success: "%{model} wurde erfolgreich erstellt." - update: - flash: - success: "%{model} wurde erfolgreich aktualisiert." - destroy: - flash: - success: "%{model} wurde erfolgreich gelöscht." - failure: "%{model} konnte nicht gelöscht werden." + time: + formats: + time: "%H:%M" diff --git a/config/locales/crud.en.yml b/config/locales/crud.en.yml index 637fbdfb0..621d688bc 100644 --- a/config/locales/crud.en.yml +++ b/config/locales/crud.en.yml @@ -1,64 +1,48 @@ -# Translations of all crud strings. -# See also StandardHelper#translate_inheritable and #translate_association. - +--- en: - # global scope + crud: + create: + flash: + success: "%{model} was successfully created." + destroy: + flash: + failure: "%{model} could not be deleted." + success: "%{model} was successfully deleted." + edit: + title: Edit %{model} + new: + title: New %{model} + show: + title: "%{model}" + update: + flash: + success: "%{model} was successfully updated." global: - "yes": "yes" - "no": "no" - no_list_entries: No entries found. - confirm_delete: Do you really want to delete this entry? - associations: - # association keys may be customized per model with the prefix - # 'activerecord.associations.{model}.' or even per actual association with - # 'activerecord.associations.models.{holder_model}.{assoc_name}.' - no_entry: (none) - none_available: (none available) + no_entry: "(none)" + none_available: "(none available)" please_select: Please select - button: - save: Save cancel: Cancel + save: Save search: Search - + confirm_delete: Do you really want to delete this entry? + errors: + header: + one: 'One error prohibited this entry from being saved:' + other: "%{count} errors prohibited this entry from being saved:" link: - show: Show - edit: Edit add: Add delete: Delete + edit: Edit list: List - - errors: - header: - one: "1 error prohibited this entry from being saved:" - other: "%{count} errors prohibited this entry from being saved:" - - # formats - time: - formats: - time: "%H:%M" - - # list controller + show: Show + 'no': 'no' + no_list_entries: No entries found. + 'yes': 'yes' list: index: title: Listing %{models} - - # crud controller - crud: - show: - title: "%{model}" - new: - title: "New %{model}" - edit: - title: "Edit %{model}" - create: - flash: - success: "%{model} was successfully created." - update: - flash: - success: "%{model} was successfully updated." - destroy: - flash: - success: "%{model} was successfully deleted." - failure: "%{model} could not be deleted." + time: + formats: + time: "%H:%M" diff --git a/config/locales/crud.fr.yml b/config/locales/crud.fr.yml new file mode 100644 index 000000000..8b4b835f9 --- /dev/null +++ b/config/locales/crud.fr.yml @@ -0,0 +1,48 @@ +--- +fr: + crud: + create: + flash: + success: "%{model} a été créé avec succès." + destroy: + flash: + failure: "%{model} n'a pas pu être supprimé." + success: "%{model} a été supprimé avec succès." + edit: + title: "%{model} éditer" + new: + title: "%{model} créer" + show: + title: "%{model}" + update: + flash: + success: "%{model} a été mis à jour avec succès." + global: + associations: + no_entry: "(aucune)" + none_available: "(aucun disponible)" + please_select: Veuillez sélectionner + button: + cancel: Annuler + save: Enregistrer + search: Rechercher + confirm_delete: Voulez-vous vraiment supprimer cette entrée ? + errors: + header: + one: 'Une erreur a empêché l''enregistrement de cette entrée:' + other: "%{count} Des erreurs ont empêché l'enregistrement de cette entrée:" + link: + add: Créer + delete: Supprimer + edit: Modifier + list: Liste + show: Annonces + 'no': non + no_list_entries: Aucune entrée trouvée. + 'yes': oui + list: + index: + title: "%{models}" + time: + formats: + time: "%H:%M" diff --git a/config/locales/crud.it.yml b/config/locales/crud.it.yml index 6e375f352..1c48e77b0 100644 --- a/config/locales/crud.it.yml +++ b/config/locales/crud.it.yml @@ -1,64 +1,48 @@ -# Translations of all crud strings by mberlanda -# See also StandardHelper#translate_inheritable and #translate_association. - +--- it: - # global scope + crud: + create: + flash: + success: "%{model} è stato creato con successo." + destroy: + flash: + failure: Non è stato possibile eliminare %{model}. + success: "%{model} è stato eliminato con successo." + edit: + title: Modifica %{model} + new: + title: Nuovo %{model} + show: + title: "%{model}" + update: + flash: + success: "%{model} è stato aggiornato con successo." global: - "yes": "si" - "no": "no" - no_list_entries: Nessun elemento trovato. - confirm_delete: Vuoi davvero eliminare questo elemento? - associations: - # association keys may be customized per model with the prefix - # 'activerecord.associations.{model}.' or even per actual association with - # 'activerecord.associations.models.{holder_model}.{assoc_name}.' - no_entry: (nessuno) - none_available: (non disponibile) + no_entry: "(nessuno)" + none_available: "(non disponibile)" please_select: Prego selezionare - button: - save: Salva cancel: Annulla + save: Salva search: Cerca - + confirm_delete: Vuoi davvero eliminare questo elemento? + errors: + header: + one: 'Un errore impedisce il salvataggio di questo elemento:' + other: "%{count} errori impediscono il salvataggio di questo elemento:" link: - show: Mostra - edit: Modifica add: Aggiungi delete: Elimina + edit: Modifica list: Elenco - - errors: - header: - one: "1 errore impedisce il salvataggio di questo elemento:" - other: "%{count} errori impediscono il salvataggio di questo elemento:" - - # formats - time: - formats: - time: "%H:%M" - - # list controller + show: Mostra + 'no': 'no' + no_list_entries: Nessun elemento trovato. + 'yes': si list: index: title: Elenco %{models} - - # crud controller - crud: - show: - title: "%{model}" - new: - title: "Nuovo %{model}" - edit: - title: "Modifica %{model}" - create: - flash: - success: "%{model} è stato creato con successo." - update: - flash: - success: "%{model} è stato aggiornato con successo." - destroy: - flash: - success: "%{model} è stato eliminato con successo." - failure: "Non è stato possibile eliminare %{model}." + time: + formats: + time: "%H:%M" diff --git a/config/locales/de.yml b/config/locales/de.yml index 8b9ee4da9..8019c37a8 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,128 +1,259 @@ +--- de: - errors: - profile-not-found: Profil konnte nicht gefunden werden. - messages: - max_size_error: sollte nicht grösser als 10MB sein. - helpers: - submit: - edit: "%{model} bearbeiten" - add: "%{model} hinzufügen" - cancel: Abbrechen - delete: Löschen - save-and-new: Speichern & Neu - button: - edit: Bearbeiten - profile: - personal-data: Personalien - core-competences: Kernkompetenzen - educations: Ausbildungen - advanced-trainings: Weiterbildungen - activities: Stationen - projects: Projekte - updated_at: Zuletzt bearbeitet - no_skills_rated_msg: Dieses Profil hat noch keine bewerteten Skills. Gehe zum Skills Tab und bewerte die für dich relevanten Skills. - attributes: - year_from: Jahr von - year_to: Jahr bis - month_from: Monat von - month_to: Monat bis activerecord: + attributes: + activity: + description: Firmenangaben und Beschreibung der Tätigkeit + role: Rolle + year_from: Startdatum + advanced_training: + description: Beschreibung + year_from: Startdatum + education: + location: Ausbildungsort + title: Ausbildung + year_from: Startdatum + people_skill: + certificate: Zertifikat + core_competence: Kernkompetenz + level: Level + skill: Skill + person: + activities: + one: Station + other: Stationen + advanced_trainings: + one: Weiterbildung + other: Weiterbildungen + birthdate: Geburtsdatum + competence_notes: Notizen Member + department: Organisationseinheit + dual_citizen: Doppelbürger + educations: + one: Ausbildung + other: Ausbildungen + email: Email + languages: + one: Sprache + other: Sprachen + location: Ort + marital_status: Zivilstand + name: Name + nationality: Nationalität + person_roles: + one: Funktion + other: Funktionen + picture: Bild + projects: + one: Projekt + other: Projekte + roles: + one: Funktion + other: Funktionen + shortname: Kurzname + skills: + one: Skill + other: Skills + title: Abschluss + project: + description: Beschreibung + role: Rolle und Aufgaben + technology: Eingesetzte Technologien + title: Projekt + year_from: Startdatum + skill: + category: Kategorie models: - advanced_training: Weiterbildung - education: Ausbildung activity: Station - project: Projekt - skill: Skill - people_skill: Skill - role: - one: Rolle - other: Rollen + advanced_training: + one: Weiterbildung + other: Weiterbildungen + category: + one: Kategorie + other: Kategorien company: one: Firma other: Firmen department: one: Organisationseinheit other: Organisationseinheiten - attributes: - person: - picture: Bild - advanced_training: - description: Beschreibung education: - title: Ausbildung - location: Ausbildungsort - activity: - role: Rolle - description: Firmenangaben und Beschreibung der Tätigkeit - project: - title: Projekt - description: Beschreibung - role: Rolle und Aufgaben - technology: Eingesetzte Technologien + one: Ausbildung + other: Ausbildungen + people_skill: + one: Skill + other: Skills + project: + one: Projekt + other: Projekte + role: + one: Rolle + other: Rollen + skill: + one: Skill + other: Skills admin: - panel: - title: Admin Panel - skills: - header: + global: + link: + list: Admin Panel + cv_search: + global: + search_placeholder: CVs durchsuchen... + search_skills: Skills ebenfalls durchsuchen + errors: + messages: + cannot_remove: darf nicht gelöscht werden. + invalid_date_range: muss vor dem Enddatum sein. + max_size_10MB: darf nicht grösser als 10MB sein. + max_size_error: darf nicht grösser als 10MB sein. + profile-not-found: Profil konnte nicht gefunden werden. + valid_percent_range: muss zwischen 0 und 200 liegen. + global: + date: + from: Von + month: Monat + till_today: Bis Heute + to: Bis + today: Heute + with_enddate: Mit Enddatum + year: Jahr + devise: + admin: "(Admin)" + admin_panel: Admin Bereich + devise: Devise + mockdata: Mockdata + no_omniauth_providers: Ein Fehler ist aufgetreten, es sind keine Omniauth-Anbieter verfügbar, bitte kontaktieren Sie den Administrator. + sign_in: Anmelden + sign_in_with: Mit %{provider} anmelden + sign_out: Abmelden + 'false': Nein + filter: all: Alle - new: Neue default: Default - category: Kategorie - search: Skills suchen - table: - skill: Skill - members: Mitglieder - category: Kategorie - subcategory: Subkategorie - default_set: Default-Set - radar: Radar - portfolio: Portfolio - modify: Ändern + new: Neue + rated: Bewertet + search: "%{target} suchen" + unrated: Nicht bewertet + link: + cancel: Abbrechen + download: Herunterladen + export: Exportieren + remove: Entfernen + save_new: Speichern & Neu + navbar: + cv_search: CV Suche + profile: Profil + skill_search: Skill Suche + skillset: Skillset + new: Neu + people_skills: + certificate: Zertifikat + core-competence: Kernkompetenz + interest: Interesse + levels: + expert: Experte + junior: Junior + level: Level + professional: Professionell + senior: Senior + trainee: Azubi + unweighted: Nicht bewertet + search: + found_in: Gefunden in + no_results: Keine Resultate + search_results: Suchergebnisse + 'true': Ja + helpers: + cancel: Abbrechen + submit: + add: "%{model} hinzufügen" + delete: Löschen + edit: "%{model} bearbeiten" marital_statuses: - single: ledig + divorced: geschieden married: verheiratet - widowed: verwitwet registered_partnership: eingetragene Partnerschaft - divorced: geschieden - people-skills: - levels: - level: Erfahrung - unweighted: Nicht bewertet - trainee: Trainee - junior: Junior - professional: Professional - senior: Senior - expert: Expert - filter: - all: Alle - rated: Bewertet - unrated: Nicht bewertet - interest: Interesse - certificate: Zertifikat - core-competence: Kernkompetenz - date_range_picker: - from: Von - to: Bis - today: Heute - till_today: Bis Heute - with_enddate: Mit Enddatum - - cv_search: - search_skills: Skills ebenfalls durchsuchen - advanced_trainings: Weiterbildungen - educations: Ausbildungen - activities: Stationen - projects: Projekte - name: Name - location: Wohnort - title: Abschluss - competence_notes: Kompetenzen - roles: Funktionen - department: Organisationseinheit - skills: Skills + single: ledig + widowed: verwitwet people: - show: + cv: + no_skills_rated_msg: Dieses Profil hat noch keine bewerteten Skills. Gehe zum Skills Tab und bewerte die für dich relevanten Skills. + export_cv: + export_form: + anonymised_cv: Anonymisierter CV + competences_skills: Kernkompetenzen - Skills + location: 'Niederlassung (für Footer):' + skills_by_level: Skills nach Level + trainee: Trainee + global: confirm_delete: Willst du diese Person wirklich löschen? + link: + add: Neues Profil + delete: Person löschen more_actions: Weitere Aktionen + tabbar: + cv: CV + skills: Skills + index: + choose_create_person: Wähle eine Person aus oder erfasse ein neues Profil + welcome: Willkommen bei + new: + personals: Personalien + profile: + add_function: Funktion hinzufügen + add_language: Sprache hinzufügen + change_image: Bild ändern + core_competences: Kernkompetenzen + personals: Personalien + upload_image: Bild hochladen + scroll_to_menu: + activities: Station + advanced-trainings: Weiterbildungen + core-competences: Kernkompetenzen + educations: Ausbildungen + personal-data: Personliche Daten + projects: Projekte + search: + new_profile: Neues Profil + updated_at: Zuletzt bearbeitet + people/people_skills: + edit_form: + rate: Bewerten + unrate: Nicht bewerten + global: + confirm_delete: Willst du diese Person wirklich löschen? link: + add: Neues Profil delete: Person löschen + more_actions: Weitere Aktionen + tabbar: + cv: CV + skills: Skills + index: + new_skills_to_rate: Neue Skills zur Bewertung + scroll_to_menu: + link: + add: Skill hinzufügen + people_skills: + global: + link: + add: Skill hinzufügen (max. 5) + people_skills/filter_form: + global: + link: + add: Skill hinzufügen (max. 5) + profile: + updated_at: Zuletzt bearbeitet + skills: + global: + table: + category: Kategorie + default_set: Default-Set + members: Mitglieder + modify: Ändern + portfolio: Portfolio + radar: Radar + skill: Skill + subcategory: Subkategorie + show: + title: 'Skill: %{title} (%{amount} Members)' diff --git a/config/locales/devise.de.yml b/config/locales/devise.de.yml index 5ef1959c3..32409924c 100644 --- a/config/locales/devise.de.yml +++ b/config/locales/devise.de.yml @@ -1,3 +1,4 @@ +--- de: activerecord: attributes: @@ -17,16 +18,16 @@ de: locked_at: Gesperrt am password: Passwort password_confirmation: Passwortbestätigung + privacy_accepted_at: Datenschutzerklärung remember_created_at: Angemeldet bleiben vom remember_me: Angemeldet bleiben reset_password_sent_at: Passwort-Zurücksetzen-E-Mail gesendet am reset_password_token: Passwort-Zurücksetzen-Token sign_in_count: Anzahl Anmeldungen + terms_accepted_at: AGB unconfirmed_email: Unbestätigte E-Mail-Adresse unlock_token: Entsperrungs-Token updated_at: Aktualisiert am - terms_accepted_at: AGB - privacy_accepted_at: Datenschutzerklärung models: user: Benutzer devise: @@ -44,11 +45,11 @@ de: locked: Ihr Konto ist gesperrt. not_found_in_database: "%{authentication_keys} oder Passwort ungültig." timeout: Ihre Sitzung ist abgelaufen, bitte melde Sie sich erneut an. + titles: + unauthorized: 401 Keine ausreichenden Berechtigungen unauthenticated: Sie müssen sich anmelden oder registrieren, bevor Sie fortfahren können. - unconfirmed: Sie müssen Ihr Konto bestätigen, bevor Sie fortfahren können. unauthorized: Sie sind nicht berechtigt, auf diese Seite zuzugreifen. - titles: - unauthorized: "401 Keine ausreichenden Berechtigungen" + unconfirmed: Sie müssen Ihr Konto bestätigen, bevor Sie fortfahren können. mailer: confirmation_instructions: action: Mein Konto bestätigen diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 260e1c4ba..9f8540f3c 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -1,65 +1,94 @@ -# Additional translations at https://github.com/heartcombo/devise/wiki/I18n - +--- en: + activerecord: + attributes: + user: + confirmation_sent_at: Confirmation sent on + confirmation_token: Confirmation token + confirmed_at: Confirmed on + created_at: Created on + current_password: Previous password + current_sign_in_at: Current registration from + current_sign_in_ip: IP of the current application + email: E-mail + encrypted_password: Encrypted password + failed_attempts: Failed attempts + last_sign_in_at: Last registration on + last_sign_in_ip: IP of the last login + locked_at: Locked on + password: Password + password_confirmation: Password confirmation + privacy_accepted_at: Privacy policy + remember_created_at: Stay registered from + remember_me: Stay logged in + reset_password_sent_at: Password reset e-mail sent on + reset_password_token: Password reset token + sign_in_count: Number of registrations + terms_accepted_at: GTC + unconfirmed_email: Unconfirmed e-mail address + unlock_token: Unlock token + updated_at: Updated on + models: + user: Users devise: confirmations: - confirmed: "Your email address has been successfully confirmed." - send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." + confirmed: Your email address has been successfully confirmed. + send_instructions: You will receive an email with instructions for how to confirm your email address in a few minutes. + send_paranoid_instructions: If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes. failure: - already_authenticated: "You are already signed in." - inactive: "Your account is not activated yet." - invalid: "Invalid %{authentication_keys} or password." - locked: "Your account is locked." - last_attempt: "You have one more attempt before your account is locked." - not_found_in_database: "Invalid %{authentication_keys} or password." - timeout: "Your session expired. Please sign in again to continue." - unauthenticated: "You need to sign in or sign up before continuing." - unconfirmed: "You have to confirm your email address before continuing." + already_authenticated: You are already signed in. + inactive: Your account is not activated yet. + invalid: Invalid %{authentication_keys} or password. + last_attempt: You have one more attempt before your account is locked. + locked: Your account is locked. + not_found_in_database: Invalid %{authentication_keys} or password. + timeout: Your session expired. Please sign in again to continue. + unauthenticated: You need to sign in or sign up before continuing. + unconfirmed: You have to confirm your email address before continuing. mailer: confirmation_instructions: - subject: "Confirmation instructions" - reset_password_instructions: - subject: "Reset password instructions" - unlock_instructions: - subject: "Unlock instructions" + subject: Confirmation instructions email_changed: - subject: "Email Changed" + subject: Email Changed password_change: - subject: "Password Changed" + subject: Password Changed + reset_password_instructions: + subject: Reset password instructions + unlock_instructions: + subject: Unlock instructions omniauth_callbacks: - failure: "Could not authenticate you from %{kind} because \"%{reason}\"." - success: "Successfully authenticated from %{kind} account." + failure: Could not authenticate you from %{kind} because "%{reason}". + success: Successfully authenticated from %{kind} account. passwords: - no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." - send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." - updated: "Your password has been changed successfully. You are now signed in." - updated_not_active: "Your password has been changed successfully." + no_token: You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided. + send_instructions: You will receive an email with instructions on how to reset your password in a few minutes. + send_paranoid_instructions: If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes. + updated: Your password has been changed successfully. You are now signed in. + updated_not_active: Your password has been changed successfully. registrations: - destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." - signed_up: "Welcome! You have signed up successfully." - signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." - signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." - signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." - update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address." - updated: "Your account has been updated successfully." - updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again." + destroyed: Bye! Your account has been successfully cancelled. We hope to see you again soon. + signed_up: Welcome! You have signed up successfully. + signed_up_but_inactive: You have signed up successfully. However, we could not sign you in because your account is not yet activated. + signed_up_but_locked: You have signed up successfully. However, we could not sign you in because your account is locked. + signed_up_but_unconfirmed: A message with a confirmation link has been sent to your email address. Please follow the link to activate your account. + update_needs_confirmation: You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address. + updated: Your account has been updated successfully. + updated_but_not_signed_in: Your account has been updated successfully, but since your password was changed, you need to sign in again. sessions: - signed_in: "Signed in successfully." - signed_out: "Signed out successfully." - already_signed_out: "Signed out successfully." + already_signed_out: Signed out successfully. + signed_in: Signed in successfully. + signed_out: Signed out successfully. unlocks: - send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." - send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." - unlocked: "Your account has been unlocked successfully. Please sign in to continue." + send_instructions: You will receive an email with instructions for how to unlock your account in a few minutes. + send_paranoid_instructions: If your account exists, you will receive an email with instructions for how to unlock it in a few minutes. + unlocked: Your account has been unlocked successfully. Please sign in to continue. errors: messages: - already_confirmed: "was already confirmed, please try signing in" - confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" - expired: "has expired, please request a new one" - not_found: "not found" - not_locked: "was not locked" + already_confirmed: was already confirmed, please try signing in + confirmation_period_expired: needs to be confirmed within %{period}, please request a new one + expired: has expired, please request a new one + not_found: not found + not_locked: was not locked not_saved: - one: "1 error prohibited this %{resource} from being saved:" + one: 'One error prohibited this %{resource} from being saved:' other: "%{count} errors prohibited this %{resource} from being saved:" diff --git a/config/locales/devise.fr.yml b/config/locales/devise.fr.yml new file mode 100644 index 000000000..cb244820a --- /dev/null +++ b/config/locales/devise.fr.yml @@ -0,0 +1,42 @@ +--- +fr: + activerecord: + attributes: + user: + confirmation_sent_at: Confirmation envoyée le + confirmation_token: Jeton de confirmation + confirmed_at: Confirmé le + created_at: Créé le + current_password: Ancien mot de passe + current_sign_in_at: Inscription actuelle du + current_sign_in_ip: IP de la connexion actuelle + email: Courrier électronique + encrypted_password: Mot de passe crypté + failed_attempts: Tentatives ratées + last_sign_in_at: Dernière inscription le + last_sign_in_ip: IP de la dernière connexion + locked_at: Bloqué le + password: Mot de passe + password_confirmation: Confirmation du mot de passe + privacy_accepted_at: Déclaration de confidentialité + remember_created_at: Rester connecté du + remember_me: Rester connecté + reset_password_sent_at: E-mail de réinitialisation du mot de passe envoyé le + reset_password_token: Jeton de réinitialisation du mot de passe + sign_in_count: Nombre d'inscriptions + terms_accepted_at: Conditions générales de vente + unconfirmed_email: Adresse e-mail non confirmée + unlock_token: Jeton de déverrouillage + updated_at: Mis à jour le + models: + user: Utilisateur + errors: + messages: + already_confirmed: a déjà été confirmé, veuillez essayer de vous connecter + confirmation_period_expired: devait être confirmée dans un délai de %{period}, veuillez en faire la demande à nouveau. + expired: a expiré, veuillez en redemander + not_found: pas trouvé + not_locked: n'est pas bloqué + not_saved: + one: "%{resource} n'a pas pu être enregistré en raison d'une erreur :" + other: "%{count} Des erreurs empêchaient l'enregistrement de %{resource}:" diff --git a/config/locales/devise.it.yml b/config/locales/devise.it.yml new file mode 100644 index 000000000..47f6e0dfd --- /dev/null +++ b/config/locales/devise.it.yml @@ -0,0 +1,42 @@ +--- +it: + activerecord: + attributes: + user: + confirmation_sent_at: Conferma inviata su + confirmation_token: Gettone di conferma + confirmed_at: Confermato su + created_at: Creato il + current_password: Parola d'ordine precedente + current_sign_in_at: Registrazione attuale da + current_sign_in_ip: IP dell'applicazione corrente + email: E-mail + encrypted_password: Password criptata + failed_attempts: Tentativi falliti + last_sign_in_at: Ultima registrazione il + last_sign_in_ip: IP dell'ultimo accesso + locked_at: Bloccato su + password: Password + password_confirmation: Conferma della password + privacy_accepted_at: Informativa sulla privacy + remember_created_at: Rimanere registrati da + remember_me: Rimani connesso + reset_password_sent_at: Email di reimpostazione della password inviata il + reset_password_token: Token per la reimpostazione della password + sign_in_count: Numero di registrazioni + terms_accepted_at: GTC + unconfirmed_email: Indirizzo e-mail non confermato + unlock_token: Gettone di sblocco + updated_at: Aggiornato il + models: + user: Utenti + errors: + messages: + already_confirmed: è già stato confermato, si prega di provare ad accedere + confirmation_period_expired: "%{period} doveva essere confermato entro , si prega di richiedere nuovamente." + expired: è scaduto, richiederne uno nuovo + not_found: non trovato + not_locked: non è bloccato + not_saved: + one: "%{resource} non è stato possibile salvarlo a causa di un errore:" + other: "%{count} %{resource} Gli errori hanno impedito il salvataggio di :" diff --git a/config/locales/en.yml b/config/locales/en.yml index b46f71e1a..ac2c9c21e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,99 +1,255 @@ +--- en: - errors: - profile-not-found: Profile could not be found. - helpers: - submit: - edit: "Edit %{model}" - add: "Add %{model}" - cancel: Cancel - delete: Delete - save-and-new: Save & new - edit: Edit - active_record: + activerecord: + attributes: + activity: + description: Company details and description of the activity + role: Role + year_from: Start date + advanced_training: + description: Description + year_from: Start date + education: + location: Training location + title: Education + year_from: Start date + people_skill: + certificate: Certificate + core_competence: Core competence + level: Level + skill: Skill + person: + activities: + one: Station + other: Stations + advanced_trainings: + one: Further training + other: Further training + birthdate: Date of birth + competence_notes: Notes Member + department: Department + dual_citizen: Dual citizens + educations: + one: Education + other: Educations + email: Email + languages: + one: Language + other: Languages + location: Location + marital_status: Marital status + name: Name + nationality: Nationality + person_roles: + one: Function + other: Functions + picture: Image + projects: + one: Project + other: Projects + roles: + one: Function + other: Functions + shortname: Short name + skills: + one: Skill + other: Skills + title: Degree + project: + description: Description + role: Role and tasks + technology: Technologies used + title: Project + year_from: Start date + skill: + category: Category models: - skill: Skill - people_skill: Skill - role: - one: Role - other: Roles + activity: Station + advanced_training: Further training + category: + one: Category + other: Categories company: one: Company other: Companies department: one: Department other: Departments + education: + one: Education + other: Educations + people_skill: + one: Skill + other: Skills + project: Project + role: + one: Role + other: Roles + skill: + one: Skill + other: Skills admin: - panel: - title: Admin panel - profile: - personal-data: Personal data - core-competences: Core competences - educations: Educations - advanced-trainings: Advanced trainings - activities: Activities - projects: Projects - updated_at: Zuletzt bearbeitet - no_skills_rated_msg: This profile doesn't have any rated skills yet, head to the Skills Tab and rate some of the skills relevant to you. - skills: - header: + global: + link: + list: Admin Panel + cv_search: + global: + search_placeholder: Search CVs... + search_skills: Search skills as well + errors: + messages: + cannot_remove: must not be deleted. + invalid_date_range: must be before the end date. + max_size_10MB: must not be larger than 10MB. + max_size_error: must not be larger than 10MB. + profile-not-found: Profile could not be found. + valid_percent_range: must be between 0 and 200. + global: + date: + from: From + month: Month + till_today: Until today + to: Until + today: Today + with_enddate: With end date + year: Year + devise: + admin: "(Admin)" + admin_panel: Admin area + devise: Devise + mockdata: Mockdata + no_omniauth_providers: An error has occurred, there are no Omniauth providers available, please contact the administrator. + sign_in: Log in + sign_in_with: 'Log in with %{provider} ' + sign_out: Log out + 'false': 'No' + filter: all: All - new: New default: Default - category: Category - search: Search skills - table: - skill: Skill - members: Members - category: Category - subcategory: Subcategory - default_set: Defaultset - radar: Radar - portfolio: Portfolio - modify: Modify + new: New + rated: Rated + search: "%{target} search" + unrated: Not rated + link: + cancel: Cancel + download: Download + export: Export + remove: Remove + save_new: Save & New + navbar: + cv_search: CV search + profile: Profile + skill_search: Skill search + skillset: Skillset + new: New + people_skills: + certificate: Certificate + core-competence: Core competence + interest: Interest + levels: + expert: Expert + junior: Junior + level: Level + professional: Professional + senior: Senior + trainee: Trainee + unweighted: Not rated + search: + found_in: Found in + no_results: No results + search_results: Search results + 'true': 'Yes' + helpers: + cancel: Cancel + submit: + add: "%{model} add" + delete: Delete + edit: "%{model} edit" marital_statuses: - single: single + divorced: divorced married: married - widowed: widowed registered_partnership: registered partnership - divorced: divorced - people-skills: - levels: - level: Experience - unweighted: Unweighted - trainee: Trainee - junior: Junior - professional: Professional - senior: Senior - expert: Expert - interest: Interest - certificate: Certificate - core-competence: Core Competence - date_range_picker: - from: From - to: To - today: Today - - people-skills: - level: - trainee: Trainee - junior: Junior - professional: Professional - senior: Senior - expert: Expert - interest: Interest - certificate: Certificate - core-competence: Core Competence - filter: - all: ALl - rated: Rated - unrated: Unrated - date_range_picker: - from: From - to: To - today: Today + single: single + widowed: widowed people: - show: - confirm_delete: Are you sure you want to delete this person? + cv: + no_skills_rated_msg: This profile has no rated skills yet. Go to the Skills tab and rate the skills relevant to you. + export_cv: + export_form: + anonymised_cv: Anonymized CV + competences_skills: Core competencies - Skills + location: 'Branch office (for footer):' + skills_by_level: Skills by level + trainee: Trainee + global: + confirm_delete: Do you really want to delete this person? + link: + add: New profile + delete: Delete person more_actions: More actions + tabbar: + cv: CV + skills: Skills + index: + choose_create_person: Select a person or create a new profile + welcome: Welcome to + new: + personals: Personal details + profile: + add_function: Add function + add_language: Add language + change_image: Change picture + core_competences: Core competencies + personals: Personal details + upload_image: Upload image + scroll_to_menu: + activities: Station + advanced-trainings: Further training + core-competences: Core competencies + educations: Trainings + personal-data: Personal data + projects: Projects + search: + new_profile: New profile + updated_at: Last edited + people/people_skills: + edit_form: + rate: Rate + unrate: Do not rate + global: + confirm_delete: Do you really want to delete this person? link: + add: New profile delete: Delete person + more_actions: More actions + tabbar: + cv: CV + skills: Skills + index: + new_skills_to_rate: New skills to rate + scroll_to_menu: + link: + add: Add skill + people_skills: + global: + link: + add: Add skill (max. 5) + people_skills/filter_form: + global: + link: + add: Add skill (max. 5) + profile: + updated_at: Last edited + skills: + global: + table: + category: Category + default_set: Default set + members: Members + modify: Change + portfolio: Portfolio + radar: Radar + skill: Skill + subcategory: Subcategory + show: + title: 'Skill: %{title} (%{amount} Members)' diff --git a/config/locales/fr.yml b/config/locales/fr.yml new file mode 100644 index 000000000..ae83fa505 --- /dev/null +++ b/config/locales/fr.yml @@ -0,0 +1,255 @@ +--- +fr: + activerecord: + attributes: + activity: + description: Coordonnées de la société et description de l'activité + role: Rouleau + year_from: Date de début + advanced_training: + description: Description + year_from: Date de début + education: + location: Lieu de formation + title: Formation + year_from: Date de début + people_skill: + certificate: Certificat + core_competence: Compétence clé + level: Niveau + skill: Compétence + person: + activities: + one: Station + other: Stations + advanced_trainings: + one: Formation continue + other: Formations continues + birthdate: Date de naissance + competence_notes: Notes Member + department: Unité organisationnelle + dual_citizen: Double nationalité + educations: + one: Formation + other: Formations + email: Email + languages: + one: Langue + other: Langues + location: Lieu + marital_status: État civil + name: Nom + nationality: Nationalité + person_roles: + one: Fonction + other: Fonctions + picture: Image + projects: + one: Projet + other: Projets + roles: + one: Fonction + other: Fonctions + shortname: Nom court + skills: + one: Compétence + other: Compétences + title: Conclusion + project: + description: Description + role: Rôle et tâches + technology: Technologies utilisées + title: Projet + year_from: Date de début + skill: + category: Catégorie + models: + activity: Station + advanced_training: Formation continue + category: + one: Catégorie + other: Catégories + company: + one: Société + other: Entreprises + department: + one: Unité organisationnelle + other: Unités organisationnelles + education: + one: Formation + other: Formations + people_skill: + one: Compétence + other: Compétences + project: Projet + role: + one: Rouleau + other: Rouleaux + skill: + one: Compétence + other: Compétences + admin: + global: + link: + list: Panneau d'administration + cv_search: + global: + search_placeholder: Chercher dans les CV... + search_skills: Rechercher également des compétences + errors: + messages: + cannot_remove: ne doit pas être supprimé. + invalid_date_range: doit être antérieure à la date de fin. + max_size_10MB: ne doit pas dépasser 10 Mo. + max_size_error: ne doit pas dépasser 10 Mo. + profile-not-found: Le profil n'a pas été trouvé. + valid_percent_range: doit être compris entre 0 et 200. + global: + date: + from: De + month: Mois + till_today: Jusqu'à aujourd'hui + to: Jusqu'à + today: Aujourd'hui + with_enddate: Avec date de fin + year: Année + devise: + admin: "(Admin)" + admin_panel: Zone d'administration + devise: Devise + mockdata: Mockdata + no_omniauth_providers: Une erreur s'est produite, aucun fournisseur Omniauth n'est disponible, veuillez contacter l'administrateur. + sign_in: S'inscrire + sign_in_with: 'S''inscrire avec %{provider} ' + sign_out: Se désinscrire + 'false': Non + filter: + all: Tous les + default: Défaut + new: Nouveau + rated: Évalué + search: "%{target} cherchent" + unrated: Non évalué + link: + cancel: Annuler + download: Télécharger + export: Exporter + remove: Supprimer + save_new: Enregistrer & Nouveau + navbar: + cv_search: Recherche de CV + profile: Profil + skill_search: Recherche de compétences + skillset: Kit de compétences + new: Nouveau + people_skills: + certificate: Certificat + core-competence: Compétence clé + interest: Intérêt + levels: + expert: Expert + junior: Junior + level: Niveau + professional: Professionnel + senior: Senior + trainee: Apprenti + unweighted: Non évalué + search: + found_in: Trouvé dans + no_results: Pas de résultats + search_results: Résultats de la recherche + 'true': Oui + helpers: + cancel: Annuler + submit: + add: "%{model} ajouter" + delete: Supprimer + edit: "%{model} éditer" + marital_statuses: + divorced: divorcé(e) + married: marié(e) + registered_partnership: partenariat enregistré + single: célibataire + widowed: veuf/veuve + people: + cv: + no_skills_rated_msg: Ce profil n'a pas encore de skills évalués. Va dans l'onglet Skills et évalue les skills qui te concernent. + export_cv: + export_form: + anonymised_cv: CV anonyme + competences_skills: Compétences clés - Skills + location: 'Établissement (pour le pied de page) :' + skills_by_level: Compétences par niveau + trainee: Stagiaire + global: + confirm_delete: Veux-tu vraiment supprimer cette personne ? + link: + add: Nouveau profil + delete: Supprimer une personne + more_actions: Autres actions + tabbar: + cv: CV + skills: Compétences + index: + choose_create_person: Sélectionne une personne ou saisis un nouveau profil + welcome: Bienvenue chez + new: + personals: Données personnelles + profile: + add_function: Ajouter une fonction + add_language: Ajouter une langue + change_image: Modifier l'image + core_competences: Compétences clés + personals: Données personnelles + upload_image: Télécharger une image + scroll_to_menu: + activities: Station + advanced-trainings: Formations continues + core-competences: Compétences clés + educations: Formations + personal-data: Données personnelles + projects: Projets + search: + new_profile: Nouveau profil + updated_at: Dernièrement édité + people/people_skills: + edit_form: + rate: Évaluer + unrate: Ne pas évaluer + global: + confirm_delete: Veux-tu vraiment supprimer cette personne ? + link: + add: Nouveau profil + delete: Supprimer une personne + more_actions: Autres actions + tabbar: + cv: CV + skills: Compétences + index: + new_skills_to_rate: Nouvelles compétences pour l'évaluation + scroll_to_menu: + link: + add: Ajouter une compétence + people_skills: + global: + link: + add: Ajouter une compétence (max. 5) + people_skills/filter_form: + global: + link: + add: Ajouter une compétence (max. 5) + profile: + updated_at: Dernièrement édité + skills: + global: + table: + category: Catégorie + default_set: Set par défaut + members: Membres + modify: Modifier + portfolio: Portefeuille + radar: Radar + skill: Compétence + subcategory: Sous-catégorie + show: + title: 'Compétence : %{title} (%{amount} Members)' diff --git a/config/locales/it.yml b/config/locales/it.yml new file mode 100644 index 000000000..808322a7e --- /dev/null +++ b/config/locales/it.yml @@ -0,0 +1,255 @@ +--- +it: + activerecord: + attributes: + activity: + description: Dati dell'azienda e descrizione dell'attività + role: Ruolo + year_from: Data di inizio + advanced_training: + description: Descrizione del + year_from: Data di inizio + education: + location: Luogo di formazione + title: Istruzione + year_from: Data di inizio + people_skill: + certificate: Certificato + core_competence: Competenza di base + level: Livello + skill: Abilità + person: + activities: + one: Stazione + other: Stazioni + advanced_trainings: + one: Formazione continua + other: Formazione continua + birthdate: Data di nascita + competence_notes: Note Membro + department: Unità organizzativa + dual_citizen: Doppi cittadini + educations: + one: Istruzione + other: Programmi di formazione + email: E-mail + languages: + one: Lingua + other: Le lingue + location: Posizione + marital_status: Stato civile + name: Nome + nationality: Nazionalità + person_roles: + one: Funzione + other: Funzioni + picture: Immagine + projects: + one: Progetto + other: Progetti + roles: + one: Funzione + other: Funzioni + shortname: Nome breve + skills: + one: Abilità + other: Competenze + title: Conclusione + project: + description: Descrizione del + role: Ruolo e compiti + technology: Tecnologie utilizzate + title: Progetto + year_from: Data di inizio + skill: + category: Categoria + models: + activity: Stazione + advanced_training: Formazione continua + category: + one: Categoria + other: Categorie + company: + one: Azienda + other: Aziende + department: + one: Unità organizzativa + other: Unità organizzative + education: + one: Istruzione + other: Programmi di formazione + people_skill: + one: Abilità + other: Competenze + project: Progetto + role: + one: Ruolo + other: Rulli + skill: + one: Abilità + other: Competenze + admin: + global: + link: + list: Pannello di amministrazione + cv_search: + global: + search_placeholder: Ricerca CV... + search_skills: Anche le capacità di ricerca + errors: + messages: + cannot_remove: non deve essere cancellato. + invalid_date_range: deve essere precedente alla data di scadenza. + max_size_10MB: non deve essere più grande di 10 MB. + max_size_error: non deve essere più grande di 10 MB. + profile-not-found: Il profilo non è stato trovato. + valid_percent_range: deve essere compreso tra 0 e 200. + global: + date: + from: Da + month: Mese + till_today: Fino ad oggi + to: Fino a quando + today: Oggi + with_enddate: Con data di scadenza + year: Anno + devise: + admin: "(Admin)" + admin_panel: Area amministrativa + devise: Motto + mockdata: Mockdata + no_omniauth_providers: Si è verificato un errore, non sono disponibili provider Omniauth, contattare l'amministratore. + sign_in: Accedi + sign_in_with: "%{provider} Accedere con" + sign_out: Disconnettersi + 'false': 'No' + filter: + all: Tutti + default: Predefinito + new: Nuovo + rated: Valutazione + search: "%{target} ricerca" + unrated: Non valutato + link: + cancel: Annullamento + download: Scaricare + export: Esportazione + remove: Rimuovere + save_new: Risparmi e novità + navbar: + cv_search: Ricerca di CV + profile: Profilo + skill_search: Ricerca di competenze + skillset: Competenze + new: Nuovo + people_skills: + certificate: Certificato + core-competence: Competenza di base + interest: Interesse per + levels: + expert: Esperto + junior: Junior + level: Livello + professional: Professionale + senior: Senior + trainee: Apprendista + unweighted: Non valutato + search: + found_in: Trovato in + no_results: Nessun risultato + search_results: Risultati della ricerca + 'true': Sì + helpers: + cancel: Annullamento + submit: + add: "%{model} aggiungere" + delete: Cancellare + edit: "%{model} modifica" + marital_statuses: + divorced: divorziato + married: sposato + registered_partnership: società registrata + single: singolo + widowed: vedova + people: + cv: + no_skills_rated_msg: Questo profilo non ha ancora competenze valutate. Andate alla scheda Competenze e valutate le competenze che vi interessano. + export_cv: + export_form: + anonymised_cv: CV anonimo + competences_skills: Competenze di base - Capacità + location: 'Sede secondaria (per il piè di pagina):' + skills_by_level: Competenze per livello + trainee: Apprendista + global: + confirm_delete: Volete davvero cancellare questa persona? + link: + add: Nuovo profilo + delete: Cancellare una persona + more_actions: Ulteriori azioni + tabbar: + cv: CV + skills: Competenze + index: + choose_create_person: Selezionare una persona o creare un nuovo profilo + welcome: Benvenuti a + new: + personals: Dati personali + profile: + add_function: Aggiungi funzione + add_language: Aggiungi lingua + change_image: Cambia immagine + core_competences: Competenze di base + personals: Dati personali + upload_image: Carica immagine + scroll_to_menu: + activities: Stazione + advanced-trainings: Formazione continua + core-competences: Competenze di base + educations: Programmi di formazione + personal-data: Dati personali + projects: Progetti + search: + new_profile: Nuovo profilo + updated_at: Ultima modifica + people/people_skills: + edit_form: + rate: Tasso + unrate: Non valutare + global: + confirm_delete: Volete davvero cancellare questa persona? + link: + add: Nuovo profilo + delete: Cancellare una persona + more_actions: Ulteriori azioni + tabbar: + cv: CV + skills: Competenze + index: + new_skills_to_rate: Nuove competenze per la valutazione + scroll_to_menu: + link: + add: Aggiungi abilità + people_skills: + global: + link: + add: Aggiungi abilità (max. 5) + people_skills/filter_form: + global: + link: + add: Aggiungi abilità (max. 5) + profile: + updated_at: Ultima modifica + skills: + global: + table: + category: Categoria + default_set: Set predefinito + members: Membri + modify: Cambiamento + portfolio: Portafoglio + radar: Radar + skill: Abilità + subcategory: Sottocategoria + show: + title: "%{title}%{amount} Abilità: ( Membri)" diff --git a/config/routes.rb b/config/routes.rb index e4a65bd60..ee0812f9c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,27 +1,17 @@ -Rails.application.routes.draw do - get root to: 'people#index' +LOCALE_REGEX = /#{I18n.available_locales.join('|')}/ unless defined?(LOCALE_REGEX) +Rails.application.routes.draw do + # Devise devise_for :auth_users, - skip: [:sessions], - controllers: - { omniauth_callbacks: 'omniauth_callbacks' } + skip: [:sessions], + controllers: + { omniauth_callbacks: 'omniauth_callbacks' } - devise_scope :auth_user do - get 'sign_in', :to => 'devise/sessions#new', :as => :new_auth_user_session - delete 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_auth_user_session - end - - resources :skills do - collection do - get 'export', to: 'skills#export' - end + devise_scope :auth_user do + get 'sign_in', :to => 'devise/sessions#new', :as => :new_auth_user_session + delete 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_auth_user_session end - resources :people_skills do - collection do - get 'filter_form', to: "people_skills/filter_form#index" - end - end # Status scope 'status' do @@ -29,34 +19,55 @@ get 'readiness', to: 'status#readiness' end - resources :cv_search + get root to: redirect(path: "/people") - resources :admin, only: :index - namespace :admin do - resources :departments - resources :roles - resources :companies - end - resources :people do - resources :advanced_trainings - resources :educations - resources :activities - resources :projects - resources :people_skills, controller: 'people/people_skills_create' - - member do - get 'export-cv', to: 'people/export_cv#show' - put 'picture', to: 'people/picture#update' - get 'picture', to: 'people/picture#show' - get 'export', to: 'people#export' - get 'competence-notes', to: 'people/competence_notes#edit' - post 'competence-notes', to: 'people/competence_notes#update' - - get 'people-skills-edit', to: 'people/people_skills#edit' - patch 'people-skills', to: 'people/people_skills#update' + scope "/:locale", locale: LOCALE_REGEX do + get '/:locale' => redirect("%{locale}/people") + + resources :skills do + collection do + get 'export', to: 'skills#export' + end + end + + resources :people_skills do + collection do + get 'filter_form', to: "people_skills/filter_form#index" + end + end + + resources :cv_search + + resources :admin, only: :index + namespace :admin do + resources :departments + resources :roles + resources :companies + end + + resources :people do + resources :advanced_trainings + resources :educations + resources :activities + resources :projects + resources :people_skills, controller: 'people/people_skills_create' + + member do + get 'export-cv', to: 'people/export_cv#show' + put 'picture', to: 'people/picture#update' + get 'picture', to: 'people/picture#show' + get 'export', to: 'people#export' + get 'competence-notes', to: 'people/competence_notes#edit' + post 'competence-notes', to: 'people/competence_notes#update' + + get 'people-skills-edit', to: 'people/people_skills#edit' + patch 'people-skills', to: 'people/people_skills#update' + end end end + match '*path', to: redirect("/#{I18n.locale}/%{path}"), :via => [:get, :post] + # Outdated api routes namespace :api do diff --git a/lib/custom_cops/translated_haml_files.rb b/lib/custom_cops/translated_haml_files.rb new file mode 100644 index 000000000..89a80ac18 --- /dev/null +++ b/lib/custom_cops/translated_haml_files.rb @@ -0,0 +1,23 @@ +module CustomCops + class TranslatedHamlFiles < RuboCop::Cop::Base + MSG = 'Each line in a HAML file must start with `=`, `-`, or `%`.'.freeze + + + def on_new_investigation + return unless haml_file? + + processed_source.lines.each_with_index do |line, index| + next if line.strip.empty? || line.strip.start_with?('=', '-', '%') + + add_offense(processed_source.buffer, + location: source_range(processed_source.buffer, index + 1, 0, line.length)) + end + end + + private + + def haml_file? + processed_source.buffer.name.end_with?('.haml') + end + end +end diff --git a/spec/controllers/api/people/picture_controller_spec.rb b/spec/controllers/api/people/picture_controller_spec.rb index b23054202..1aa17fdd0 100644 --- a/spec/controllers/api/people/picture_controller_spec.rb +++ b/spec/controllers/api/people/picture_controller_spec.rb @@ -17,10 +17,10 @@ path = json['data']['picture_path'] bob.reload - + expect(response.status).to eq(200) expect(bob['picture']).to eq('picture.png') - expect(path).to eq("/api/people/#{bob.id}/picture") + expect(path).to eq(picture_api_person_path(bob)) process :show, method: :get , params: { id: bob.id } diff --git a/spec/controllers/api/people/search_controller_spec.rb b/spec/controllers/api/people/search_controller_spec.rb index 32ef8bb65..9bfb39c9f 100644 --- a/spec/controllers/api/people/search_controller_spec.rb +++ b/spec/controllers/api/people/search_controller_spec.rb @@ -15,6 +15,6 @@ expect(alice_attrs.count).to eq(2) expect(alice_attrs['person']['name']).to eq('Alice Mante') - expect(alice_attrs['found_in']).to eq('location') + expect(alice_attrs['found_in']).to eq('Ort') end end diff --git a/spec/controllers/people/picture_controller_spec.rb b/spec/controllers/people/picture_controller_spec.rb index 7a1298f1d..e3619e16e 100644 --- a/spec/controllers/people/picture_controller_spec.rb +++ b/spec/controllers/people/picture_controller_spec.rb @@ -15,7 +15,7 @@ end it 'should update picture' do - process :update, method: :put, params: { id: bob.id, picture: fixture_file_upload('picture.png', 'image/png') } + put :update, params: { id: bob.id, picture: fixture_file_upload('picture.png', 'image/png') } path = json['data']['picture_path'] @@ -23,9 +23,9 @@ expect(response.status).to eq(200) expect(bob['picture']).to eq('picture.png') - expect(path).to eq("/people/#{bob.id}/picture") + expect(path).to eq(picture_person_path(bob)) - process :show, method: :get , params: { id: bob.id } + get :show, params: { id: bob.id } new_picture_md5 = 'c903aeff2bec840bd7c028631bd56596' diff --git a/spec/controllers/people_skills_controller_spec.rb b/spec/controllers/people_skills_controller_spec.rb index f14bdefa9..817dcef11 100644 --- a/spec/controllers/people_skills_controller_spec.rb +++ b/spec/controllers/people_skills_controller_spec.rb @@ -35,4 +35,4 @@ expect(response.body).to include("Wally Allround") end end -end \ No newline at end of file +end diff --git a/spec/domain/people_search_spec.rb b/spec/domain/people_search_spec.rb index f5ef3778f..f707ef3d2 100644 --- a/spec/domain/people_search_spec.rb +++ b/spec/domain/people_search_spec.rb @@ -7,14 +7,14 @@ search_term = 'duckduck' people = PeopleSearch.new(search_term).entries person = people[0] - expect(person[:found_in]).to eq('projects') + expect(person[:found_in]).to eq('Projekte') end it 'finds in which person attribute the search term has been found' do search_term = 'Alice' people = PeopleSearch.new(search_term).entries person = people[0] - expect(person[:found_in]).to eq('name') + expect(person[:found_in]).to eq('Name') end it 'returns nothing for nonsense search term' do diff --git a/spec/features/activities_spec.rb b/spec/features/activities_spec.rb index 56415ca3a..5ea4ff1ce 100644 --- a/spec/features/activities_spec.rb +++ b/spec/features/activities_spec.rb @@ -88,7 +88,9 @@ role = activity.role open_edit_form(activity) within("turbo-frame#activity_#{activity.id}") do - click_link("Löschen") + accept_confirm do + click_link("Löschen") + end end expect(page).not_to have_content(role) end diff --git a/spec/features/advanced_trainings_spec.rb b/spec/features/advanced_trainings_spec.rb index 11ed6981d..5dba57d96 100644 --- a/spec/features/advanced_trainings_spec.rb +++ b/spec/features/advanced_trainings_spec.rb @@ -92,7 +92,7 @@ click_default_submit end - expect(page).to have_css(".alert.alert-danger", text: "Beschreibung muss ausgefüllt werden") + expect(page).to have_css(".alert.alert-danger", text: /Beschreibung muss ausgefüllt werden/) end it 'year_from cant be empty' do @@ -102,7 +102,7 @@ click_default_submit end - expect(page).to have_css(".alert.alert-danger", text: "Jahr von muss ausgefüllt werden") + expect(page).to have_css(".alert.alert-danger", text: /Startdatum muss ausgefüllt werden/) end it 'Update entry and clear description' do @@ -113,7 +113,7 @@ fill_in 'advanced_training_description', with: "" click_default_submit end - expect(page).to have_css(".alert.alert-danger", text: "Beschreibung muss ausgefüllt werden") + expect(page).to have_css(".alert.alert-danger", text: /Beschreibung muss ausgefüllt werden/) end it 'Update entry and clear description' do @@ -125,7 +125,7 @@ select '2010', from: 'advanced_training_year_to' click_default_submit end - expect(page).to have_css(".alert.alert-danger", text: "Jahr von muss vor \"Datum bis\" sein") + expect(page).to have_css(".alert.alert-danger", text: /Startdatum muss vor dem Enddatum sein/) end end end diff --git a/spec/features/auth_spec.rb b/spec/features/auth_spec.rb index 5f7124d2e..32563c148 100644 --- a/spec/features/auth_spec.rb +++ b/spec/features/auth_spec.rb @@ -34,7 +34,7 @@ it 'Admin can create new skill' do visit skills_path click_link(href: new_skill_path) - expect(page).to have_selector("form[action='/skills']") + expect(page).to have_field('skill_title') end end end diff --git a/spec/features/core_competences_spec.rb b/spec/features/core_competences_spec.rb index a094c6a63..be9d311fc 100644 --- a/spec/features/core_competences_spec.rb +++ b/spec/features/core_competences_spec.rb @@ -1,10 +1,11 @@ require 'rails_helper' -describe "Core competences" do +describe "Core competences", type: :feature, js: true do before(:each) do sign_in auth_users(:user), scope: :auth_user visit root_path end + let(:alice) { people(:alice) } it 'should display core competences' do visit person_path(people(:bob)) @@ -14,33 +15,33 @@ end it 'should display competence notes and edit link correctly' do - visit person_path(people(:alice)) + visit person_path(alice) expect(page).to have_text("LaTex Puppet Bash", normalize_ws: true) - expect(page).to have_selector('#edit-link') + expect(page).to have_selector('.icon-pencil') end it 'should update competence notes' do - visit person_path(people(:alice)) - page.find('#edit-link').click + visit person_path(alice) + click_link(href: competence_notes_person_path(alice)) expect(page).to have_selector('.form-control') fill_in 'person_competence_notes', with: 'Hello World here' - page.find('#save').click - expect(page).to have_text('Hello World here') + click_button "Person aktualisieren" + expect(page).to have_content('Hello World here') end it 'should not update competence notes when clicking cancel button' do - visit person_path(people(:alice)) - page.find('#edit-link').click + visit person_path(alice) + click_link(href: competence_notes_person_path(alice)) expect(page).to have_selector('.form-control') fill_in 'person_competence_notes', with: 'Hello World here' - page.find('#cancel').click + click_link(text: "Abbrechen") expect(page).to have_text("LaTex Puppet Bash", normalize_ws: true) end it 'should display skill with same parent category in same row with divider' do - visit person_path(people(:alice)) + visit person_path(alice) expect(page).to have_selector('.circle-divider') expect(page).to have_selector('.core-competence', count: 1, text: "Software-Engineering Rails ember", normalize_ws: true) diff --git a/spec/features/cv_search_spec.rb b/spec/features/cv_search_spec.rb index d44ed7908..5e3e2dc45 100644 --- a/spec/features/cv_search_spec.rb +++ b/spec/features/cv_search_spec.rb @@ -12,39 +12,38 @@ describe 'Search' do it 'should find correct results' do fill_in 'cv_search_field', with: person.name - check_search_results(I18n.t("cv_search.name")) + check_search_results(Person.human_attribute_name(:name)) fill_in 'cv_search_field', with: person.projects.first.technology - check_search_results(I18n.t("cv_search.projects")) + check_search_results(Person.human_attribute_name(:projects)) fill_in 'cv_search_field', with: person.title - check_search_results(I18n.t("cv_search.title")) + check_search_results(Person.human_attribute_name(:title)) fill_in 'cv_search_field', with: person.roles.first.name - check_search_results(I18n.t("cv_search.roles")) + check_search_results(Person.human_attribute_name(:roles)) fill_in 'cv_search_field', with: person.department.name - check_search_results(I18n.t("cv_search.department")) + check_search_results(Person.human_attribute_name(:department)) fill_in 'cv_search_field', with: person.competence_notes.split.first - check_search_results(I18n.t("cv_search.competence_notes")) + check_search_results(Person.human_attribute_name(:competence_notes)) fill_in 'cv_search_field', with: person.advanced_trainings.first.description - check_search_results(I18n.t("cv_search.advanced_trainings")) + check_search_results(Person.human_attribute_name(:advanced_trainings)) fill_in 'cv_search_field', with: person.educations.first.location - check_search_results(I18n.t("cv_search.educations")) + check_search_results(Person.human_attribute_name(:educations)) fill_in 'cv_search_field', with: person.activities.first.description - check_search_results(I18n.t("cv_search.activities")) + check_search_results(Person.human_attribute_name(:activities)) fill_in 'cv_search_field', with: person.projects.first.description - check_search_results(I18n.t("cv_search.projects")) end it 'should open person when clicking result' do fill_in 'cv_search_field', with: person.projects.first.technology - check_search_results(I18n.t("cv_search.projects")) + check_search_results(Person.human_attribute_name(:projects)) first("a", text: person.name).click(); expect(page).to have_current_path(person_path(person)) - visit("/cv_search") + visit(cv_search_index_path) education_location = person.educations.first.location fill_in 'cv_search_field', with: education_location - check_search_results(I18n.t("cv_search.educations")) - click_link(I18n.t("cv_search.educations")) - expect(page).to have_current_path("#{person_path(person)}?q=#{education_location.split(" ").join("+")}") + check_search_results(Person.human_attribute_name(:educations)) + click_link(Person.human_attribute_name(:educations)) + expect(current_url).to end_with(person_path(person, q: education_location)) end it 'should only display results when length of search-text is > 3' do @@ -60,8 +59,9 @@ expect(page).to have_content("Keine Resultate") page.check('search_skills') expect(page).not_to have_content("Keine Resultate") - check_search_results(I18n.t("cv_search.skills")) - expect(page).to have_link(href: "#{person_people_skills_path(person)}?q=#{skill_title.split(" ").join("+")}&rating=1") + check_search_results(Skill.model_name.human.pluralize) + link = person_people_skills_path(person, q: skill_title, rating: 1) + expect(page).to have_link(href: link) end end end diff --git a/spec/features/edit_people_skills_spec.rb b/spec/features/edit_people_skills_spec.rb index 13a30b28d..ce5b6a206 100644 --- a/spec/features/edit_people_skills_spec.rb +++ b/spec/features/edit_people_skills_spec.rb @@ -98,7 +98,7 @@ alice = people(:alice) visit person_people_skills_path(alice, rating: 1) within('#people-skills') do - expect(page).to have_content(I18n.t('people-skills.levels.unweighted'), count: alice.people_skills.where(level: 0, interest: 0).count) + expect(page).to have_content(t('global.people_skills.levels.unweighted'), count: alice.people_skills.where(level: 0, interest: 0).count) end end end @@ -134,7 +134,7 @@ def not_rated_default_skills(person) expect(page).to have_content(person_skill.skill.title) end - expect(page).to have_content('Trainee', count: not_rated_default_skills.count) + expect(page).to have_content('Azubi', count: not_rated_default_skills.count) expect(not_rated_default_skills.pluck(:interest).all?(&:zero?)).to be(true) @@ -206,7 +206,7 @@ def not_rated_default_skills(person) end it 'hides default skills form when canceling with cancel-x' do - page.find('#x-button').click + page.find('.icon.icon-close').click expect(page).not_to have_css('#default-skills') end end diff --git a/spec/features/people_skill_search_spec.rb b/spec/features/people_skill_search_spec.rb index 13a123b31..f79b78b3b 100644 --- a/spec/features/people_skill_search_spec.rb +++ b/spec/features/people_skill_search_spec.rb @@ -66,7 +66,7 @@ # remove skill filter - page.find('#remove-row-1').click + page.find('#remove-row-2').click expect(page).to have_text("Alice Mante") expect(page).to have_text("Wally Allround") expect(page).to have_text("Hope Sunday") @@ -75,9 +75,11 @@ def add_and_fill_out_row(skill, level, interest) old_row_number = last_row[:id][-1, 1].to_i - find('#add-row-button').click + click_link(t("people_skills.global.link.add")) + new_row_id = "filter-row-#{old_row_number + 1}" - expect(page).to have_css("[id='#{new_row_id}']") + expect(page).to have_selector("[id='#{new_row_id}']") + fill_out_row(skill, level, interest) end diff --git a/spec/features/people_spec.rb b/spec/features/people_spec.rb index 7a4f20c8e..a86c71ebc 100644 --- a/spec/features/people_spec.rb +++ b/spec/features/people_spec.rb @@ -80,7 +80,7 @@ def fill_out_person_form check 'nat-two-checkbox' select ISO3166::Country["DE"].translations[I18n.locale], from: 'person_nationality' select ISO3166::Country["US"].translations[I18n.locale], from: 'person_nationality2' - select I18n.t('marital_statuses.married'), from: 'person_marital_status' + select t('marital_statuses.married'), from: 'person_marital_status' fill_in 'person_shortname', with: 'bb' page.all(".add_fields").last.click @@ -151,7 +151,7 @@ def check_edit_fields(person, editing) expect(page.all('.nationality-two').count).to equal(person.nationality2.nil? ? 0 : 2) expect(page).to have_select('person_nationality', selected: person.nationality.nil? ? ISO3166::Country[common_languages_translated.first.first].translations[I18n.locale] : ISO3166::Country[person.nationality].translations[I18n.locale]) person.nationality2.nil? ? (expect(page).not_to have_select('person_nationality2')) : (expect(page).to have_select('person_nationality2', selected: ISO3166::Country[person.nationality2].translations[I18n.locale])) - expect(page).to have_select('person_marital_status', selected: I18n.t("marital_statuses.#{person.marital_status}")) + expect(page).to have_select('person_marital_status', selected: t("marital_statuses.#{person.marital_status}")) expect(page).to have_field('person_shortname', with: person.shortname) language_skills = person.language_skills @@ -198,7 +198,7 @@ def add_language(language) it 'should have all edit fields' do bob = people(:bob) visit person_path(bob) - page.find('#edit-button').click + click_link('Bearbeiten', href: edit_person_path(bob)) check_edit_fields(bob, true) end @@ -206,9 +206,9 @@ def add_language(language) bob = people(:bob) old_number_of_roles = bob.person_roles.count visit person_path(bob) - page.find('#edit-button').click + click_link('Bearbeiten', href: edit_person_path(bob)) fill_out_person_form - save_button = find_button("Speichern") + save_button = find_button("Person aktualisieren") scroll_to(save_button, align: :center) save_button.click assert_form_persisted(old_number_of_roles) @@ -217,16 +217,16 @@ def add_language(language) it 'should edit and cancel without saving' do person = Person.first visit person_path(person) - page.find('#edit-button').click + click_link('Bearbeiten', href: edit_person_path(person)) fill_out_person_form - page.find('#cancel-button').click + click_link 'Abbrechen' expect(person.attributes).to eql(Person.first.attributes) end it('should correctly disable languages if they are selected, changed, created or deleted') { bob = people(:bob) visit person_path(bob) - page.find('#edit-button').click + click_link('Bearbeiten', href: edit_person_path(bob)) add_language('JA') add_language('ZH') @@ -264,13 +264,13 @@ def add_language(language) it('should display error when uploading a too big avatar file') do bob = people(:bob) visit person_path(bob) - page.find('#edit-button').click + click_link('Bearbeiten', href: edit_person_path(bob)) allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:size).and_return(12.megabytes) page.attach_file("avatar-uploader", Rails.root + 'app/assets/images/favicon.png') page.find("#save-button").click - expect(page).to have_css('.alert-danger', text: 'Bild sollte nicht grösser als 10MB sein') + expect(page).to have_css('.alert-danger', text: 'Bild darf nicht grösser als 10MB sein') end end @@ -282,25 +282,25 @@ def add_language(language) it 'should have all edit fields' do visit people_path new_person = Person.new - page.find('#new-person-button').click + click_link 'Neues Profil' check_edit_fields(new_person, false) end it 'should create new person' do visit people_path - page.find('#new-person-button').click + click_link 'Neues Profil' fill_out_person_form - page.find("#save-button").click + click_button "Person erstellen" assert_form_persisted(0) end it 'should go back to overview after cancelling and not save new person' do visit people_path - page.find('#new-person-button').click + click_link 'Neues Profil' fill_out_person_form - page.find("#cancel-button").click - expect(page).to have_current_path("/people") + click_link 'Abbrechen' + expect(page).to have_current_path(people_path) expect(Person.all.find_by(name: "Hansjakobli")).to be_nil end end @@ -314,14 +314,14 @@ def add_language(language) it 'should display message when no skills are rated' do visit person_path(longmax) - expect(page).to have_selector('p.alert.alert-info.d-flex.justify-content-between', text: I18n.t('profile.no_skills_rated_msg')) + expect(page).to have_selector('p.alert.alert-info.d-flex.justify-content-between', text: t("people.cv.no_skills_rated_msg")) end it 'should delete person' do visit person_path(longmax) - click_button(I18n.t("people.show.more_actions")) + click_button(t("people.global.more_actions")) accept_confirm do - click_link(I18n.t("people.show.link.delete"), href: person_path(longmax)) + click_link(t("people.global.link.delete"), href: person_path(longmax)) end expect(page).to have_selector('.alert', text: I18n.t("crud.destroy.flash.success", model: longmax)) end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 2c6f80433..01c95b381 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -105,7 +105,9 @@ role = project.role open_edit_form(project) within("turbo-frame##{dom_id project}") do - click_link("Löschen") + accept_confirm do + click_link("Löschen") + end end expect(page).not_to have_content(role) end diff --git a/spec/features/routing_spec.rb b/spec/features/routing_spec.rb new file mode 100644 index 000000000..b227fe5d7 --- /dev/null +++ b/spec/features/routing_spec.rb @@ -0,0 +1,44 @@ +require 'rails_helper' + +describe 'Routing', type: :feature, js: true do + + let(:bob) { people(:bob) } + + before(:each) do + sign_in auth_users(:user), scope: :auth_user + end + + describe "Check auto rerouting" do + ROUTES = { + "/": "/de/people", + "/de/": "/de/people", + "/people": "/de/people", + "/people_skills": "/de/people_skills", + "/en": "/en/people", + } + + ROUTES.each do |url, target| + it "Should route from '#{url}' to #{target}" do + visit url + expect(current_path).to eq(target) + end + end + end + + describe "Check if language is applied correctly" do + context "Set locale via dropdown" do + before(:each) do + visit people_path + select 'Italiano', from: "i18n_language" + default_url_options[:locale] = :it + end + + it "Should open profile with correct language" do + select_from_slim_select("#person_id_person", bob.name) + expect(page).to have_text("Dati personali") + click_link(href: person_people_skills_path(bob)) + expect(page).to have_text("Nuove competenze per la valutazione") + end + end + end +end diff --git a/spec/features/skills_controller_spec.rb b/spec/features/skills_controller_spec.rb index a646bfb94..120c5224c 100644 --- a/spec/features/skills_controller_spec.rb +++ b/spec/features/skills_controller_spec.rb @@ -20,7 +20,7 @@ def fill_out_form it 'can edit skill in table ' do visit skills_path within "#skill_#{Skill.second.id}" do - page.find('.edit-button').click + page.find('.icon.icon-pencil').click expect(page).to have_field('skill_title', with: Skill.second.title) expect(page).to have_select('skill_category_parent', selected: Skill.second.category.parent.title) expect(page).to have_select('skill_category_id', selected: Skill.second.category.title) @@ -32,7 +32,7 @@ def fill_out_form it 'can save edited skill' do visit skills_path - page.all('.edit-button')[1].click + page.all('.icon.icon-pencil')[1].click fill_out_form save_button = page.find("input[type='image']") save_button.click @@ -48,7 +48,8 @@ def fill_out_form it 'can cancel edited skill' do visit skills_path - page.all('.edit-button')[1].click + page.all('.icon.icon-pencil')[1].click + fill_out_form save_button = page.first("img.pointer") save_button.click diff --git a/spec/features/tabbar_spec.rb b/spec/features/tabbar_spec.rb new file mode 100644 index 000000000..22ab62771 --- /dev/null +++ b/spec/features/tabbar_spec.rb @@ -0,0 +1,81 @@ +require 'rails_helper' + +describe 'Tabbar', type: :feature, js:true do + let(:bob) { people(:bob) } + + GLOBAL_TABS = + [ + { title: 'global.navbar.profile', path: "/%{locale}/people" }, + { title: 'global.navbar.skill_search', path: "/%{locale}/people_skills" }, + { title: 'global.navbar.cv_search', path: "/%{locale}/cv_search" }, + { title: 'global.navbar.skillset', path: "/%{locale}/skills" } + ] + + PERSON_TABS = + [ + { title: 'people.global.tabbar.cv', path: "/%{locale}/people/%{id}" }, + { title: 'people.global.tabbar.skills', path: "/%{locale}/people/%{id}/people_skills" } + ] + + [:de, :en, :it, :fr].each do |locale| + describe "Check if tabbar works for #{locale}" do + + before(:each) do + sign_in auth_users(:admin) + I18n.locale = locale + default_url_options[:locale] = locale + + visit people_path + end + + after(:each) do + expect(current_path).to start_with("/#{locale}") + end + + describe 'Global' do + GLOBAL_TABS.each do |hash| + let(:path) { hash[:path] % { locale: locale } } + let(:title) { t hash[:title] } + + it "Should highlight '#{hash[:title]}' tab using click" do + click_link(href: path) + check_highlighted_tab(title) + end + + it "Should highlight '#{hash[:title]}' tab after visit by url" do + visit (path) + check_highlighted_tab(title) + end + end + + def check_highlighted_tab(text) + expect(page).to have_selector("div.skills-navbar .btn .nav-link.active", text: text) + end + end + + describe 'Person' do + PERSON_TABS.each do |hash| + let(:path) { hash[:path] % { id: bob.id, locale: locale } } + let(:title) { t hash[:title] } + + it "Should highlight '#{hash[:title]}' tab using dropdown" do + visit people_path + select_from_slim_select("#person_id_person", bob.name) + check_highlighted_tab("CV") + click_link(href: path) + check_highlighted_tab(title) + end + + it "Should highlight '#{hash[:title]}' tab after visit by url" do + visit (path) + check_highlighted_tab(title) + end + end + + def check_highlighted_tab(text) + expect(page).to have_selector(".nav.nav-tabs .btn .nav-link.active", text: text) + end + end + end + end +end diff --git a/spec/i18n_spec.rb b/spec/i18n_spec.rb new file mode 100644 index 000000000..157cd4674 --- /dev/null +++ b/spec/i18n_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'i18n/tasks' +require 'openssl' + +RSpec.describe I18n do + let(:i18n) { I18n::Tasks::BaseTask.new } + let(:missing_keys) { i18n.missing_keys } + let(:unused_keys) { i18n.unused_keys } + let(:inconsistent_interpolations) { i18n.inconsistent_interpolations } + + it 'does not have missing keys' do + expect(missing_keys).to be_empty, + "Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them" + end + + + xit 'does not have unused keys' do + expect(unused_keys).to be_empty, + "#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them" + end + + it 'files are normalized' do + non_normalized = i18n.non_normalized_paths + error_message = "The following files need to be normalized:\n" \ + "#{non_normalized.map { |path| " #{path}" }.join("\n")}\n" \ + "Please run `i18n-tasks normalize' to fix" + expect(non_normalized).to be_empty, error_message + end + + it 'does not have inconsistent interpolations' do + error_message = "#{inconsistent_interpolations.leaves.count} i18n keys have inconsistent interpolations.\n" \ + "Run `i18n-tasks check-consistent-interpolations' to show them" + expect(inconsistent_interpolations).to be_empty, error_message + end +end diff --git a/spec/models/activity_spec.rb b/spec/models/activity_spec.rb index 7f11b3044..d6bddc4f6 100644 --- a/spec/models/activity_spec.rb +++ b/spec/models/activity_spec.rb @@ -45,7 +45,7 @@ activity.year_from = 2016 activity.valid? - expect(activity.errors[:year_from].first).to eq('muss vor "Datum bis" sein') + expect(activity.errors[:year_from].first).to eq('muss vor dem Enddatum sein.') end it 'year_to can be blank' do diff --git a/spec/models/advanced_training_spec.rb b/spec/models/advanced_training_spec.rb index ce68851e7..f92093568 100644 --- a/spec/models/advanced_training_spec.rb +++ b/spec/models/advanced_training_spec.rb @@ -42,7 +42,7 @@ advanced_training.year_from = 2016 advanced_training.valid? - expect(advanced_training.errors[:year_from].first).to eq('muss vor "Datum bis" sein') + expect(advanced_training.errors[:year_from].first).to eq('muss vor dem Enddatum sein.') end it 'year_to can be blank' do diff --git a/spec/models/education_spec.rb b/spec/models/education_spec.rb index 3b8c503c0..7e21d7b86 100644 --- a/spec/models/education_spec.rb +++ b/spec/models/education_spec.rb @@ -54,7 +54,7 @@ education.year_from = 2016 education.valid? - expect(education.errors[:year_from].first).to eq('muss vor "Datum bis" sein') + expect(education.errors[:year_from].first).to eq('muss vor dem Enddatum sein.') end it 'orders education correctly with list scope' do diff --git a/spec/models/language_skill_spec.rb b/spec/models/language_skill_spec.rb index 1863cfd14..9d01901b9 100644 --- a/spec/models/language_skill_spec.rb +++ b/spec/models/language_skill_spec.rb @@ -33,7 +33,7 @@ skill = language_skills(:deutsch) skill.destroy - expect(skill.errors[:language].first).to eq('darf nicht gelöscht werden') + expect(skill.errors[:language].first).to eq('darf nicht gelöscht werden.') end end end diff --git a/spec/models/people_role_spec.rb b/spec/models/people_role_spec.rb index fbd3c5046..16c35193c 100644 --- a/spec/models/people_role_spec.rb +++ b/spec/models/people_role_spec.rb @@ -28,7 +28,7 @@ person_role.percent = 300 person_role.valid? - expect(person_role.errors[:percent].first).to eq('muss zwischen 0 und 200 sein') + expect(person_role.errors[:percent].first).to eq('muss zwischen 0 und 200 liegen.') end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index da1a0fdaa..458cc5d0c 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -56,7 +56,7 @@ project.year_from = 2016 project.valid? - expect(project.errors[:year_from].first).to eq('muss vor "Datum bis" sein') + expect(project.errors[:year_from].first).to eq('muss vor dem Enddatum sein.') end it 'year_to can be blank' do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5229018ee..b2690726b 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -66,6 +66,8 @@ config.include(JsonMacros, type: :controller) config.include(JsonAssertion, type: :controller) config.include(ControllerHelpers, type: :controller) + config.include DefaultParams, type: :controller + # Feature helper @@ -78,7 +80,16 @@ config.include(PersonRelationsHelpers, type: :feature) config.include(SlimselectHelpers, type: :feature) config.include(PeopleSkillsHelpers, type: :feature) + config.include(UtilitiesHelpers) config.infer_spec_type_from_file_location! config.filter_rails_from_backtrace! + + config.after(:each) do + I18n.locale = I18n.default_locale + end + + config.before(:each, type: :feature) do + default_url_options[:locale] = I18n.locale + end end diff --git a/spec/serializer/error_serializer_spec.rb b/spec/serializer/error_serializer_spec.rb index 86cf5093c..c2f853fab 100644 --- a/spec/serializer/error_serializer_spec.rb +++ b/spec/serializer/error_serializer_spec.rb @@ -14,7 +14,7 @@ expect(json[:errors].first[:id]).to eq(:company) expect(json[:errors].first[:title]).to eq('Company muss ausgefüllt werden') expect(json[:errors].second[:id]).to eq(:birthdate) - expect(json[:errors].second[:title]).to eq('Birthdate muss ausgefüllt werden') + expect(json[:errors].second[:title]).to eq('Geburtsdatum muss ausgefüllt werden') end end end diff --git a/spec/support/default_params.rb b/spec/support/default_params.rb new file mode 100644 index 000000000..074c35211 --- /dev/null +++ b/spec/support/default_params.rb @@ -0,0 +1,25 @@ +require 'active_support/concern' + +module DefaultParams + extend ActiveSupport::Concern + + included do + let(:default_params) {{locale: I18n.locale}} + prepend RequestHelpersCustomized + end + + module RequestHelpersCustomized + l = lambda do |path, **kwargs| + if default_params + kwargs[:params] ||= {} + default_params.each do |key, value| + kwargs[:params][key] ||= value + end + end + super(path, params: kwargs[:params]) + end + %w(get post patch put delete).each do |method| + define_method(method, l) + end + end +end diff --git a/spec/support/people_skills_helper.rb b/spec/support/people_skills_helper.rb index 90eaf6680..2b74161e7 100644 --- a/spec/support/people_skills_helper.rb +++ b/spec/support/people_skills_helper.rb @@ -39,7 +39,7 @@ def people_skill_from_skill_name(person, skill_name) def validate_skill_level_label(level) skill_level_key = ExpertiseTopicSkillValue.skill_levels.key(level-1) - skill_level_label = I18n.t("people-skills.levels.#{skill_level_key}") + skill_level_label = t("global.people_skills.levels.#{skill_level_key}") expect(page).to have_selector('[data-people-skills-target="label"]', text: /#{skill_level_label}/i) end diff --git a/spec/support/utilities_helpers.rb b/spec/support/utilities_helpers.rb new file mode 100644 index 000000000..21186e152 --- /dev/null +++ b/spec/support/utilities_helpers.rb @@ -0,0 +1,5 @@ +module UtilitiesHelpers + def t(string, options={}) + I18n.t(string, **options) + end +end