diff --git a/README.md b/README.md
index 74fe409a..32b952dd 100644
--- a/README.md
+++ b/README.md
@@ -123,6 +123,7 @@ You need to use an S3-compatible storage service to store your files. At Zoonk,
- `AWS_BUCKET`: Your AWS bucket name.
- `AWS_ENDPOINT_URL_S3`: Your AWS endpoint URL.
- `AWS_CDN_URL`: Your AWS CDN URL (optional. If missing, we'll use the S3 endpoint URL).
+- `CSP_CONNECT_SRC`: Your S3 domain (i.e. `https://fly.storage.tigris.dev`).
## Sponsors
diff --git a/config/config.exs b/config/config.exs
index 24164caa..9cfadb38 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -72,6 +72,9 @@ config :zoonk, ZoonkWeb.Endpoint,
# Configure translation
config :zoonk, ZoonkWeb.Gettext, default_locale: "en", locales: ~w(en pt)
+# Content security policy
+config :zoonk, :csp, connect_src: System.get_env("CSP_CONNECT_SRC")
+
# Storage config
config :zoonk, :storage,
bucket: System.get_env("AWS_BUCKET"),
diff --git a/lib/components/upload.ex b/lib/components/upload.ex
index 3260c11e..6490d742 100644
--- a/lib/components/upload.ex
+++ b/lib/components/upload.ex
@@ -47,7 +47,6 @@ defmodule ZoonkWeb.Components.Upload do
<%= gettext("Uploading: %{progress}%", progress: entry.progress) %>
-
<%= gettext("Processing file...") %>
<%= error_to_string(err) %>
@@ -59,14 +58,15 @@ defmodule ZoonkWeb.Components.Upload do
def mount(socket) do
socket =
socket
- |> assign(:uploading?, false)
|> allow_upload(
:file,
accept: ~w(.jpg .jpeg .png .avif .gif .webp),
max_entries: 1,
auto_upload: true,
+ external: &presign_upload/2,
progress: &handle_progress/3
)
+ |> assign(:uploaded_file_key, nil)
{:ok, socket}
end
@@ -92,25 +92,35 @@ defmodule ZoonkWeb.Components.Upload do
:ok
end
- # Only upload a file to the cloud after the progress is done.
+ defp presign_upload(entry, socket) do
+ config = ExAws.Config.new(:s3)
+ bucket = StorageAPI.get_bucket()
+ timestamp = DateTime.to_unix(DateTime.utc_now())
+ key = "#{timestamp}_#{entry.client_name}"
+
+ {:ok, url} =
+ ExAws.S3.presigned_url(config, :put, bucket, key,
+ expires_in: 3600,
+ query_params: [{"Content-Type", entry.client_type}]
+ )
+
+ {:ok, %{uploader: "S3", key: key, url: url}, assign(socket, :uploaded_file_key, key)}
+ end
+
defp handle_progress(_key, %{done?: true}, socket) do
- [file | _] =
- consume_uploaded_entries(socket, :file, fn %{path: path}, entry ->
- StorageAPI.upload(path, entry.client_type)
- {:ok, Path.basename(path)}
- end)
+ %{uploaded_file_key: key} = socket.assigns
# Optimize the image in the background.
- %{key: file} |> ImageOptimizer.new() |> Oban.insert!()
+ %{key: key} |> ImageOptimizer.new() |> Oban.insert!()
# Notify the parent component that the upload is done.
- notify_parent(socket, file)
+ notify_parent(socket, key)
- {:noreply, assign(socket, uploading?: false)}
+ {:noreply, socket}
end
defp handle_progress(_key, _entry, socket) do
- {:noreply, assign(socket, uploading?: true)}
+ {:noreply, socket}
end
# Since we only allow uploading one file, we only care about the first entry.
diff --git a/lib/router.ex b/lib/router.ex
index d137696c..af8d172c 100644
--- a/lib/router.ex
+++ b/lib/router.ex
@@ -7,6 +7,7 @@ defmodule ZoonkWeb.Router do
import ZoonkWeb.Plugs.UserAuth
alias Zoonk.Storage.StorageAPI
+ alias ZoonkWeb.Plugs.ContentSecurityPolicy
alias ZoonkWeb.Plugs.Course
alias ZoonkWeb.Plugs.School
alias ZoonkWeb.Plugs.Translate
@@ -23,7 +24,7 @@ defmodule ZoonkWeb.Router do
plug :put_secure_browser_headers, %{
"content-security-policy" =>
- "default-src 'self'; script-src-elem 'self' https://plausible.io; connect-src 'self' https://plausible.io; img-src 'self' #{StorageAPI.get_domain()} data: blob:; frame-src 'self' www.youtube-nocookie.com;"
+ "default-src 'self'; script-src-elem 'self' https://plausible.io; connect-src 'self' https://plausible.io #{ContentSecurityPolicy.get_connect_src()}; img-src 'self' #{StorageAPI.get_domain()} data: blob:; frame-src 'self' www.youtube-nocookie.com;"
}
plug :fetch_current_user
@@ -37,7 +38,7 @@ defmodule ZoonkWeb.Router do
plug :accepts, ["html"]
plug :fetch_session
plug :protect_from_forgery
- plug ZoonkWeb.Plugs.CspNonce, nonce: @nonce
+ plug ContentSecurityPolicy, nonce: @nonce
plug :put_secure_browser_headers, %{"content-security-policy" => "style-src 'self' 'nonce-#{@nonce}'"}
end
diff --git a/lib/shared/content_security_policy.ex b/lib/shared/content_security_policy.ex
new file mode 100644
index 00000000..93439325
--- /dev/null
+++ b/lib/shared/content_security_policy.ex
@@ -0,0 +1,25 @@
+defmodule ZoonkWeb.Plugs.ContentSecurityPolicy do
+ @moduledoc """
+ Set a CSP nonce for the current request.
+ """
+
+ @spec init(Keyword.t()) :: Keyword.t()
+ def init(options), do: options
+
+ @spec call(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t()
+ def call(conn, opts) do
+ nonce = Keyword.get(opts, :nonce)
+ Plug.Conn.assign(conn, :csp_nonce, nonce)
+ end
+
+ @doc """
+ Get allowed connect-src domains.
+
+ ## Examples
+
+ iex> ZoonkWeb.Plugs.CspNonce.get_connect_src()
+ "https://fly.storage.tigris.dev"
+ """
+ @spec get_connect_src() :: String.t()
+ def get_connect_src, do: Application.get_env(:zoonk, :csp)[:connect_src]
+end
diff --git a/lib/shared/csp_nonce_plug.ex b/lib/shared/csp_nonce_plug.ex
deleted file mode 100644
index 69e10110..00000000
--- a/lib/shared/csp_nonce_plug.ex
+++ /dev/null
@@ -1,14 +0,0 @@
-defmodule ZoonkWeb.Plugs.CspNonce do
- @moduledoc """
- Set a CSP nonce for the current request.
- """
-
- @spec init(Keyword.t()) :: Keyword.t()
- def init(options), do: options
-
- @spec call(Plug.Conn.t(), Keyword.t()) :: Plug.Conn.t()
- def call(conn, opts) do
- nonce = Keyword.get(opts, :nonce)
- Plug.Conn.assign(conn, :csp_nonce, nonce)
- end
-end
diff --git a/lib/storage/storage_api.ex b/lib/storage/storage_api.ex
index 6faa09ca..199b1442 100644
--- a/lib/storage/storage_api.ex
+++ b/lib/storage/storage_api.ex
@@ -4,23 +4,8 @@ defmodule Zoonk.Storage.StorageAPI do
"""
alias ExAws.S3
- @callback upload(String.t(), String.t()) :: {:ok, term()} | {:error, term()}
@callback delete(String.t()) :: {:ok, term()} | {:error, term()}
- @doc """
- Uploads a file to the storage service.
-
- ## Examples
-
- iex> StorageAPI.upload("path/to/file", "image/webp")
- {:ok, %{}}
-
- iex> StorageAPI.upload("path/to/file", "image/webp")
- {:error, %{}}
- """
- @spec upload(String.t(), String.t()) :: {:ok, term()} | {:error, term()}
- def upload(file_path, content_type), do: impl().upload(file_path, content_type)
-
@doc """
Deletes a file from the storage service.
@@ -88,14 +73,6 @@ defmodule Zoonk.ExternalStorageAPI do
alias ExAws.S3
alias Zoonk.Storage.StorageAPI
- @spec upload(String.t(), String.t()) :: {:ok, term()} | {:error, term()}
- def upload(file_path, content_type) do
- file_path
- |> S3.Upload.stream_file()
- |> S3.upload(StorageAPI.get_bucket(), Path.basename(file_path), content_type: content_type)
- |> ExAws.request()
- end
-
@spec delete(String.t()) :: {:ok, term()} | {:error, term()}
def delete(key) do
StorageAPI.get_bucket()
diff --git a/priv/gettext/courses.pot b/priv/gettext/courses.pot
index 8a38d00b..c6eab796 100644
--- a/priv/gettext/courses.pot
+++ b/priv/gettext/courses.pot
@@ -11,7 +11,7 @@
msgid ""
msgstr ""
-#: lib/content/course_live/course_view.ex:59
+#: lib/content/course_live/course_view.ex:60
#, elixir-autogen, elixir-format
msgid "A request to enroll has been sent to the course teacher."
msgstr ""
@@ -36,7 +36,7 @@ msgstr ""
msgid "Confirming..."
msgstr ""
-#: lib/content/course_live/course_view.ex:58
+#: lib/content/course_live/course_view.ex:59
#, elixir-autogen, elixir-format
msgid "Enrolled successfully!"
msgstr ""
@@ -51,7 +51,7 @@ msgstr ""
msgid "Expert"
msgstr ""
-#: lib/content/course_live/course_view.ex:43
+#: lib/content/course_live/course_view.ex:44
#, elixir-autogen, elixir-format
msgid "Failed to enroll"
msgstr ""
@@ -91,7 +91,7 @@ msgstr ""
msgid "Request to join"
msgstr ""
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "That's incorrect."
msgstr ""
@@ -101,12 +101,12 @@ msgstr ""
msgid "There's room for improvement"
msgstr ""
-#: lib/content/course_live/lesson_play.ex:90
+#: lib/content/course_live/lesson_play.ex:91
#, elixir-autogen, elixir-format
msgid "Unable to complete lesson"
msgstr ""
-#: lib/content/course_live/lesson_play.ex:53
+#: lib/content/course_live/lesson_play.ex:54
#, elixir-autogen, elixir-format
msgid "Unable to select option"
msgstr ""
@@ -116,7 +116,7 @@ msgstr ""
msgid "Very good!"
msgstr ""
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr ""
@@ -151,7 +151,7 @@ msgstr ""
msgid "No courses"
msgstr ""
-#: lib/content/course_live/lesson_play.ex:76
+#: lib/content/course_live/lesson_play.ex:77
#, elixir-autogen, elixir-format
msgid "Unable to send answer"
msgstr ""
diff --git a/priv/gettext/de/LC_MESSAGES/courses.po b/priv/gettext/de/LC_MESSAGES/courses.po
index 561ea95b..9f0fb48a 100644
--- a/priv/gettext/de/LC_MESSAGES/courses.po
+++ b/priv/gettext/de/LC_MESSAGES/courses.po
@@ -11,7 +11,7 @@ msgstr ""
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: lib/content/course_live/course_view.ex:59
+#: lib/content/course_live/course_view.ex:60
#, elixir-autogen, elixir-format
msgid "A request to enroll has been sent to the course teacher."
msgstr "Ein Antrag auf Einschreibung wurde an den Kursleiter geschickt."
@@ -36,7 +36,7 @@ msgstr "Anfänger"
msgid "Confirming..."
msgstr "Bestätigen..."
-#: lib/content/course_live/course_view.ex:58
+#: lib/content/course_live/course_view.ex:59
#, elixir-autogen, elixir-format
msgid "Enrolled successfully!"
msgstr "Erfolgreich eingeschrieben!"
@@ -51,7 +51,7 @@ msgstr "Ausgezeichnet!"
msgid "Expert"
msgstr "Experte"
-#: lib/content/course_live/course_view.ex:43
+#: lib/content/course_live/course_view.ex:44
#, elixir-autogen, elixir-format
msgid "Failed to enroll"
msgstr "Einschreibung fehlgeschlagen"
@@ -91,7 +91,7 @@ msgstr "Perfekt!"
msgid "Request to join"
msgstr "Antrag auf Beitritt"
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "That's incorrect."
msgstr "Das ist nicht richtig."
@@ -101,12 +101,12 @@ msgstr "Das ist nicht richtig."
msgid "There's room for improvement"
msgstr "Es gibt Raum für Verbesserungen"
-#: lib/content/course_live/lesson_play.ex:90
+#: lib/content/course_live/lesson_play.ex:91
#, elixir-autogen, elixir-format
msgid "Unable to complete lesson"
msgstr "Lektion kann nicht abgeschlossen werden"
-#: lib/content/course_live/lesson_play.ex:53
+#: lib/content/course_live/lesson_play.ex:54
#, elixir-autogen, elixir-format
msgid "Unable to select option"
msgstr "Option kann nicht ausgewählt werden"
@@ -116,7 +116,7 @@ msgstr "Option kann nicht ausgewählt werden"
msgid "Very good!"
msgstr "Sehr gut!"
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr "Gut gemacht!"
@@ -151,7 +151,7 @@ msgstr "Beginnen Sie mit der Teilnahme an einem Kurs."
msgid "No courses"
msgstr "Keine Kurse"
-#: lib/content/course_live/lesson_play.ex:76
+#: lib/content/course_live/lesson_play.ex:77
#, elixir-autogen, elixir-format
msgid "Unable to send answer"
msgstr "Senden der Antwort fehlgeschlagen"
diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po
index bac2fe65..a30ca2cb 100644
--- a/priv/gettext/de/LC_MESSAGES/default.po
+++ b/priv/gettext/de/LC_MESSAGES/default.po
@@ -95,7 +95,7 @@ msgstr "Startseite"
#: lib/dashboard/schools/school_edit.ex:92
#: lib/dashboard/schools/school_edit.html.heex:1
-#: lib/layouts/menu_utils.ex:98
+#: lib/layouts/menu_utils.ex:99
#: lib/layouts/templates/auth.html.heex:3
#, elixir-autogen, elixir-format
msgid "Logo"
@@ -117,7 +117,7 @@ msgstr "Abmelden"
#: lib/dashboard/courses/course_edit.html.heex:5
#: lib/dashboard/schools/school_edit.ex:91
#: lib/layouts/components/app_menu.ex:40
-#: lib/layouts/menu_utils.ex:100
+#: lib/layouts/menu_utils.ex:101
#: lib/layouts/templates/dashboard_course.html.heex:42
#, elixir-autogen, elixir-format
msgid "Settings"
@@ -228,7 +228,7 @@ msgstr "Aktualisieren"
msgid "Updating..."
msgstr "Aktualisiert..."
-#: lib/components/upload.ex:23
+#: lib/components/upload.ex:24
#, elixir-autogen, elixir-format
msgid "Remove"
msgstr "Entfernen"
@@ -262,7 +262,7 @@ msgstr "Seitenleiste schließen"
#: lib/components/delete_item.ex:17
#: lib/components/delete_item.ex:21
#: lib/dashboard/schools/school_edit.ex:93
-#: lib/layouts/menu_utils.ex:101
+#: lib/layouts/menu_utils.ex:102
#: lib/layouts/templates/app.html.heex:78
#: lib/layouts/templates/dashboard_course.html.heex:50
#, elixir-autogen, elixir-format
@@ -284,7 +284,7 @@ msgstr "Neu"
msgid "Open sidebar"
msgstr "Seitenleiste öffnen"
-#: lib/layouts/menu_utils.ex:95
+#: lib/layouts/menu_utils.ex:96
#: lib/layouts/templates/dashboard_course.html.heex:26
#, elixir-autogen, elixir-format
msgid "Overview"
@@ -341,7 +341,7 @@ msgstr "Verliere deinen Fortschritt nicht. "
msgid "Update your email address"
msgstr "Aktualisiere deine E-Mail Adresse"
-#: lib/layouts/menu_utils.ex:96
+#: lib/layouts/menu_utils.ex:97
#, elixir-autogen, elixir-format
msgid "Schools"
msgstr "Schulen"
@@ -381,7 +381,7 @@ msgstr "Einrichtung"
#: lib/dashboard/schools/school_edit.ex:94
#: lib/dashboard/schools/school_edit.html.heex:2
-#: lib/layouts/menu_utils.ex:99
+#: lib/layouts/menu_utils.ex:100
#, elixir-autogen, elixir-format
msgid "Icon"
msgstr "Icon"
@@ -398,11 +398,6 @@ msgstr "Etwas ist schief gelaufen!"
#: lib/components/upload.ex:49
#, elixir-autogen, elixir-format
-msgid "Processing file..."
-msgstr "Datei wird verarbeitet..."
-
-#: lib/components/upload.ex:48
-#, elixir-autogen, elixir-format
msgid "Uploading: %{progress}%"
msgstr "Hochladen: %{progress}%"
diff --git a/priv/gettext/de/LC_MESSAGES/errors.po b/priv/gettext/de/LC_MESSAGES/errors.po
index fd6fbc57..eecf7ffe 100644
--- a/priv/gettext/de/LC_MESSAGES/errors.po
+++ b/priv/gettext/de/LC_MESSAGES/errors.po
@@ -206,17 +206,22 @@ msgstr "Zugriff verweigert"
msgid "is not allowed"
msgstr "ist nicht erlaubt"
-#: lib/components/upload.ex:133
+#: lib/components/upload.ex:130
#, elixir-autogen, elixir-format
msgid "Too large"
msgstr "Zu groß"
-#: lib/components/upload.ex:134
+#: lib/components/upload.ex:131
#, elixir-autogen, elixir-format
msgid "You have selected an unacceptable file type"
msgstr "Sie haben einen nicht akzeptablen Dateityp ausgewählt"
-#: lib/components/upload.ex:135
+#: lib/components/upload.ex:132
#, elixir-autogen, elixir-format
msgid "You have selected too many files"
msgstr "Sie haben zu viele Dateien ausgewählt"
+
+#: lib/components/upload.ex:86
+#, elixir-autogen, elixir-format
+msgid "Failed to remove file"
+msgstr "Datei konnte nicht gelöscht werden"
diff --git a/priv/gettext/de/LC_MESSAGES/orgs.po b/priv/gettext/de/LC_MESSAGES/orgs.po
index e9f70191..f73b34df 100644
--- a/priv/gettext/de/LC_MESSAGES/orgs.po
+++ b/priv/gettext/de/LC_MESSAGES/orgs.po
@@ -475,7 +475,7 @@ msgstr "Eine Lektion hat mehrere Schritte. Verwende sie, um eine Geschichte zu e
msgid "Add image to step"
msgstr "Bild zum Schritt hinzufügen"
-#: lib/dashboard/lessons/components/step_image.ex:33
+#: lib/dashboard/lessons/components/step_image.ex:34
#, elixir-autogen, elixir-format
msgid "Click to add an image to this step."
msgstr "Klicken, um ein Bild zu diesem Schritt hinzuzufügen."
@@ -505,7 +505,7 @@ msgstr "Schritt Aktualisieren"
msgid "Edit image"
msgstr "Bild bearbeiten"
-#: lib/dashboard/lessons/components/step_image.ex:21
+#: lib/dashboard/lessons/components/step_image.ex:22
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit step image"
msgstr "Schritt Bild bearbeiten"
@@ -678,7 +678,7 @@ msgstr "Lehrer"
#: lib/dashboard/courses/course_user_list.html.heex:2
#: lib/dashboard/schools/school_user_list.ex:76
#: lib/dashboard/schools/school_user_list.html.heex:2
-#: lib/layouts/menu_utils.ex:97
+#: lib/layouts/menu_utils.ex:98
#: lib/layouts/templates/dashboard_course.html.heex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Users"
diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot
index 947323c6..9d201acc 100644
--- a/priv/gettext/default.pot
+++ b/priv/gettext/default.pot
@@ -95,7 +95,7 @@ msgstr ""
#: lib/dashboard/schools/school_edit.ex:92
#: lib/dashboard/schools/school_edit.html.heex:1
-#: lib/layouts/menu_utils.ex:98
+#: lib/layouts/menu_utils.ex:99
#: lib/layouts/templates/auth.html.heex:3
#, elixir-autogen, elixir-format
msgid "Logo"
@@ -117,7 +117,7 @@ msgstr ""
#: lib/dashboard/courses/course_edit.html.heex:5
#: lib/dashboard/schools/school_edit.ex:91
#: lib/layouts/components/app_menu.ex:40
-#: lib/layouts/menu_utils.ex:100
+#: lib/layouts/menu_utils.ex:101
#: lib/layouts/templates/dashboard_course.html.heex:42
#, elixir-autogen, elixir-format
msgid "Settings"
@@ -228,7 +228,7 @@ msgstr ""
msgid "Updating..."
msgstr ""
-#: lib/components/upload.ex:23
+#: lib/components/upload.ex:24
#, elixir-autogen, elixir-format
msgid "Remove"
msgstr ""
@@ -262,7 +262,7 @@ msgstr ""
#: lib/components/delete_item.ex:17
#: lib/components/delete_item.ex:21
#: lib/dashboard/schools/school_edit.ex:93
-#: lib/layouts/menu_utils.ex:101
+#: lib/layouts/menu_utils.ex:102
#: lib/layouts/templates/app.html.heex:78
#: lib/layouts/templates/dashboard_course.html.heex:50
#, elixir-autogen, elixir-format
@@ -284,7 +284,7 @@ msgstr ""
msgid "Open sidebar"
msgstr ""
-#: lib/layouts/menu_utils.ex:95
+#: lib/layouts/menu_utils.ex:96
#: lib/layouts/templates/dashboard_course.html.heex:26
#, elixir-autogen, elixir-format
msgid "Overview"
@@ -341,7 +341,7 @@ msgstr ""
msgid "Update your email address"
msgstr ""
-#: lib/layouts/menu_utils.ex:96
+#: lib/layouts/menu_utils.ex:97
#, elixir-autogen, elixir-format
msgid "Schools"
msgstr ""
@@ -381,7 +381,7 @@ msgstr ""
#: lib/dashboard/schools/school_edit.ex:94
#: lib/dashboard/schools/school_edit.html.heex:2
-#: lib/layouts/menu_utils.ex:99
+#: lib/layouts/menu_utils.ex:100
#, elixir-autogen, elixir-format
msgid "Icon"
msgstr ""
@@ -398,11 +398,6 @@ msgstr ""
#: lib/components/upload.ex:49
#, elixir-autogen, elixir-format
-msgid "Processing file..."
-msgstr ""
-
-#: lib/components/upload.ex:48
-#, elixir-autogen, elixir-format
msgid "Uploading: %{progress}%"
msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/courses.po b/priv/gettext/en/LC_MESSAGES/courses.po
index b732bec9..881c9b6d 100644
--- a/priv/gettext/en/LC_MESSAGES/courses.po
+++ b/priv/gettext/en/LC_MESSAGES/courses.po
@@ -11,7 +11,7 @@ msgstr ""
"Language: en\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: lib/content/course_live/course_view.ex:59
+#: lib/content/course_live/course_view.ex:60
#, elixir-autogen, elixir-format
msgid "A request to enroll has been sent to the course teacher."
msgstr ""
@@ -36,7 +36,7 @@ msgstr ""
msgid "Confirming..."
msgstr ""
-#: lib/content/course_live/course_view.ex:58
+#: lib/content/course_live/course_view.ex:59
#, elixir-autogen, elixir-format
msgid "Enrolled successfully!"
msgstr ""
@@ -51,7 +51,7 @@ msgstr ""
msgid "Expert"
msgstr ""
-#: lib/content/course_live/course_view.ex:43
+#: lib/content/course_live/course_view.ex:44
#, elixir-autogen, elixir-format
msgid "Failed to enroll"
msgstr ""
@@ -91,7 +91,7 @@ msgstr ""
msgid "Request to join"
msgstr ""
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "That's incorrect."
msgstr ""
@@ -101,12 +101,12 @@ msgstr ""
msgid "There's room for improvement"
msgstr ""
-#: lib/content/course_live/lesson_play.ex:90
+#: lib/content/course_live/lesson_play.ex:91
#, elixir-autogen, elixir-format
msgid "Unable to complete lesson"
msgstr ""
-#: lib/content/course_live/lesson_play.ex:53
+#: lib/content/course_live/lesson_play.ex:54
#, elixir-autogen, elixir-format
msgid "Unable to select option"
msgstr ""
@@ -116,7 +116,7 @@ msgstr ""
msgid "Very good!"
msgstr ""
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr ""
@@ -151,7 +151,7 @@ msgstr ""
msgid "No courses"
msgstr ""
-#: lib/content/course_live/lesson_play.ex:76
+#: lib/content/course_live/lesson_play.ex:77
#, elixir-autogen, elixir-format
msgid "Unable to send answer"
msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po
index e9697289..a9fb65b5 100644
--- a/priv/gettext/en/LC_MESSAGES/default.po
+++ b/priv/gettext/en/LC_MESSAGES/default.po
@@ -95,7 +95,7 @@ msgstr ""
#: lib/dashboard/schools/school_edit.ex:92
#: lib/dashboard/schools/school_edit.html.heex:1
-#: lib/layouts/menu_utils.ex:98
+#: lib/layouts/menu_utils.ex:99
#: lib/layouts/templates/auth.html.heex:3
#, elixir-autogen, elixir-format
msgid "Logo"
@@ -117,7 +117,7 @@ msgstr ""
#: lib/dashboard/courses/course_edit.html.heex:5
#: lib/dashboard/schools/school_edit.ex:91
#: lib/layouts/components/app_menu.ex:40
-#: lib/layouts/menu_utils.ex:100
+#: lib/layouts/menu_utils.ex:101
#: lib/layouts/templates/dashboard_course.html.heex:42
#, elixir-autogen, elixir-format
msgid "Settings"
@@ -228,7 +228,7 @@ msgstr ""
msgid "Updating..."
msgstr ""
-#: lib/components/upload.ex:23
+#: lib/components/upload.ex:24
#, elixir-autogen, elixir-format
msgid "Remove"
msgstr ""
@@ -262,7 +262,7 @@ msgstr ""
#: lib/components/delete_item.ex:17
#: lib/components/delete_item.ex:21
#: lib/dashboard/schools/school_edit.ex:93
-#: lib/layouts/menu_utils.ex:101
+#: lib/layouts/menu_utils.ex:102
#: lib/layouts/templates/app.html.heex:78
#: lib/layouts/templates/dashboard_course.html.heex:50
#, elixir-autogen, elixir-format
@@ -284,7 +284,7 @@ msgstr ""
msgid "Open sidebar"
msgstr ""
-#: lib/layouts/menu_utils.ex:95
+#: lib/layouts/menu_utils.ex:96
#: lib/layouts/templates/dashboard_course.html.heex:26
#, elixir-autogen, elixir-format
msgid "Overview"
@@ -341,7 +341,7 @@ msgstr ""
msgid "Update your email address"
msgstr ""
-#: lib/layouts/menu_utils.ex:96
+#: lib/layouts/menu_utils.ex:97
#, elixir-autogen, elixir-format
msgid "Schools"
msgstr ""
@@ -381,7 +381,7 @@ msgstr ""
#: lib/dashboard/schools/school_edit.ex:94
#: lib/dashboard/schools/school_edit.html.heex:2
-#: lib/layouts/menu_utils.ex:99
+#: lib/layouts/menu_utils.ex:100
#, elixir-autogen, elixir-format
msgid "Icon"
msgstr ""
@@ -398,11 +398,6 @@ msgstr "Something went wrong!"
#: lib/components/upload.ex:49
#, elixir-autogen, elixir-format
-msgid "Processing file..."
-msgstr ""
-
-#: lib/components/upload.ex:48
-#, elixir-autogen, elixir-format
msgid "Uploading: %{progress}%"
msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/errors.po b/priv/gettext/en/LC_MESSAGES/errors.po
index 838a9977..7751cd01 100644
--- a/priv/gettext/en/LC_MESSAGES/errors.po
+++ b/priv/gettext/en/LC_MESSAGES/errors.po
@@ -206,17 +206,22 @@ msgstr ""
msgid "is not allowed"
msgstr ""
-#: lib/components/upload.ex:133
+#: lib/components/upload.ex:130
#, elixir-autogen, elixir-format
msgid "Too large"
msgstr ""
-#: lib/components/upload.ex:134
+#: lib/components/upload.ex:131
#, elixir-autogen, elixir-format
msgid "You have selected an unacceptable file type"
msgstr ""
-#: lib/components/upload.ex:135
+#: lib/components/upload.ex:132
#, elixir-autogen, elixir-format
msgid "You have selected too many files"
msgstr ""
+
+#: lib/components/upload.ex:86
+#, elixir-autogen, elixir-format
+msgid "Failed to remove file"
+msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/orgs.po b/priv/gettext/en/LC_MESSAGES/orgs.po
index b98db6c5..3579117b 100644
--- a/priv/gettext/en/LC_MESSAGES/orgs.po
+++ b/priv/gettext/en/LC_MESSAGES/orgs.po
@@ -475,7 +475,7 @@ msgstr ""
msgid "Add image to step"
msgstr ""
-#: lib/dashboard/lessons/components/step_image.ex:33
+#: lib/dashboard/lessons/components/step_image.ex:34
#, elixir-autogen, elixir-format
msgid "Click to add an image to this step."
msgstr ""
@@ -505,7 +505,7 @@ msgstr ""
msgid "Edit image"
msgstr ""
-#: lib/dashboard/lessons/components/step_image.ex:21
+#: lib/dashboard/lessons/components/step_image.ex:22
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit step image"
msgstr ""
@@ -678,7 +678,7 @@ msgstr ""
#: lib/dashboard/courses/course_user_list.html.heex:2
#: lib/dashboard/schools/school_user_list.ex:76
#: lib/dashboard/schools/school_user_list.html.heex:2
-#: lib/layouts/menu_utils.ex:97
+#: lib/layouts/menu_utils.ex:98
#: lib/layouts/templates/dashboard_course.html.heex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Users"
diff --git a/priv/gettext/errors.pot b/priv/gettext/errors.pot
index 25293db4..061b9069 100644
--- a/priv/gettext/errors.pot
+++ b/priv/gettext/errors.pot
@@ -203,17 +203,22 @@ msgstr ""
msgid "is not allowed"
msgstr ""
-#: lib/components/upload.ex:133
+#: lib/components/upload.ex:130
#, elixir-autogen, elixir-format
msgid "Too large"
msgstr ""
-#: lib/components/upload.ex:134
+#: lib/components/upload.ex:131
#, elixir-autogen, elixir-format
msgid "You have selected an unacceptable file type"
msgstr ""
-#: lib/components/upload.ex:135
+#: lib/components/upload.ex:132
#, elixir-autogen, elixir-format
msgid "You have selected too many files"
msgstr ""
+
+#: lib/components/upload.ex:86
+#, elixir-autogen, elixir-format
+msgid "Failed to remove file"
+msgstr ""
diff --git a/priv/gettext/orgs.pot b/priv/gettext/orgs.pot
index a1219334..538e3a31 100644
--- a/priv/gettext/orgs.pot
+++ b/priv/gettext/orgs.pot
@@ -475,7 +475,7 @@ msgstr ""
msgid "Add image to step"
msgstr ""
-#: lib/dashboard/lessons/components/step_image.ex:33
+#: lib/dashboard/lessons/components/step_image.ex:34
#, elixir-autogen, elixir-format
msgid "Click to add an image to this step."
msgstr ""
@@ -505,7 +505,7 @@ msgstr ""
msgid "Edit image"
msgstr ""
-#: lib/dashboard/lessons/components/step_image.ex:21
+#: lib/dashboard/lessons/components/step_image.ex:22
#, elixir-autogen, elixir-format
msgid "Edit step image"
msgstr ""
@@ -678,7 +678,7 @@ msgstr ""
#: lib/dashboard/courses/course_user_list.html.heex:2
#: lib/dashboard/schools/school_user_list.ex:76
#: lib/dashboard/schools/school_user_list.html.heex:2
-#: lib/layouts/menu_utils.ex:97
+#: lib/layouts/menu_utils.ex:98
#: lib/layouts/templates/dashboard_course.html.heex:38
#, elixir-autogen, elixir-format
msgid "Users"
diff --git a/priv/gettext/pt/LC_MESSAGES/courses.po b/priv/gettext/pt/LC_MESSAGES/courses.po
index 60c841ea..b657dccd 100644
--- a/priv/gettext/pt/LC_MESSAGES/courses.po
+++ b/priv/gettext/pt/LC_MESSAGES/courses.po
@@ -11,7 +11,7 @@ msgstr ""
"Language: pt\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: lib/content/course_live/course_view.ex:59
+#: lib/content/course_live/course_view.ex:60
#, elixir-autogen, elixir-format
msgid "A request to enroll has been sent to the course teacher."
msgstr "Uma solicitação de matrícula foi enviada ao professor do curso."
@@ -36,7 +36,7 @@ msgstr "Iniciante"
msgid "Confirming..."
msgstr "Confirmando..."
-#: lib/content/course_live/course_view.ex:58
+#: lib/content/course_live/course_view.ex:59
#, elixir-autogen, elixir-format
msgid "Enrolled successfully!"
msgstr "Matriculado com sucesso!"
@@ -51,7 +51,7 @@ msgstr "Excelente!"
msgid "Expert"
msgstr "Especialista"
-#: lib/content/course_live/course_view.ex:43
+#: lib/content/course_live/course_view.ex:44
#, elixir-autogen, elixir-format
msgid "Failed to enroll"
msgstr "Falha ao se matricular"
@@ -91,7 +91,7 @@ msgstr "Perfeito!"
msgid "Request to join"
msgstr "Pedir para participar"
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "That's incorrect."
msgstr "Está incorreto."
@@ -101,12 +101,12 @@ msgstr "Está incorreto."
msgid "There's room for improvement"
msgstr "Tem espaço para melhorar"
-#: lib/content/course_live/lesson_play.ex:90
+#: lib/content/course_live/lesson_play.ex:91
#, elixir-autogen, elixir-format
msgid "Unable to complete lesson"
msgstr "Não foi possível concluir a aula"
-#: lib/content/course_live/lesson_play.ex:53
+#: lib/content/course_live/lesson_play.ex:54
#, elixir-autogen, elixir-format
msgid "Unable to select option"
msgstr "Não foi possível selecionar a alternativa"
@@ -116,7 +116,7 @@ msgstr "Não foi possível selecionar a alternativa"
msgid "Very good!"
msgstr "Muito bem!"
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr "Boa!"
@@ -151,7 +151,7 @@ msgstr "Para começar, entre em um curso."
msgid "No courses"
msgstr "Nenhum curso"
-#: lib/content/course_live/lesson_play.ex:76
+#: lib/content/course_live/lesson_play.ex:77
#, elixir-autogen, elixir-format
msgid "Unable to send answer"
msgstr "Não foi possível enviar a resposta"
diff --git a/priv/gettext/pt/LC_MESSAGES/default.po b/priv/gettext/pt/LC_MESSAGES/default.po
index 74780d09..36bf3156 100644
--- a/priv/gettext/pt/LC_MESSAGES/default.po
+++ b/priv/gettext/pt/LC_MESSAGES/default.po
@@ -95,7 +95,7 @@ msgstr "Início"
#: lib/dashboard/schools/school_edit.ex:92
#: lib/dashboard/schools/school_edit.html.heex:1
-#: lib/layouts/menu_utils.ex:98
+#: lib/layouts/menu_utils.ex:99
#: lib/layouts/templates/auth.html.heex:3
#, elixir-autogen, elixir-format
msgid "Logo"
@@ -117,7 +117,7 @@ msgstr "Sair"
#: lib/dashboard/courses/course_edit.html.heex:5
#: lib/dashboard/schools/school_edit.ex:91
#: lib/layouts/components/app_menu.ex:40
-#: lib/layouts/menu_utils.ex:100
+#: lib/layouts/menu_utils.ex:101
#: lib/layouts/templates/dashboard_course.html.heex:42
#, elixir-autogen, elixir-format
msgid "Settings"
@@ -228,7 +228,7 @@ msgstr "Atualizar"
msgid "Updating..."
msgstr "Atualizando..."
-#: lib/components/upload.ex:23
+#: lib/components/upload.ex:24
#, elixir-autogen, elixir-format
msgid "Remove"
msgstr "Remover"
@@ -262,7 +262,7 @@ msgstr "Fechar barra lateral"
#: lib/components/delete_item.ex:17
#: lib/components/delete_item.ex:21
#: lib/dashboard/schools/school_edit.ex:93
-#: lib/layouts/menu_utils.ex:101
+#: lib/layouts/menu_utils.ex:102
#: lib/layouts/templates/app.html.heex:78
#: lib/layouts/templates/dashboard_course.html.heex:50
#, elixir-autogen, elixir-format
@@ -284,7 +284,7 @@ msgstr "Novo"
msgid "Open sidebar"
msgstr "Abrir barra lateral"
-#: lib/layouts/menu_utils.ex:95
+#: lib/layouts/menu_utils.ex:96
#: lib/layouts/templates/dashboard_course.html.heex:26
#, elixir-autogen, elixir-format
msgid "Overview"
@@ -341,7 +341,7 @@ msgstr "Não perca o seu progresso. "
msgid "Update your email address"
msgstr "Atualize o endereço de e-mail"
-#: lib/layouts/menu_utils.ex:96
+#: lib/layouts/menu_utils.ex:97
#, elixir-autogen, elixir-format
msgid "Schools"
msgstr "Escolas"
@@ -381,7 +381,7 @@ msgstr "Configuração"
#: lib/dashboard/schools/school_edit.ex:94
#: lib/dashboard/schools/school_edit.html.heex:2
-#: lib/layouts/menu_utils.ex:99
+#: lib/layouts/menu_utils.ex:100
#, elixir-autogen, elixir-format
msgid "Icon"
msgstr "Ícone"
@@ -398,11 +398,6 @@ msgstr "Algo deu errado!"
#: lib/components/upload.ex:49
#, elixir-autogen, elixir-format
-msgid "Processing file..."
-msgstr "Processando arquivo..."
-
-#: lib/components/upload.ex:48
-#, elixir-autogen, elixir-format
msgid "Uploading: %{progress}%"
msgstr "Enviando: %{progress}%"
diff --git a/priv/gettext/pt/LC_MESSAGES/errors.po b/priv/gettext/pt/LC_MESSAGES/errors.po
index b4487e7a..b95a2614 100644
--- a/priv/gettext/pt/LC_MESSAGES/errors.po
+++ b/priv/gettext/pt/LC_MESSAGES/errors.po
@@ -196,17 +196,22 @@ msgstr "Permissão negada"
msgid "is not allowed"
msgstr "não é permitido"
-#: lib/components/upload.ex:133
+#: lib/components/upload.ex:130
#, elixir-autogen, elixir-format
msgid "Too large"
msgstr "Muito grande"
-#: lib/components/upload.ex:134
+#: lib/components/upload.ex:131
#, elixir-autogen, elixir-format
msgid "You have selected an unacceptable file type"
msgstr "Você selecionou um tipo de arquivo incompatível"
-#: lib/components/upload.ex:135
+#: lib/components/upload.ex:132
#, elixir-autogen, elixir-format
msgid "You have selected too many files"
msgstr "Você selecionou muitos arquivos"
+
+#: lib/components/upload.ex:86
+#, elixir-autogen, elixir-format
+msgid "Failed to remove file"
+msgstr "Falha ao remover arquivo"
diff --git a/priv/gettext/pt/LC_MESSAGES/orgs.po b/priv/gettext/pt/LC_MESSAGES/orgs.po
index f0b9f457..9dc8478e 100644
--- a/priv/gettext/pt/LC_MESSAGES/orgs.po
+++ b/priv/gettext/pt/LC_MESSAGES/orgs.po
@@ -475,7 +475,7 @@ msgstr "Uma aula tem várias etapas. Use-as para contar uma história, explicar
msgid "Add image to step"
msgstr "Adicionar imagem à etapa"
-#: lib/dashboard/lessons/components/step_image.ex:33
+#: lib/dashboard/lessons/components/step_image.ex:34
#, elixir-autogen, elixir-format
msgid "Click to add an image to this step."
msgstr "Clique para adicionar uma imagem a esta etapa."
@@ -505,7 +505,7 @@ msgstr "Atualizar etapa"
msgid "Edit image"
msgstr "Editar imagem"
-#: lib/dashboard/lessons/components/step_image.ex:21
+#: lib/dashboard/lessons/components/step_image.ex:22
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit step image"
msgstr "Editar imagem da etapa"
@@ -678,7 +678,7 @@ msgstr "Professor"
#: lib/dashboard/courses/course_user_list.html.heex:2
#: lib/dashboard/schools/school_user_list.ex:76
#: lib/dashboard/schools/school_user_list.html.heex:2
-#: lib/layouts/menu_utils.ex:97
+#: lib/layouts/menu_utils.ex:98
#: lib/layouts/templates/dashboard_course.html.heex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Users"
diff --git a/priv/gettext/zh_TW/LC_MESSAGES/courses.po b/priv/gettext/zh_TW/LC_MESSAGES/courses.po
index 6954090e..07443a73 100644
--- a/priv/gettext/zh_TW/LC_MESSAGES/courses.po
+++ b/priv/gettext/zh_TW/LC_MESSAGES/courses.po
@@ -11,7 +11,7 @@ msgstr ""
"Language: zh_TW\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: lib/content/course_live/course_view.ex:59
+#: lib/content/course_live/course_view.ex:60
#, elixir-autogen, elixir-format
msgid "A request to enroll has been sent to the course teacher."
msgstr "已向教師報名課程。"
@@ -36,7 +36,7 @@ msgstr "初級"
msgid "Confirming..."
msgstr "確認中..."
-#: lib/content/course_live/course_view.ex:58
+#: lib/content/course_live/course_view.ex:59
#, elixir-autogen, elixir-format
msgid "Enrolled successfully!"
msgstr "成功報名!"
@@ -51,7 +51,7 @@ msgstr "優秀!"
msgid "Expert"
msgstr "專家"
-#: lib/content/course_live/course_view.ex:43
+#: lib/content/course_live/course_view.ex:44
#, elixir-autogen, elixir-format
msgid "Failed to enroll"
msgstr "報名失敗"
@@ -91,7 +91,7 @@ msgstr "完美!"
msgid "Request to join"
msgstr "請求加入"
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "That's incorrect."
msgstr "這是不正確的。"
@@ -101,12 +101,12 @@ msgstr "這是不正確的。"
msgid "There's room for improvement"
msgstr "有改進的空間"
-#: lib/content/course_live/lesson_play.ex:90
+#: lib/content/course_live/lesson_play.ex:91
#, elixir-autogen, elixir-format
msgid "Unable to complete lesson"
msgstr "無法完成課程"
-#: lib/content/course_live/lesson_play.ex:53
+#: lib/content/course_live/lesson_play.ex:54
#, elixir-autogen, elixir-format
msgid "Unable to select option"
msgstr "無法選擇選項"
@@ -116,7 +116,7 @@ msgstr "無法選擇選項"
msgid "Very good!"
msgstr "非常好!"
-#: lib/content/course_live/components/lesson_step.ex:37
+#: lib/content/course_live/components/lesson_step.ex:38
#, elixir-autogen, elixir-format
msgid "Well done!"
msgstr "做得好!"
@@ -151,7 +151,7 @@ msgstr "加入課程開始學習。"
msgid "No courses"
msgstr "沒有課程"
-#: lib/content/course_live/lesson_play.ex:76
+#: lib/content/course_live/lesson_play.ex:77
#, elixir-autogen, elixir-format
msgid "Unable to send answer"
msgstr "無法傳送答案"
diff --git a/priv/gettext/zh_TW/LC_MESSAGES/default.po b/priv/gettext/zh_TW/LC_MESSAGES/default.po
index d821fad4..7a28f098 100644
--- a/priv/gettext/zh_TW/LC_MESSAGES/default.po
+++ b/priv/gettext/zh_TW/LC_MESSAGES/default.po
@@ -95,7 +95,7 @@ msgstr "首頁"
#: lib/dashboard/schools/school_edit.ex:92
#: lib/dashboard/schools/school_edit.html.heex:1
-#: lib/layouts/menu_utils.ex:98
+#: lib/layouts/menu_utils.ex:99
#: lib/layouts/templates/auth.html.heex:3
#, elixir-autogen, elixir-format
msgid "Logo"
@@ -117,7 +117,7 @@ msgstr "登出"
#: lib/dashboard/courses/course_edit.html.heex:5
#: lib/dashboard/schools/school_edit.ex:91
#: lib/layouts/components/app_menu.ex:40
-#: lib/layouts/menu_utils.ex:100
+#: lib/layouts/menu_utils.ex:101
#: lib/layouts/templates/dashboard_course.html.heex:42
#, elixir-autogen, elixir-format
msgid "Settings"
@@ -228,7 +228,7 @@ msgstr "更新"
msgid "Updating..."
msgstr "更新中..."
-#: lib/components/upload.ex:23
+#: lib/components/upload.ex:24
#, elixir-autogen, elixir-format
msgid "Remove"
msgstr "移除"
@@ -262,7 +262,7 @@ msgstr "關閉側邊欄"
#: lib/components/delete_item.ex:17
#: lib/components/delete_item.ex:21
#: lib/dashboard/schools/school_edit.ex:93
-#: lib/layouts/menu_utils.ex:101
+#: lib/layouts/menu_utils.ex:102
#: lib/layouts/templates/app.html.heex:78
#: lib/layouts/templates/dashboard_course.html.heex:50
#, elixir-autogen, elixir-format
@@ -284,7 +284,7 @@ msgstr "新建"
msgid "Open sidebar"
msgstr "開啟側邊欄"
-#: lib/layouts/menu_utils.ex:95
+#: lib/layouts/menu_utils.ex:96
#: lib/layouts/templates/dashboard_course.html.heex:26
#, elixir-autogen, elixir-format
msgid "Overview"
@@ -341,7 +341,7 @@ msgstr "不要失去您的進度。"
msgid "Update your email address"
msgstr "更新您的電子郵件地址"
-#: lib/layouts/menu_utils.ex:96
+#: lib/layouts/menu_utils.ex:97
#, elixir-autogen, elixir-format
msgid "Schools"
msgstr "學校"
@@ -381,7 +381,7 @@ msgstr "設定"
#: lib/dashboard/schools/school_edit.ex:94
#: lib/dashboard/schools/school_edit.html.heex:2
-#: lib/layouts/menu_utils.ex:99
+#: lib/layouts/menu_utils.ex:100
#, elixir-autogen, elixir-format
msgid "Icon"
msgstr "圖示"
@@ -398,11 +398,6 @@ msgstr "出了些問題!"
#: lib/components/upload.ex:49
#, elixir-autogen, elixir-format
-msgid "Processing file..."
-msgstr "處理檔案中..."
-
-#: lib/components/upload.ex:48
-#, elixir-autogen, elixir-format
msgid "Uploading: %{progress}%"
msgstr "上傳中:%{progress}%"
diff --git a/priv/gettext/zh_TW/LC_MESSAGES/errors.po b/priv/gettext/zh_TW/LC_MESSAGES/errors.po
index 8f02852e..c493c2a8 100644
--- a/priv/gettext/zh_TW/LC_MESSAGES/errors.po
+++ b/priv/gettext/zh_TW/LC_MESSAGES/errors.po
@@ -206,17 +206,22 @@ msgstr "權限不足"
msgid "is not allowed"
msgstr "不允許"
-#: lib/components/upload.ex:133
+#: lib/components/upload.ex:130
#, elixir-autogen, elixir-format
msgid "Too large"
msgstr "太大"
-#: lib/components/upload.ex:134
+#: lib/components/upload.ex:131
#, elixir-autogen, elixir-format
msgid "You have selected an unacceptable file type"
msgstr "您選擇了一個不可接受的檔案類型"
-#: lib/components/upload.ex:135
+#: lib/components/upload.ex:132
#, elixir-autogen, elixir-format
msgid "You have selected too many files"
msgstr "您選擇了太多檔案"
+
+#: lib/components/upload.ex:86
+#, elixir-autogen, elixir-format
+msgid "Failed to remove file"
+msgstr "刪除檔案失敗"
diff --git a/priv/gettext/zh_TW/LC_MESSAGES/orgs.po b/priv/gettext/zh_TW/LC_MESSAGES/orgs.po
index 316d2cc1..ae400aa3 100644
--- a/priv/gettext/zh_TW/LC_MESSAGES/orgs.po
+++ b/priv/gettext/zh_TW/LC_MESSAGES/orgs.po
@@ -475,7 +475,7 @@ msgstr "一堂課有多個步驟。使用它們來講故事,解釋概念或提
msgid "Add image to step"
msgstr "為步驟新增圖片"
-#: lib/dashboard/lessons/components/step_image.ex:33
+#: lib/dashboard/lessons/components/step_image.ex:34
#, elixir-autogen, elixir-format
msgid "Click to add an image to this step."
msgstr "點選以為此步驟新增圖片。"
@@ -505,7 +505,7 @@ msgstr "更新步驟"
msgid "Edit image"
msgstr "編輯圖片"
-#: lib/dashboard/lessons/components/step_image.ex:21
+#: lib/dashboard/lessons/components/step_image.ex:22
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit step image"
msgstr "編輯步驟圖片"
@@ -678,7 +678,7 @@ msgstr "老師"
#: lib/dashboard/courses/course_user_list.html.heex:2
#: lib/dashboard/schools/school_user_list.ex:76
#: lib/dashboard/schools/school_user_list.html.heex:2
-#: lib/layouts/menu_utils.ex:97
+#: lib/layouts/menu_utils.ex:98
#: lib/layouts/templates/dashboard_course.html.heex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Users"