Skip to content

Commit

Permalink
Merge pull request #37 from curiosum-dev/release/0.3.1
Browse files Browse the repository at this point in the history
Release/0.3.1
  • Loading branch information
arturz authored Oct 13, 2023
2 parents a7effc0 + dd955e2 commit b3d5613
Show file tree
Hide file tree
Showing 26 changed files with 466 additions and 28 deletions.
37 changes: 33 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ by adding `kanta` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:kanta, "~> 0.3.0"},
{:kanta, "~> 0.3.1"},
{:gettext, git: "[email protected]:ravensiris/gettext.git", branch: "runtime-gettext"}
]
end
Expand Down Expand Up @@ -180,9 +180,9 @@ In the `application.ex` file of our project, we add Kanta and its configuration

## Kanta UI

Inside your `router.ex` file we need to connect the Kanta panel using the kanta_dashboard macro.
Inside your `router.ex` file we need to connect the Kanta panel using the kanta_dashboard macro.

```elixir
```elixir
import KantaWeb.Router

scope "/" do
Expand Down Expand Up @@ -226,7 +226,7 @@ Not all of us are polyglots, and sometimes we need the help of machine translati

```elixir
# mix.exs
defp deps
defp deps do
...
{:kanta_deep_l_plugin, "~> 0.1.1"}
end
Expand All @@ -241,6 +241,35 @@ config :kanta,
]
```

## KantaSync

The [KantaSync plugin](https://github.com/curiosum-dev/kanta_sync_plugin) allows you to synchronize translations between your production and staging/dev environments. It ensures that any changes made to translations in one are reflected in the others, helping you maintain consistency across different stages of development.

```elixir
# mix.exs
defp deps do
...
{:kanta_sync_plugin, "~> 0.1.0"}
end
```

You need to have Kanta API configured by using kanta_api macro.

```elixir
# router.ex
import KantaWeb.Router

scope "/" do
kanta_api("/kanta-api")
end
```

### Authorization

Set `KANTA_SECRET_TOKEN` environment variable for restricting API access. It should be generated with `mix phx.gen.secret 256` and both environments must have the same `KANTA_SECRET_TOKEN` environment variables.

You can also disable default authorization mechanism and use your own, by passing `disable_api_authorization: true` option into Kanta's config.

## PO Writer

Kanta was created to allow easy management of static text translations in the application, however, for various reasons like wanting a backup or parallel use of other tools like TMS etc. you may want to overwrite .po files with translations entered in Kanta. To install it append `{:kanta_po_writer_plugin, git: "https://github.com/curiosum-dev/kanta_po_writer_plugin"}` to your `deps` list. Currently, it's not on Hex because it's in a pre-release version. Then add `Kanta.Plugins.POWriter` to the list of plugins, and new functions will appear in the Kanta UI to allow writing to .po files.
Expand Down
15 changes: 13 additions & 2 deletions lib/kanta/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ defmodule Kanta.Config do
otp_name: atom(),
repo: module(),
endpoint: module(),
plugins: false | [module() | {module() | Keyword.t()}]
plugins: false | [module() | {module() | Keyword.t()}],
disable_api_authorization: boolean()
}

defstruct name: Kanta,
otp_name: nil,
repo: nil,
endpoint: nil,
plugins: []
plugins: [],
disable_api_authorization: false

alias Kanta.Validator

Expand Down Expand Up @@ -71,6 +73,15 @@ defmodule Kanta.Config do
end
end

defp validate_opt(_opts, {:disable_api_authorization, disable_api_authorization}) do
if is_boolean(disable_api_authorization) do
:ok
else
{:error,
"expected :disable_api_authorization to be a boolean, got: #{inspect(disable_api_authorization)}"}
end
end

defp validate_opt(_opts, option) do
{:unknown, option, __MODULE__}
end
Expand Down
17 changes: 14 additions & 3 deletions lib/kanta/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,21 @@ defmodule Kanta.Query do
Repo.get_repo().one(query, opts)
end

def paginate(query, page \\ 1, per_page \\ 15)
def paginate(query, nil, nil), do: paginate(query, 1, 15)
@default_page_size 100
@minimum_per_page 10

@spec paginate(Ecto.Query.t(), integer() | nil, integer() | nil) :: map()
@spec paginate(Ecto.Query.t(), integer() | nil) :: map()
@spec paginate(Ecto.Query.t()) :: map()

def paginate(query, page \\ 1, per_page \\ @default_page_size)

def paginate(query, page, per_page) do
page = if is_number(page), do: max(page, 1), else: 1

per_page =
if is_number(per_page), do: max(per_page, @minimum_per_page), else: @default_page_size

%{
entries: entries,
page_number: page_number,
Expand All @@ -51,7 +62,7 @@ defmodule Kanta.Query do
caller: self(),
module: Repo.get_repo(),
page_number: page || 1,
page_size: per_page || 15,
page_size: per_page || @default_page_size,
options: []
}
)
Expand Down
7 changes: 7 additions & 0 deletions lib/kanta/specs/schemata_spec.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Kanta.Specs.SchemataSpec do
@moduledoc false

@type schema() :: {String.t(), %{schema: atom(), conflict_target: atom() | [atom()]}}

@type t() :: [schema()]
end
9 changes: 7 additions & 2 deletions lib/kanta/translations/context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ defmodule Kanta.Translations.Context do

alias Kanta.Translations.Message

@required_fields ~w(name)a
@optional_fields ~w(description color)a

@type t() :: Kanta.Translations.ContextSpec.t()

@derive {Jason.Encoder, only: [:id] ++ @required_fields ++ @optional_fields}

schema "kanta_contexts" do
field :name, :string
field :description, :string
Expand All @@ -22,7 +27,7 @@ defmodule Kanta.Translations.Context do

def changeset(struct, params) do
struct
|> cast(params, [:name, :description, :color])
|> validate_required([:name])
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
9 changes: 7 additions & 2 deletions lib/kanta/translations/domain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ defmodule Kanta.Translations.Domain do

alias Kanta.Translations.Message

@required_fields ~w(name)a
@optional_fields ~w(description color)a

@type t() :: Kanta.Translations.DomainSpec.t()

@derive {Jason.Encoder, only: [:id] ++ @required_fields ++ @optional_fields}

schema "kanta_domains" do
field :name, :string
field :description, :string
Expand All @@ -22,7 +27,7 @@ defmodule Kanta.Translations.Domain do

def changeset(struct, params) do
struct
|> cast(params, [:name, :description, :color])
|> validate_required([:name])
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
6 changes: 4 additions & 2 deletions lib/kanta/translations/locale.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ defmodule Kanta.Translations.Locale do
import Ecto.Changeset
alias Kanta.Translations.SingularTranslation

@all_fields ~w(iso639_code name plurals_header native_name family wiki_url colors)a
@required_fields ~w(iso639_code name native_name)a
@optional_fields ~w(plurals_header family wiki_url colors)a

@type t() :: Kanta.Translations.LocaleSpec.t()

@derive {Jason.Encoder, only: [:id] ++ @required_fields ++ @optional_fields}

schema "kanta_locales" do
field :iso639_code, :string
field :name, :string
Expand All @@ -29,7 +31,7 @@ defmodule Kanta.Translations.Locale do

def changeset(struct, params) do
struct
|> cast(params, @all_fields)
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
1 change: 1 addition & 0 deletions lib/kanta/translations/locale/finders/list_locales.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Kanta.Translations.Locale.Finders.ListLocales do

def find(params \\ []) do
base()
|> order_by(:id)
|> filter_query(params[:filter])
|> preload_resources(params[:preloads] || [])
|> paginate(params[:page], params[:per_page])
Expand Down
8 changes: 5 additions & 3 deletions lib/kanta/translations/message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ defmodule Kanta.Translations.Message do

alias Kanta.Translations.{Context, Domain, PluralTranslation, SingularTranslation}

@required_fields ~w(msgid message_type)a
@optional_fields ~w(domain_id context_id)a

@type t() :: Kanta.Translations.MessageSpec.t()

@all_fields ~w(msgid message_type domain_id context_id)a
@required_fields ~w(msgid message_type)a
@derive {Jason.Encoder, only: [:id] ++ @required_fields ++ @optional_fields}

schema "kanta_messages" do
field :msgid, :string
Expand All @@ -28,7 +30,7 @@ defmodule Kanta.Translations.Message do

def changeset(struct, params) do
struct
|> cast(params, @all_fields)
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
17 changes: 13 additions & 4 deletions lib/kanta/translations/messages/finders/list_messages.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ defmodule Kanta.Translations.Messages.Finders.ListMessages do
@available_filters ~w(domain_id context_id)

def find(params \\ []) do
filters = params[:filter] || %{}
query_filters = Map.take(filters, @available_filters)

base()
|> filter_query(Map.take(params[:filter], @available_filters))
|> not_translated_query(params[:filter])
|> search_subquery([locale_id: params[:filter]["locale_id"]], params[:search])
|> filter_query(query_filters)
|> not_translated_query(filters)
|> search_subquery(filters, params[:search])
|> distinct(true)
|> preload_resources(params[:preloads] || [])
|> paginate(String.to_integer(params[:page] || "1"), params[:per_page])
|> paginate(params[:page], params[:per_page])
end

defp not_translated_query(query, %{"locale_id" => locale_id, "not_translated" => "true"}) do
Expand All @@ -41,6 +44,12 @@ defmodule Kanta.Translations.Messages.Finders.ListMessages do
defp search_subquery(query, _, nil), do: query
defp search_subquery(query, _, ""), do: query

defp search_subquery(query, %{"locale_id" => locale_id}, search) do
search_subquery(query, [locale_id: locale_id], search)
end

defp search_subquery(query, filter, _) when is_map(filter), do: query

defp search_subquery(query, filter, search) do
sub =
base()
Expand Down
6 changes: 4 additions & 2 deletions lib/kanta/translations/plural_translation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ defmodule Kanta.Translations.PluralTranslation do

alias Kanta.Translations.{Locale, Message}

@all_fields ~w(nplural_index original_text translated_text locale_id message_id)a
@required_fields ~w(nplural_index message_id locale_id)a
@optional_fields ~w(original_text translated_text)a

@type t() :: Kanta.Translations.PluralTranslationSpec.t()

@derive {Jason.Encoder, only: [:id] ++ @required_fields ++ @optional_fields}

schema "kanta_plural_translations" do
field :nplural_index, :integer
field :original_text, :string
Expand All @@ -26,7 +28,7 @@ defmodule Kanta.Translations.PluralTranslation do

def changeset(struct, attrs \\ %{}) do
struct
|> cast(attrs, @all_fields)
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> foreign_key_constraint(:locale_id)
|> foreign_key_constraint(:message_id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Kanta.Translations.PluralTranslations.Finders.ListTranslatedPluralTranslations do
@moduledoc """
Query module aka Finder responsible for listing translated plural translations
"""

use Kanta.Query,
module: Kanta.Translations.PluralTranslation,
binding: :plural_translation

alias Kanta.Repo

def find do
base()
|> translated_query()
|> Repo.get_repo().all()
end

defp translated_query(query) do
from(pt in query,
where: not is_nil(pt.translated_text) and pt.translated_text != ""
)
end
end
6 changes: 4 additions & 2 deletions lib/kanta/translations/singular_translation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ defmodule Kanta.Translations.SingularTranslation do
import Ecto.Changeset
alias Kanta.Translations.{Locale, Message}

@all_fields ~w(original_text translated_text locale_id message_id)a
@required_fields ~w(message_id locale_id)a
@optional_fields ~w(original_text translated_text)a

@type t() :: Kanta.Translations.SingularTranslationSpec.t()

@derive {Jason.Encoder, only: [:id] ++ @required_fields ++ @optional_fields}

schema "kanta_singular_translations" do
field :original_text, :string
field :translated_text, :string
Expand All @@ -24,7 +26,7 @@ defmodule Kanta.Translations.SingularTranslation do

def changeset(struct, attrs \\ %{}) do
struct
|> cast(attrs, @all_fields)
|> cast(attrs, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
|> foreign_key_constraint(:locale_id)
|> foreign_key_constraint(:message_id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Kanta.Translations.SingularTranslations.Finders.ListTranslatedSingularTranslations do
@moduledoc """
Query module aka Finder responsible for listing translated singular translations
"""

use Kanta.Query,
module: Kanta.Translations.SingularTranslation,
binding: :singular_translation

alias Kanta.Repo

def find do
base()
|> translated_query()
|> Repo.get_repo().all()
end

defp translated_query(query) do
from(st in query,
where: not is_nil(st.translated_text) and st.translated_text != ""
)
end
end
Loading

0 comments on commit b3d5613

Please sign in to comment.