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"