From 1cd879bcb6560ed43f35a366281f40042d6c1370 Mon Sep 17 00:00:00 2001 From: Maximilian Grundke Date: Thu, 9 Jun 2016 22:38:19 +0200 Subject: [PATCH 1/6] Scaffold file templates --- .../javascripts/file_templates.js.coffee | 3 + .../stylesheets/file_templates.css.scss | 3 + app/controllers/file_templates_controller.rb | 86 +++++++++++++++++++ app/models/file_template.rb | 10 +++ app/models/file_type.rb | 1 + app/policies/file_template_policy.rb | 7 ++ app/views/file_templates/_form.html.slim | 12 +++ app/views/file_templates/edit.html.slim | 3 + app/views/file_templates/index.html.slim | 20 +++++ app/views/file_templates/new.html.slim | 3 + app/views/file_templates/show.html.slim | 7 ++ config/locales/de.yml | 4 + config/locales/en.yml | 4 + config/routes.rb | 1 + .../20160609185708_create_file_templates.rb | 10 +++ db/schema.rb | 10 ++- 16 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/file_templates.js.coffee create mode 100644 app/assets/stylesheets/file_templates.css.scss create mode 100644 app/controllers/file_templates_controller.rb create mode 100644 app/models/file_template.rb create mode 100644 app/policies/file_template_policy.rb create mode 100644 app/views/file_templates/_form.html.slim create mode 100644 app/views/file_templates/edit.html.slim create mode 100644 app/views/file_templates/index.html.slim create mode 100644 app/views/file_templates/new.html.slim create mode 100644 app/views/file_templates/show.html.slim create mode 100644 db/migrate/20160609185708_create_file_templates.rb diff --git a/app/assets/javascripts/file_templates.js.coffee b/app/assets/javascripts/file_templates.js.coffee new file mode 100644 index 00000000..24f83d18 --- /dev/null +++ b/app/assets/javascripts/file_templates.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/file_templates.css.scss b/app/assets/stylesheets/file_templates.css.scss new file mode 100644 index 00000000..bf8e27e8 --- /dev/null +++ b/app/assets/stylesheets/file_templates.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the FileTemplates controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/file_templates_controller.rb b/app/controllers/file_templates_controller.rb new file mode 100644 index 00000000..45636d61 --- /dev/null +++ b/app/controllers/file_templates_controller.rb @@ -0,0 +1,86 @@ +class FileTemplatesController < ApplicationController + before_action :set_file_template, only: [:show, :edit, :update, :destroy] + + def authorize! + authorize(@file_template || @file_templates) + end + private :authorize! + + # GET /file_templates + # GET /file_templates.json + def index + @file_templates = FileTemplate.all.order(:file_type_id).paginate(page: params[:page]) + authorize! + end + + # GET /file_templates/1 + # GET /file_templates/1.json + def show + authorize! + end + + # GET /file_templates/new + def new + @file_template = FileTemplate.new + authorize! + end + + # GET /file_templates/1/edit + def edit + authorize! + end + + # POST /file_templates + # POST /file_templates.json + def create + @file_template = FileTemplate.new(file_template_params) + authorize! + + respond_to do |format| + if @file_template.save + format.html { redirect_to @file_template, notice: 'File template was successfully created.' } + format.json { render :show, status: :created, location: @file_template } + else + format.html { render :new } + format.json { render json: @file_template.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /file_templates/1 + # PATCH/PUT /file_templates/1.json + def update + authorize! + respond_to do |format| + if @file_template.update(file_template_params) + format.html { redirect_to @file_template, notice: 'File template was successfully updated.' } + format.json { render :show, status: :ok, location: @file_template } + else + format.html { render :edit } + format.json { render json: @file_template.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /file_templates/1 + # DELETE /file_templates/1.json + def destroy + authorize! + @file_template.destroy + respond_to do |format| + format.html { redirect_to file_templates_url, notice: 'File template was successfully destroyed.' } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_file_template + @file_template = FileTemplate.find(params[:id]) + end + + # Never trust parameters from the scary internet, only allow the white list through. + def file_template_params + params[:file_template].permit(:name, :file_type_id, :content) + end +end diff --git a/app/models/file_template.rb b/app/models/file_template.rb new file mode 100644 index 00000000..ef068e13 --- /dev/null +++ b/app/models/file_template.rb @@ -0,0 +1,10 @@ +class FileTemplate < ActiveRecord::Base + + belongs_to :file_type + + + def to_s + name + end + +end diff --git a/app/models/file_type.rb b/app/models/file_type.rb index 53bf18dc..d3b519d5 100644 --- a/app/models/file_type.rb +++ b/app/models/file_type.rb @@ -12,6 +12,7 @@ class FileType < ActiveRecord::Base has_many :execution_environments has_many :files + has_many :file_templates validates :binary, boolean_presence: true validates :editor_mode, presence: true, unless: :binary? diff --git a/app/policies/file_template_policy.rb b/app/policies/file_template_policy.rb new file mode 100644 index 00000000..b2f780a8 --- /dev/null +++ b/app/policies/file_template_policy.rb @@ -0,0 +1,7 @@ +class FileTemplatePolicy < AdminOnlyPolicy + + def show? + everyone + end + +end diff --git a/app/views/file_templates/_form.html.slim b/app/views/file_templates/_form.html.slim new file mode 100644 index 00000000..1a5c34bc --- /dev/null +++ b/app/views/file_templates/_form.html.slim @@ -0,0 +1,12 @@ += form_for(@file_template) do |f| + = render('shared/form_errors', object: @file_template) + .form-group + = f.label(:name) + = f.text_field(:name, class: 'form-control', required: true) + .form-group + = f.label(:file_type_id) + = f.collection_select(:file_type_id, FileType.all.order(:name), :id, :name, {}, class: 'form-control') + .form-group + = f.label(:content) + = f.text_area(:content, class: 'form-control') + .actions = render('shared/submit_button', f: f, object: @file_template) diff --git a/app/views/file_templates/edit.html.slim b/app/views/file_templates/edit.html.slim new file mode 100644 index 00000000..c198271f --- /dev/null +++ b/app/views/file_templates/edit.html.slim @@ -0,0 +1,3 @@ +h1 = @file_template + += render('form') diff --git a/app/views/file_templates/index.html.slim b/app/views/file_templates/index.html.slim new file mode 100644 index 00000000..3022ea53 --- /dev/null +++ b/app/views/file_templates/index.html.slim @@ -0,0 +1,20 @@ +h1 = FileTemplate.model_name.human(count: 2) + +.table-responsive + table.table + thead + tr + th = t('activerecord.attributes.file_template.name') + th = t('activerecord.attributes.file_template.file_type') + th colspan=3 = t('shared.actions') + tbody + - @file_templates.each do |file_template| + tr + td = file_template.name + td = link_to(file_template.file_type, file_type_path(file_template.file_type)) + td = link_to(t('shared.show'), file_template) + td = link_to(t('shared.edit'), edit_file_template_path(file_template)) + td = link_to(t('shared.destroy'), file_template, data: {confirm: t('shared.confirm_destroy')}, method: :delete) + += render('shared/pagination', collection: @file_templates) +p = render('shared/new_button', model: FileTemplate) diff --git a/app/views/file_templates/new.html.slim b/app/views/file_templates/new.html.slim new file mode 100644 index 00000000..bf434860 --- /dev/null +++ b/app/views/file_templates/new.html.slim @@ -0,0 +1,3 @@ +h1 = t('shared.new_model', model: FileTemplate.model_name.human) + += render('form') diff --git a/app/views/file_templates/show.html.slim b/app/views/file_templates/show.html.slim new file mode 100644 index 00000000..19f0d28f --- /dev/null +++ b/app/views/file_templates/show.html.slim @@ -0,0 +1,7 @@ +h1 + = @file_template + = render('shared/edit_button', object: @file_template) + += row(label: 'file_template.name', value: @file_template.name) += row(label: 'file_template.file_type', value: link_to(@file_template.file_type, file_type_path(@file_template.file_type))) += row(label: 'file_template.content', value: @file_template.content) diff --git a/config/locales/de.yml b/config/locales/de.yml index e7d78943..4a98e0a0 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -93,6 +93,10 @@ de: team: internal_user_ids: Mitglieder name: Name + file_template: + name: "Name" + file_type: "Dateityp" + content: "Code" models: code_harbor_link: one: CodeHarbor-Link diff --git a/config/locales/en.yml b/config/locales/en.yml index f2470fc8..de0f3aa4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -93,6 +93,10 @@ en: team: internal_user_ids: Members name: Name + file_template: + name: "Name" + file_type: "File Type" + content: "Content" models: code_harbor_link: one: CodeHarbor Link diff --git a/config/routes.rb b/config/routes.rb index 72ccb489..7965f0a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ FILENAME_REGEXP = /[\w\.]+/ unless Kernel.const_defined?(:FILENAME_REGEXP) Rails.application.routes.draw do + resources :file_templates resources :code_harbor_links resources :request_for_comments get '/my_request_for_comments', as: 'my_request_for_comments', to: 'request_for_comments#get_my_comment_requests' diff --git a/db/migrate/20160609185708_create_file_templates.rb b/db/migrate/20160609185708_create_file_templates.rb new file mode 100644 index 00000000..43cde0d0 --- /dev/null +++ b/db/migrate/20160609185708_create_file_templates.rb @@ -0,0 +1,10 @@ +class CreateFileTemplates < ActiveRecord::Migration + def change + create_table :file_templates do |t| + t.string :name + t.text :content + t.belongs_to :file_type + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 104a1469..4f7fc833 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160512131539) do +ActiveRecord::Schema.define(version: 20160609185708) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -101,6 +101,14 @@ ActiveRecord::Schema.define(version: 20160512131539) do t.datetime "updated_at" end + create_table "file_templates", force: true do |t| + t.string "name" + t.text "content" + t.integer "file_type_id" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "file_types", force: true do |t| t.string "editor_mode" t.string "file_extension" From 4f8feb38e10c7e3591a6f7c60436c45dbd67e29d Mon Sep 17 00:00:00 2001 From: Maximilian Grundke Date: Fri, 10 Jun 2016 13:41:38 +0200 Subject: [PATCH 2/6] Use file template to generate new file content --- app/controllers/code_ocean/files_controller.rb | 3 +++ app/controllers/concerns/file_parameters.rb | 2 +- app/views/code_ocean/files/_form.html.slim | 3 +++ config/locales/de.yml | 1 + config/locales/en.yml | 1 + db/migrate/20160610111602_add_file_template_to_file.rb | 5 +++++ db/schema.rb | 3 ++- 7 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20160610111602_add_file_template_to_file.rb diff --git a/app/controllers/code_ocean/files_controller.rb b/app/controllers/code_ocean/files_controller.rb index 74c1932f..e38607c2 100644 --- a/app/controllers/code_ocean/files_controller.rb +++ b/app/controllers/code_ocean/files_controller.rb @@ -10,6 +10,9 @@ module CodeOcean def create @file = CodeOcean::File.new(file_params) + if @file.file_template_id + @file.content = FileTemplate.find(@file.file_template_id).content + end authorize! create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise, tab: 2) }) end diff --git a/app/controllers/concerns/file_parameters.rb b/app/controllers/concerns/file_parameters.rb index e61e719e..295b66c3 100644 --- a/app/controllers/concerns/file_parameters.rb +++ b/app/controllers/concerns/file_parameters.rb @@ -1,6 +1,6 @@ module FileParameters def file_attributes - %w(content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight) + %w(content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight file_template_id) end private :file_attributes end diff --git a/app/views/code_ocean/files/_form.html.slim b/app/views/code_ocean/files/_form.html.slim index 07dd3355..ee74f4b8 100644 --- a/app/views/code_ocean/files/_form.html.slim +++ b/app/views/code_ocean/files/_form.html.slim @@ -8,5 +8,8 @@ .form-group = f.label(:file_type_id, t('activerecord.attributes.file.file_type_id')) = f.collection_select(:file_type_id, FileType.where(binary: false).order(:name), :id, :name, {selected: @exercise.execution_environment.file_type.try(:id)}, class: 'form-control') + .form-group + = f.label(:file_template_id, t('activerecord.attributes.file.file_template_id')) + = f.collection_select(:file_template_id, FileTemplate.all.order(:name), :id, :name, {}, class: 'form-control') = f.hidden_field(:context_id) .actions = render('shared/submit_button', f: f, object: CodeOcean::File.new) diff --git a/config/locales/de.yml b/config/locales/de.yml index 4a98e0a0..9a48ee4f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -54,6 +54,7 @@ de: read_only: Schreibgeschützt role: Rolle weight: Punktzahl + file_template_id: "Dateivorlage" file_type: binary: Binär editor_mode: Editor-Modus diff --git a/config/locales/en.yml b/config/locales/en.yml index de0f3aa4..49fc8bbb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -54,6 +54,7 @@ en: read_only: Read-only role: Role weight: Score + file_template_id: "File Template" file_type: binary: Binary editor_mode: Editor Mode diff --git a/db/migrate/20160610111602_add_file_template_to_file.rb b/db/migrate/20160610111602_add_file_template_to_file.rb new file mode 100644 index 00000000..a595e90b --- /dev/null +++ b/db/migrate/20160610111602_add_file_template_to_file.rb @@ -0,0 +1,5 @@ +class AddFileTemplateToFile < ActiveRecord::Migration + def change + add_reference :files, :file_template + end +end diff --git a/db/schema.rb b/db/schema.rb index 4f7fc833..bed23c98 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160609185708) do +ActiveRecord::Schema.define(version: 20160610111602) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -140,6 +140,7 @@ ActiveRecord::Schema.define(version: 20160609185708) do t.string "feedback_message" t.float "weight" t.string "path" + t.integer "file_template_id" end add_index "files", ["context_id", "context_type"], name: "index_files_on_context_id_and_context_type", using: :btree From c10b07690ad29138dd7be79bc2fdf21836b90b48 Mon Sep 17 00:00:00 2001 From: Maximilian Grundke Date: Fri, 10 Jun 2016 13:46:13 +0200 Subject: [PATCH 3/6] Make file template optional --- app/views/code_ocean/files/_form.html.slim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/code_ocean/files/_form.html.slim b/app/views/code_ocean/files/_form.html.slim index ee74f4b8..4b44647d 100644 --- a/app/views/code_ocean/files/_form.html.slim +++ b/app/views/code_ocean/files/_form.html.slim @@ -10,6 +10,6 @@ = f.collection_select(:file_type_id, FileType.where(binary: false).order(:name), :id, :name, {selected: @exercise.execution_environment.file_type.try(:id)}, class: 'form-control') .form-group = f.label(:file_template_id, t('activerecord.attributes.file.file_template_id')) - = f.collection_select(:file_template_id, FileTemplate.all.order(:name), :id, :name, {}, class: 'form-control') + = f.collection_select(:file_template_id, FileTemplate.all.order(:name), :id, :name, {:include_blank => true}, class: 'form-control') = f.hidden_field(:context_id) .actions = render('shared/submit_button', f: f, object: CodeOcean::File.new) From 4d2676fea75a724faed1ef7a2beaf0d04d22c4c2 Mon Sep 17 00:00:00 2001 From: Maximilian Grundke Date: Fri, 10 Jun 2016 17:48:04 +0200 Subject: [PATCH 4/6] Only show file templates which are available for the selected file type --- app/assets/javascripts/exercises.js | 20 ++++++++++++++++++++ app/controllers/file_templates_controller.rb | 8 ++++++++ app/policies/file_template_policy.rb | 4 ++++ app/views/code_ocean/files/_form.html.slim | 1 + config/locales/de.yml | 2 ++ config/locales/en.yml | 2 ++ config/routes.rb | 6 +++++- 7 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/exercises.js b/app/assets/javascripts/exercises.js index 1f861ef6..0e3805db 100644 --- a/app/assets/javascripts/exercises.js +++ b/app/assets/javascripts/exercises.js @@ -148,6 +148,22 @@ $(function() { }); }; + var updateFileTemplates = function(fileType) { + var jqxhr = $.ajax({ + url: '/file_templates/by_file_type/' + fileType + '.json', + dataType: 'json' + }); + jqxhr.done(function(response) { + var noTemplateLabel = $('#noTemplateLabel').data('text'); + var options = ""; + for (var i = 0; i < response.length; i++) { + options += "" + } + $("#code_ocean_file_file_template_id").find('option').remove().end().append($(options)); + }); + jqxhr.fail(ajaxError); + } + if ($.isController('exercises')) { if ($('table').isPresent()) { enableBatchUpdate(); @@ -162,6 +178,10 @@ $(function() { inferFileAttributes(); observeFileRoleChanges(); overrideTextareaTabBehavior(); + } else if ($('#files.jstree').isPresent()) { + var fileTypeSelect = $('#code_ocean_file_file_type_id'); + fileTypeSelect.on("change", function() {updateFileTemplates(fileTypeSelect.val())}); + updateFileTemplates(fileTypeSelect.val()); } toggleCodeHeight(); if (window.hljs) { diff --git a/app/controllers/file_templates_controller.rb b/app/controllers/file_templates_controller.rb index 45636d61..a6039500 100644 --- a/app/controllers/file_templates_controller.rb +++ b/app/controllers/file_templates_controller.rb @@ -6,6 +6,14 @@ class FileTemplatesController < ApplicationController end private :authorize! + def by_file_type + @file_templates = FileTemplate.where(:file_type_id => params[:file_type_id]) + authorize! + respond_to do |format| + format.json { render :show, status: :ok, json: @file_templates.to_json } + end + end + # GET /file_templates # GET /file_templates.json def index diff --git a/app/policies/file_template_policy.rb b/app/policies/file_template_policy.rb index b2f780a8..92ced442 100644 --- a/app/policies/file_template_policy.rb +++ b/app/policies/file_template_policy.rb @@ -4,4 +4,8 @@ class FileTemplatePolicy < AdminOnlyPolicy everyone end + def by_file_type? + everyone + end + end diff --git a/app/views/code_ocean/files/_form.html.slim b/app/views/code_ocean/files/_form.html.slim index 4b44647d..46c5b2c2 100644 --- a/app/views/code_ocean/files/_form.html.slim +++ b/app/views/code_ocean/files/_form.html.slim @@ -12,4 +12,5 @@ = f.label(:file_template_id, t('activerecord.attributes.file.file_template_id')) = f.collection_select(:file_template_id, FileTemplate.all.order(:name), :id, :name, {:include_blank => true}, class: 'form-control') = f.hidden_field(:context_id) + .hidden#noTemplateLabel data-text=t('file_template.no_template_label') .actions = render('shared/submit_button', f: f, object: CodeOcean::File.new) diff --git a/config/locales/de.yml b/config/locales/de.yml index 9a48ee4f..c0aa4b13 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -432,3 +432,5 @@ de: next_label: 'Nächste Seite →' page_gap: '…' previous_label: '← Vorherige Seite' + file_template: + no_template_label: "Leere Datei" diff --git a/config/locales/en.yml b/config/locales/en.yml index 49fc8bbb..f03e42fb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -432,3 +432,5 @@ en: next_label: 'Next Page →' page_gap: '…' previous_label: '← Previous Page' + file_template: + no_template_label: "Empty File" diff --git a/config/routes.rb b/config/routes.rb index 7965f0a3..afd8c8ce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,11 @@ FILENAME_REGEXP = /[\w\.]+/ unless Kernel.const_defined?(:FILENAME_REGEXP) Rails.application.routes.draw do - resources :file_templates + resources :file_templates do + collection do + get 'by_file_type/:file_type_id', as: :by_file_type, to: :by_file_type + end + end resources :code_harbor_links resources :request_for_comments get '/my_request_for_comments', as: 'my_request_for_comments', to: 'request_for_comments#get_my_comment_requests' From 8d030e42e9621391c4c9aa4a7de32eb731cdba27 Mon Sep 17 00:00:00 2001 From: Maximilian Grundke Date: Fri, 10 Jun 2016 18:08:57 +0200 Subject: [PATCH 5/6] Allow templates to include the file name as a macro --- app/controllers/code_ocean/files_controller.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/code_ocean/files_controller.rb b/app/controllers/code_ocean/files_controller.rb index e38607c2..55d8b369 100644 --- a/app/controllers/code_ocean/files_controller.rb +++ b/app/controllers/code_ocean/files_controller.rb @@ -11,7 +11,9 @@ module CodeOcean def create @file = CodeOcean::File.new(file_params) if @file.file_template_id - @file.content = FileTemplate.find(@file.file_template_id).content + content = FileTemplate.find(@file.file_template_id).content + content.sub! '{{file_name}}', @file.name + @file.content = content end authorize! create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise, tab: 2) }) From 7ef401f75aa97c9dd4fc86ec7deb87151891d187 Mon Sep 17 00:00:00 2001 From: Maximilian Grundke Date: Fri, 10 Jun 2016 18:15:37 +0200 Subject: [PATCH 6/6] Add navigation item for file templates --- app/views/application/_navigation.html.slim | 2 +- config/locales/de.yml | 3 +++ config/locales/en.yml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/views/application/_navigation.html.slim b/app/views/application/_navigation.html.slim index 4ab39e30..0f859844 100644 --- a/app/views/application/_navigation.html.slim +++ b/app/views/application/_navigation.html.slim @@ -8,7 +8,7 @@ - if current_user.admin? li = link_to(t('breadcrumbs.dashboard.show'), admin_dashboard_path) li.divider - - models = [ExecutionEnvironment, Exercise, Consumer, CodeHarborLink, ExternalUser, FileType, InternalUser, Submission, Team].sort_by { |model| model.model_name.human(count: 2) } + - models = [ExecutionEnvironment, Exercise, Consumer, CodeHarborLink, ExternalUser, FileType, FileTemplate, InternalUser, Submission, Team].sort_by { |model| model.model_name.human(count: 2) } - models.each do |model| - if policy(model).index? li = link_to(model.model_name.human(count: 2), send(:"#{model.model_name.collection}_path")) diff --git a/config/locales/de.yml b/config/locales/de.yml index c0aa4b13..c0013777 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -120,6 +120,9 @@ de: file: one: Datei other: Dateien + file_template: + one: Dateivorlage + other: Dateivorlagen file_type: one: Dateityp other: Dateitypen diff --git a/config/locales/en.yml b/config/locales/en.yml index f03e42fb..1d597bf8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -120,6 +120,9 @@ en: file: one: File other: Files + file_template: + one: File Template + other: File Templates file_type: one: File Type other: File Types