add locale as per user setting

This commit is contained in:
shibao 2022-05-05 23:26:29 -04:00
parent 42b4d0758f
commit 4b420f313c
27 changed files with 324 additions and 170 deletions

View File

@ -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`

View File

@ -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`.

View File

@ -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!

View File

@ -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

View File

@ -47,6 +47,7 @@ defmodule CanneryWeb do
use Phoenix.LiveView,
layout: {CanneryWeb.LayoutView, "live.html"}
on_mount CanneryWeb.InitAssigns
unquote(view_helpers())
end
end

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 %>

View File

@ -1,17 +1,16 @@
<div class="mx-auto mb-8 max-w-2xl flex flex-col justify-center items-center space-y-4">
<div class="mx-auto mb-8 max-w-2xl flex flex-col justify-center items-center text-center space-y-4">
<h1 class="pb-4 title text-primary-600 text-xl">
<%= gettext("Settings") %>
</h1>
<hr class="hr" />
<%= 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"
>
<h3 class="title text-primary-600 text-lg col-span-3">
<%= dgettext("actions", "Change email") %>
</h3>
@ -45,17 +44,16 @@
<%= submit(dgettext("actions", "Change email"),
class: "mx-auto btn btn-primary col-span-3"
) %>
<% end %>
</.form>
<hr class="hr" />
<%= 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"
>
<h3 class="title text-primary-600 text-lg col-span-3">
<%= dgettext("actions", "Change password") %>
</h3>
@ -101,7 +99,43 @@
<%= submit(dgettext("actions", "Change password"),
class: "mx-auto btn btn-primary col-span-3"
) %>
<% end %>
</.form>
<hr class="hr" />
<.form
let={f}
for={@locale_changeset}
action={Routes.user_settings_path(@conn, :update)}
class="flex flex-col space-y-4 justify-center items-center"
>
<h3 class="title text-primary-600 text-lg">
<%= dgettext("actions", "Change Language") %>
</h3>
<%= if @locale_changeset.action && not @locale_changeset.valid? do %>
<div class="alert alert-danger">
<p>
<%= dgettext("errors", "Oops, something went wrong! Please check the errors below.") %>
</p>
</div>
<% 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?")]
) %>
</.form>
<hr class="hr" />

View File

@ -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"

View File

@ -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 ""

View File

@ -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 ""

View File

@ -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 ""

View File

@ -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 ""

View File

@ -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