mirror of
https://github.com/mirego/accent.git
synced 2024-10-05 14:38:05 +03:00
Add languagetool vendored integration for performant and accurate spelling lint check
This commit is contained in:
parent
44a32ac1e9
commit
2aa9b82e5a
@ -33,3 +33,5 @@ jipt/.cache
|
||||
jipt/dist
|
||||
jipt/webapp-dist
|
||||
cli
|
||||
|
||||
priv/native/language-tool.jar
|
||||
|
@ -1,5 +1,11 @@
|
||||
[
|
||||
inputs: ["mix.exs", ".formatter.exs", ".credo.exs", "{config,lib,test,rel,priv}/**/*.{ex,exs}"],
|
||||
inputs: [
|
||||
"mix.exs",
|
||||
".formatter.exs",
|
||||
".credo.exs",
|
||||
"vendor/language_tool/**/*.ex",
|
||||
"{config,lib,test,rel,priv}/**/*.{ex,exs}"
|
||||
],
|
||||
plugins: [Styler],
|
||||
import_deps: [:ecto, :phoenix],
|
||||
line_length: 120
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -43,3 +43,7 @@ cli/*-debug.log
|
||||
cli/*-error.log
|
||||
cli/.oclif.manifest.json
|
||||
.elixir_ls
|
||||
|
||||
priv/native/language-tool.jar
|
||||
vendor/language_tool/priv/native/languagetool/.gradle
|
||||
vendor/language_tool/priv/native/languagetool/app/build
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
## v1.19.0
|
||||
|
||||
Added: Optional spelling server to add spelling check to linting.
|
||||
Added: Spellchecker with https://languagetool.org/
|
||||
|
||||
We bundle a jar file and install Java runtime in docker to be able to use languagetool spellchecker locally and very fast.
|
||||
This is the first version of the integration, we are still missing some important feature like "Ignore rules", "Custom project dictionary" or "Placeholder handling".
|
||||
|
||||
## v1.18.4
|
||||
|
||||
|
16
Dockerfile
16
Dockerfile
@ -24,7 +24,7 @@ RUN npm ci --no-audit --no-color && \
|
||||
#
|
||||
# Build the OTP binary
|
||||
#
|
||||
FROM hexpm/elixir:1.14.3-erlang-25.1.2-debian-bullseye-20221004-slim AS builder
|
||||
FROM hexpm/elixir:1.15.7-erlang-26.1.2-debian-bullseye-20230612-slim AS builder
|
||||
|
||||
ENV MIX_ENV=prod
|
||||
|
||||
@ -32,7 +32,7 @@ WORKDIR /build
|
||||
|
||||
# Install Debian dependencies
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y build-essential git libyaml-dev && \
|
||||
apt-get install -y build-essential git libyaml-dev default-jre && \
|
||||
apt-get clean && \
|
||||
rm -f /var/lib/apt/lists/*_*
|
||||
|
||||
@ -48,6 +48,12 @@ COPY mix.lock .
|
||||
|
||||
RUN mix deps.get --only prod
|
||||
RUN mix deps.compile --only prod
|
||||
|
||||
COPY vendor vendor
|
||||
|
||||
RUN cd ./vendor/language_tool/priv/native/languagetool && ./gradlew shadowJar
|
||||
RUN cp ./vendor/language_tool/priv/native/languagetool/app/build/libs/language-tool.jar priv/native/language-tool.jar
|
||||
|
||||
RUN mix compile --only prod
|
||||
|
||||
# Move static assets from other stages into the OTP release.
|
||||
@ -65,12 +71,10 @@ RUN mkdir -p /opt/build && \
|
||||
#
|
||||
# Build a lean runtime container
|
||||
#
|
||||
FROM alpine:3.17.0
|
||||
|
||||
FROM debian:bullseye-20230109
|
||||
FROM debian:bullseye-20231009
|
||||
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y bash libyaml-dev openssl libncurses5 locales fontconfig hunspell hunspell-fr hunspell-en-ca hunspell-en-us hunspell-es && \
|
||||
apt-get install -y default-jre bash libyaml-dev openssl libncurses5 locales fontconfig hunspell hunspell-fr hunspell-en-ca hunspell-en-us hunspell-es && \
|
||||
apt-get clean && \
|
||||
rm -f /var/lib/apt/lists/*_*
|
||||
|
||||
|
6
Makefile
6
Makefile
@ -67,6 +67,12 @@ build: ## Build the Docker image for the OTP release
|
||||
compose-build: ## Build the Docker image from the docker-compose.yml file
|
||||
docker-compose build
|
||||
|
||||
.PHONY: build-language-tool
|
||||
build-language-tool:
|
||||
rm -f vendor/language_tool/priv/native/language-tool.jar
|
||||
cd vendor/language_tool/priv/native/languagetool && ./gradlew shadowJar
|
||||
cp vendor/language_tool/priv/native/languagetool/app/build/libs/language-tool.jar priv/native/language-tool.jar
|
||||
|
||||
# CI targets
|
||||
# ----------
|
||||
|
||||
|
@ -124,19 +124,11 @@ config :ueberauth, Ueberauth.Strategy.Microsoft.OAuth,
|
||||
client_secret: get_env("MICROSOFT_CLIENT_SECRET"),
|
||||
tenant_id: get_env("MICROSOFT_TENANT_ID")
|
||||
|
||||
config :accent, Accent.Lint, spelling_server_url: get_env("SPELLING_SERVER_URL")
|
||||
|
||||
config :accent, Accent.WebappView,
|
||||
path: "priv/static/webapp/index.html",
|
||||
sentry_dsn: get_env("WEBAPP_SENTRY_DSN") || "",
|
||||
skip_subresource_integrity: get_env("WEBAPP_SKIP_SUBRESOURCE_INTEGRITY", :boolean)
|
||||
|
||||
if get_env("GOOGLE_TRANSLATIONS_SERVICE_ACCOUNT_KEY") do
|
||||
config :goth, json: get_env("GOOGLE_TRANSLATIONS_SERVICE_ACCOUNT_KEY")
|
||||
else
|
||||
config :goth, disabled: true
|
||||
end
|
||||
|
||||
config :tesla, logger_enabled: true
|
||||
|
||||
config :new_relic_agent,
|
||||
|
@ -10,6 +10,7 @@ defmodule Accent do
|
||||
Accent.Repo,
|
||||
{Oban, oban_config()},
|
||||
Accent.Vault,
|
||||
{LanguageTool.Server, language_tool_config()},
|
||||
{TelemetryUI, Accent.TelemetryUI.config()},
|
||||
{Phoenix.PubSub, [name: Accent.PubSub, adapter: Phoenix.PubSub.PG2]}
|
||||
]
|
||||
@ -33,6 +34,14 @@ defmodule Accent do
|
||||
:ok
|
||||
end
|
||||
|
||||
defp language_tool_config do
|
||||
[
|
||||
languages:
|
||||
~w(ar be-BY br-FR ca-ES da-DK de de-AT de-CH de-DE de-LU el-GR en en-AU en-CA en-GB en-NZ en-US en-ZA eo es es-AR es-ES fa fa-IR fr fr-BE fr-CA fr-CH fr-FR it it-IT ja-JP nl nl-BE nl-NL pl-PL pt pt-AO pt-BR pt-MZ pt-PT ro-RO ru-RU sk-SK sl-SI sv sv-SE ta-IN tl-PH uk-UA zh-CN),
|
||||
disabled_rule_ids: ~w(UPPERCASE_SENTENCE_START POINTS_2 FRENCH_WHITESPACE DETERMINER_SENT_END)
|
||||
]
|
||||
end
|
||||
|
||||
defp oban_config do
|
||||
opts = Application.get_env(:accent, Oban)
|
||||
|
||||
|
@ -66,10 +66,20 @@ defmodule Accent.Translation do
|
||||
locked: translation.locked,
|
||||
plural: translation.plural,
|
||||
placeholders: translation.placeholders,
|
||||
placeholder_regex: extract_translation_document_placeholder_regex(translation),
|
||||
language_slug: language_slug
|
||||
}
|
||||
end
|
||||
|
||||
defp extract_translation_document_placeholder_regex(translation) do
|
||||
with true <- is_struct(translation.document, Accent.Document),
|
||||
{:ok, regex} <- Langue.placeholder_regex_from_format(translation.document.format) do
|
||||
regex
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
def maybe_natural_order_by(translations, "key") do
|
||||
Enum.sort_by(translations, & &1.key)
|
||||
end
|
||||
|
@ -12,7 +12,7 @@ defmodule Accent.Scopes.Project do
|
||||
iex> Accent.Scopes.Project.from_search(Accent.Project, 1234)
|
||||
Accent.Project
|
||||
iex> Accent.Scopes.Project.from_search(Accent.Project, "test")
|
||||
#Ecto.Query<from p0 in Accent.Project, where: ilike(p0.name, ^"%test%")>
|
||||
#Ecto.Query<from p0 in Accent.Project, where: ilike(p0.name, ^"%test%") or ^false>
|
||||
"""
|
||||
@spec from_search(Ecto.Queryable.t(), any()) :: Ecto.Queryable.t()
|
||||
def from_search(query, term) do
|
||||
|
@ -14,25 +14,19 @@ defmodule Accent.Scopes.Search do
|
||||
iex> Accent.Scopes.Search.from_search(Accent.Project, "test", :name)
|
||||
#Ecto.Query<from p0 in Accent.Project, where: ilike(p0.name, ^"%test%")>
|
||||
"""
|
||||
@spec from_search(Ecto.Queryable.t(), any(), atom()) :: Ecto.Queryable.t()
|
||||
@spec from_search(Ecto.Queryable.t(), any(), atom() | list(atom())) :: Ecto.Queryable.t()
|
||||
def from_search(query, nil, _), do: query
|
||||
def from_search(query, term, _) when term === "", do: query
|
||||
def from_search(query, term, _) when not is_binary(term), do: query
|
||||
|
||||
def from_search(query, term, fields) when is_list(fields) do
|
||||
def from_search(query, term, fields) do
|
||||
term = "%" <> term <> "%"
|
||||
|
||||
conditions =
|
||||
Enum.reduce(fields, false, fn field, conditions ->
|
||||
Enum.reduce(List.wrap(fields), false, fn field, conditions ->
|
||||
dynamic([q], ilike(field(q, ^field), ^term) or ^conditions)
|
||||
end)
|
||||
|
||||
from(query, where: ^conditions)
|
||||
end
|
||||
|
||||
def from_search(query, term, field) do
|
||||
term = "%" <> term <> "%"
|
||||
|
||||
from(q in query, where: ilike(field(q, ^field), ^term))
|
||||
end
|
||||
end
|
||||
|
@ -345,7 +345,7 @@ defmodule Accent.Scopes.Translation do
|
||||
iex> Accent.Scopes.Translation.from_search(Accent.Translation, 1234)
|
||||
Accent.Translation
|
||||
iex> Accent.Scopes.Translation.from_search(Accent.Translation, "test")
|
||||
#Ecto.Query<from t0 in Accent.Translation, where: ilike(t0.key, ^\"%test%\") or ilike(t0.corrected_text, ^\"%test%\")>
|
||||
#Ecto.Query<from t0 in Accent.Translation, where: ilike(t0.corrected_text, ^\"%test%\") or (ilike(t0.key, ^\"%test%\") or ^false)>
|
||||
"""
|
||||
@spec from_search(Queryable.t(), any()) :: Queryable.t()
|
||||
def from_search(query, nil), do: query
|
||||
@ -353,12 +353,8 @@ defmodule Accent.Scopes.Translation do
|
||||
def from_search(query, term) when not is_binary(term), do: query
|
||||
|
||||
def from_search(query, search_term) do
|
||||
term = "%" <> search_term <> "%"
|
||||
|
||||
from_search_id(
|
||||
from(translation in query,
|
||||
where: ilike(translation.key, ^term) or ilike(translation.corrected_text, ^term)
|
||||
),
|
||||
Accent.Scopes.Search.from_search(query, search_term, [:key, :corrected_text]),
|
||||
search_term
|
||||
)
|
||||
end
|
||||
|
@ -12,6 +12,7 @@ defmodule Accent.TelemetryUI do
|
||||
{"Absinthe", absinthe_metrics(), ui_options: [metrics_class: "grid-cols-8 gap-4"]},
|
||||
{"Ecto", ecto_metrics(), ui_options: [metrics_class: "grid-cols-8 gap-4"]},
|
||||
{"PSQL Extras", EctoPSQLExtras.all(Accent.Repo)},
|
||||
{"Lint", lint_metrics(), ui_options: [metrics_class: "grid-cols-8 gap-4"]},
|
||||
{"System", system_metrics()}
|
||||
],
|
||||
theme: theme(),
|
||||
@ -19,6 +20,47 @@ defmodule Accent.TelemetryUI do
|
||||
]
|
||||
end
|
||||
|
||||
def lint_metrics do
|
||||
[
|
||||
counter("accent.language_tool.check.stop.duration",
|
||||
description: "Number of spellchecks",
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-3", unit: " checks"]
|
||||
),
|
||||
count_over_time("accent.language_tool.check.stop.duration",
|
||||
description: "Number of spellchecks over time",
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-5", unit: " checks"]
|
||||
),
|
||||
average("accent.language_tool.check.stop.duration",
|
||||
description: "Spellchecks duration",
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-3", unit: " ms"]
|
||||
),
|
||||
average_over_time("accent.language_tool.check.stop.duration",
|
||||
description: "Spellchecks duration over time",
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-5", unit: " ms"]
|
||||
),
|
||||
count_over_time("accent.language_tool.check.stop.duration",
|
||||
description: "Spellchecks per language over time",
|
||||
tags: [:language_code],
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [unit: " checks"]
|
||||
),
|
||||
count_list("accent.language_tool.check.stop.duration",
|
||||
description: "Count spellchecks by language",
|
||||
tags: [:language_code],
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [unit: " checks"]
|
||||
),
|
||||
average_over_time("accent.language_tool.check.stop.duration",
|
||||
description: "Spellchecks duration per language",
|
||||
tags: [:language_code]
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
def http_metrics do
|
||||
http_keep = &(&1[:route] not in ~w(/metrics /graphql))
|
||||
|
||||
@ -52,23 +94,20 @@ defmodule Accent.TelemetryUI do
|
||||
keep: http_keep,
|
||||
tags: [:route],
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [unit: " requests"],
|
||||
reporter_options: [class: "col-span-4"]
|
||||
ui_options: [unit: " requests"]
|
||||
),
|
||||
counter("phoenix.router_dispatch.stop.duration",
|
||||
count_list("phoenix.router_dispatch.stop.duration",
|
||||
description: "Count HTTP requests by route",
|
||||
keep: http_keep,
|
||||
tags: [:route],
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [unit: " requests"],
|
||||
reporter_options: [class: "col-span-4"]
|
||||
ui_options: [unit: " requests"]
|
||||
),
|
||||
average_over_time("phoenix.router_dispatch.stop.duration",
|
||||
description: "HTTP requests duration per route",
|
||||
keep: http_keep,
|
||||
tags: [:route],
|
||||
unit: {:native, :millisecond},
|
||||
reporter_options: [class: "col-span-4"]
|
||||
unit: {:native, :millisecond}
|
||||
),
|
||||
distribution("phoenix.router_dispatch.stop.duration",
|
||||
description: "Requests duration",
|
||||
@ -97,12 +136,19 @@ defmodule Accent.TelemetryUI do
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-5", unit: " ms"]
|
||||
),
|
||||
average("accent.repo.query.total_time",
|
||||
average_list("accent.repo.query.total_time",
|
||||
description: "Database query total time per source",
|
||||
keep: ecto_keep,
|
||||
tags: [:source],
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-full", unit: " ms"]
|
||||
),
|
||||
count_list("accent.repo.query.total_time",
|
||||
description: "Database query count per source",
|
||||
keep: ecto_keep,
|
||||
tags: [:source],
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-full", unit: " ms"]
|
||||
)
|
||||
]
|
||||
end
|
||||
@ -139,7 +185,7 @@ defmodule Accent.TelemetryUI do
|
||||
unit: {:native, :millisecond},
|
||||
ui_options: [class: "col-span-5", unit: " ms"]
|
||||
),
|
||||
counter("absinthe.execute.operation.stop.duration",
|
||||
count_list("absinthe.execute.operation.stop.duration",
|
||||
description: "Count Absinthe executions per operation",
|
||||
tags: [:operation_name],
|
||||
tag_values: absinthe_tag_values,
|
||||
@ -151,13 +197,6 @@ defmodule Accent.TelemetryUI do
|
||||
tag_values: absinthe_tag_values,
|
||||
unit: {:native, :millisecond}
|
||||
),
|
||||
count_list("absinthe.resolve.field.stop.duration",
|
||||
description: "Absinthe field resolve count",
|
||||
tags: [:resolution_path],
|
||||
keep: list_keep,
|
||||
tag_values: list_tag_values,
|
||||
unit: {:native, :millisecond}
|
||||
),
|
||||
average_list("absinthe.resolve.field.stop.duration",
|
||||
description: "Absinthe field resolve",
|
||||
tags: [:resolution_path],
|
||||
@ -305,7 +344,7 @@ defmodule Accent.TelemetryUI do
|
||||
pruner_threshold: [months: -1],
|
||||
pruner_interval_ms: 84_000,
|
||||
max_buffer_size: 10_000,
|
||||
flush_interval_ms: 1_000,
|
||||
flush_interval_ms: 30_000,
|
||||
verbose: false
|
||||
}
|
||||
end
|
||||
|
@ -38,7 +38,7 @@ defmodule Accent.GraphQL.Resolvers.Lint do
|
||||
end
|
||||
|
||||
def preload_translations(_, [translation | _] = translations) do
|
||||
translations = Repo.preload(translations, revision: :language)
|
||||
translations = Repo.preload(translations, [:document, [revision: :language]])
|
||||
|
||||
project =
|
||||
translation
|
||||
|
@ -135,7 +135,7 @@ defmodule Accent.GraphQL.Resolvers.Project do
|
||||
|> TranslationScope.active()
|
||||
|> TranslationScope.not_locked()
|
||||
|> Query.distinct(true)
|
||||
|> Query.preload(revision: :language)
|
||||
|> Query.preload([:document, [revision: :language]])
|
||||
|> Query.order_by({:asc, :key})
|
||||
|> Repo.all()
|
||||
|
||||
|
@ -12,6 +12,7 @@ defmodule Langue.Entry do
|
||||
locked: false,
|
||||
plural: false,
|
||||
placeholders: [],
|
||||
placeholder_regex: nil,
|
||||
language_slug: nil
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
@ -26,6 +27,7 @@ defmodule Langue.Entry do
|
||||
locked: boolean(),
|
||||
plural: boolean(),
|
||||
placeholders: list(binary),
|
||||
placeholder_regex: Regex.t() | nil,
|
||||
language_slug: String.t()
|
||||
}
|
||||
end
|
||||
|
@ -7,5 +7,5 @@ defmodule Langue.Formatter.Json do
|
||||
parser: Langue.Formatter.Json.Parser,
|
||||
serializer: Langue.Formatter.Json.Serializer
|
||||
|
||||
def placeholder_regex, do: ~r/{{[^}]*}}/
|
||||
def placeholder_regex, do: ~r/{{?[^}]*}?}/
|
||||
end
|
||||
|
@ -7,5 +7,5 @@ defmodule Langue.Formatter.SimpleJson do
|
||||
parser: Langue.Formatter.SimpleJson.Parser,
|
||||
serializer: Langue.Formatter.SimpleJson.Serializer
|
||||
|
||||
def placeholder_regex, do: ~r/{{[^}]*}}/
|
||||
def placeholder_regex, do: ~r/{{?[^}]*}?}/
|
||||
end
|
||||
|
@ -34,6 +34,12 @@ defmodule Langue do
|
||||
|
||||
def serializer_from_format(_), do: {:error, :unknown_serializer}
|
||||
|
||||
for module <- @format_modules, id = module.id() do
|
||||
def placeholder_regex_from_format(unquote(id)), do: {:ok, unquote(module).placeholder_regex()}
|
||||
end
|
||||
|
||||
def placeholder_regex_from_format(_), do: {:error, :unknown_format}
|
||||
|
||||
def placeholder_regex do
|
||||
@format_modules
|
||||
|> Enum.map(& &1.placeholder_regex())
|
||||
|
@ -6,32 +6,35 @@ defmodule Accent.Lint.Checks.Spelling do
|
||||
alias Accent.Lint.Replacement
|
||||
|
||||
@impl true
|
||||
def enabled?, do: not is_nil(base_url())
|
||||
def enabled?, do: LanguageTool.available?()
|
||||
|
||||
@impl true
|
||||
def applicable(entry) do
|
||||
((!entry.is_master and entry.value !== entry.master_value) or entry.is_master) and
|
||||
LanguageTool.ready?() and
|
||||
not String.match?(entry.value, ~r/MMM|YYY|HH|AA/i) and
|
||||
not String.starts_with?(entry.value, "{") and
|
||||
((!entry.is_master and entry.value !== entry.master_value) or entry.is_master) and
|
||||
String.length(entry.value) < 100 and String.length(entry.value) > 3
|
||||
end
|
||||
|
||||
@impl true
|
||||
def check(entry) do
|
||||
req =
|
||||
Req.new(
|
||||
base_url: base_url(),
|
||||
params: %{text: entry.value, language: build_language_slug(entry.language_slug)}
|
||||
)
|
||||
|
||||
matches = Req.get!(req, url: "/v2/check").body["matches"]
|
||||
{matches, markups} =
|
||||
case LanguageTool.check(entry.language_slug, entry.value, placeholder_regex: entry.placeholder_regex) do
|
||||
%{"matches" => matches, "markups" => markups} -> {matches, markups}
|
||||
_ -> {[], []}
|
||||
end
|
||||
|
||||
for match <- matches do
|
||||
offset = match["offset"] + length(markups)
|
||||
|
||||
replacement =
|
||||
case match["replacements"] do
|
||||
[%{"value" => fixed_value} | _] ->
|
||||
value =
|
||||
String.replace(
|
||||
entry.value,
|
||||
String.slice(entry.value, match["offset"], match["length"]),
|
||||
String.slice(entry.value, offset, match["length"]),
|
||||
fixed_value
|
||||
)
|
||||
|
||||
@ -44,23 +47,11 @@ defmodule Accent.Lint.Checks.Spelling do
|
||||
%Message{
|
||||
check: :spelling,
|
||||
text: entry.value,
|
||||
offset: match["offset"],
|
||||
offset: offset,
|
||||
length: match["length"],
|
||||
message: match["message"],
|
||||
replacement: replacement
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
defp build_language_slug(slug) do
|
||||
if String.match?(slug, ~r/..-.*/) do
|
||||
slug
|
||||
else
|
||||
slug <> "-CA"
|
||||
end
|
||||
end
|
||||
|
||||
defp base_url do
|
||||
Application.get_env(:accent, Accent.Lint)[:spelling_server_url]
|
||||
end
|
||||
end
|
||||
|
@ -157,7 +157,7 @@ defmodule Accent.MachineTranslations.Provider.GoogleTranslate do
|
||||
|
||||
@impl Tesla.Middleware
|
||||
def call(env, next, opts) do
|
||||
case auth_enabled?() && Goth.Token.for_scope(opts[:scope]) do
|
||||
case auth_enabled?() && Goth.Token.fetch(%{source: opts}) do
|
||||
{:ok, %{token: token, type: type}} ->
|
||||
env
|
||||
|> Tesla.put_header("authorization", type <> " " <> token)
|
||||
@ -174,13 +174,13 @@ defmodule Accent.MachineTranslations.Provider.GoogleTranslate do
|
||||
end
|
||||
|
||||
defp client(config) do
|
||||
project_id = project_id_from_config(config)
|
||||
{base_url, auth_source} = parse_auth_config(config)
|
||||
|
||||
middlewares =
|
||||
List.flatten([
|
||||
{Middleware.Timeout, [timeout: :infinity]},
|
||||
{Middleware.BaseUrl, "https://translation.googleapis.com/v3/projects/#{project_id}"},
|
||||
{Auth, [scope: "https://www.googleapis.com/auth/cloud-translation"]},
|
||||
{Middleware.BaseUrl, base_url},
|
||||
{Auth, auth_source},
|
||||
Middleware.DecodeJson,
|
||||
Middleware.EncodeJson,
|
||||
Middleware.Logger,
|
||||
@ -190,9 +190,16 @@ defmodule Accent.MachineTranslations.Provider.GoogleTranslate do
|
||||
Tesla.client(middlewares)
|
||||
end
|
||||
|
||||
defp project_id_from_config(config) do
|
||||
key = Map.fetch!(config, "key")
|
||||
Jason.decode!(key)["project_id"]
|
||||
defp parse_auth_config(config) do
|
||||
config = Jason.decode!(Map.fetch!(config, "key"))
|
||||
|
||||
case config do
|
||||
%{"project_id" => project_id, "type" => "service_account"} = credentials ->
|
||||
{
|
||||
"https://translation.googleapis.com/v3/projects/#{project_id}",
|
||||
{:service_account, credentials, [scopes: ["https://www.googleapis.com/auth/cloud-translation"]]}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -112,7 +112,7 @@ defmodule Accent.LintController do
|
||||
|> base_translations(conn)
|
||||
|> TranslationScope.from_revision(conn.assigns[:revision].id)
|
||||
|> Repo.all()
|
||||
|> Repo.preload(:revision)
|
||||
|> Repo.preload([:revision, :document])
|
||||
|> Map.new(&{{&1.key, &1.document_id}, &1})
|
||||
|
||||
assign(conn, :translations, translations)
|
||||
|
7
mix.exs
7
mix.exs
@ -42,7 +42,6 @@ defmodule Accent.Mixfile do
|
||||
|
||||
# Plugs
|
||||
{:plug_assign, "~> 1.0.0"},
|
||||
{:canada, "~> 1.0"},
|
||||
{:canary, "~> 1.1.0"},
|
||||
{:corsica, "~> 2.0"},
|
||||
{:plug_cowboy, "~> 2.0"},
|
||||
@ -57,8 +56,8 @@ defmodule Accent.Mixfile do
|
||||
{:postgrex, "~> 0.14"},
|
||||
{:cloak_ecto, "~> 1.2"},
|
||||
|
||||
# Spelling
|
||||
{:req, "~> 0.1"},
|
||||
# Spelling interop with Java runtime
|
||||
{:exile, "~> 0.7"},
|
||||
|
||||
# Phoenix data helpers
|
||||
{:phoenix_ecto, "~> 4.0"},
|
||||
@ -113,7 +112,7 @@ defmodule Accent.Mixfile do
|
||||
{:mock, "~> 0.3.0", only: :test},
|
||||
|
||||
# Google API authentication
|
||||
{:goth, "~> 1.2.0"},
|
||||
{:goth, "~> 1.4"},
|
||||
|
||||
# Network request
|
||||
{:tesla, "~> 1.3"},
|
||||
|
30
mix.lock
30
mix.lock
@ -8,40 +8,40 @@
|
||||
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
|
||||
"canada": {:hex, :canada, "1.0.2", "040e4c47609b0a67d5773ac1fbe5e99f840cef173d69b739beda7c98453e0770", [:mix], [], "hexpm", "4269f74153fe89583fe50bd4d5de57bfe01f31258a6b676d296f3681f1483c68"},
|
||||
"canary": {:hex, :canary, "1.1.1", "4138d5e05db8497c477e4af73902eb9ae06e49dceaa13c2dd9f0b55525ded48b", [:mix], [{:canada, "~> 1.0.1", [hex: :canada, repo: "hexpm", optional: false]}, {:ecto, ">= 1.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f348d9848693c830a65b707bba9e4dfdd6434e8c356a8d4477e4535afb0d653b"},
|
||||
"castore": {:hex, :castore, "1.0.3", "7130ba6d24c8424014194676d608cb989f62ef8039efd50ff4b3f33286d06db8", [:mix], [], "hexpm", "680ab01ef5d15b161ed6a95449fac5c6b8f60055677a8e79acf01b27baa4390b"},
|
||||
"castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"},
|
||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||
"cloak": {:hex, :cloak, "1.1.2", "7e0006c2b0b98d976d4f559080fabefd81f0e0a50a3c4b621f85ceeb563e80bb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "940d5ac4fcd51b252930fd112e319ea5ae6ab540b722f3ca60a85666759b9585"},
|
||||
"cloak_ecto": {:hex, :cloak_ecto, "1.2.0", "e86a3df3bf0dc8980f70406bcb0af2858bac247d55494d40bc58a152590bd402", [:mix], [{:cloak, "~> 1.1.1", [hex: :cloak, repo: "hexpm", optional: false]}, {:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm", "8bcc677185c813fe64b786618bd6689b1707b35cd95acaae0834557b15a0c62f"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"con_cache": {:hex, :con_cache, "0.14.0", "863acb90fa08017be3129074993af944cf7a4b6c3ee7c06c5cd0ed6b94fbc223", [:mix], [], "hexpm", "50887a8949377d0b707a3c6653b7610de06074751b52d0f267f52135f391aece"},
|
||||
"corsica": {:hex, :corsica, "2.1.2", "0f1bc7648f9a41abca557c8158c110269d61a1465468be2416621991e316ff56", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c778c6ded25ec78c57c64a7b769edb388ec8f162ea3b6f10fa2580fb13fb2afb"},
|
||||
"corsica": {:hex, :corsica, "2.1.3", "dccd094ffce38178acead9ae743180cdaffa388f35f0461ba1e8151d32e190e6", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "616c08f61a345780c2cf662ff226816f04d8868e12054e68963e95285b5be8bc"},
|
||||
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
|
||||
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
|
||||
"cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
|
||||
"credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"},
|
||||
"credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"},
|
||||
"credo_envvar": {:hex, :credo_envvar, "0.1.4", "40817c10334e400f031012c0510bfa0d8725c19d867e4ae39cf14f2cbebc3b20", [:mix], [{:credo, "~> 1.0", [hex: :credo, repo: "hexpm", optional: false]}], "hexpm", "5055cdb4bcbaf7d423bc2bb3ac62b4e2d825e2b1e816884c468dee59d0363009"},
|
||||
"csv": {:hex, :csv, "2.5.0", "c47b5a5221bf2e56d6e8eb79e77884046d7fd516280dc7d9b674251e0ae46246", [:mix], [{:parallel_stream, "~> 1.0.4 or ~> 1.1.0", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm", "e821f541487045c7591a1963eeb42afff0dfa99bdcdbeb3410795a2f59c77d34"},
|
||||
"dataloader": {:hex, :dataloader, "2.0.0", "49b42d60b9bb06d761a71d7b034c4b34787957e713d4fae15387a25fcd639112", [:mix], [{:ecto, ">= 3.4.3 and < 4.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:opentelemetry_process_propagator, "~> 0.2.1", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "09d61781b76ce216e395cdbc883ff00d00f46a503e215c22722dba82507dfef0"},
|
||||
"db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"},
|
||||
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
|
||||
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
||||
"dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"},
|
||||
"dialyxir": {:hex, :dialyxir, "1.4.2", "764a6e8e7a354f0ba95d58418178d486065ead1f69ad89782817c296d0d746a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "516603d8067b2fd585319e4b13d3674ad4f314a5902ba8130cd97dc902ce6bbd"},
|
||||
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
|
||||
"ecto_dev_logger": {:hex, :ecto_dev_logger, "0.9.0", "cb631469ac1940e97655d6fce85905b792ac9250ab18b19c664978b79f8dad59", [:mix], [{:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "2e8bc98b4ae4fcc7108896eef7da5a109afad829f4fb2eb46d677fdc9101c2d5"},
|
||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.13", "9947637f82b92dcec93d44ad09ba24d1990bd7ca69e1c68981fb3b6f8bd18829", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "0f2288e6163f6aacd7e59545a56adc8df7d2079d18be7d3d6159d10f4dffc396"},
|
||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.14", "7a20cfe913b0476542b43870e67386461258734896035e3f284039fd18bd4c4c", [:mix], [{:ecto_sql, "~> 3.7", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "22f5f98592dd597db9416fcef00effae0787669fdcb6faf447e982b553798e98"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.10.2", "6b98b46534b5c2f8b8b5f03f126e75e2a73c64f3c071149d32987a5378b0fdbd", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "68c018debca57cb9235e3889affdaec7a10616a4e3a80c99fa1d01fdafaa9007"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"erlsom": {:hex, :erlsom, "1.5.1", "c8fe2babd33ff0846403f6522328b8ab676f896b793634cfe7ef181c05316c03", [:rebar3], [], "hexpm", "7965485494c5844dd127656ac40f141aadfa174839ec1be1074e7edf5b4239eb"},
|
||||
"ex_cmd": {:hex, :ex_cmd, "0.10.0", "f746150fea4421b49be9c773825f2e26f5f526e272515334135340ada2749fa6", [:mix], [{:gen_state_machine, "~> 3.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}], "hexpm", "d2575237e754676cd3d38dc39d36a99da455253a0889c1c2231a619d3ca5d7a4"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.17.1", "83fa7906ef23aa7fc8ad7ee469c357a63b1b3d55dd701ff5b9ce1f72442b2874", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "95bc6fda953e84c60f14da4a198880336205464e75383ec0f570180567985ae0"},
|
||||
"excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"},
|
||||
"exile": {:hex, :exile, "0.7.0", "a07228b191c7233f48e225289cc512dd268b54b5e799d952d03b6ee6db3b7ba5", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f61ecfc4e0b2e9cc1ef177adf6b00a9bed2e8c2f4a2c2cfff0f3a28ae965720e"},
|
||||
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
|
||||
"finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"},
|
||||
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
|
||||
"gen_state_machine": {:hex, :gen_state_machine, "3.0.0", "1e57f86a494e5c6b14137ebef26a7eb342b3b0070c7135f2d6768ed3f6b6cdff", [:mix], [], "hexpm", "0a59652574bebceb7309f6b749d2a41b45fdeda8dbb4da0791e355dd19f0ed15"},
|
||||
"gettext": {:hex, :gettext, "0.20.0", "75ad71de05f2ef56991dbae224d35c68b098dd0e26918def5bb45591d5c8d429", [:mix], [], "hexpm", "1c03b177435e93a47441d7f681a7040bd2a816ece9e2666d1c9001035121eb3d"},
|
||||
"goth": {:hex, :goth, "1.2.0", "92d6d926065a72a7e0da8818cc3a133229b56edf378022c00d9886c4125ce769", [:mix], [{:httpoison, "~> 0.11 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:joken, "~> 2.0", [hex: :joken, repo: "hexpm", optional: false]}], "hexpm", "4974932ab3b782c99a6fdeb0b968ddd61436ef14de5862bd6bb0227386c63b26"},
|
||||
"hackney": {:hex, :hackney, "1.19.1", "59de4716e985dd2b5cbd4954fa1ae187e2b610a9c4520ffcb0b1653c3d6e5559", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "8aa08234bdefc269995c63c2282cf3cd0e36febe3a6bfab11b610572fdd1cad0"},
|
||||
"goth": {:hex, :goth, "1.4.2", "a598dfbce6fe65db3f5f43b1ab2ce8fbe3b2fe20a7569ad62d71c11c0ddc3f41", [:mix], [{:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "d51bb6544dc551fe5754ab72e6cf194120b3c06d924282aaa3321a516ed3b98a"},
|
||||
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
"httpoison": {:hex, :httpoison, "1.8.2", "9eb9c63ae289296a544842ef816a85d881d4a31f518a0fec089aaa744beae290", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "2bb350d26972e30c96e2ca74a1aaf8293d61d0742ff17f01e0279fef11599921"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
@ -63,12 +63,12 @@
|
||||
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
|
||||
"nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"},
|
||||
"oauth2": {:hex, :oauth2, "2.1.0", "beb657f393814a3a7a8a15bd5e5776ecae341fd344df425342a3b6f1904c2989", [:mix], [{:tesla, "~> 1.5", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "8ac07f85b3307dd1acfeb0ec852f64161b22f57d0ce0c15e616a1dfc8ebe2b41"},
|
||||
"oban": {:hex, :oban, "2.16.1", "606242b4651c7a46747669ff5cfea4dc33bb7af8091ac44df93dedd8775b0d9e", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3dc78588bedaf7589c2619f9cee5c2e681a9af9e296ef0f9fc4671513243334b"},
|
||||
"oban": {:hex, :oban, "2.16.2", "ec8dfd2f6dfdcd885061b58aeaa2794a0a6f62bad20c15939e4bb80bfd74ed76", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3d343c80948676abf9652da1e793ab6140ba64e9de7c8d6630eb5bb4aa8fea79"},
|
||||
"parallel_stream": {:hex, :parallel_stream, "1.1.0", "f52f73eb344bc22de335992377413138405796e0d0ad99d995d9977ac29f1ca9", [:mix], [], "hexpm", "684fd19191aedfaf387bbabbeb8ff3c752f0220c8112eb907d797f4592d6e871"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
|
||||
"phoenix": {:hex, :phoenix, "1.7.7", "4cc501d4d823015007ba3cdd9c41ecaaf2ffb619d6fb283199fa8ddba89191e0", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8966e15c395e5e37591b6ed0bd2ae7f48e961f0f60ac4c733f9566b519453085"},
|
||||
"phoenix": {:hex, :phoenix, "1.7.9", "9a2b873e2cb3955efdd18ad050f1818af097fa3f5fc3a6aaba666da36bdd3f02", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "83e32da028272b4bfd076c61a964e6d2b9d988378df2f1276a0ed21b13b5e997"},
|
||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "3.3.2", "d6ce982c6d8247d2fc0defe625255c721fb8d5f1942c5ac051f6177bffa5973f", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "44adaf8e667c1c20fb9d284b6b0fa8dc7946ce29e81ce621860aa7e96de9a11d"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"},
|
||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.0", "3f3531c835e46a3b45b4c3ca4a09cef7ba1d0f0d0035eef751c7084b8adb1299", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "29875f8a58fb031f2dc8f3be025c92ed78d342b46f9bbf6dfe579549d7c81050"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
|
||||
@ -89,7 +89,7 @@
|
||||
"scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"},
|
||||
"sentry": {:hex, :sentry, "7.2.5", "570db92c3bbacd6ad02ac81cba8ac5af11235a55d65ac4375e3ec833975b83d3", [:mix], [{:hackney, "1.6.5 or ~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "ea84ed6848505ff2a246567df562f465d2b34c317d3ecba7c7df58daa56e5e5d"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||
"styler": {:hex, :styler, "0.9.5", "6862ffa1d00adb4ec69cc4af60f72e17986c283e6287b778d2f0c3f50de01c8e", [:mix], [], "hexpm", "376674398da4126fbcbbc07ed51de30a5a45822b0d73e5f4d6e26d7942d54b7c"},
|
||||
"styler": {:hex, :styler, "0.9.6", "749dd911ab5d99e80ebba29f3f63b1f1319c026e4b71dd88afb03bc10fe87791", [:mix], [], "hexpm", "70adc3f329f6ed8c1713748607c4ceea9a0ae3350c819394c68ed771ae3ee2ae"},
|
||||
"table": {:hex, :table, "0.1.2", "87ad1125f5b70c5dea0307aa633194083eb5182ec537efc94e96af08937e14a8", [:mix], [], "hexpm", "7e99bc7efef806315c7e65640724bf165c3061cdc5d854060f74468367065029"},
|
||||
"table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"},
|
||||
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
|
||||
@ -105,8 +105,8 @@
|
||||
"ueberauth_discord": {:hex, :ueberauth_discord, "0.7.0", "463f6dfe1ed10a76739331ce8e1dd3600ab611f10524dd828eb3aa50e76e9d43", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "d6f98ef91abb4ddceada4b7acba470e0e68c4d2de9735ff2f24172a8e19896b4"},
|
||||
"ueberauth_github": {:hex, :ueberauth_github, "0.8.3", "1c478629b4c1dae446c68834b69194ad5cead3b6c67c913db6fdf64f37f0328f", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "ae0ab2879c32cfa51d7287a48219b262bfdab0b7ec6629f24160564247493cc6"},
|
||||
"ueberauth_gitlab_strategy": {:hex, :ueberauth_gitlab_strategy, "0.4.0", "96605d304ebb87ce508eccbeb1f94da9ea1c9da20d8913771b6cf24a6cc6c633", [:mix], [{:oauth2, "~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "e86e2e794bb063c07c05a6b1301b73f2be3ba9308d8f47ecc4d510ef9226091e"},
|
||||
"ueberauth_google": {:hex, :ueberauth_google, "0.11.0", "0689498c8bf9905cca304e2c6cfab26d5a3e4259f4dfe262a5a05534ec9b93a3", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.10.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "79ced73a06ce40e3d1b67ef4354d3383d1068783ac06b813288800332a6ac5a7"},
|
||||
"ueberauth_microsoft": {:hex, :ueberauth_microsoft, "0.22.0", "25cb94b9493bff16be6b43e28b2a85dd123fe09f8bedb3c02299005496248752", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "f46660e56a7029cc982191df8c9e784dcb54a0dd108ac4f472132e7043095267"},
|
||||
"ueberauth_google": {:hex, :ueberauth_google, "0.12.0", "e1aaaf5c0413a35623059cc177df4f755c5c8348a2f91a1e25a51f24c39b4c74", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.10.0", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "caa774ea8524ea6bb3b1233c4e2199c2443a5a2ca0f9b10c7729b6c1f8eb4905"},
|
||||
"ueberauth_microsoft": {:hex, :ueberauth_microsoft, "0.23.0", "5c78e02a83d821ee45f96216bb6140ba688cc79b8b26e7ff438e3abe24615e1d", [:mix], [{:oauth2, "~> 1.0 or ~> 2.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "0c08d98203e6d3069f30306f09a6cb55b95c2bda94d6f8e90f05bd442ee96b82"},
|
||||
"ueberauth_slack": {:hex, :ueberauth_slack, "0.7.0", "91dfd089371a6c5a21a505b3e3e140cced95d4cdc7b73afb5337bcf5f3c91a00", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:oauth2, "~> 1.0", [hex: :oauth2, repo: "hexpm", optional: false]}, {:ueberauth, "~> 0.7", [hex: :ueberauth, repo: "hexpm", optional: false]}], "hexpm", "5cba654352596f74a9e2547a19a3aab56634f2a0b928e93cd659ac7d05bf790e"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
"vega_lite": {:hex, :vega_lite, "0.1.8", "7f6119126ecaf4bc2c1854084370d7091424f5cce4795fbac044eee9963f0752", [:mix], [{:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "6c8a9271f850612dd8a90de8d1ebd433590ed07ffef76fc2397c240dc04d3fdc"},
|
||||
|
0
priv/native/.gitkeep
Normal file
0
priv/native/.gitkeep
Normal file
@ -2,6 +2,9 @@ defmodule Accent.Repo.Migrations.AddTelemetryUiEventsTable do
|
||||
@moduledoc false
|
||||
use Ecto.Migration
|
||||
|
||||
@disable_ddl_transaction true
|
||||
@disable_migration_lock true
|
||||
|
||||
def up do
|
||||
TelemetryUI.Backend.EctoPostgres.Migrations.up()
|
||||
end
|
||||
|
@ -2,6 +2,9 @@ defmodule Accent.Repo.Migrations.UpgradeTelemetryUi2 do
|
||||
@moduledoc false
|
||||
use Ecto.Migration
|
||||
|
||||
@disable_ddl_transaction true
|
||||
@disable_migration_lock true
|
||||
|
||||
def up do
|
||||
TelemetryUI.Backend.EctoPostgres.Migrations.up(version: 3)
|
||||
end
|
||||
|
@ -48,7 +48,7 @@ defmodule AccentTest.GraphQL.Resolvers.Lint do
|
||||
master_translation: master_translation,
|
||||
conflicted: false,
|
||||
key: "ok",
|
||||
corrected_text: "bar foo",
|
||||
corrected_text: " bar foo",
|
||||
proposed_text: "bar"
|
||||
})
|
||||
|
||||
@ -57,8 +57,8 @@ defmodule AccentTest.GraphQL.Resolvers.Lint do
|
||||
assert result === [
|
||||
%Message{
|
||||
replacement: %Replacement{value: "bar foo", label: "bar foo"},
|
||||
check: :double_spaces,
|
||||
text: "bar foo"
|
||||
check: :leading_spaces,
|
||||
text: " bar foo"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
@ -62,19 +62,6 @@ defmodule AccentTest.Lint do
|
||||
]
|
||||
end
|
||||
|
||||
test "lint double spaces entry" do
|
||||
entry = %Entry{key: "a", value: "fo o", master_value: "foo", value_type: "string"}
|
||||
[{_, messages}] = Lint.lint([entry])
|
||||
|
||||
assert messages === [
|
||||
%Message{
|
||||
replacement: %Replacement{value: "fo o", label: "fo o"},
|
||||
check: :double_spaces,
|
||||
text: "fo o"
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
test "lint three dots ellipsis entry" do
|
||||
entry = %Entry{key: "a", value: "foo...", master_value: "foo...", value_type: "string"}
|
||||
[{_, messages}] = Lint.lint([entry])
|
||||
|
43
vendor/language_tool/lib/language_tool.ex
vendored
Normal file
43
vendor/language_tool/lib/language_tool.ex
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
defmodule LanguageTool do
|
||||
@moduledoc false
|
||||
|
||||
def check(lang, text, opts \\ []) do
|
||||
if lang in list_languages() do
|
||||
metadata = %{language_code: lang, text_length: String.length(text)}
|
||||
|
||||
:telemetry.span(
|
||||
[:accent, :language_tool, :check],
|
||||
metadata,
|
||||
fn ->
|
||||
placeholder_regex = Keyword.get(opts, :placeholder_regex)
|
||||
annotated_text = LanguageTool.AnnotatedText.build(text, placeholder_regex)
|
||||
|
||||
result =
|
||||
GenServer.call(LanguageTool.Server, {:check, lang, Jason.encode!(%{items: annotated_text})}, :infinity)
|
||||
|
||||
{result, metadata}
|
||||
end
|
||||
)
|
||||
else
|
||||
empty_matches(lang, text)
|
||||
end
|
||||
catch
|
||||
_ -> empty_matches(lang, text)
|
||||
end
|
||||
|
||||
defp empty_matches(lang, text) do
|
||||
%{"error" => nil, "language" => lang, "matches" => [], "text" => text, "markups" => []}
|
||||
end
|
||||
|
||||
def available? do
|
||||
LanguageTool.Server.available?()
|
||||
end
|
||||
|
||||
def list_languages do
|
||||
LanguageTool.Server.list_languages()
|
||||
end
|
||||
|
||||
def ready? do
|
||||
LanguageTool.Server.ready?()
|
||||
end
|
||||
end
|
37
vendor/language_tool/lib/language_tool/annotated_text.ex
vendored
Normal file
37
vendor/language_tool/lib/language_tool/annotated_text.ex
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
defmodule LanguageTool.AnnotatedText do
|
||||
@moduledoc false
|
||||
def build(input, regex) do
|
||||
matches = if regex, do: Regex.scan(regex, input, return: :index), else: []
|
||||
matches = matches ++ Regex.scan(~r/<[^>]*>/, input, return: :index)
|
||||
matches = Enum.sort_by(matches, fn [{match_index, _}] -> match_index end)
|
||||
split_tokens(input, matches, 0, [])
|
||||
end
|
||||
|
||||
defp split_tokens(input, [], position, acc) do
|
||||
to_add =
|
||||
case binary_slice(input, position..byte_size(input)) do
|
||||
text_after when byte_size(text_after) > 1 ->
|
||||
[%{text: text_after}]
|
||||
|
||||
_ ->
|
||||
[]
|
||||
end
|
||||
|
||||
acc ++ to_add
|
||||
end
|
||||
|
||||
defp split_tokens(input, [[{start_index, match_length}] | matches], position, acc) do
|
||||
text_before =
|
||||
if position !== start_index do
|
||||
case binary_slice(input, position..(start_index - 1)) do
|
||||
"" -> []
|
||||
text_before -> [%{text: String.trim_leading(text_before)}]
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
markup = binary_slice(input, start_index, match_length)
|
||||
split_tokens(input, matches, start_index + match_length, acc ++ text_before ++ [%{markup: markup}])
|
||||
end
|
||||
end
|
97
vendor/language_tool/lib/language_tool/backend.ex
vendored
Normal file
97
vendor/language_tool/lib/language_tool/backend.ex
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
defmodule LanguageTool.Backend do
|
||||
@moduledoc false
|
||||
|
||||
require Logger
|
||||
|
||||
def start(config) do
|
||||
path = Application.app_dir(:accent, "priv/native")
|
||||
|
||||
args = [
|
||||
executable(),
|
||||
"-cp",
|
||||
Path.join(path, "language-tool.jar"),
|
||||
"com.mirego.accent.languagetool.AppKt",
|
||||
"--languages",
|
||||
Enum.join(config.languages, ",")
|
||||
]
|
||||
|
||||
args =
|
||||
if Enum.any?(config.disabled_rule_ids) do
|
||||
args ++ ["--disabledRuleIds", Enum.join(config.disabled_rule_ids, ",")]
|
||||
else
|
||||
args
|
||||
end
|
||||
|
||||
{:ok, backend} = Exile.Process.start_link(args)
|
||||
receive_ready?(backend)
|
||||
backend
|
||||
end
|
||||
|
||||
def available? do
|
||||
!!executable()
|
||||
end
|
||||
|
||||
defp executable do
|
||||
System.find_executable("java")
|
||||
end
|
||||
|
||||
def check(process, lang, text) do
|
||||
result =
|
||||
text
|
||||
|> String.split("\n")
|
||||
|> Enum.map(&process_check(process, lang, &1))
|
||||
|> Enum.reject(&is_nil/1)
|
||||
|> Enum.reduce(
|
||||
%{"offset" => 0, "language" => nil, "error" => nil, "text" => [], "matches" => [], "markups" => []},
|
||||
fn result, acc ->
|
||||
matches =
|
||||
Enum.map(result["matches"], fn match ->
|
||||
Map.update!(match, "offset", &(&1 + acc["offset"]))
|
||||
end)
|
||||
|
||||
acc
|
||||
|> Map.update!("markups", &(&1 ++ result["markups"]))
|
||||
|> Map.update!("matches", &(&1 ++ matches))
|
||||
|> Map.put("language", result["language"])
|
||||
|> Map.put("error", result["error"])
|
||||
|> Map.update!("offset", &(&1 + String.length(result["text"]) + 1))
|
||||
|> Map.update!("text", &(&1 ++ [result["text"]]))
|
||||
end
|
||||
)
|
||||
|
||||
result
|
||||
|> Map.delete("offset")
|
||||
|> Map.update!("text", &Enum.join(&1, "\n"))
|
||||
end
|
||||
|
||||
defp receive_ready?(backend) do
|
||||
case Exile.Process.read(backend) do
|
||||
{:ok, ">\n"} ->
|
||||
Logger.info("LanguageTool is ready to spellcheck")
|
||||
true
|
||||
|
||||
_ ->
|
||||
receive_ready?(backend)
|
||||
end
|
||||
end
|
||||
|
||||
defp process_check(process, lang, text) do
|
||||
lang = sanitize_lang(lang)
|
||||
Exile.Process.write(process, IO.iodata_to_binary([String.pad_trailing(lang, 7), text, "\n"]))
|
||||
|
||||
with {:ok, data} <- Exile.Process.read(process),
|
||||
{:ok, data} <- Jason.decode(data) do
|
||||
data
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp sanitize_lang(lang) do
|
||||
if lang === "en" do
|
||||
"en-US"
|
||||
else
|
||||
lang
|
||||
end
|
||||
end
|
||||
end
|
60
vendor/language_tool/lib/language_tool/server.ex
vendored
Normal file
60
vendor/language_tool/lib/language_tool/server.ex
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
defmodule LanguageTool.Server do
|
||||
@moduledoc false
|
||||
use GenServer
|
||||
|
||||
defmodule Config do
|
||||
@moduledoc false
|
||||
defstruct languages: [], disabled_rule_ids: []
|
||||
|
||||
def parse(opts) do
|
||||
%__MODULE__{
|
||||
languages: Keyword.fetch!(opts, :languages),
|
||||
disabled_rule_ids: Keyword.get(opts, :disabled_rule_ids, [])
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def init(opts) do
|
||||
Process.send_after(self(), :init_server_process, 1)
|
||||
|
||||
{:ok, opts}
|
||||
end
|
||||
|
||||
def start_link(opts) do
|
||||
config = Config.parse(opts)
|
||||
:persistent_term.put({:language_tool, :config}, config)
|
||||
:persistent_term.put({:language_tool, :ready}, false)
|
||||
|
||||
GenServer.start_link(__MODULE__, %{config: config, backend: nil}, name: __MODULE__)
|
||||
end
|
||||
|
||||
def list_languages do
|
||||
:persistent_term.get({:language_tool, :config}).languages
|
||||
end
|
||||
|
||||
def ready? do
|
||||
:persistent_term.get({:language_tool, :ready})
|
||||
end
|
||||
|
||||
def available? do
|
||||
LanguageTool.Backend.available?()
|
||||
end
|
||||
|
||||
def handle_call({:check, lang, text}, _, state) do
|
||||
response = LanguageTool.Backend.check(state.backend, lang, text)
|
||||
{:reply, response, state}
|
||||
end
|
||||
|
||||
def handle_info(:init_server_process, state) do
|
||||
backend = LanguageTool.Backend.start(state.config)
|
||||
state = %{state | backend: backend}
|
||||
|
||||
:persistent_term.put({:language_tool, :ready}, true)
|
||||
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_info(_message, state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
end
|
97
vendor/language_tool/priv/native/languagetool/app/build.gradle.kts
vendored
Normal file
97
vendor/language_tool/priv/native/languagetool/app/build.gradle.kts
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Kotlin application project to get you started.
|
||||
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.4/userguide/building_java_projects.html in the Gradle documentation.
|
||||
*/
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("gradle.plugin.com.github.johnrengelman:shadow:7.1.2")
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
// Apply the org.jetbrains.kotlin.jvm Plugin to add support for Kotlin.
|
||||
id("org.jetbrains.kotlin.jvm") version "1.9.10"
|
||||
kotlin("plugin.serialization") version "1.9.10"
|
||||
//java
|
||||
|
||||
// Apply the application plugin to add support for building a CLI application in Java.
|
||||
application
|
||||
}
|
||||
|
||||
apply(plugin = "com.github.johnrengelman.shadow")
|
||||
|
||||
repositories {
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Use the Kotlin JUnit 5 integration.
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
|
||||
|
||||
// Use the JUnit 5 integration.
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
|
||||
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
|
||||
// This dependency is used by the application.
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
|
||||
implementation("com.google.guava:guava:32.1.1-jre")
|
||||
implementation("org.languagetool:language-all:6.3")
|
||||
implementation("com.googlecode.json-simple:json-simple:1.1.1")
|
||||
implementation("org.slf4j:slf4j-nop:2.0.7")
|
||||
|
||||
}
|
||||
|
||||
// Apply a specific Java toolchain to ease working on different environments.
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(11))
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<ShadowJar> {
|
||||
archiveBaseName.set("language-tool")
|
||||
archiveClassifier.set("")
|
||||
archiveVersion.set("")
|
||||
mergeServiceFiles("META-INF/org/languagetool/language-module.properties")
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
manifest {
|
||||
attributes["Main-Class"] = "com.mirego.accent.languagetool.AppKt"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Jar>("customFatJar") {
|
||||
manifest {
|
||||
attributes["Main-Class"] = "com.baeldung.fatjar.Application"
|
||||
}
|
||||
//baseName = "all-in-one-jar"
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
from(configurations.runtimeClasspath.get().map {
|
||||
if (it.isDirectory) {
|
||||
it
|
||||
} else {
|
||||
zipTree(it)
|
||||
}
|
||||
})
|
||||
with(tasks.jar.get())
|
||||
}
|
||||
application {
|
||||
// Define the main class for the application.
|
||||
mainClass.set("com.mirego.accent.languagetool.AppKt")
|
||||
}
|
||||
|
||||
tasks.named<Test>("test") {
|
||||
// Use JUnit Platform for unit tests.
|
||||
useJUnitPlatform()
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
package com.mirego.accent.languagetool
|
||||
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.util.*
|
||||
import java.util.concurrent.*
|
||||
import org.json.simple.*
|
||||
import org.languagetool.*
|
||||
import org.languagetool.language.*
|
||||
import org.languagetool.rules.*
|
||||
import org.languagetool.markup.AnnotatedTextBuilder;
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.*
|
||||
|
||||
@Serializable
|
||||
data class Base(val items: Array<Item>)
|
||||
|
||||
@Serializable
|
||||
data class Item(val markup: String = "", val text: String = "")
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val reader = BufferedReader(InputStreamReader(System.`in`))
|
||||
val tools = HashMap<String, JLanguageTool>()
|
||||
val languages = ArrayList<String>()
|
||||
val disabledRuleIds = ArrayList<String>()
|
||||
|
||||
for (i in args.indices) {
|
||||
when (args[i]) {
|
||||
"--languages" -> {
|
||||
if (i + 1 < args.size) {
|
||||
val codes = args[i + 1].split(",")
|
||||
for (code in codes) {
|
||||
languages.add(code.trim())
|
||||
}
|
||||
} else {
|
||||
println("Error: Missing languages.")
|
||||
return
|
||||
}
|
||||
}
|
||||
"--disabledRuleIds" -> {
|
||||
if (i + 1 < args.size) {
|
||||
val ids = args[i + 1].split(",")
|
||||
for (id in ids) {
|
||||
disabledRuleIds.add(id)
|
||||
}
|
||||
} else {
|
||||
println("Error: Missing rule ids.")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (code in languages) {
|
||||
val cache = ResultCache(10000, 600, TimeUnit.SECONDS)
|
||||
val globalConfig = GlobalConfig()
|
||||
val userConfig = UserConfig()
|
||||
|
||||
val lt =
|
||||
JLanguageTool(
|
||||
Languages.getLanguageForShortCode(code),
|
||||
ArrayList(),
|
||||
null,
|
||||
cache,
|
||||
globalConfig,
|
||||
userConfig
|
||||
)
|
||||
for (id in disabledRuleIds) {
|
||||
lt.disableRule(id)
|
||||
}
|
||||
|
||||
lt.check("")
|
||||
tools[code] = lt
|
||||
}
|
||||
|
||||
var input: String?
|
||||
|
||||
println(">")
|
||||
|
||||
while (true) {
|
||||
input = reader.readLine()
|
||||
if (input == null) break
|
||||
val languageShortCode = input.substring(0, Math.min(7, input.length)).trim()
|
||||
val text = input.substring(Math.min(7, input.length))
|
||||
val langTool = tools[languageShortCode]
|
||||
|
||||
if (text.length == 0) {
|
||||
printError("invalid_input", text, languageShortCode)
|
||||
continue
|
||||
}
|
||||
|
||||
if (langTool == null) {
|
||||
printError("unsupported_language", text, languageShortCode)
|
||||
continue
|
||||
}
|
||||
|
||||
val parsedText = Json.decodeFromString<Base>(text)
|
||||
val annotatedBuilder = AnnotatedTextBuilder()
|
||||
val markups = JSONArray()
|
||||
|
||||
for (item in parsedText.items) {
|
||||
if (item.markup != "") {
|
||||
markups.add(item.markup)
|
||||
annotatedBuilder.addMarkup(item.markup, "x");
|
||||
} else {
|
||||
annotatedBuilder.addText(item.text);
|
||||
}
|
||||
}
|
||||
|
||||
val annotatedText = annotatedBuilder.build()
|
||||
val matches = langTool.check(annotatedText)
|
||||
val responseObject = JSONObject()
|
||||
|
||||
responseObject.put("text", annotatedText.getTextWithMarkup())
|
||||
responseObject.put("markups", markups)
|
||||
responseObject.put("language", languageShortCode)
|
||||
|
||||
val matchesList = JSONArray()
|
||||
|
||||
for (match in matches) {
|
||||
val matchObject = JSONObject()
|
||||
matchObject.put("offset", match.fromPos)
|
||||
matchObject.put("message", cleanSuggestion(match.message))
|
||||
matchObject.put("length", match.toPos - match.fromPos)
|
||||
|
||||
matchObject.put("replacements", getReplacements(match))
|
||||
matchObject.put("rule", getRule(match))
|
||||
|
||||
matchesList.add(matchObject)
|
||||
}
|
||||
|
||||
responseObject.put("matches", matchesList)
|
||||
|
||||
println(responseObject.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun printError(error: String, text: String, languageShortCode: String) {
|
||||
val errorObject = JSONObject()
|
||||
errorObject.put("error", error)
|
||||
errorObject.put("text", text)
|
||||
errorObject.put("matches", JSONArray())
|
||||
errorObject.put("markups", JSONArray())
|
||||
errorObject.put("language", languageShortCode)
|
||||
println(errorObject.toString())
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun getRule(match: RuleMatch): JSONObject {
|
||||
val rule = match.rule
|
||||
val ruleObject = JSONObject()
|
||||
ruleObject.put("description", rule.description)
|
||||
ruleObject.put("id", match.specificRuleId)
|
||||
return ruleObject
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun getReplacements(match: RuleMatch): JSONArray {
|
||||
val replacements = JSONArray()
|
||||
val matches = match.suggestedReplacementObjects
|
||||
|
||||
for (replacement in matches.subList(0, Math.min(5, Math.max(0, matches.size - 1)))) {
|
||||
val replacementObject = JSONObject()
|
||||
replacementObject.put("value", replacement.replacement)
|
||||
replacementObject.put("confidence", replacement.confidence)
|
||||
|
||||
replacements.add(replacementObject)
|
||||
}
|
||||
|
||||
return replacements
|
||||
}
|
||||
|
||||
private fun cleanSuggestion(s: String): String {
|
||||
return s.replace("<suggestion>", "\"").replace("</suggestion>", "\"")
|
||||
}
|
BIN
vendor/language_tool/priv/native/languagetool/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
vendor/language_tool/priv/native/languagetool/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
vendor/language_tool/priv/native/languagetool/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
vendor/language_tool/priv/native/languagetool/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
vendor/language_tool/priv/native/languagetool/gradlew
vendored
Executable file
249
vendor/language_tool/priv/native/languagetool/gradlew
vendored
Executable file
@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
vendor/language_tool/priv/native/languagetool/gradlew.bat
vendored
Normal file
92
vendor/language_tool/priv/native/languagetool/gradlew.bat
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
14
vendor/language_tool/priv/native/languagetool/settings.gradle.kts
vendored
Normal file
14
vendor/language_tool/priv/native/languagetool/settings.gradle.kts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
* For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.4/userguide/building_swift_projects.html in the Gradle documentation.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
// Apply the foojay-resolver plugin to allow automatic download of JDKs
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
|
||||
}
|
||||
|
||||
rootProject.name = "languagetool"
|
||||
include("app")
|
@ -41,7 +41,7 @@
|
||||
},
|
||||
"revision_selector": {
|
||||
"languages_count": "{count, plural, =1 {1 other language} other {# other languages}}",
|
||||
"master": "master"
|
||||
"master": "main"
|
||||
},
|
||||
"translation_comments_subscriptions": {
|
||||
"title": "Notify on new messages"
|
||||
@ -115,7 +115,7 @@
|
||||
"instructions": {
|
||||
"sync": {
|
||||
"title": "Sync",
|
||||
"text": "Update the list of strings in Accent, removing ones missing in the file and adding new ones.<em>The sync is always done in the master language.</em>New strings and removed strings changes will be reflected in all translated languages."
|
||||
"text": "Update the list of strings in Accent, removing ones missing in the file and adding new ones.<em>The sync is always done in the main language.</em>New strings and removed strings changes will be reflected in all translated languages."
|
||||
},
|
||||
"merge": {
|
||||
"title": "Add translations",
|
||||
@ -124,8 +124,8 @@
|
||||
"mistakes": {
|
||||
"title": "Common mistakes",
|
||||
"item_1": "Export Accent files locally before a sync. This will force you to resolve conflicts locally and potentially override reviewed texts or adding removed strings.",
|
||||
"item_2": "Sync a translated language (not your master language). This will effectively generates conflicts for all your keys, changing the text of the master language for your translated language.",
|
||||
"item_3": "Sync one file per language. The purpose of the \"file\" in Accent is to be translated in X languages. Sync your master language and let the translated languages be translated in the UI."
|
||||
"item_2": "Sync a translated language (not your main language). This will effectively generates conflicts for all your keys, changing the text of the main language for your translated language.",
|
||||
"item_3": "Sync one file per language. The purpose of the \"file\" in Accent is to be translated in X languages. Sync your main language and let the translated languages be translated in the UI."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -178,7 +178,7 @@
|
||||
},
|
||||
"keys": "strings",
|
||||
"last_synced_at_label": "Last sync:",
|
||||
"master_language_label": "Master language is:",
|
||||
"master_language_label": "Main language is:",
|
||||
"never_synced": "Sync the project for the first time",
|
||||
"reviewed": "reviewed"
|
||||
},
|
||||
@ -191,10 +191,10 @@
|
||||
"last_synced_at_label": "Last sync:",
|
||||
"manage_languages_link_title": "Manage languages",
|
||||
"new_language_link_title": "New language",
|
||||
"new_language_link_text": "With another language, you can keep track of translation based on the master language.",
|
||||
"new_language_link_text": "With another language, you can keep track of translation based on the main language.",
|
||||
"view_more_activities": "View more activities →",
|
||||
"title": "Dashboard",
|
||||
"master": "Master language",
|
||||
"master": "Main language",
|
||||
"slaves": "Translations",
|
||||
"sync": "Sync",
|
||||
"strings": "strings",
|
||||
@ -216,7 +216,7 @@
|
||||
"update": "Edit"
|
||||
},
|
||||
"documents_list": {
|
||||
"empty_text": "Files are the actual listing of your project’s master language files. Add them here or from the CLI and keep them in sync with your project.",
|
||||
"empty_text": "Files are the actual listing of your project’s main language files. Add them here or from the CLI and keep them in sync with your project.",
|
||||
"export_all": "Export all",
|
||||
"show_deleted": "Show deleted",
|
||||
"hide_deleted": "Hide deleted",
|
||||
@ -306,7 +306,7 @@
|
||||
"create_version": "When a user freeze the state of all strings to tag it with a version. Used to maintain multiple versions of the same app in parallel.",
|
||||
"conflict_on_corrected": "When the uploaded text is different than the last synced text and the last synced text is different than the current text. This happens if the text has been touched by a user in Accent. It is uselful to identify a conflict that is caused by a difference in a sync and the modified version in Accent.",
|
||||
"conflict_on_proposed": "When the uploaded text is different than the last uploaded text and the last synced text is equal to the current text. This happens if the text has not been touched by a user in Accent. It is uselful to identify a conflict that is only caused by a sync and not a human intervention.",
|
||||
"conflict_on_slave": "When the activity \"conflict on proposed\" or \"conflict on corrected\" happens on a string, the matching keys in other languages apply this activity. The goal of this activity is to flag a change of meaning in the master language in the translations. The string will be flagged as \"in review\"",
|
||||
"conflict_on_slave": "When the activity \"conflict on proposed\" or \"conflict on corrected\" happens on a string, the matching keys in other languages apply this activity. The goal of this activity is to flag a change of meaning in the main language in the translations. The string will be flagged as \"in review\"",
|
||||
"correct_all": "When all the strings are manually marked as reviewed.",
|
||||
"correct_conflict": "When a string is manually marked as reviewed.",
|
||||
"batch_correct_conflict": "When multiple strings were marked as reviewed in a short lapse of time.",
|
||||
@ -610,7 +610,7 @@
|
||||
"title": "New project",
|
||||
"error": "Invalid project",
|
||||
"cancel_button": "Cancel",
|
||||
"language_label": "Master language:",
|
||||
"language_label": "Main language:",
|
||||
"language_search_placeholder": "Search…",
|
||||
"name_label": "Name:",
|
||||
"save_button": "Create"
|
||||
@ -700,12 +700,12 @@
|
||||
"project_manage_languages": {
|
||||
"create_error": "Language can not be added right now. Try again later.",
|
||||
"conflicts_explain_title": "On conflicts",
|
||||
"conflicts_explain_text": "Every string addition or deletion will be reflected in the language. When a text changes in the master revision, the string in the language will be marked as in review.",
|
||||
"conflicts_explain_text": "Every string addition or deletion will be reflected in the language. When a text changes in the main revision, the string in the language will be marked as in review.",
|
||||
"sync_explain_title": "On sync",
|
||||
"sync_explain_text": "The master language will be the default source when syncing a file. The other languages are never \"synced\", they just follow the master language.",
|
||||
"sync_explain_text": "The main language will be the default source when syncing a file. The other languages are never \"synced\", they just follow the main language.",
|
||||
"add_translations_explain_title": "On add translations",
|
||||
"add_translations_explain_text": "Every languages can have strings \"merged\" into it by adding translations. Conflict resolution will work the same but will never add or remove strings.",
|
||||
"main_text": "You can add a new language that will follow the master language.",
|
||||
"main_text": "You can add a new language that will follow the main language.",
|
||||
"title": "Manage languages"
|
||||
},
|
||||
"projects_filters": {
|
||||
@ -727,7 +727,7 @@
|
||||
"related_translations_list": {
|
||||
"comments_label": "{count, plural, =0 {No comments} =1 {1 comment} other {# comments}}",
|
||||
"conflicted_label": "in review",
|
||||
"master_label": "master",
|
||||
"master_label": "main",
|
||||
"save_button": "Save",
|
||||
"last_updated_label": "Last updated:",
|
||||
"new_language_link": "New language",
|
||||
@ -746,11 +746,11 @@
|
||||
"list_languages": "Languages:",
|
||||
"revision_inserted_at_label": "Created",
|
||||
"revision_deleted_label": "The language is currently being removed from your project. It will automatically disappear once all operations are propagated in the system.",
|
||||
"master_badge": "master",
|
||||
"master_badge": "main",
|
||||
"delete_revision_confirm": "Are you sure you want to remove this language from your project? This action cannot be rollbacked.",
|
||||
"delete_revision_button": "Remove this language",
|
||||
"promote_revision_master_confirm": "Are you sure you want to use this language as the master language from your project?",
|
||||
"promote_revision_master_button": "Use as master"
|
||||
"promote_revision_master_confirm": "Are you sure you want to use this language as the main language from your project?",
|
||||
"promote_revision_master_button": "Use as main"
|
||||
},
|
||||
"revision_export_options": {
|
||||
"default_format": "Default format",
|
||||
@ -858,15 +858,16 @@
|
||||
"URL_COUNT": "URLs count"
|
||||
},
|
||||
"checks": {
|
||||
"PLACEHOLDER_COUNT": "Number of placeholders does not match the master string",
|
||||
"PLACEHOLDER_COUNT": "Number of placeholders does not match the main string",
|
||||
"TRAILING_SPACE": "String contains a trailing space",
|
||||
"LEADING_SPACES": "String contains leading spaces",
|
||||
"DOUBLE_SPACES": "String contains double spaces",
|
||||
"APOSTROPHE_AS_SINGLE_QUOTE": "A single quote as been used instead of an apostrophe",
|
||||
"FIRST_LETTER_CASE": "First letter of translation does not match case of the master’s",
|
||||
"SPELLING": "String contains a spelling mistake",
|
||||
"FIRST_LETTER_CASE": "First letter of translation does not match case of the main’s",
|
||||
"THREE_DOTS_ELLIPSIS": "String contains three dots instead of ellipsis",
|
||||
"SAME_TRAILING_CHARACTER": "String does not match the trailing character of master",
|
||||
"URL_COUNT": "Number of URL does not match the master string"
|
||||
"SAME_TRAILING_CHARACTER": "String does not match the trailing character of main",
|
||||
"URL_COUNT": "Number of URL does not match the main string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -880,7 +881,7 @@
|
||||
"translation_splash_title": {
|
||||
"plural_label": "plural",
|
||||
"conflicted_label": "in review",
|
||||
"master_label": "master",
|
||||
"master_label": "main",
|
||||
"last_updated_label": "Last updated:",
|
||||
"removed_label": "This string was removed {removedAt}"
|
||||
},
|
||||
@ -923,7 +924,7 @@
|
||||
"sync_file": "Sync a new file",
|
||||
"sync_file_text": "Add strings from multiple file formats to review them",
|
||||
"manage_languages": "Add languages",
|
||||
"manage_languages_text": "Target languages follow your master language strings and conflicts",
|
||||
"manage_languages_text": "Target languages follow your main language strings and conflicts",
|
||||
"add_collaborator": "Add collaborator",
|
||||
"add_collaborator_text": "Translators, developers, etc.",
|
||||
"api_token": "Get an API Token",
|
||||
@ -1131,8 +1132,8 @@
|
||||
"add_revision_success": "The new language has been created with success",
|
||||
"delete_revision_failure": "The language could not be deleted",
|
||||
"delete_revision_success": "The language has been deleted with success",
|
||||
"promote_master_revision_failure": "The language could not be promoted as master",
|
||||
"promote_master_revision_success": "The language has been promoted as master with success"
|
||||
"promote_master_revision_failure": "The language could not be promoted as main",
|
||||
"promote_master_revision_success": "The language has been promoted as main with success"
|
||||
}
|
||||
},
|
||||
"comments": {
|
||||
|
@ -854,6 +854,7 @@
|
||||
"FIRST_LETTER_CASE": "La casse de la première lettre ne concorde pas",
|
||||
"THREE_DOTS_ELLIPSIS": "Trois points pour des points de suspension",
|
||||
"SAME_TRAILING_CHARACTER": "Le caractère de fin ne concorde pas",
|
||||
"SPELLING": "Ortographe",
|
||||
"URL_COUNT": "Le nombre d’URL ne concorde pas"
|
||||
},
|
||||
"checks": {
|
||||
@ -865,6 +866,7 @@
|
||||
"FIRST_LETTER_CASE": "La première lettre de traduction ne correspond pas à la casse de la langue principal",
|
||||
"THREE_DOTS_ELLIPSIS": "La chaîne contient trois points au lieu de points de suspension",
|
||||
"SAME_TRAILING_CHARACTER": "La chaîne ne correspond pas au caractère de fin de la langue principal",
|
||||
"SPELLING": "La chaîne contient une faute d’ortographe",
|
||||
"URL_COUNT": "Le cnombre d’URL ne correspond pas à la chaîne principale"
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ import {dropTask} from 'ember-concurrency-decorators';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
import {MutationResponse} from 'accent-webapp/services/apollo-mutate';
|
||||
|
||||
const ALWAYS_SHOWN_COUNT = 3;
|
||||
|
||||
interface Conflict {
|
||||
id: string;
|
||||
key: string;
|
||||
@ -66,9 +64,6 @@ export default class ConflictItem extends Component<Args> {
|
||||
@tracked
|
||||
inputDisabled = false;
|
||||
|
||||
@tracked
|
||||
show = this.args.index <= ALWAYS_SHOWN_COUNT;
|
||||
|
||||
conflictKey = parsedKeyProperty(this.args.conflict.key);
|
||||
textOriginal = this.args.conflict.correctedText;
|
||||
|
||||
@ -116,11 +111,6 @@ export default class ConflictItem extends Component<Args> {
|
||||
: this.args.conflict.revision.language.rtl;
|
||||
}
|
||||
|
||||
@action
|
||||
didEnterViewport() {
|
||||
this.show = true;
|
||||
}
|
||||
|
||||
@action
|
||||
changeTranslationText(text: string) {
|
||||
this.textInput = text;
|
||||
|
@ -48,8 +48,7 @@
|
||||
justify-content: center;
|
||||
margin-left: 3px;
|
||||
border-radius: 50%;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
height: 17px;
|
||||
background: transparent;
|
||||
color: var(--color-black);
|
||||
line-height: 1;
|
||||
|
@ -1,9 +1,32 @@
|
||||
<div local-class='root' {{in-viewport onEnter=(fn this.didEnterViewport) scrollableArea='.conflict-items'}}>
|
||||
{{#if this.show}}
|
||||
<div local-class='conflict-item {{if this.resolved "resolved"}} {{if this.error "errored"}}'>
|
||||
<li>
|
||||
{{#if this.resolved}}
|
||||
<div local-class='textResolved'>
|
||||
<div local-class='root'>
|
||||
<div local-class='conflict-item {{if this.resolved "resolved"}} {{if this.error "errored"}}'>
|
||||
<li>
|
||||
{{#if this.resolved}}
|
||||
<div local-class='textResolved'>
|
||||
<LinkTo @route='logged-in.project.translation' @models={{array @project.id @conflict.id}} local-class='key'>
|
||||
<strong local-class='item-key'>
|
||||
{{this.conflictKey.value}}
|
||||
<small local-class='item-key-prefix'>
|
||||
{{#if this.conflictKey.prefix}}
|
||||
{{this.conflictKey.prefix}}
|
||||
{{else}}
|
||||
{{@conflict.document.path}}
|
||||
{{/if}}
|
||||
</small>
|
||||
</strong>
|
||||
</LinkTo>
|
||||
|
||||
<div local-class='textResolved-content'>
|
||||
{{#if this.error}}
|
||||
<div local-class='error'>
|
||||
{{t 'components.conflict_item.uncorrect_error_text'}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div local-class='item-details'>
|
||||
<div local-class='item-details__column'>
|
||||
<LinkTo @route='logged-in.project.translation' @models={{array @project.id @conflict.id}} local-class='key'>
|
||||
<strong local-class='item-key'>
|
||||
{{this.conflictKey.value}}
|
||||
@ -17,106 +40,81 @@
|
||||
</strong>
|
||||
</LinkTo>
|
||||
|
||||
<div local-class='textResolved-content'>
|
||||
{{#if this.error}}
|
||||
<div local-class='error'>
|
||||
{{t 'components.conflict_item.uncorrect_error_text'}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if this.error}}
|
||||
<div local-class='error'>
|
||||
{{t 'components.conflict_item.correct_error_text'}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div local-class='item-details'>
|
||||
<div local-class='item-details__column'>
|
||||
<LinkTo @route='logged-in.project.translation' @models={{array @project.id @conflict.id}} local-class='key'>
|
||||
<strong local-class='item-key'>
|
||||
{{this.conflictKey.value}}
|
||||
<small local-class='item-key-prefix'>
|
||||
{{#if this.conflictKey.prefix}}
|
||||
{{this.conflictKey.prefix}}
|
||||
{{else}}
|
||||
{{@conflict.document.path}}
|
||||
<div local-class='item-details__column'>
|
||||
<div local-class='textInput'>
|
||||
<TranslationEdit::Form
|
||||
@projectId={{@project.id}}
|
||||
@translationId={{@conflict.id}}
|
||||
@lintMessages={{@conflict.lintMessages}}
|
||||
@valueType={{@conflict.valueType}}
|
||||
@value={{this.textInput}}
|
||||
@inputDisabled={{this.inputDisabled}}
|
||||
@showTypeHints={{false}}
|
||||
@onKeyUp={{fn this.changeTranslationText}}
|
||||
@onSubmit={{fn this.correct}}
|
||||
@rtl={{this.revisionTextDirRtl}}
|
||||
lang={{this.revisionSlug}}
|
||||
as |form|
|
||||
>
|
||||
{{#component form.submit}}
|
||||
<div local-class='button-submit' data-dir={{form.dir}}>
|
||||
{{#if this.showOriginalButton}}
|
||||
<AsyncButton @onClick={{fn this.setOriginalText}} local-class='revert-button' class='button button--iconOnly button--white'>
|
||||
{{inline-svg '/assets/revert.svg' class='button-icon'}}
|
||||
</AsyncButton>
|
||||
{{/if}}
|
||||
</small>
|
||||
</strong>
|
||||
</LinkTo>
|
||||
|
||||
{{#if this.error}}
|
||||
<div local-class='error'>
|
||||
{{t 'components.conflict_item.correct_error_text'}}
|
||||
{{#if (get @permissions 'use_prompt_improve_text')}}
|
||||
<ImprovePrompt
|
||||
@project={{@project}}
|
||||
@prompts={{@prompts}}
|
||||
@text={{this.textInput}}
|
||||
@onUpdatingText={{fn this.onImprovingPrompt}}
|
||||
@onUpdateText={{fn this.onImprovePrompt}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if (get @permissions 'correct_translation')}}
|
||||
<AsyncButton @onClick={{fn this.correct}} @loading={{this.loading}} class='button button--iconOnly button--filled button--green'>
|
||||
{{inline-svg '/assets/check.svg' class='button-icon'}}
|
||||
</AsyncButton>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/component}}
|
||||
</TranslationEdit::Form>
|
||||
</div>
|
||||
|
||||
<div local-class='conflictedText-references'>
|
||||
{{#if this.showTextDiff}}
|
||||
<div local-class='conflictedText-references-conflicted'>
|
||||
<span local-class='conflictedText-references-conflicted-label'>
|
||||
{{inline-svg '/assets/diff.svg' local-class='conflictedText-references-conflicted-icon'}}
|
||||
</span>
|
||||
|
||||
<div local-class='conflictedText-references-conflicted-value'>{{string-diff this.textInput @conflict.conflictedText}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div local-class='item-details__column'>
|
||||
<div local-class='textInput'>
|
||||
<TranslationEdit::Form
|
||||
@projectId={{@project.id}}
|
||||
@translationId={{@conflict.id}}
|
||||
@lintMessages={{@conflict.lintMessages}}
|
||||
@valueType={{@conflict.valueType}}
|
||||
@value={{this.textInput}}
|
||||
@inputDisabled={{this.inputDisabled}}
|
||||
@showTypeHints={{false}}
|
||||
@onKeyUp={{fn this.changeTranslationText}}
|
||||
@onSubmit={{fn this.correct}}
|
||||
@rtl={{this.revisionTextDirRtl}}
|
||||
lang={{this.revisionSlug}}
|
||||
as |form|
|
||||
>
|
||||
{{#component form.submit}}
|
||||
<div local-class='button-submit' data-dir={{form.dir}}>
|
||||
{{#if this.showOriginalButton}}
|
||||
<AsyncButton @onClick={{fn this.setOriginalText}} local-class='revert-button' class='button button--iconOnly button--white'>
|
||||
{{inline-svg '/assets/revert.svg' class='button-icon'}}
|
||||
</AsyncButton>
|
||||
{{/if}}
|
||||
|
||||
{{#if (get @permissions 'use_prompt_improve_text')}}
|
||||
<ImprovePrompt
|
||||
@project={{@project}}
|
||||
@prompts={{@prompts}}
|
||||
@text={{this.textInput}}
|
||||
@onUpdatingText={{fn this.onImprovingPrompt}}
|
||||
@onUpdateText={{fn this.onImprovePrompt}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
{{#if (get @permissions 'correct_translation')}}
|
||||
<AsyncButton @onClick={{fn this.correct}} @loading={{this.loading}} class='button button--iconOnly button--filled button--green'>
|
||||
{{inline-svg '/assets/check.svg' class='button-icon'}}
|
||||
</AsyncButton>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/component}}
|
||||
</TranslationEdit::Form>
|
||||
</div>
|
||||
|
||||
<div local-class='conflictedText-references'>
|
||||
{{#if this.showTextDiff}}
|
||||
<div local-class='conflictedText-references-conflicted'>
|
||||
<span local-class='conflictedText-references-conflicted-label'>
|
||||
{{inline-svg '/assets/diff.svg' local-class='conflictedText-references-conflicted-icon'}}
|
||||
</span>
|
||||
|
||||
<div local-class='conflictedText-references-conflicted-value'>{{string-diff this.textInput @conflict.conflictedText}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if @conflict.relatedTranslations}}
|
||||
{{#each this.relatedTranslations key='id' as |relatedTranslation|}}
|
||||
<ConflictsList::Item::RelatedTranslation
|
||||
@project={{@project}}
|
||||
@translation={{relatedTranslation}}
|
||||
@permissions={{@permissions}}
|
||||
@onCopyTranslation={{perform this.copyTranslationTask}}
|
||||
/>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if @conflict.relatedTranslations}}
|
||||
{{#each this.relatedTranslations key='id' as |relatedTranslation|}}
|
||||
<ConflictsList::Item::RelatedTranslation
|
||||
@project={{@project}}
|
||||
@translation={{relatedTranslation}}
|
||||
@permissions={{@permissions}}
|
||||
@onCopyTranslation={{perform this.copyTranslationTask}}
|
||||
/>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
@ -1,4 +1,4 @@
|
||||
<ul local-class='conflicts-items' class='conflict-items'>
|
||||
<ul local-class='conflicts-items'>
|
||||
{{#each @conflicts key='id' as |conflict index|}}
|
||||
<ConflictsList::Item
|
||||
@index={{index}}
|
||||
|
@ -262,10 +262,6 @@
|
||||
padding: 2px 6px !important;
|
||||
}
|
||||
|
||||
:global(.button).button-sync {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@media (max-width: (1300px)) {
|
||||
.links {
|
||||
transform: translate3d(0, 0, 0);
|
||||
|
@ -87,7 +87,7 @@
|
||||
@models={{array @project.id @document.id}}
|
||||
local-class='button-sync'
|
||||
title={{t 'components.documents_list.sync'}}
|
||||
class='tooltip tooltip--top button button--filled button--white button--iconOnly'
|
||||
class='tooltip tooltip--top button button--filled button--iconOnly'
|
||||
>
|
||||
{{inline-svg '/assets/sync.svg' class='button-icon'}}
|
||||
</LinkTo>
|
||||
|
@ -9,23 +9,54 @@ interface Args {
|
||||
export default class LintTranslationsPageItem extends Component<Args> {
|
||||
translationKey = parsedKeyProperty(this.args.lintTranslation.translation.key);
|
||||
|
||||
get messages() {
|
||||
const mapSet = new Set();
|
||||
return this.args.lintTranslation.messages.flatMap((message: any) => {
|
||||
if (mapSet.has(message.check)) {
|
||||
return [];
|
||||
} else {
|
||||
mapSet.add(message.check);
|
||||
return [message];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get annotatedText() {
|
||||
return this.args.lintTranslation.messages.reduce(
|
||||
(text: string, message: any) => {
|
||||
if (message.offset && message.length && message.replacement) {
|
||||
let offsetTotal = 0;
|
||||
|
||||
return this.args.lintTranslation.messages
|
||||
.sort((a: any, b: any) => a.offset || 0 >= b.offset || 0)
|
||||
.reduce((text: string, message: any) => {
|
||||
if (message.length) {
|
||||
const error = text.slice(
|
||||
message.offset,
|
||||
message.offset + message.length
|
||||
);
|
||||
return String(text).replace(
|
||||
error,
|
||||
`<span>${error}</span><strong>${message.replacement.label}</strong>`
|
||||
message.offset + offsetTotal,
|
||||
message.offset + message.length + offsetTotal
|
||||
);
|
||||
|
||||
if (message.replacement) {
|
||||
const replacement = `<span data-underline>${error}</span><strong>${message.replacement.label}</strong>`;
|
||||
offsetTotal += replacement.length - error.length;
|
||||
|
||||
return String(text).replace(error, replacement);
|
||||
} else {
|
||||
const replacement = `<span data-underline>${error}</span>`;
|
||||
offsetTotal += replacement.length - error.length;
|
||||
|
||||
return String(text).replace(error, replacement);
|
||||
}
|
||||
} else if (message.check === 'LEADING_SPACES') {
|
||||
const replacement = `<span data-rect> </span>`;
|
||||
offsetTotal += replacement.length - 1;
|
||||
|
||||
return String(text).replace(/^ /, replacement);
|
||||
} else if (message.check === 'TRAILING_SPACE') {
|
||||
const replacement = `<span data-rect> </span>`;
|
||||
offsetTotal += replacement.length - 1;
|
||||
|
||||
return String(text).replace(/ $/, replacement);
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
this.args.lintTranslation.translation.text
|
||||
);
|
||||
}, this.args.lintTranslation.messages[0].text);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,6 @@
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.details,
|
||||
.messages {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.details {
|
||||
padding-right: 25px;
|
||||
}
|
||||
@ -54,6 +49,7 @@
|
||||
display: block;
|
||||
color: #959595;
|
||||
font-weight: 300;
|
||||
flex-shrink: 0;
|
||||
|
||||
&::before {
|
||||
content: '/';
|
||||
@ -79,7 +75,7 @@
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-size: 13px;
|
||||
color: var(--color-black);
|
||||
color: var(--text-color-normal);
|
||||
padding: 0;
|
||||
cursor: text;
|
||||
white-space: pre-wrap;
|
||||
@ -102,23 +98,23 @@
|
||||
.item-text {
|
||||
strong {
|
||||
color: var(--color-green);
|
||||
font-weight: normal;
|
||||
margin-left: 3px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
span {
|
||||
span[data-underline] {
|
||||
position: relative;
|
||||
color: var(--color-error);
|
||||
margin-right: 4px;
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: wavy;
|
||||
text-decoration-color: var(--color-error);
|
||||
text-decoration-skip-ink: none;
|
||||
text-decoration-thickness: 1px;
|
||||
}
|
||||
|
||||
span::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: var(--color-error);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
span[data-rect] {
|
||||
position: relative;
|
||||
background-color: var(--color-error);
|
||||
padding: 0 2px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,34 @@
|
||||
<div local-class='wrapper'>
|
||||
<ul local-class='messages'>
|
||||
{{#each @lintTranslation.messages as |message|}}
|
||||
<span local-class='description'>
|
||||
{{#if message.message}}
|
||||
{{message.message}}
|
||||
{{else}}
|
||||
{{t (concat 'components.translation_edit.lint_message.checks.' message.check)}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
<div local-class='details'>
|
||||
<LinkTo @route='logged-in.project.translation' @models={{array @project.id @lintTranslation.translation.id}} local-class='item-link'>
|
||||
<strong local-class='item-key'>
|
||||
{{this.translationKey.value}}
|
||||
<small local-class='item-key-prefix'>
|
||||
{{#if this.translationKey.prefix}}
|
||||
{{this.translationKey.prefix}}
|
||||
{{#if @lintTranslation.messages}}
|
||||
<div local-class='wrapper'>
|
||||
<ul local-class='messages'>
|
||||
{{#each this.messages as |message|}}
|
||||
<span local-class='description'>
|
||||
{{#if message.message}}
|
||||
{{message.message}}
|
||||
{{else}}
|
||||
{{@lintTranslation.translation.document.path}}
|
||||
{{t (concat 'components.translation_edit.lint_message.checks.' message.check)}}
|
||||
{{/if}}
|
||||
</small>
|
||||
</strong>
|
||||
</LinkTo>
|
||||
</div>
|
||||
</span>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
<div local-class='item-text'>{{{this.annotatedText}}}</div>
|
||||
</div>
|
||||
{{#if @project}}
|
||||
<div local-class='details'>
|
||||
<LinkTo @route='logged-in.project.translation' @models={{array @project.id @lintTranslation.translation.id}} local-class='item-link'>
|
||||
<strong local-class='item-key'>
|
||||
{{this.translationKey.value}}
|
||||
<small local-class='item-key-prefix'>
|
||||
{{#if this.translationKey.prefix}}
|
||||
{{this.translationKey.prefix}}
|
||||
{{else}}
|
||||
{{@lintTranslation.translation.document.path}}
|
||||
{{/if}}
|
||||
</small>
|
||||
</strong>
|
||||
</LinkTo>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div local-class='item-text'>{{{this.annotatedText}}}</div>
|
||||
</div>
|
||||
{{/if}}
|
@ -13,7 +13,7 @@
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0.1rem;
|
||||
letter-spacing: -0.4px;
|
||||
}
|
||||
|
||||
> svg {
|
||||
|
@ -8,7 +8,7 @@
|
||||
.section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 10px 0;
|
||||
margin: 6px 0;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
padding: 5px 12px 4px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
border-radius: var(--border-radius);
|
||||
margin-bottom: 3px;
|
||||
color: var(--text-color-normal);
|
||||
@ -74,9 +74,9 @@
|
||||
}
|
||||
|
||||
.list-item-link-text {
|
||||
width: 127px;
|
||||
padding: 0 0 0 10px;
|
||||
padding: 0 0 0 7px;
|
||||
opacity: 0.9;
|
||||
letter-spacing: -0.4px;
|
||||
}
|
||||
|
||||
.list-item-link-icon {
|
||||
|
@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
.project {
|
||||
padding: 20px 0 20px 20px;
|
||||
padding: 20px 0 20px 23px;
|
||||
margin-left: 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
@ -24,7 +24,7 @@
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
transition: 0.2s ease-in-out;
|
||||
transition-property: background, box-shadow, color;
|
||||
transition-property: background, box-shadow, color, transform;
|
||||
|
||||
strong {
|
||||
padding: 10px 20px 5px;
|
||||
@ -47,6 +47,7 @@
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
box-shadow: 0 3px 8px var(--shadow-color), 0 9px 12px var(--shadow-color);
|
||||
transform: scale(1.02);
|
||||
|
||||
.link-check {
|
||||
color: var(--color-primary);
|
||||
|
@ -49,7 +49,10 @@ export default class TranslationEditForm extends Component<Args> {
|
||||
apollo: Apollo;
|
||||
|
||||
@tracked
|
||||
lintMessages = this.args.lintMessages;
|
||||
lintTranslation = {
|
||||
translation: {id: this.args.translationId, text: this.args.value},
|
||||
messages: this.args.lintMessages,
|
||||
};
|
||||
|
||||
@tracked
|
||||
showTypeHints = true;
|
||||
@ -137,7 +140,9 @@ export default class TranslationEditForm extends Component<Args> {
|
||||
},
|
||||
});
|
||||
|
||||
this.lintMessages = data.viewer.project.translation.lintMessages;
|
||||
this.lintTranslation = Object.assign(this.lintTranslation, {
|
||||
messages: data.viewer.project.translation.lintMessages,
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -113,7 +113,5 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#each this.lintMessages as |message|}}
|
||||
<TranslationEdit::LintMessage @message={{message}} @onReplaceText={{fn this.replaceText}} />
|
||||
{{/each}}
|
||||
<LintTranslationsPage::Item @lintTranslation={{this.lintTranslation}} />
|
||||
</div>
|
@ -1,25 +0,0 @@
|
||||
import {inject as service} from '@ember/service';
|
||||
import IntlService from 'ember-intl/services/intl';
|
||||
import Component from '@glimmer/component';
|
||||
import {action} from '@ember/object';
|
||||
|
||||
interface Args {
|
||||
message: any;
|
||||
onReplaceText?: (value: string) => void;
|
||||
}
|
||||
|
||||
export default class LintMessage extends Component<Args> {
|
||||
@service('intl')
|
||||
intl: IntlService;
|
||||
|
||||
@action
|
||||
replaceText() {
|
||||
this.args.onReplaceText?.(this.args.message.replacement.value);
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.intl.t(
|
||||
`components.translation_edit.lint_message.checks.${this.args.message.check}`
|
||||
);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
.translation-edit-lint-message {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
padding: 4px 0 0;
|
||||
margin-bottom: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: 2px;
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
.text {
|
||||
padding: 0 4px;
|
||||
color: var(--color-error);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
margin-left: 5px;
|
||||
color: var(--color-grey);
|
||||
}
|
||||
|
||||
.replacement {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.replacement-text {
|
||||
color: var(--text-color-normal);
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
<div local-class='translation-edit-lint-message'>
|
||||
<span local-class='description'>
|
||||
{{#if @message.message}}
|
||||
{{@message.message}}
|
||||
{{else}}
|
||||
|
||||
{{this.description}}
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
{{#if @message.replacement}}
|
||||
<div local-class='replacement'>
|
||||
<span local-class='replacement-text'>
|
||||
{{truncate @message.replacement.value 500}}
|
||||
</span>
|
||||
|
||||
{{#if @onReplaceText}}
|
||||
<button class='button button--small button--filled button--white' {{on 'click' this.replaceText}}>
|
||||
{{t 'components.translation_edit.lint_message.replace'}}
|
||||
</button>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
@ -3,8 +3,8 @@
|
||||
}
|
||||
|
||||
.language {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
display: inline-block;
|
||||
margin-bottom: 4px;
|
||||
color: var(--color-black);
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
|
@ -2,8 +2,8 @@
|
||||
transition: 0.2s ease-in-out;
|
||||
transition-property: background, transform;
|
||||
display: block;
|
||||
margin: 4px 0 0;
|
||||
padding: 10px 10px 4px;
|
||||
margin: 0;
|
||||
padding: 4px 10px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
@ -15,6 +15,11 @@
|
||||
transform: translateX(-40px);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.item-updatedAt {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
&.item--editMode {
|
||||
@ -82,6 +87,7 @@
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
color: #959595;
|
||||
flex-shrink: 0;
|
||||
font-weight: 300;
|
||||
|
||||
&::before {
|
||||
@ -96,12 +102,12 @@
|
||||
gap: 2px;
|
||||
transition: 0.2s ease-in-out;
|
||||
transition-property: color;
|
||||
margin-right: 15px;
|
||||
margin-right: 10px;
|
||||
color: var(--color-primary);
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@ -113,7 +119,7 @@
|
||||
.item-text {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-size: 12px;
|
||||
font-size: 13px;
|
||||
color: var(--color-black);
|
||||
padding: 2px 0;
|
||||
cursor: text;
|
||||
@ -140,9 +146,13 @@
|
||||
}
|
||||
|
||||
.item-updatedAt {
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
margin-left: 5px;
|
||||
color: var(--color-grey);
|
||||
font-size: 11px;
|
||||
transition: 0.2s ease-in-out;
|
||||
transition-property: opacity, transform;
|
||||
}
|
||||
|
||||
.item-textEdit {
|
||||
|
@ -7,6 +7,9 @@ export default gql`
|
||||
id
|
||||
translation(id: $translationId) {
|
||||
id
|
||||
key
|
||||
text: correctedText
|
||||
|
||||
lintMessages(text: $text) {
|
||||
text
|
||||
message
|
||||
|
@ -27,6 +27,8 @@ export default gql`
|
||||
lintMessages {
|
||||
text
|
||||
check
|
||||
offset
|
||||
length
|
||||
message
|
||||
replacement {
|
||||
value
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Service, { inject as service } from '@ember/service';
|
||||
import Service, {inject as service} from '@ember/service';
|
||||
import RouterService from '@ember/routing/router-service';
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { BatchHttpLink } from 'apollo-link-batch-http';
|
||||
import {ApolloClient} from 'apollo-client';
|
||||
import {BatchHttpLink} from 'apollo-link-batch-http';
|
||||
import {
|
||||
IntrospectionFragmentMatcher,
|
||||
InMemoryCache,
|
||||
@ -11,7 +11,7 @@ import {
|
||||
|
||||
import Session from 'accent-webapp/services/session';
|
||||
|
||||
const dataIdFromObject = (result: { id?: string; __typename: string }) => {
|
||||
const dataIdFromObject = (result: {id?: string; __typename: string}) => {
|
||||
if (result.id && result.__typename) return `${result.__typename}${result.id}`;
|
||||
|
||||
return null;
|
||||
@ -25,9 +25,9 @@ const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
kind: 'INTERFACE',
|
||||
name: 'ProjectIntegration',
|
||||
possibleTypes: [
|
||||
{ name: 'ProjectIntegrationDiscord' },
|
||||
{ name: 'ProjectIntegrationSlack' },
|
||||
{ name: 'ProjectIntegrationGitHub' },
|
||||
{name: 'ProjectIntegrationDiscord'},
|
||||
{name: 'ProjectIntegrationSlack'},
|
||||
{name: 'ProjectIntegrationGitHub'},
|
||||
],
|
||||
},
|
||||
],
|
||||
@ -36,8 +36,8 @@ const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
});
|
||||
|
||||
const uri = '/graphql';
|
||||
const cache = new InMemoryCache({ dataIdFromObject, fragmentMatcher });
|
||||
const link = new BatchHttpLink({ uri, batchInterval: 1, batchMax: 1 });
|
||||
const cache = new InMemoryCache({dataIdFromObject, fragmentMatcher});
|
||||
const link = new BatchHttpLink({uri, batchInterval: 1, batchMax: 1});
|
||||
|
||||
const absintheBatchLink = new ApolloLink((operation, forward) => {
|
||||
return forward(operation).map((response: any) => response.payload);
|
||||
@ -48,7 +48,7 @@ const authLink = (getSession: any) => {
|
||||
const token = getSession().credentials.token;
|
||||
|
||||
if (token) {
|
||||
operation.setContext(({ headers = {} }: any) => ({
|
||||
operation.setContext(({headers = {}}: any) => ({
|
||||
headers: {
|
||||
...headers,
|
||||
authorization: `Bearer ${token}`,
|
||||
|
@ -7,7 +7,7 @@ export default class FromRoute extends Service {
|
||||
router: RouterService;
|
||||
|
||||
transitionTo(from: any | null, current: string, ...fallback: any[]) {
|
||||
if (from && !from.name.startsWith(current)) {
|
||||
if (from && from.name && !from.name.startsWith(current)) {
|
||||
this.router.transitionTo(
|
||||
from.name,
|
||||
...Object.values(from.parent.params as object)
|
||||
|
213
webapp/package-lock.json
generated
213
webapp/package-lock.json
generated
@ -40,7 +40,6 @@
|
||||
"ember-css-modules": "2.0.0",
|
||||
"ember-css-modules-sass": "1.1.0",
|
||||
"ember-fetch": "8.1.1",
|
||||
"ember-in-viewport": "4.0.0",
|
||||
"ember-inline-svg": "1.0.1",
|
||||
"ember-intl": "5.7.2",
|
||||
"ember-keyboard": "7.0.1",
|
||||
@ -2146,13 +2145,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/macros/-/macros-1.2.0.tgz",
|
||||
"integrity": "sha512-WD2V3OKXZB73OymI/zC2+MbqIYaAskhjtSOVVY6yG6kWILyVsJ6+fcbNHEnZyGqs4sm0TvHVJfevmA2OXV8Pww==",
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/macros/-/macros-1.13.2.tgz",
|
||||
"integrity": "sha512-AUgJ71xG8kjuTx8XB1AQNBiebJuXRfhcHr318dCwnQz9VRXdYSnEEqf38XRvGYIoCvIyn/3c72LrSwzaJqknOA==",
|
||||
"dependencies": {
|
||||
"@embroider/shared-internals": "1.2.0",
|
||||
"@embroider/shared-internals": "2.5.0",
|
||||
"assert-never": "^1.2.1",
|
||||
"babel-import-util": "^1.1.0",
|
||||
"babel-import-util": "^2.0.0",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"find-up": "^5.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
@ -2161,6 +2160,77 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": "12.* || 14.* || >= 16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@glint/template": "^1.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@glint/template": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/@embroider/shared-internals": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/shared-internals/-/shared-internals-2.5.0.tgz",
|
||||
"integrity": "sha512-7qzrb7GVIyNqeY0umxoeIvjDC+ay1b+wb2yCVuYTUYrFfLAkLEy9FNI3iWCi3RdQ9OFjgcAxAnwsAiPIMZZ3pQ==",
|
||||
"dependencies": {
|
||||
"babel-import-util": "^2.0.0",
|
||||
"debug": "^4.3.2",
|
||||
"ember-rfc176-data": "^0.3.17",
|
||||
"fs-extra": "^9.1.0",
|
||||
"js-string-escape": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"resolve-package-path": "^4.0.1",
|
||||
"semver": "^7.3.5",
|
||||
"typescript-memoize": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "12.* || 14.* || >= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/babel-import-util": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-import-util/-/babel-import-util-2.0.1.tgz",
|
||||
"integrity": "sha512-N1ZfNprtf/37x0R05J0QCW/9pCAcuI+bjZIK9tlu0JEkwEST7ssdD++gxHRbD58AiG5QE5OuNYhRoEFsc1wESw==",
|
||||
"engines": {
|
||||
"node": ">= 12.*"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/resolve-package-path": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/resolve-package-path/-/resolve-package-path-4.0.3.tgz",
|
||||
"integrity": "sha512-SRpNAPW4kewOaNUt8VPqhJ0UMxawMwzJD8V7m1cJfdSTK9ieZwS6K7Dabsm4bmLFM96Z5Y/UznrpG5kt1im8yA==",
|
||||
"dependencies": {
|
||||
"path-root": "^0.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/semver": {
|
||||
@ -2177,6 +2247,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/macros/node_modules/universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@embroider/shared-internals": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/shared-internals/-/shared-internals-1.2.0.tgz",
|
||||
@ -15533,22 +15611,6 @@
|
||||
"node": "8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/ember-in-viewport": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ember-in-viewport/-/ember-in-viewport-4.0.0.tgz",
|
||||
"integrity": "sha512-woEBMovlmRD8nV634GIqalOQV6AnmxleRE6XaWrKNmHMEHcg/IkmivWct+LdVFHCkSXi+kC36eiD/G9TVXo3eQ==",
|
||||
"dependencies": {
|
||||
"ember-auto-import": "^2.2.3",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-modifier": "^2.1.2 || ^3.0.0",
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"intersection-observer-admin": "~0.3.2",
|
||||
"raf-pool": "~0.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "12.* || 14.* || >= 16"
|
||||
}
|
||||
},
|
||||
"node_modules/ember-inline-svg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ember-inline-svg/-/ember-inline-svg-1.0.1.tgz",
|
||||
@ -19889,11 +19951,6 @@
|
||||
"integrity": "sha512-HaFMBi7r+oEC9iJNpc3bvcW7Z7iLmM26hPDmlb0mFwyANSsOQAtJxbdWsXITKOzZUyMYK0zYCv3h5yDj9TsiXg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
|
||||
@ -21937,11 +21994,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/intersection-observer-admin": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/intersection-observer-admin/-/intersection-observer-admin-0.3.2.tgz",
|
||||
"integrity": "sha512-kJEcF9iVRuI4thXiJd28UzFDgvFHBNUgwkKA4F0bPMmRdzc+1Eq7/J13n2gSgfZ5tsVxb+wJOV7k3DXcsc7D6Q=="
|
||||
},
|
||||
"node_modules/intl-messageformat": {
|
||||
"version": "9.11.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.11.4.tgz",
|
||||
@ -25411,11 +25463,6 @@
|
||||
"underscore.string": "~3.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/raf-pool": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/raf-pool/-/raf-pool-0.1.4.tgz",
|
||||
"integrity": "sha512-BBPamTVuSprPq7CUmgxc+ycbsYUtUYnQtJYEfMHXMaostPaNpQzipLfSa/rwjmlgjBPiD7G+I+8W340sLOPu6g=="
|
||||
},
|
||||
"node_modules/randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -30698,13 +30745,13 @@
|
||||
}
|
||||
},
|
||||
"@embroider/macros": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/macros/-/macros-1.2.0.tgz",
|
||||
"integrity": "sha512-WD2V3OKXZB73OymI/zC2+MbqIYaAskhjtSOVVY6yG6kWILyVsJ6+fcbNHEnZyGqs4sm0TvHVJfevmA2OXV8Pww==",
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/macros/-/macros-1.13.2.tgz",
|
||||
"integrity": "sha512-AUgJ71xG8kjuTx8XB1AQNBiebJuXRfhcHr318dCwnQz9VRXdYSnEEqf38XRvGYIoCvIyn/3c72LrSwzaJqknOA==",
|
||||
"requires": {
|
||||
"@embroider/shared-internals": "1.2.0",
|
||||
"@embroider/shared-internals": "2.5.0",
|
||||
"assert-never": "^1.2.1",
|
||||
"babel-import-util": "^1.1.0",
|
||||
"babel-import-util": "^2.0.0",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"find-up": "^5.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
@ -30712,6 +30759,55 @@
|
||||
"semver": "^7.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@embroider/shared-internals": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@embroider/shared-internals/-/shared-internals-2.5.0.tgz",
|
||||
"integrity": "sha512-7qzrb7GVIyNqeY0umxoeIvjDC+ay1b+wb2yCVuYTUYrFfLAkLEy9FNI3iWCi3RdQ9OFjgcAxAnwsAiPIMZZ3pQ==",
|
||||
"requires": {
|
||||
"babel-import-util": "^2.0.0",
|
||||
"debug": "^4.3.2",
|
||||
"ember-rfc176-data": "^0.3.17",
|
||||
"fs-extra": "^9.1.0",
|
||||
"js-string-escape": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"resolve-package-path": "^4.0.1",
|
||||
"semver": "^7.3.5",
|
||||
"typescript-memoize": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"babel-import-util": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-import-util/-/babel-import-util-2.0.1.tgz",
|
||||
"integrity": "sha512-N1ZfNprtf/37x0R05J0QCW/9pCAcuI+bjZIK9tlu0JEkwEST7ssdD++gxHRbD58AiG5QE5OuNYhRoEFsc1wESw=="
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"requires": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
|
||||
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6",
|
||||
"universalify": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"resolve-package-path": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/resolve-package-path/-/resolve-package-path-4.0.3.tgz",
|
||||
"integrity": "sha512-SRpNAPW4kewOaNUt8VPqhJ0UMxawMwzJD8V7m1cJfdSTK9ieZwS6K7Dabsm4bmLFM96Z5Y/UznrpG5kt1im8yA==",
|
||||
"requires": {
|
||||
"path-root": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
||||
@ -30719,6 +30815,11 @@
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -41875,19 +41976,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ember-in-viewport": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ember-in-viewport/-/ember-in-viewport-4.0.0.tgz",
|
||||
"integrity": "sha512-woEBMovlmRD8nV634GIqalOQV6AnmxleRE6XaWrKNmHMEHcg/IkmivWct+LdVFHCkSXi+kC36eiD/G9TVXo3eQ==",
|
||||
"requires": {
|
||||
"ember-auto-import": "^2.2.3",
|
||||
"ember-cli-babel": "^7.26.6",
|
||||
"ember-modifier": "^2.1.2 || ^3.0.0",
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"intersection-observer-admin": "~0.3.2",
|
||||
"raf-pool": "~0.1.4"
|
||||
}
|
||||
},
|
||||
"ember-inline-svg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ember-inline-svg/-/ember-inline-svg-1.0.1.tgz",
|
||||
@ -45361,11 +45449,6 @@
|
||||
"integrity": "sha512-HaFMBi7r+oEC9iJNpc3bvcW7Z7iLmM26hPDmlb0mFwyANSsOQAtJxbdWsXITKOzZUyMYK0zYCv3h5yDj9TsiXg==",
|
||||
"dev": true
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
|
||||
@ -46992,11 +47075,6 @@
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"intersection-observer-admin": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/intersection-observer-admin/-/intersection-observer-admin-0.3.2.tgz",
|
||||
"integrity": "sha512-kJEcF9iVRuI4thXiJd28UzFDgvFHBNUgwkKA4F0bPMmRdzc+1Eq7/J13n2gSgfZ5tsVxb+wJOV7k3DXcsc7D6Q=="
|
||||
},
|
||||
"intl-messageformat": {
|
||||
"version": "9.11.4",
|
||||
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.11.4.tgz",
|
||||
@ -49751,11 +49829,6 @@
|
||||
"underscore.string": "~3.3.4"
|
||||
}
|
||||
},
|
||||
"raf-pool": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/raf-pool/-/raf-pool-0.1.4.tgz",
|
||||
"integrity": "sha512-BBPamTVuSprPq7CUmgxc+ycbsYUtUYnQtJYEfMHXMaostPaNpQzipLfSa/rwjmlgjBPiD7G+I+8W340sLOPu6g=="
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
|
@ -59,7 +59,6 @@
|
||||
"ember-css-modules": "2.0.0",
|
||||
"ember-css-modules-sass": "1.1.0",
|
||||
"ember-fetch": "8.1.1",
|
||||
"ember-in-viewport": "4.0.0",
|
||||
"ember-inline-svg": "1.0.1",
|
||||
"ember-intl": "5.7.2",
|
||||
"ember-keyboard": "7.0.1",
|
||||
|
Loading…
Reference in New Issue
Block a user