From 4b420f313c4ef61f67cc325ca9a1a03fc1922437 Mon Sep 17 00:00:00 2001 From: shibao Date: Thu, 5 May 2022 23:26:29 -0400 Subject: [PATCH] add locale as per user setting --- CONTRIBUTING.md | 2 +- README.md | 2 +- lib/cannery/accounts.ex | 29 +++++ lib/cannery/accounts/user.ex | 14 ++- lib/cannery_web.ex | 1 + .../controllers/user_settings_controller.ex | 46 ++++--- lib/cannery_web/live/ammo_group_live/index.ex | 4 +- lib/cannery_web/live/ammo_group_live/show.ex | 4 +- lib/cannery_web/live/ammo_type_live/index.ex | 4 +- lib/cannery_web/live/ammo_type_live/show.ex | 4 +- lib/cannery_web/live/container_live/index.ex | 4 +- lib/cannery_web/live/container_live/show.ex | 4 +- lib/cannery_web/live/home_live.ex | 9 +- lib/cannery_web/live/init_assigns.ex | 19 +++ lib/cannery_web/live/invite_live/index.ex | 4 +- lib/cannery_web/live/live_helpers.ex | 11 -- lib/cannery_web/live/range_live/index.ex | 4 +- lib/cannery_web/live/tag_live/index.ex | 4 +- lib/cannery_web/router.ex | 11 +- .../templates/user_registration/new.html.heex | 9 ++ .../templates/user_settings/edit.html.heex | 68 +++++++--- mix.exs | 2 + priv/gettext/actions.pot | 26 ++-- priv/gettext/default.pot | 119 +++++++++++------- priv/gettext/errors.pot | 25 ++-- priv/gettext/prompts.pot | 56 +++++---- .../20220506015344_add_locale_setting.exs | 9 ++ 27 files changed, 324 insertions(+), 170 deletions(-) create mode 100644 lib/cannery_web/live/init_assigns.ex create mode 100644 priv/repo/migrations/20220506015344_add_locale_setting.exs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 621aabef..bee90181 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,7 +109,7 @@ In `dev` mode, Cannery will listen for these environment variables at runtime. Defaults to `false`. - `POOL_SIZE`: Controls the pool size to use with PostgreSQL. Defaults to `10`. - `REGISTRATION`: Controls if user sign-up should be invite only or set to public. Set to `public` to enable public registration. Defaults to `invite`. -- `LOCALE`: Sets a custom locale. Defaults to `en_US`. +- `LOCALE`: Sets a custom default locale. Defaults to `en_US`. - Available options: `en_US`, `de`, and `fr` ## `MIX_ENV=test` diff --git a/README.md b/README.md index 76d597d4..6102d3a3 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ You can use the following environment variables to configure Cannery in with `docker run -it shibaobun/cannery mix phx.gen.secret` and set for server to start. - `REGISTRATION`: Controls if user sign-up should be invite only or set to public. Set to `public` to enable public registration. Defaults to `invite`. -- `LOCALE`: Sets a custom locale. Defaults to `en_US` +- `LOCALE`: Sets a custom default locale. Defaults to `en_US` - Available options: `en_US`, `de`, and `fr` - `SMTP_HOST`: The url for your SMTP email provider. Must be set - `SMTP_PORT`: The port for your SMTP relay. Defaults to `587`. diff --git a/lib/cannery/accounts.ex b/lib/cannery/accounts.ex index 55c2c6bc..c1d038af 100644 --- a/lib/cannery/accounts.ex +++ b/lib/cannery/accounts.ex @@ -269,6 +269,35 @@ defmodule Cannery.Accounts do end end + @doc """ + Returns an `%Changeset{}` for changing the user locale. + + ## Examples + + iex> change_user_locale(user) + %Changeset{data: %User{}} + + """ + @spec change_user_locale(User.t()) :: Changeset.t(User.t()) + def change_user_locale(%{locale: locale} = user), do: User.locale_changeset(user, locale) + + @doc """ + Updates the user locale. + + ## Examples + + iex> update_user_locale(user, "valid locale") + {:ok, %User{}} + + iex> update_user_password(user, "invalid locale") + {:error, %Changeset{}} + + """ + @spec update_user_locale(User.t(), locale :: String.t()) :: + {:ok, User.t()} | {:error, Changeset.t(User.t())} + def update_user_locale(user, locale), + do: user |> User.locale_changeset(locale) |> Repo.update() + @doc """ Deletes a user. must be performed by an admin or the same user! diff --git a/lib/cannery/accounts/user.ex b/lib/cannery/accounts/user.ex index 1ac4e966..88ff9cf5 100644 --- a/lib/cannery/accounts/user.ex +++ b/lib/cannery/accounts/user.ex @@ -18,6 +18,7 @@ defmodule Cannery.Accounts.User do field :hashed_password, :string field :confirmed_at, :naive_datetime field :role, Ecto.Enum, values: [:admin, :user], default: :user + field :locale, :string has_many :invites, Invite, on_delete: :delete_all @@ -31,6 +32,7 @@ defmodule Cannery.Accounts.User do hashed_password: String.t(), confirmed_at: NaiveDateTime.t(), role: atom(), + locale: String.t() | nil, invites: [Invite.t()], inserted_at: NaiveDateTime.t(), updated_at: NaiveDateTime.t() @@ -60,7 +62,7 @@ defmodule Cannery.Accounts.User do Changeset.t(t() | new_user()) def registration_changeset(user, attrs, opts \\ []) do user - |> cast(attrs, [:email, :password, :role]) + |> cast(attrs, [:email, :password, :role, :locale]) |> validate_email() |> validate_password(opts) end @@ -185,4 +187,14 @@ defmodule Cannery.Accounts.User do do: changeset, else: changeset |> add_error(:current_password, dgettext("errors", "is not valid")) end + + @doc """ + A changeset for changing the user's locale + """ + @spec locale_changeset(t() | Changeset.t(t()), locale :: String.t() | nil) :: Changeset.t(t()) + def locale_changeset(user_or_changeset, locale) do + user_or_changeset + |> cast(%{"locale" => locale}, [:locale]) + |> validate_required(:locale) + end end diff --git a/lib/cannery_web.ex b/lib/cannery_web.ex index bdf581d3..1fbd9a43 100644 --- a/lib/cannery_web.ex +++ b/lib/cannery_web.ex @@ -47,6 +47,7 @@ defmodule CanneryWeb do use Phoenix.LiveView, layout: {CanneryWeb.LayoutView, "live.html"} + on_mount CanneryWeb.InitAssigns unquote(view_helpers()) end end diff --git a/lib/cannery_web/controllers/user_settings_controller.ex b/lib/cannery_web/controllers/user_settings_controller.ex index 312a03bb..10e69f4b 100644 --- a/lib/cannery_web/controllers/user_settings_controller.ex +++ b/lib/cannery_web/controllers/user_settings_controller.ex @@ -10,10 +10,11 @@ defmodule CanneryWeb.UserSettingsController do render(conn, "edit.html", page_title: gettext("Settings")) end - def update(conn, %{"action" => "update_email"} = params) do - %{"current_password" => password, "user" => user_params} = params - user = conn.assigns.current_user - + def update(%{assigns: %{current_user: user}} = conn, %{ + "action" => "update_email", + "current_password" => password, + "user" => user_params + }) do case Accounts.apply_user_email(user, password, user_params) do {:ok, applied_user} -> Accounts.deliver_update_email_instructions( @@ -33,14 +34,15 @@ defmodule CanneryWeb.UserSettingsController do |> redirect(to: Routes.user_settings_path(conn, :edit)) {:error, changeset} -> - render(conn, "edit.html", email_changeset: changeset) + conn |> render("edit.html", email_changeset: changeset) end end - def update(conn, %{"action" => "update_password"} = params) do - %{"current_password" => password, "user" => user_params} = params - user = conn.assigns.current_user - + def update(%{assigns: %{current_user: user}} = conn, %{ + "action" => "update_password", + "current_password" => password, + "user" => user_params + }) do case Accounts.update_user_password(user, password, user_params) do {:ok, user} -> conn @@ -49,12 +51,27 @@ defmodule CanneryWeb.UserSettingsController do |> UserAuth.log_in_user(user) {:error, changeset} -> - render(conn, "edit.html", password_changeset: changeset) + conn |> render("edit.html", password_changeset: changeset) end end - def confirm_email(conn, %{"token" => token}) do - case Accounts.update_user_email(conn.assigns.current_user, token) do + def update( + %{assigns: %{current_user: user}} = conn, + %{"action" => "update_locale", "user" => %{"locale" => locale}} + ) do + case Accounts.update_user_locale(user, locale) do + {:ok, _user} -> + conn + |> put_flash(:info, dgettext("prompts", "Language updated successfully.")) + |> redirect(to: Routes.user_settings_path(conn, :edit)) + + {:error, changeset} -> + conn |> render("edit.html", locale_changeset: changeset) + end + end + + def confirm_email(%{assigns: %{current_user: user}} = conn, %{"token" => token}) do + case Accounts.update_user_email(user, token) do :ok -> conn |> put_flash(:info, dgettext("prompts", "Email changed successfully.")) @@ -84,11 +101,10 @@ defmodule CanneryWeb.UserSettingsController do end end - defp assign_email_and_password_changesets(conn, _opts) do - user = conn.assigns.current_user - + defp assign_email_and_password_changesets(%{assigns: %{current_user: user}} = conn, _opts) do conn |> assign(:email_changeset, Accounts.change_user_email(user)) |> assign(:password_changeset, Accounts.change_user_password(user)) + |> assign(:locale_changeset, Accounts.change_user_locale(user)) end end diff --git a/lib/cannery_web/live/ammo_group_live/index.ex b/lib/cannery_web/live/ammo_group_live/index.ex index 3b5e3481..e5fe96c3 100644 --- a/lib/cannery_web/live/ammo_group_live/index.ex +++ b/lib/cannery_web/live/ammo_group_live/index.ex @@ -8,8 +8,8 @@ defmodule CanneryWeb.AmmoGroupLive.Index do alias CanneryWeb.Endpoint @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session) |> display_ammo_groups()} + def mount(_params, _session, socket) do + {:ok, socket |> display_ammo_groups()} end @impl true diff --git a/lib/cannery_web/live/ammo_group_live/show.ex b/lib/cannery_web/live/ammo_group_live/show.ex index c019ce35..58f2e1ed 100644 --- a/lib/cannery_web/live/ammo_group_live/show.ex +++ b/lib/cannery_web/live/ammo_group_live/show.ex @@ -10,9 +10,7 @@ defmodule CanneryWeb.AmmoGroupLive.Show do alias Phoenix.LiveView.Socket @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session)} - end + def mount(_params, _session, socket), do: {:ok, socket} @impl true def handle_params( diff --git a/lib/cannery_web/live/ammo_type_live/index.ex b/lib/cannery_web/live/ammo_type_live/index.ex index 2fbe1e86..25e51420 100644 --- a/lib/cannery_web/live/ammo_type_live/index.ex +++ b/lib/cannery_web/live/ammo_type_live/index.ex @@ -9,8 +9,8 @@ defmodule CanneryWeb.AmmoTypeLive.Index do alias CanneryWeb.Endpoint @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session) |> list_ammo_types()} + def mount(_params, _session, socket) do + {:ok, socket |> list_ammo_types()} end @impl true diff --git a/lib/cannery_web/live/ammo_type_live/show.ex b/lib/cannery_web/live/ammo_type_live/show.ex index c71b9169..18e74b31 100644 --- a/lib/cannery_web/live/ammo_type_live/show.ex +++ b/lib/cannery_web/live/ammo_type_live/show.ex @@ -9,9 +9,7 @@ defmodule CanneryWeb.AmmoTypeLive.Show do alias CanneryWeb.Endpoint @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session)} - end + def mount(_params, _session, socket), do: {:ok, socket} @impl true def handle_params(%{"id" => id}, _params, %{assigns: %{current_user: current_user}} = socket) do diff --git a/lib/cannery_web/live/container_live/index.ex b/lib/cannery_web/live/container_live/index.ex index eb505b79..28d646cb 100644 --- a/lib/cannery_web/live/container_live/index.ex +++ b/lib/cannery_web/live/container_live/index.ex @@ -10,9 +10,7 @@ defmodule CanneryWeb.ContainerLive.Index do alias Ecto.Changeset @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session)} - end + def mount(_params, _session, socket), do: {:ok, socket} @impl true def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do diff --git a/lib/cannery_web/live/container_live/show.ex b/lib/cannery_web/live/container_live/show.ex index 8bf74414..26665015 100644 --- a/lib/cannery_web/live/container_live/show.ex +++ b/lib/cannery_web/live/container_live/show.ex @@ -11,9 +11,7 @@ defmodule CanneryWeb.ContainerLive.Show do alias Phoenix.LiveView.Socket @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session)} - end + def mount(_params, _session, socket), do: {:ok, socket} @impl true def handle_params( diff --git a/lib/cannery_web/live/home_live.ex b/lib/cannery_web/live/home_live.ex index 7d901177..c8ebe34a 100644 --- a/lib/cannery_web/live/home_live.ex +++ b/lib/cannery_web/live/home_live.ex @@ -7,14 +7,9 @@ defmodule CanneryWeb.HomeLive do alias Cannery.Accounts @impl true - def mount(_params, session, socket) do + def mount(_params, _session, socket) do admins = Accounts.list_users_by_role(:admin) - - socket = - socket - |> assign_defaults(session) - |> assign(page_title: "Home", query: "", results: %{}, admins: admins) - + socket = socket |> assign(page_title: "Home", query: "", results: %{}, admins: admins) {:ok, socket} end diff --git a/lib/cannery_web/live/init_assigns.ex b/lib/cannery_web/live/init_assigns.ex new file mode 100644 index 00000000..60f75dce --- /dev/null +++ b/lib/cannery_web/live/init_assigns.ex @@ -0,0 +1,19 @@ +defmodule CanneryWeb.InitAssigns do + @moduledoc """ + Ensures common `assigns` are applied to all LiveViews attaching this hook. + """ + import Phoenix.LiveView + alias Cannery.Accounts + + def on_mount(:default, _params, %{"locale" => locale, "user_token" => user_token}, socket) do + Gettext.put_locale(locale) + + socket = + socket + |> assign_new(:current_user, fn -> Accounts.get_user_by_session_token(user_token) end) + + {:cont, socket} + end + + def on_mount(:default, _params, _session, socket), do: {:cont, socket} +end diff --git a/lib/cannery_web/live/invite_live/index.ex b/lib/cannery_web/live/invite_live/index.ex index 8715e0f0..2a75059b 100644 --- a/lib/cannery_web/live/invite_live/index.ex +++ b/lib/cannery_web/live/invite_live/index.ex @@ -10,9 +10,7 @@ defmodule CanneryWeb.InviteLive.Index do alias Phoenix.LiveView.JS @impl true - def mount(_params, session, socket) do - %{assigns: %{current_user: current_user}} = socket = socket |> assign_defaults(session) - + def mount(_params, _session, %{assigns: %{current_user: current_user}} = socket) do socket = if current_user |> Map.get(:role) == :admin do socket |> display_invites() diff --git a/lib/cannery_web/live/live_helpers.ex b/lib/cannery_web/live/live_helpers.ex index 7e278a2b..d6b9d7ed 100644 --- a/lib/cannery_web/live/live_helpers.ex +++ b/lib/cannery_web/live/live_helpers.ex @@ -3,20 +3,9 @@ defmodule CanneryWeb.LiveHelpers do Contains common helper functions for liveviews """ - import Phoenix.LiveView import Phoenix.LiveView.Helpers - alias Cannery.Accounts alias Phoenix.LiveView.JS - def assign_defaults(socket, %{"user_token" => user_token} = _session) do - socket - |> assign_new(:current_user, fn -> Accounts.get_user_by_session_token(user_token) end) - end - - def assign_defaults(socket, _session) do - socket - end - @doc """ Renders a live component inside a modal. diff --git a/lib/cannery_web/live/range_live/index.ex b/lib/cannery_web/live/range_live/index.ex index 8951dfcc..ff711b7a 100644 --- a/lib/cannery_web/live/range_live/index.ex +++ b/lib/cannery_web/live/range_live/index.ex @@ -10,9 +10,7 @@ defmodule CanneryWeb.RangeLive.Index do alias Phoenix.LiveView.Socket @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session) |> display_shot_groups()} - end + def mount(_params, _session, socket), do: {:ok, socket |> display_shot_groups()} @impl true def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do diff --git a/lib/cannery_web/live/tag_live/index.ex b/lib/cannery_web/live/tag_live/index.ex index 15e9012f..fbd1deed 100644 --- a/lib/cannery_web/live/tag_live/index.ex +++ b/lib/cannery_web/live/tag_live/index.ex @@ -9,9 +9,7 @@ defmodule CanneryWeb.TagLive.Index do alias CanneryWeb.Endpoint @impl true - def mount(_params, session, socket) do - {:ok, socket |> assign_defaults(session) |> display_tags()} - end + def mount(_params, _session, socket), do: {:ok, socket |> display_tags()} @impl true def handle_params(params, _url, %{assigns: %{live_action: live_action}} = socket) do diff --git a/lib/cannery_web/router.ex b/lib/cannery_web/router.ex index 88acf06e..f7f77c75 100644 --- a/lib/cannery_web/router.ex +++ b/lib/cannery_web/router.ex @@ -11,8 +11,17 @@ defmodule CanneryWeb.Router do plug :protect_from_forgery plug :put_secure_browser_headers plug :fetch_current_user + plug :put_user_locale, default: Application.get_env(:gettext, :default_locale, "en_US") + end - Gettext.put_locale(Application.get_env(:gettext, :default_locale, "en_US")) + defp put_user_locale(%{assigns: %{current_user: %{locale: locale}}} = conn, default: default) do + Gettext.put_locale(locale || default) + conn |> put_session(:locale, locale || default) + end + + defp put_user_locale(conn, default: default) do + Gettext.put_locale(default) + conn |> put_session(:locale, default) end pipeline :require_admin do diff --git a/lib/cannery_web/templates/user_registration/new.html.heex b/lib/cannery_web/templates/user_registration/new.html.heex index ddc9cb81..5ff5a2cc 100644 --- a/lib/cannery_web/templates/user_registration/new.html.heex +++ b/lib/cannery_web/templates/user_registration/new.html.heex @@ -30,6 +30,15 @@ <%= password_input(f, :password, required: true, class: "input input-primary col-span-2") %> <%= error_tag(f, :password, "col-span-3") %> + <%= label(f, :locale, gettext("Language"), class: "title text-lg text-primary-600") %> + <%= select( + f, + :locale, + [{gettext("English"), "en_US"}, {gettext("German"), "de"}, {gettext("French"), "fr"}], + class: "input input-primary col-span-2" + ) %> + <%= error_tag(f, :locale) %> + <%= submit(dgettext("actions", "Register"), class: "mx-auto btn btn-primary col-span-3") %> <% end %> diff --git a/lib/cannery_web/templates/user_settings/edit.html.heex b/lib/cannery_web/templates/user_settings/edit.html.heex index c0f500db..56a8116e 100644 --- a/lib/cannery_web/templates/user_settings/edit.html.heex +++ b/lib/cannery_web/templates/user_settings/edit.html.heex @@ -1,17 +1,16 @@ -
+

<%= gettext("Settings") %>


- <%= form_for @email_changeset, - Routes.user_settings_path(@conn, :update), - [ - class: - "flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" - ], - fn f -> %> + <.form + let={f} + for={@email_changeset} + action={Routes.user_settings_path(@conn, :update)} + class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" + >

<%= dgettext("actions", "Change email") %>

@@ -45,17 +44,16 @@ <%= submit(dgettext("actions", "Change email"), class: "mx-auto btn btn-primary col-span-3" ) %> - <% end %> +
- <%= form_for @password_changeset, - Routes.user_settings_path(@conn, :update), - [ - class: - "flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" - ], - fn f -> %> + <.form + let={f} + for={@password_changeset} + action={Routes.user_settings_path(@conn, :update)} + class="flex flex-col space-y-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 justify-center items-center" + >

<%= dgettext("actions", "Change password") %>

@@ -101,7 +99,43 @@ <%= submit(dgettext("actions", "Change password"), class: "mx-auto btn btn-primary col-span-3" ) %> - <% end %> + + +
+ + <.form + let={f} + for={@locale_changeset} + action={Routes.user_settings_path(@conn, :update)} + class="flex flex-col space-y-4 justify-center items-center" + > +

+ <%= dgettext("actions", "Change Language") %> +

+ + <%= if @locale_changeset.action && not @locale_changeset.valid? do %> +
+

+ <%= dgettext("errors", "Oops, something went wrong! Please check the errors below.") %> +

+
+ <% end %> + + <%= hidden_input(f, :action, name: "action", value: "update_locale") %> + + <%= select( + f, + :locale, + [{gettext("English"), "en_US"}, {gettext("German"), "de"}, {gettext("French"), "fr"}], + class: "mx-2 my-1 min-w-md input input-primary" + ) %> + <%= error_tag(f, :locale) %> + + <%= submit(dgettext("actions", "Change language"), + class: "whitespace-nowrap mx-auto btn btn-primary", + data: [qa: dgettext("prompts", "Are you sure you want to change your language?")] + ) %> +
diff --git a/mix.exs b/mix.exs index 3c94ebfb..f97200ba 100644 --- a/mix.exs +++ b/mix.exs @@ -13,6 +13,7 @@ defmodule Cannery.MixProject do deps: deps(), dialyzer: [plt_add_apps: [:ex_unit]], consolidate_protocols: Mix.env() not in [:dev, :test], + preferred_cli_env: [test: :test], # ExDoc name: "Cannery", source_url: "https://gitea.bubbletea.dev/shibao/cannery", @@ -91,6 +92,7 @@ defmodule Cannery.MixProject do "dialyzer", "credo --strict", "format --check-formatted", + "ecto.drop --quiet", "ecto.create --quiet", "ecto.migrate --quiet", "test" diff --git a/priv/gettext/actions.pot b/priv/gettext/actions.pot index 98f13737..106e2772 100644 --- a/priv/gettext/actions.pot +++ b/priv/gettext/actions.pot @@ -31,14 +31,14 @@ msgid "Add your first type!" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:16 -#: lib/cannery_web/templates/user_settings/edit.html.heex:45 +#: lib/cannery_web/templates/user_settings/edit.html.heex:15 +#: lib/cannery_web/templates/user_settings/edit.html.heex:44 msgid "Change email" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:60 -#: lib/cannery_web/templates/user_settings/edit.html.heex:101 +#: lib/cannery_web/templates/user_settings/edit.html.heex:58 +#: lib/cannery_web/templates/user_settings/edit.html.heex:99 msgid "Change password" msgstr "" @@ -48,12 +48,12 @@ msgid "Create Invite" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:108 +#: lib/cannery_web/templates/user_settings/edit.html.heex:142 msgid "Delete User" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_registration/new.html.heex:43 +#: lib/cannery_web/templates/user_registration/new.html.heex:52 #: lib/cannery_web/templates/user_reset_password/new.html.heex:3 #: lib/cannery_web/templates/user_session/new.html.heex:45 msgid "Forgot your password?" @@ -67,7 +67,7 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/topbar.ex:106 #: lib/cannery_web/templates/user_confirmation/new.html.heex:30 -#: lib/cannery_web/templates/user_registration/new.html.heex:39 +#: lib/cannery_web/templates/user_registration/new.html.heex:48 #: lib/cannery_web/templates/user_reset_password/edit.html.heex:48 #: lib/cannery_web/templates/user_reset_password/new.html.heex:30 #: lib/cannery_web/templates/user_session/new.html.heex:3 @@ -104,7 +104,7 @@ msgstr "" #: lib/cannery_web/components/topbar.ex:99 #: lib/cannery_web/templates/user_confirmation/new.html.heex:25 #: lib/cannery_web/templates/user_registration/new.html.heex:3 -#: lib/cannery_web/templates/user_registration/new.html.heex:33 +#: lib/cannery_web/templates/user_registration/new.html.heex:42 #: lib/cannery_web/templates/user_reset_password/edit.html.heex:43 #: lib/cannery_web/templates/user_reset_password/new.html.heex:25 #: lib/cannery_web/templates/user_session/new.html.heex:40 @@ -201,3 +201,13 @@ msgstr "" #: lib/cannery_web/live/ammo_group_live/form_component.html.heex:66 msgid "Create" msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_settings/edit.html.heex:113 +msgid "Change Language" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_settings/edit.html.heex:134 +msgid "Change language" +msgstr "" diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index f4bf9e8a..ce950ffa 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -11,12 +11,12 @@ msgid "" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:61 +#: lib/cannery_web/live/home_live.ex:56 msgid "%{name} lets you easily keep an eye on your ammo levels before and after range day" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:83 +#: lib/cannery_web/live/home_live.ex:78 msgid "Access from any internet-capable device" msgstr "" @@ -26,14 +26,14 @@ msgid "Admins" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:97 +#: lib/cannery_web/live/home_live.ex:92 msgid "Admins:" msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/topbar.ex:50 #: lib/cannery_web/live/ammo_group_live/index.html.heex:3 -#: lib/cannery_web/live/range_live/index.ex:82 +#: lib/cannery_web/live/range_live/index.ex:80 msgid "Ammo" msgstr "" @@ -110,7 +110,7 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/topbar.ex:44 -#: lib/cannery_web/live/container_live/index.ex:38 +#: lib/cannery_web/live/container_live/index.ex:36 #: lib/cannery_web/live/container_live/index.html.heex:3 msgid "Containers" msgstr "" @@ -152,29 +152,29 @@ msgid "Disable" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:58 +#: lib/cannery_web/live/home_live.ex:53 msgid "Easy to Use:" msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_group_live/index.ex:38 -#: lib/cannery_web/live/ammo_group_live/show.ex:42 +#: lib/cannery_web/live/ammo_group_live/show.ex:40 msgid "Edit Ammo group" msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_type_live/index.ex:23 -#: lib/cannery_web/live/ammo_type_live/show.ex:47 +#: lib/cannery_web/live/ammo_type_live/show.ex:45 msgid "Edit Ammo type" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:35 +#: lib/cannery_web/live/invite_live/index.ex:33 msgid "Edit Invite" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/tag_live/index.ex:23 +#: lib/cannery_web/live/tag_live/index.ex:21 msgid "Edit Tag" msgstr "" @@ -208,7 +208,7 @@ msgid "Incendiary" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:92 +#: lib/cannery_web/live/home_live.ex:87 msgid "Instance Information" msgstr "" @@ -218,13 +218,13 @@ msgid "Invite Disabled" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:123 +#: lib/cannery_web/live/home_live.ex:118 msgid "Invite Only" msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/topbar.ex:69 -#: lib/cannery_web/live/invite_live/index.ex:43 +#: lib/cannery_web/live/invite_live/index.ex:41 #: lib/cannery_web/live/invite_live/index.html.heex:3 msgid "Invites" msgstr "" @@ -288,17 +288,17 @@ msgid "New Ammo type" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/index.ex:33 +#: lib/cannery_web/live/container_live/index.ex:31 msgid "New Container" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:39 +#: lib/cannery_web/live/invite_live/index.ex:37 msgid "New Invite" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/tag_live/index.ex:29 +#: lib/cannery_web/live/tag_live/index.ex:27 msgid "New Tag" msgstr "" @@ -341,9 +341,9 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/add_shot_group_component.html.heex:30 #: lib/cannery_web/live/ammo_group_live/form_component.html.heex:41 -#: lib/cannery_web/live/ammo_group_live/show.ex:90 +#: lib/cannery_web/live/ammo_group_live/show.ex:88 #: lib/cannery_web/live/range_live/form_component.html.heex:29 -#: lib/cannery_web/live/range_live/index.ex:84 +#: lib/cannery_web/live/range_live/index.ex:82 msgid "Notes" msgstr "" @@ -384,17 +384,17 @@ msgid "Primer type" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:122 +#: lib/cannery_web/live/home_live.ex:117 msgid "Public Signups" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:70 +#: lib/cannery_web/live/home_live.ex:65 msgid "Secure:" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:73 +#: lib/cannery_web/live/home_live.ex:68 msgid "Self-host your own instance, or use an instance from someone you trust." msgstr "" @@ -410,17 +410,17 @@ msgid "Settings" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:41 +#: lib/cannery_web/live/ammo_group_live/show.ex:39 msgid "Show Ammo group" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_type_live/show.ex:46 +#: lib/cannery_web/live/ammo_type_live/show.ex:44 msgid "Show Ammo type" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:80 +#: lib/cannery_web/live/home_live.ex:75 msgid "Simple:" msgstr "" @@ -436,7 +436,7 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/components/topbar.ex:38 -#: lib/cannery_web/live/tag_live/index.ex:34 +#: lib/cannery_web/live/tag_live/index.ex:32 #: lib/cannery_web/live/tag_live/index.html.heex:3 msgid "Tags" msgstr "" @@ -452,7 +452,7 @@ msgid "Text color" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:49 +#: lib/cannery_web/live/home_live.ex:44 msgid "The self-hosted firearm tracker website" msgstr "" @@ -496,12 +496,12 @@ msgid "Uses left" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:45 +#: lib/cannery_web/live/home_live.ex:40 msgid "Welcome to %{name}" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:74 +#: lib/cannery_web/live/home_live.ex:69 msgid "Your data stays with you, period" msgstr "" @@ -522,8 +522,8 @@ msgid "Range day" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:91 -#: lib/cannery_web/live/range_live/index.ex:85 +#: lib/cannery_web/live/ammo_group_live/show.ex:89 +#: lib/cannery_web/live/range_live/index.ex:83 msgid "Date" msgstr "" @@ -572,13 +572,13 @@ msgid "Date (UTC)" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:39 -#: lib/cannery_web/live/range_live/index.ex:34 +#: lib/cannery_web/live/ammo_group_live/show.ex:37 +#: lib/cannery_web/live/range_live/index.ex:32 msgid "Edit Shot Records" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/range_live/index.ex:40 +#: lib/cannery_web/live/range_live/index.ex:38 msgid "New Shot Records" msgstr "" @@ -593,19 +593,19 @@ msgid "Rounds left" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:89 -#: lib/cannery_web/live/range_live/index.ex:83 +#: lib/cannery_web/live/ammo_group_live/show.ex:87 +#: lib/cannery_web/live/range_live/index.ex:81 msgid "Rounds shot" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/range_live/index.ex:46 +#: lib/cannery_web/live/range_live/index.ex:44 msgid "Shot Records" msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_group_live/index.ex:32 -#: lib/cannery_web/live/ammo_group_live/show.ex:40 +#: lib/cannery_web/live/ammo_group_live/show.ex:38 msgid "Move Ammo group" msgstr "" @@ -675,18 +675,18 @@ msgid "UPC" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:80 +#: lib/cannery_web/templates/user_settings/edit.html.heex:78 msgid "Confirm new password" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:33 -#: lib/cannery_web/templates/user_settings/edit.html.heex:89 +#: lib/cannery_web/templates/user_settings/edit.html.heex:32 +#: lib/cannery_web/templates/user_settings/edit.html.heex:87 msgid "Current password" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:73 +#: lib/cannery_web/templates/user_settings/edit.html.heex:71 msgid "New password" msgstr "" @@ -718,14 +718,14 @@ msgid "Loading..." msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/index.ex:29 -#: lib/cannery_web/live/container_live/show.ex:97 +#: lib/cannery_web/live/container_live/index.ex:27 +#: lib/cannery_web/live/container_live/show.ex:95 msgid "Edit %{name}" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/index.ex:48 -#: lib/cannery_web/live/container_live/show.ex:98 +#: lib/cannery_web/live/container_live/index.ex:46 +#: lib/cannery_web/live/container_live/show.ex:96 msgid "Edit %{name} tags" msgstr "" @@ -735,7 +735,7 @@ msgid "Rounds:" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/show.ex:96 +#: lib/cannery_web/live/container_live/show.ex:94 msgid "Show %{name}" msgstr "" @@ -816,8 +816,8 @@ msgid "Reset your password" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:38 -#: lib/cannery_web/live/range_live/index.ex:28 +#: lib/cannery_web/live/ammo_group_live/show.ex:36 +#: lib/cannery_web/live/range_live/index.ex:26 msgid "Record Shots" msgstr "" @@ -847,3 +847,26 @@ msgstr "" #: lib/cannery_web/components/user_card.ex:30 msgid "User registered on" msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_registration/new.html.heex:37 +#: lib/cannery_web/templates/user_settings/edit.html.heex:129 +msgid "English" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_registration/new.html.heex:37 +#: lib/cannery_web/templates/user_settings/edit.html.heex:129 +msgid "French" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_registration/new.html.heex:37 +#: lib/cannery_web/templates/user_settings/edit.html.heex:129 +msgid "German" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_registration/new.html.heex:33 +msgid "Language" +msgstr "" diff --git a/priv/gettext/errors.pot b/priv/gettext/errors.pot index 4b293ccc..80bb167d 100644 --- a/priv/gettext/errors.pot +++ b/priv/gettext/errors.pot @@ -16,18 +16,18 @@ msgid "Container must be empty before deleting" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/index.ex:71 -#: lib/cannery_web/live/container_live/show.ex:73 +#: lib/cannery_web/live/container_live/index.ex:69 +#: lib/cannery_web/live/container_live/show.ex:71 msgid "Could not delete %{name}: %{error}" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/index.ex:59 +#: lib/cannery_web/live/container_live/index.ex:57 msgid "Could not find that container" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/controllers/user_settings_controller.ex:67 +#: lib/cannery_web/controllers/user_settings_controller.ex:84 msgid "Email change link is invalid or it has expired." msgstr "" @@ -59,8 +59,9 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/templates/user_registration/new.html.heex:16 #: lib/cannery_web/templates/user_reset_password/edit.html.heex:16 -#: lib/cannery_web/templates/user_settings/edit.html.heex:22 -#: lib/cannery_web/templates/user_settings/edit.html.heex:66 +#: lib/cannery_web/templates/user_settings/edit.html.heex:21 +#: lib/cannery_web/templates/user_settings/edit.html.heex:64 +#: lib/cannery_web/templates/user_settings/edit.html.heex:119 msgid "Oops, something went wrong! Please check the errors below." msgstr "" @@ -82,7 +83,7 @@ msgid "Sorry, this invite was not found or expired" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/controllers/user_settings_controller.ex:82 +#: lib/cannery_web/controllers/user_settings_controller.ex:99 msgid "Unable to delete user" msgstr "" @@ -97,7 +98,7 @@ msgid "User confirmation link is invalid or it has expired." msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:20 +#: lib/cannery_web/live/invite_live/index.ex:18 msgid "You are not authorized to view this page" msgstr "" @@ -107,22 +108,22 @@ msgid "You are not authorized to view this page." msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery/accounts/user.ex:128 +#: lib/cannery/accounts/user.ex:130 msgid "did not change" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery/accounts/user.ex:149 +#: lib/cannery/accounts/user.ex:151 msgid "does not match password" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery/accounts/user.ex:186 +#: lib/cannery/accounts/user.ex:188 msgid "is not valid" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery/accounts/user.ex:82 +#: lib/cannery/accounts/user.ex:84 msgid "must have the @ sign and no spaces" msgstr "" diff --git a/priv/gettext/prompts.pot b/priv/gettext/prompts.pot index c2b3fff4..5e69e09c 100644 --- a/priv/gettext/prompts.pot +++ b/priv/gettext/prompts.pot @@ -20,31 +20,31 @@ msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_type_live/index.ex:41 -#: lib/cannery_web/live/ammo_type_live/show.ex:40 -#: lib/cannery_web/live/invite_live/index.ex:55 -#: lib/cannery_web/live/invite_live/index.ex:135 -#: lib/cannery_web/live/tag_live/index.ex:40 +#: lib/cannery_web/live/ammo_type_live/show.ex:38 +#: lib/cannery_web/live/invite_live/index.ex:53 +#: lib/cannery_web/live/invite_live/index.ex:133 +#: lib/cannery_web/live/tag_live/index.ex:38 msgid "%{name} deleted succesfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:111 +#: lib/cannery_web/live/invite_live/index.ex:109 msgid "%{name} disabled succesfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:89 +#: lib/cannery_web/live/invite_live/index.ex:87 msgid "%{name} enabled succesfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/index.ex:64 -#: lib/cannery_web/live/container_live/show.ex:63 +#: lib/cannery_web/live/container_live/index.ex:62 +#: lib/cannery_web/live/container_live/show.ex:61 msgid "%{name} has been deleted" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:69 +#: lib/cannery_web/live/invite_live/index.ex:67 msgid "%{name} updated succesfully" msgstr "" @@ -57,13 +57,13 @@ msgid "%{name} updated successfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/controllers/user_settings_controller.ex:28 +#: lib/cannery_web/controllers/user_settings_controller.ex:29 msgid "A link to confirm your email change has been sent to the new address." msgstr "" #, elixir-autogen, elixir-format #: lib/cannery_web/live/ammo_group_live/index.ex:56 -#: lib/cannery_web/live/ammo_group_live/show.ex:52 +#: lib/cannery_web/live/ammo_group_live/show.ex:50 msgid "Ammo group deleted succesfully" msgstr "" @@ -99,7 +99,7 @@ msgid "Are you sure you want to delete this ammo?" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/templates/user_settings/edit.html.heex:112 +#: lib/cannery_web/templates/user_settings/edit.html.heex:146 msgid "Are you sure you want to delete your account?" msgstr "" @@ -114,7 +114,7 @@ msgid "Are you sure you want to make %{name} unlimited?" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/controllers/user_settings_controller.ex:60 +#: lib/cannery_web/controllers/user_settings_controller.ex:77 msgid "Email changed successfully." msgstr "" @@ -139,7 +139,7 @@ msgid "Password reset successfully." msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/controllers/user_settings_controller.ex:47 +#: lib/cannery_web/controllers/user_settings_controller.ex:49 msgid "Password updated successfully." msgstr "" @@ -149,7 +149,7 @@ msgid "Please check your email to verify your account" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/home_live.ex:101 +#: lib/cannery_web/live/home_live.ex:96 msgid "Register to setup %{name}" msgstr "" @@ -165,7 +165,7 @@ msgid "Saving..." msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/controllers/user_settings_controller.ex:78 +#: lib/cannery_web/controllers/user_settings_controller.ex:95 msgid "Your account has been deleted" msgstr "" @@ -180,7 +180,7 @@ msgid "%{name} added successfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/container_live/show.ex:39 +#: lib/cannery_web/live/container_live/show.ex:37 msgid "%{tag_name} has been removed from %{container_name}" msgstr "" @@ -200,19 +200,19 @@ msgid "Are you sure you want to unstage this ammo?" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/range_live/index.ex:70 +#: lib/cannery_web/live/range_live/index.ex:68 msgid "Ammo group unstaged succesfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:132 -#: lib/cannery_web/live/range_live/index.ex:130 +#: lib/cannery_web/live/ammo_group_live/show.ex:130 +#: lib/cannery_web/live/range_live/index.ex:128 msgid "Are you sure you want to delete this shot record?" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/ammo_group_live/show.ex:80 -#: lib/cannery_web/live/range_live/index.ex:56 +#: lib/cannery_web/live/ammo_group_live/show.ex:78 +#: lib/cannery_web/live/range_live/index.ex:54 msgid "Shot records deleted succesfully" msgstr "" @@ -232,7 +232,7 @@ msgid "Ammo moved to %{name} successfully" msgstr "" #, elixir-autogen, elixir-format -#: lib/cannery_web/live/invite_live/index.ex:123 +#: lib/cannery_web/live/invite_live/index.ex:121 msgid "Copied to clipboard" msgstr "" @@ -258,3 +258,13 @@ msgid "Ammo group created successfully" msgid_plural "Ammo groups created successfully" msgstr[0] "" msgstr[1] "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/templates/user_settings/edit.html.heex:136 +msgid "Are you sure you want to change your language?" +msgstr "" + +#, elixir-autogen, elixir-format +#: lib/cannery_web/controllers/user_settings_controller.ex:65 +msgid "Language updated successfully." +msgstr "" diff --git a/priv/repo/migrations/20220506015344_add_locale_setting.exs b/priv/repo/migrations/20220506015344_add_locale_setting.exs new file mode 100644 index 00000000..6c75f184 --- /dev/null +++ b/priv/repo/migrations/20220506015344_add_locale_setting.exs @@ -0,0 +1,9 @@ +defmodule Cannery.Repo.Migrations.AddLocaleSetting do + use Ecto.Migration + + def change do + alter table("users") do + add :locale, :string + end + end +end