Compare commits

...

28 Commits

Author SHA1 Message Date
Teffen Ellis
dea6e5d81a Fix typos. 2025-12-02 16:34:46 +01:00
Teffen Ellis
e9ebbc080c Clarify comment. 2025-12-02 16:34:46 +01:00
Teffen Ellis
be1052d428 Add additional regional codes. 2025-12-02 16:34:46 +01:00
Teffen Ellis
21cb17ca70 Remove comment. 2025-12-02 16:34:46 +01:00
Teffen Ellis
f646fa82fb Fix Han pattern. 2025-12-02 16:34:46 +01:00
Teffen Ellis
9982862826 web: Flesh out locale context. 2025-12-02 16:34:45 +01:00
Marcin Koziuk
f914af70f1 web/admin: fix brands default switch label (#18518) 2025-12-02 15:21:10 +00:00
dependabot[bot]
a46c5e5d89 web: bump express from 4.21.2 to 4.22.1 in /packages/docusaurus-config (#18520)
Bumps [express](https://github.com/expressjs/express) from 4.21.2 to 4.22.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.2...v4.22.1)

---
updated-dependencies:
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 15:43:19 +01:00
dependabot[bot]
1ebd7cf0f4 website: bump the goauthentik group in /website with 2 updates (#18513)
Bumps the goauthentik group in /website with 2 updates: [@goauthentik/eslint-config](https://github.com/goauthentik/authentik/tree/HEAD/packages/eslint-config) and [@goauthentik/docusaurus-config](https://github.com/goauthentik/authentik/tree/HEAD/packages/docusaurus-config).


Updates `@goauthentik/eslint-config` from 1.1.0 to 1.1.1
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits/HEAD/packages/eslint-config)

Updates `@goauthentik/docusaurus-config` from 2.2.1 to 2.2.2
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits/HEAD/packages/docusaurus-config)

---
updated-dependencies:
- dependency-name: "@goauthentik/eslint-config"
  dependency-version: 1.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: goauthentik
- dependency-name: "@goauthentik/docusaurus-config"
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: goauthentik
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 15:28:58 +01:00
authentik-automation[bot]
5a7a76f9b3 core, web: update translations (#18510)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-12-02 14:34:49 +01:00
dependabot[bot]
f607378487 ci: bump softprops/action-gh-release from 2.4.2 to 2.5.0 (#18512)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 14:32:47 +01:00
dependabot[bot]
e114a68505 core: bump astral-sh/uv from 0.9.13 to 0.9.14 (#18514)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 14:32:13 +01:00
dependabot[bot]
ebe028f3c9 core: bump goauthentik/fips-debian from de70579 to c718f60 (#18515)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 14:31:59 +01:00
Connor Peshek
eb60276846 integrations/slack: Add SCIM tutorial (#18508)
* integrations/slack: Add SCIM tutorial

* Update wording

* Update index.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Connor Peshek <connor@connorpeshek.me>

* Small changes

---------

Signed-off-by: Connor Peshek <connor@connorpeshek.me>
Co-authored-by: connor peshek <connorpeshek@connors-MacBook-Pro.local>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: dewi-tik <dewi@goauthentik.io>
2025-12-02 04:28:26 -06:00
Teffen Ellis
952a0f796d translate: fix source locale not matching transifex (#18503)
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-12-01 19:08:58 +00:00
Teffen Ellis
b7205ff167 web: Fixes for Docusaurus & ESlint Upgrade (#18452)
* Fix style regressions in Docusaurus 3.9

* Fix ignore file regression.

* Bump package versions.

* Update packages/docusaurus-config/css/navbar.css

Co-authored-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>

---------

Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Co-authored-by: Ken Sternberg <133134217+kensternberg-authentik@users.noreply.github.com>
2025-12-01 13:57:32 -05:00
Marc 'risson' Schmitt
5379c509d6 translate: fix config (#18504)
Co-authored-by: Teffen Ellis <teffen@goauthentik.io>
2025-12-01 18:20:14 +00:00
Marc 'risson' Schmitt
63119df516 core, web: unified locales (#18502)
Co-authored-by: Teffen Ellis <teffen@goauthentik.io>
2025-12-01 18:47:44 +01:00
transifex-integration[bot]
cd53ab5eba translate: Updates for project authentik and language ko (#18488)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:56:30 +00:00
transifex-integration[bot]
5aa7a1c62d translate: Updates for project authentik and language es (#18485)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:54:55 +00:00
transifex-integration[bot]
092c8a3db4 translate: Updates for project authentik and language zh_TW (#18499)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:50:40 +00:00
transifex-integration[bot]
9d8427b1b4 translate: Updates for project authentik and language ru (#18500)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:49:31 +00:00
transifex-integration[bot]
92556ca783 translate: Updates for project authentik and language pt (#18498)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:46:20 +00:00
transifex-integration[bot]
d5c2aedc8e translate: Updates for project authentik and language fr (#18496)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:46:08 +00:00
transifex-integration[bot]
02304081ed translate: Updates for project authentik and language de (#18487)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:45:48 +00:00
transifex-integration[bot]
d60b6faa61 translate: Updates for project authentik and language nl (#18497)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:45:29 +00:00
transifex-integration[bot]
b12d1ed410 translate: Updates for project authentik and language fi (#18490)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-12-01 16:44:45 +00:00
authentik-automation[bot]
1276d87d69 core, web: update translations (#18380)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-12-01 17:01:05 +01:00
135 changed files with 146958 additions and 208475 deletions

View File

@@ -1,3 +1,4 @@
---
git:
filters:
- filter_type: file

View File

@@ -89,7 +89,7 @@ jobs:
git tag "version/${{ inputs.version }}" HEAD -m "version/${{ inputs.version }}"
git push --follow-tags
- name: Create Release
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
token: "${{ steps.app-token.outputs.token }}"
tag_name: "version/${{ inputs.version }}"

View File

@@ -76,7 +76,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
# Stage 4: Download uv
FROM ghcr.io/astral-sh/uv:0.9.13@sha256:f07d1bf7b1fb4b983eed2b31320e25a2a76625bdf83d5ff0208fe105d4d8d2f5 AS uv
FROM ghcr.io/astral-sh/uv:0.9.14@sha256:fef8e5fb8809f4b57069e919ffcd1529c92b432a2c8d8ad1768087b0b018d840 AS uv
# Stage 5: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.9-slim-trixie-fips@sha256:700fc8c1e290bd14e5eaca50b1d8e8c748c820010559cbfb4c4f8dfbe2c4c9ff AS python-base

View File

@@ -1,9 +1,11 @@
{% load static %}
{% load i18n %}
{% load authentik_core %}
{% get_current_language as LANGUAGE_CODE %}
<!DOCTYPE html>
<html
lang="{{ LANGUAGE_CODE }}"
data-theme="{% if ui_theme == "dark" %}dark{% else %}light{% endif %}"
data-theme-choice="{% if ui_theme == "dark" %}dark{% elif ui_theme == "light" %}light{% else %}auto{% endif %}"
>
@@ -15,6 +17,7 @@
<title>{% block title %}{% trans title|default:brand.branding_title %}{% endblock %}</title>
<link rel="icon" href="{{ brand.branding_favicon_url }}">
<link rel="shortcut icon" href="{{ brand.branding_favicon_url }}">
{% block head_before %}
{% endblock %}

View File

@@ -36,39 +36,37 @@
<ak-skip-to-content></ak-skip-to-content>
<ak-message-container></ak-message-container>
<ak-locale-context>
<div class="pf-c-page__drawer">
<div class="pf-c-drawer pf-m-collapsed" id="flow-drawer">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<ak-flow-executor
slug="{{ flow.slug }}"
class="pf-c-login"
data-layout="{{ flow.layout|default:'stacked' }}"
>
{% include "base/placeholder.html" %}
<div class="pf-c-page__drawer">
<div class="pf-c-drawer pf-m-collapsed" id="flow-drawer">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<ak-flow-executor
slug="{{ flow.slug }}"
class="pf-c-login"
data-layout="{{ flow.layout|default:'stacked' }}"
>
{% include "base/placeholder.html" %}
<ak-brand-links
slot="footer"
exportparts="list:brand-links-list, list-item:brand-links-list-item"
role="contentinfo"
aria-label="{% trans 'Site footer' %}"
class="pf-c-login__footer {% if flow.layout == 'stacked' %}pf-m-dark{% endif %}"
></ak-brand-links>
</ak-flow-executor>
</div>
<ak-brand-links
slot="footer"
exportparts="list:brand-links-list, list-item:brand-links-list-item"
role="contentinfo"
aria-label="{% trans 'Site footer' %}"
class="pf-c-login__footer {% if flow.layout == 'stacked' %}pf-m-dark{% endif %}"
></ak-brand-links>
</ak-flow-executor>
</div>
<ak-flow-inspector
id="flow-inspector"
data-registration="lazy"
class="pf-c-drawer__panel pf-m-width-33"
slug="{{ flow.slug }}"
></ak-flow-inspector>
</div>
<ak-flow-inspector
id="flow-inspector"
data-registration="lazy"
class="pf-c-drawer__panel pf-m-width-33"
slug="{{ flow.slug }}"
></ak-flow-inspector>
</div>
</div>
</div>
</ak-locale-context>
</div>
{% endblock %}

View File

@@ -31,7 +31,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
go build -o /go/ldap ./cmd/ldap
# Stage 2: Run
FROM ghcr.io/goauthentik/fips-debian:trixie-slim-fips@sha256:de70579f5610286c5f0824180eff168cfc85a2f8a81d9190a2c4f81f52dc6db7
FROM ghcr.io/goauthentik/fips-debian:trixie-slim-fips@sha256:c718f608885a76a8940700b0c9feab75b1c967e1c291adf52dcd3ad6f6a86a66
ARG VERSION
ARG GIT_BUILD_HASH

Binary file not shown.

View File

@@ -18,7 +18,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Václav Nováček <waclaw661@gmail.com>, 2025\n"
"Language-Team: Czech (Czech Republic) (https://app.transifex.com/authentik/teams/119923/cs_CZ/)\n"
@@ -391,6 +391,12 @@ msgstr "Zobrazované jméno zdroje."
msgid "Internal source name, used in URLs."
msgstr "Interní jméno zdroje, používané v URL."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Tok používaný při ověřování existujících uživatelů."
@@ -591,6 +597,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token zařízení"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Tokeny zařízení"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -599,6 +615,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr ""
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2049,14 +2121,6 @@ msgstr "Obnovovací token OAuth2"
msgid "OAuth2 Refresh Tokens"
msgstr "Obnovovací tokeny OAuth2"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token zařízení"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Tokeny zařízení"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

View File

@@ -27,7 +27,6 @@
# Stefan Werner, 2024
# Jonas, 2025
# Niklas Kroese, 2025
# 97cce0ae0cad2a2cc552d3165d04643e_de3d740, 2025
# Dominic Wagner <mail@dominic-wagner.de>, 2025
# Till-Frederik Riechard, 2025
# Alexander Mnich, 2025
@@ -35,20 +34,21 @@
# datenschmutz, 2025
# Ulrich Stark, 2025
# Benjamin Böhmke, 2025
# 97cce0ae0cad2a2cc552d3165d04643e_de3d740, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Benjamin Böhmke, 2025\n"
"Last-Translator: 97cce0ae0cad2a2cc552d3165d04643e_de3d740, 2025\n"
"Language-Team: German (https://app.transifex.com/authentik/teams/119923/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de\n"
"Language: de_DE\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentik/admin/models.py
@@ -420,6 +420,12 @@ msgstr "Quellname"
msgid "Internal source name, used in URLs."
msgstr "Interner Quellname, genutzt für URLs"
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Flow der zur Authorisierung bereits ersteller Nutzer verwendet wird"
@@ -621,6 +627,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Geräte-Token"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Geräte-Token"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -629,6 +645,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Gerät"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2110,14 +2182,6 @@ msgstr "OAuth2-Aktualisierungs-Token"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2-Aktualisierungs-Token"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Geräte-Token"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Geräte-Token"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr "Eine Back-Channel-Logout-Anfrage an den registrierten Client senden."

Binary file not shown.

View File

@@ -8,15 +8,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 17:05+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentik/admin/models.py
msgid "Version history"
@@ -348,6 +347,12 @@ msgstr ""
msgid "Internal source name, used in URLs."
msgstr ""
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr ""
@@ -540,6 +545,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -548,6 +563,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr ""
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -1873,14 +1944,6 @@ msgstr ""
msgid "OAuth2 Refresh Tokens"
msgstr ""
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr ""
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr ""
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

Binary file not shown.

Binary file not shown.

View File

@@ -16,14 +16,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/authentik/teams/119923/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es\n"
"Language: es_ES\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: authentik/admin/models.py
@@ -394,6 +394,12 @@ msgstr "Nombre de visualización de la fuente."
msgid "Internal source name, used in URLs."
msgstr "Nombre de origen interno, utilizado en las URL."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Flujo que se utilizará al autenticar a los usuarios existentes."
@@ -595,6 +601,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token de Dispositivo"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Tokens de Dispositivo"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -603,6 +619,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Dispositivo"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2064,14 +2136,6 @@ msgstr "Token de Actualización OAuth2"
msgid "OAuth2 Refresh Tokens"
msgstr "Tokens de Actualización OAuth2"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token de Dispositivo"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Tokens de Dispositivo"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

View File

@@ -15,14 +15,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Skyler Mäntysaari, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/authentik/teams/119923/fi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fi\n"
"Language: fi_FI\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentik/admin/models.py
@@ -382,6 +382,12 @@ msgstr "Lähteen näytettävä nimi."
msgid "Internal source name, used in URLs."
msgstr "Lähteen sisäinen nimi, käytetään URLeissa."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Prosessi, jota käytetään kun todennetaan olemassa olevia käyttäjiä."
@@ -582,6 +588,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Laitetunniste"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Laitetunnisteet"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -590,6 +606,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Laite"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2048,14 +2120,6 @@ msgstr "OAuth2-päivitystunnus"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2-päivitystunnukset"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Laitetunniste"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Laitetunnisteet"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

View File

@@ -19,14 +19,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Charles Leclerc, 2025\n"
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: fr\n"
"Language: fr_FR\n"
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: authentik/admin/models.py
@@ -397,6 +397,12 @@ msgstr "Nom d'affichage de la source."
msgid "Internal source name, used in URLs."
msgstr "Nom interne de la source, utilisé dans les URLs."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Flux à utiliser pour authentifier les utilisateurs existants."
@@ -599,6 +605,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Jeton d'équipement"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Jetons d'équipement"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -607,6 +623,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Équipement"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2088,14 +2160,6 @@ msgstr "Jeton de rafraîchissement OAuth2"
msgid "OAuth2 Refresh Tokens"
msgstr "Jetons de rafraîchissement OAuth2"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Jeton d'équipement"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Jetons d'équipement"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr "Envoyer une requête de déconnexion Back-Channel au client enregistré"

Binary file not shown.

Binary file not shown.

View File

@@ -11,23 +11,23 @@
# Nicola Mersi, 2024
# tmassimi, 2024
# Marc Schmitt, 2024
# Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025
# Matteo Piccina <altermatte@gmail.com>, 2025
# albanobattistella <albanobattistella@gmail.com>, 2025
# Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-20 00:11+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: albanobattistella <albanobattistella@gmail.com>, 2025\n"
"Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n"
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Language: it_IT\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: authentik/admin/models.py
@@ -389,6 +389,12 @@ msgstr "Nome visualizzato della sorgente."
msgid "Internal source name, used in URLs."
msgstr "Nome interno della sorgente, utilizzato negli URL."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Flusso da usare per autenticare utenti esistenti."
@@ -421,7 +427,7 @@ msgstr "Token"
msgid "Tokens"
msgstr "Tokens"
#: authentik/core/models.py
#: authentik/core/models.py authentik/endpoints/connectors/agent/models.py
msgid "View token's key"
msgstr "Visualizza la chiave token"
@@ -493,6 +499,7 @@ msgid "Remove temporary users created by SAML Sources."
msgstr "Rimuovi gli utenti temporanei creati da SAML Sources."
#: authentik/core/templates/if/error.html
#: authentik/policies/templates/policies/denied.html
msgid "Go home"
msgstr "Vai alla pagina iniziale"
@@ -524,6 +531,26 @@ msgstr "rsa"
msgid "ecdsa"
msgstr "ecdsa"
#: authentik/crypto/models.py
msgid "RSA"
msgstr ""
#: authentik/crypto/models.py
msgid "Elliptic Curve"
msgstr ""
#: authentik/crypto/models.py
msgid "DSA"
msgstr ""
#: authentik/crypto/models.py
msgid "Ed25519"
msgstr ""
#: authentik/crypto/models.py
msgid "Ed448"
msgstr ""
#: authentik/crypto/models.py
msgid "PEM-encoded Certificate data"
msgstr "Dati del certificato in codifica PEM"
@@ -548,6 +575,104 @@ msgstr "Coppie certificato-chiave"
msgid "Discover, import and update certificates from the filesystem."
msgstr "Scopri, importa e aggiorna i certificati dal file system."
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Selected platform not supported"
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Token is expired"
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Invalid token for connector"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Agent Connector"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token Dispositivo"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Token Dispositivi"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Dispositivo"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
#: authentik/enterprise/api.py
msgid "Enterprise is required to create/update this object."
msgstr "Versione Enterprise richiesta per creare/aggiornare questo oggetto"
@@ -1211,10 +1336,22 @@ msgstr "Token del flusso"
msgid "Flow Tokens"
msgstr "Tokens del flusso"
#: authentik/flows/templates/if/flow.html
msgid "Site footer"
msgstr ""
#: authentik/flows/views/executor.py
msgid "Invalid next URL"
msgstr "URL successivo non valido"
#: authentik/lib/sync/outgoing/models.py
msgid "Controls the number of objects synced in a single task"
msgstr ""
#: authentik/lib/sync/outgoing/models.py
msgid "Timeout for synchronization of a single page"
msgstr ""
#: authentik/lib/sync/outgoing/models.py
msgid ""
"When enabled, provider will not modify or create objects in the remote "
@@ -1613,6 +1750,10 @@ msgstr "Avatar utente"
msgid "Not you?"
msgstr "Non sei tu?"
#: authentik/policies/templates/policies/denied.html
msgid "Error"
msgstr "Errore"
#: authentik/policies/templates/policies/denied.html
msgid "Request has been denied."
msgstr "La richiesta è stata negata."
@@ -1994,14 +2135,6 @@ msgstr "Token di aggiornamento OAuth2"
msgid "OAuth2 Refresh Tokens"
msgstr "Tokens di aggiornamento OAuth2"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token Dispositivo"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Token Dispositivi"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""
@@ -2238,18 +2371,6 @@ msgstr "Impossibile importare i metadati: {messages}"
msgid "ACS URL"
msgstr "URL ACS"
#: authentik/providers/saml/models.py
msgid ""
"Value of the audience restriction field of the assertion. When left empty, "
"no audience restriction will be added."
msgstr ""
"Valore del campo di limitazione del pubblico dell'asserzione. Se lasciato "
"vuoto, non verrà aggiunta alcuna restrizione sul pubblico."
#: authentik/providers/saml/models.py
msgid "Also known as EntityID"
msgstr "Conosciuto anche come EntityID"
#: authentik/providers/saml/models.py
msgid "Service Provider Binding"
msgstr "Associazione fornitore di servizi"
@@ -2262,6 +2383,18 @@ msgstr ""
"Ciò determina il modo in cui authentik invia la risposta al fornitore di "
"servizi."
#: authentik/providers/saml/models.py
msgid ""
"Value of the audience restriction field of the assertion. When left empty, "
"no audience restriction will be added."
msgstr ""
"Valore del campo di limitazione del pubblico dell'asserzione. Se lasciato "
"vuoto, non verrà aggiunta alcuna restrizione sul pubblico."
#: authentik/providers/saml/models.py
msgid "Also known as EntityID"
msgstr "Conosciuto anche come EntityID"
#: authentik/providers/saml/models.py
msgid "SLS URL"
msgstr ""

View File

@@ -19,14 +19,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-10 00:11+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Teffen Ellis, 2025\n"
"Language-Team: Japanese (https://app.transifex.com/authentik/teams/119923/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ja\n"
"Language: ja_JP\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: authentik/admin/models.py
@@ -363,6 +363,12 @@ msgstr "ソースの表示名。"
msgid "Internal source name, used in URLs."
msgstr "URLで使用される内部ソース名。"
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "フローは既存のユーザーを認証するときに使用されます。"
@@ -391,7 +397,7 @@ msgstr "トークン"
msgid "Tokens"
msgstr "トークン"
#: authentik/core/models.py
#: authentik/core/models.py authentik/endpoints/connectors/agent/models.py
msgid "View token's key"
msgstr "トークンのキーを表示"
@@ -461,6 +467,7 @@ msgid "Remove temporary users created by SAML Sources."
msgstr "SAMLで作成された一時ユーザを削除。"
#: authentik/core/templates/if/error.html
#: authentik/policies/templates/policies/denied.html
msgid "Go home"
msgstr "ホームに戻る"
@@ -534,6 +541,104 @@ msgstr "証明書とキーのペア"
msgid "Discover, import and update certificates from the filesystem."
msgstr "証明書をファイルシステムから検出、インポート、更新する。"
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Selected platform not supported"
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Token is expired"
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Invalid token for connector"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Agent Connector"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "デバイストークン"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "デバイストークン"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr ""
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
#: authentik/enterprise/api.py
msgid "Enterprise is required to create/update this object."
msgstr "このオブジェクトの作成/更新にはエンタープライズ契約が必要です。"
@@ -1143,6 +1248,10 @@ msgstr "フロートークン"
msgid "Flow Tokens"
msgstr "フロートークン"
#: authentik/flows/templates/if/flow.html
msgid "Site footer"
msgstr ""
#: authentik/flows/views/executor.py
msgid "Invalid next URL"
msgstr "無効なネクスト URL"
@@ -1522,6 +1631,10 @@ msgstr "アバター"
msgid "Not you?"
msgstr "あなたではありませんか?"
#: authentik/policies/templates/policies/denied.html
msgid "Error"
msgstr ""
#: authentik/policies/templates/policies/denied.html
msgid "Request has been denied."
msgstr "リクエストは拒否されました。"
@@ -1877,14 +1990,6 @@ msgstr "OAuth2 リフレッシュトークン"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2 リフレッシュトークン"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "デバイストークン"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "デバイストークン"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr "登録されたクライアントにバックチャネルログアウトリクエストを送信"

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -19,14 +19,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Alex Kruidenberg <alexkruidenberg@hotmail.com>, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/authentik/teams/119923/nl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: nl\n"
"Language: nl_NL\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: authentik/admin/models.py
@@ -388,6 +388,12 @@ msgstr "Weergavenaam van de bron."
msgid "Internal source name, used in URLs."
msgstr "Interne naam van de bron, gebruikt in URL's."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Flow om te gebruiken bij het authenticeren van bestaande gebruikers."
@@ -588,6 +594,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Apparaattoken"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Apparaattokens"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -596,6 +612,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr ""
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2022,14 +2094,6 @@ msgstr "OAuth2 Verversingstoken"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2 Verversingstokens"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Apparaattoken"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Apparaattokens"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -20,7 +20,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Rafael Mundel, 2025\n"
"Language-Team: Portuguese (Brazil) (https://app.transifex.com/authentik/teams/119923/pt_BR/)\n"
@@ -390,6 +390,12 @@ msgstr "Nome de exibição da fonte."
msgid "Internal source name, used in URLs."
msgstr "Nome da fonte interna, usado em URLs."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Fluxo a ser usado ao autenticar usuários existentes."
@@ -590,6 +596,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token do dispositivo"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Tokens de dispositivo"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -598,6 +614,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Dispositivo"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2047,14 +2119,6 @@ msgstr "Token de Atualização OAuth2"
msgid "OAuth2 Refresh Tokens"
msgstr "Tokens de Atualização OAuth2"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Token do dispositivo"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Tokens de dispositivo"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -18,14 +18,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: Russian (https://app.transifex.com/authentik/teams/119923/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru\n"
"Language: ru_RU\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
#: authentik/admin/models.py
@@ -388,6 +388,12 @@ msgstr "Отображаемое имя источника."
msgid "Internal source name, used in URLs."
msgstr "Внутреннее имя источника, используемое в URL-адресах."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Поток, используемый при аутентификации существующих пользователей."
@@ -589,6 +595,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Токен устройства"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Токены устройства"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -597,6 +613,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr ""
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2021,14 +2093,6 @@ msgstr "OAuth2 Refresh токен"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2 Refresh токены"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Токен устройства"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Токены устройства"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

Binary file not shown.

Binary file not shown.

View File

@@ -13,14 +13,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Turkish (https://app.transifex.com/authentik/teams/119923/tr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: tr\n"
"Language: tr_TR\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: authentik/admin/models.py
@@ -381,6 +381,12 @@ msgstr "Kaynağın görünen Adı."
msgid "Internal source name, used in URLs."
msgstr "URL'lerde kullanılan iç kaynak adı."
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "Mevcut kullanıcıların kimliğini doğrularken kullanılacak akış."
@@ -581,6 +587,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Cihaz Jetonu"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Cihaz Jetonları"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -589,6 +605,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "Cihaz"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -2008,14 +2080,6 @@ msgstr "OAuth2 Yenileme Jetonu"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2 Yenileme Jetonları"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "Cihaz Jetonu"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "Cihaz Jetonları"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -2,27 +2,28 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#
# Translators:
# Chen Zhikai, 2022
# 刘松, 2022
# deluxghost, 2025
# RocketDev, 2025
# Jens L. <jens@goauthentik.io>, 2025
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-25 00:09+0000\n"
"POT-Creation-Date: 2025-12-01 17:03+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Jens L. <jens@goauthentik.io>, 2025\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/"
"119923/zh_CN/)\n"
"Language: zh_Hans\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: authentik/admin/models.py
@@ -80,13 +81,14 @@ msgstr "由 authentik 管理"
#: authentik/blueprints/models.py
msgid ""
"Objects that are managed by authentik. These objects are created and updated"
" automatically. This flag only indicates that an object can be overwritten "
"by migrations. You can still modify the objects via the API, but expect "
"changes to be overwritten in a later update."
"Objects that are managed by authentik. These objects are created and updated "
"automatically. This flag only indicates that an object can be overwritten by "
"migrations. You can still modify the objects via the API, but expect changes "
"to be overwritten in a later update."
msgstr ""
"由 authentik 管理的对象。这些对象会自动创建和更新。此标记仅仅表明对象可以被 Migration 覆盖。您仍然可以通过 API "
"修改对象,但这些修改可能会在之后的更新中被覆盖。"
"由 authentik 管理的对象。这些对象会自动创建和更新。此标记仅仅表明对象可以被 "
"Migration 覆盖。您仍然可以通过 API 修改对象,但这些修改可能会在之后的更新中被"
"覆盖。"
#: authentik/blueprints/models.py
msgid "Blueprint Instance"
@@ -161,9 +163,10 @@ msgstr "无法设置组自身为父级。"
#: authentik/core/api/providers.py
msgid ""
"When not set all providers are returned. When set to true, only backchannel "
"providers are returned. When set to false, backchannel providers are "
"excluded"
msgstr "如果未设置,则返回所有提供程序。如果启用,仅返回反向通道提供程序。如果禁用,则返回非反向通道提供程序"
"providers are returned. When set to false, backchannel providers are excluded"
msgstr ""
"如果未设置,则返回所有提供程序。如果启用,仅返回反向通道提供程序。如果禁用,"
"则返回非反向通道提供程序"
#: authentik/core/api/transactional_applications.py
#, python-brace-format
@@ -320,7 +323,8 @@ msgstr "使用源特定的标识符"
msgid ""
"Link to a user with identical email address. Can have security implications "
"when a source doesn't validate email addresses."
msgstr "链接到电子邮件地址相同的用户。当源不验证电子邮件地址时,可能会有安全隐患。"
msgstr ""
"链接到电子邮件地址相同的用户。当源不验证电子邮件地址时,可能会有安全隐患。"
#: authentik/core/models.py
msgid ""
@@ -358,6 +362,12 @@ msgstr "源的显示名称。"
msgid "Internal source name, used in URLs."
msgstr "源的内部名称,在 URL 中使用。"
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "认证已存在用户时所使用的流程。"
@@ -374,8 +384,8 @@ msgstr "源怎样确定应该验证已有用户的身份还是注册新用户。
#: authentik/core/models.py
msgid ""
"How the source determines if an existing group should be used or a new group"
" created."
"How the source determines if an existing group should be used or a new group "
"created."
msgstr "源怎样确定应该使用已有组的身份还是创建新组。"
#: authentik/core/models.py authentik/providers/scim/models.py
@@ -550,6 +560,16 @@ msgstr ""
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "设备令牌"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "设备令牌"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
@@ -558,6 +578,62 @@ msgstr ""
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "设备"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
@@ -616,7 +692,9 @@ msgstr "用户密码历史记录"
msgid ""
"Check if any UniquePasswordPolicy exists, and if not, purge the password "
"history table."
msgstr "检查是否存在任何 UniquePasswordPolicy 策略,如果不存在,则清除密码历史记录表。"
msgstr ""
"检查是否存在任何 UniquePasswordPolicy 策略,如果不存在,则清除密码历史记录"
"表。"
#: authentik/enterprise/policies/unique_password/tasks.py
msgid "Remove user password history that are too old."
@@ -828,9 +906,9 @@ msgstr "正在验证您的浏览器…"
#: authentik/enterprise/stages/mtls/models.py
msgid ""
"Configure certificate authorities to validate the certificate against. This "
"option has a higher priority than the `client_certificate` option on "
"`Brand`."
msgstr "配置用于验证证书的证书机构。此选项的优先级比“品牌”中的“客户端证书”更高。"
"option has a higher priority than the `client_certificate` option on `Brand`."
msgstr ""
"配置用于验证证书的证书机构。此选项的优先级比“品牌”中的“客户端证书”更高。"
#: authentik/enterprise/stages/mtls/models.py
msgid "Mutual TLS Stage"
@@ -856,7 +934,8 @@ msgstr "未找到证书的用户。"
msgid ""
"Amount of time a user can take to return from the source to continue the "
"flow (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr "用户从源返回并继续流程可以消耗的时间格式hours=-1;minutes=-2;seconds=-3"
msgstr ""
"用户从源返回并继续流程可以消耗的时间格式hours=-1;minutes=-2;seconds=-3"
#: authentik/enterprise/stages/source/models.py
msgid "Source Stage"
@@ -890,8 +969,7 @@ msgstr "通用 Webhook"
msgid "Slack Webhook (Slack/Discord)"
msgstr "Slack WebhookSlack/Discord"
#: authentik/events/models.py
#: authentik/stages/authenticator_validate/models.py
#: authentik/events/models.py authentik/stages/authenticator_validate/models.py
msgid "Email"
msgstr "电子邮箱"
@@ -957,7 +1035,9 @@ msgstr "通知"
msgid ""
"Select which transports should be used to notify the user. If none are "
"selected, the notification will only be shown in the authentik UI."
msgstr "选择应使用哪些传输方式来通知用户。如果未选择任何内容,则通知将仅显示在 authentik UI 中。"
msgstr ""
"选择应使用哪些传输方式来通知用户。如果未选择任何内容,则通知将仅显示在 "
"authentik UI 中。"
#: authentik/events/models.py
msgid "Controls which severity level the created notifications will have."
@@ -973,7 +1053,9 @@ msgstr "定义此通知应该发送到哪些用户组。如果留空,则不会
msgid ""
"When enabled, notification will be sent to user the user that triggered the "
"event.When destination_group is configured, notification is sent to both."
msgstr "启用时,通知会被发送到触发事件的用户。当配置了 destination_group 时,通知也会同时发送到对应组。"
msgstr ""
"启用时,通知会被发送到触发事件的用户。当配置了 destination_group 时,通知也会"
"同时发送到对应组。"
#: authentik/events/models.py
msgid "Notification Rule"
@@ -1086,7 +1168,9 @@ msgstr "显示为流程页面中的标题。"
msgid ""
"Decides what this Flow is used for. For example, the Authentication flow is "
"redirect to when an un-authenticated user visits authentik."
msgstr "决定此流程的用途。例如,当未经身份验证的用户访问 authentik 时,会重定向到身份验证流程。"
msgstr ""
"决定此流程的用途。例如,当未经身份验证的用户访问 authentik 时,会重定向到身份"
"验证流程。"
#: authentik/flows/models.py
msgid "Background shown during execution"
@@ -1094,8 +1178,8 @@ msgstr "执行时的背景"
#: authentik/flows/models.py
msgid ""
"Enable compatibility mode, increases compatibility with password managers on"
" mobile devices."
"Enable compatibility mode, increases compatibility with password managers on "
"mobile devices."
msgstr "启用兼容模式,增强与移动设备上密码管理器的兼容性。"
#: authentik/flows/models.py
@@ -1141,8 +1225,9 @@ msgid ""
"executor. RESTART restarts the flow from the beginning, and "
"RESTART_WITH_CONTEXT restarts the flow while keeping the current context."
msgstr ""
"配置流程执行器应如何处理对质询的无效响应。RETRY 向执行器返回错误消息和类似的质询。RESTART "
"从头开始重新启动流程RESTART_WITH_CONTEXT 在保留当前上下文的同时重新启动流程。"
"配置流程执行器应如何处理对质询的无效响应。RETRY 向执行器返回错误消息和类似的"
"质询。RESTART 从头开始重新启动流程RESTART_WITH_CONTEXT 在保留当前上下文的同"
"时重新启动流程。"
#: authentik/flows/models.py
msgid "Flow Stage Binding"
@@ -1156,7 +1241,8 @@ msgstr "流程阶段绑定"
msgid ""
"Flow used by an authenticated user to configure this Stage. If empty, user "
"will not be able to configure this stage."
msgstr "经过身份验证的用户用来配置此阶段的流程。如果为空,用户将无法配置此阶段。"
msgstr ""
"经过身份验证的用户用来配置此阶段的流程。如果为空,用户将无法配置此阶段。"
#: authentik/flows/models.py
msgid "Flow Token"
@@ -1226,8 +1312,8 @@ msgid ""
"Can be in the format of 'unix://<path>' when connecting to a local docker "
"daemon, or 'https://<hostname>:2376' when connecting to a remote system."
msgstr ""
"当连接到本地 Docker "
"守护进程时可以使用“unix://<path>”格式,或者在连接远程系统时使用“https://<hostname>:2376”格式。"
"当连接到本地 Docker 守护进程时可以使用“unix://<path>”格式,或者在连接远程系"
"统时使用“https://<hostname>:2376”格式。"
#: authentik/outposts/models.py
msgid ""
@@ -1269,9 +1355,11 @@ msgstr "Kubernetes 服务连接"
#: authentik/outposts/models.py
msgid ""
"Select Service-Connection authentik should use to manage this outpost. Leave"
" empty if authentik should not handle the deployment."
msgstr "选择 authentik 在管理此前哨时需要使用的服务连接。如果 authentik 不应该处理此部署,则应该留空。"
"Select Service-Connection authentik should use to manage this outpost. Leave "
"empty if authentik should not handle the deployment."
msgstr ""
"选择 authentik 在管理此前哨时需要使用的服务连接。如果 authentik 不应该处理此"
"部署,则应该留空。"
#: authentik/outposts/models.py
msgid "Outpost"
@@ -1329,7 +1417,9 @@ msgstr "匹配选定应用程序创建的事件。如果留空,则匹配所有
msgid ""
"Match events created by selected model. When left empty, all models are "
"matched. When an app is selected, all the application's models are matched."
msgstr "匹配选定模型创建的事件。如果留空,则匹配所有模型。选择应用程序后,则匹配该应用程序的所有模型。"
msgstr ""
"匹配选定模型创建的事件。如果留空,则匹配所有模型。选择应用程序后,则匹配该应"
"用程序的所有模型。"
#: authentik/policies/event_matcher/api.py
msgid "At least one criteria must be set."
@@ -1587,8 +1677,8 @@ msgid ""
"that the numbers aren't too low for POSIX users. Default is 2000 to ensure "
"that we don't collide with local users uidNumber"
msgstr ""
"起始 uidNumbers这个数字会被添加到 user.pk 中,以确保对于 POSIX 用户来说,这个数字不会太低。默认值为 "
"2000以确保我们不会与本地用户的 uidNumber 发生冲突"
"起始 uidNumbers这个数字会被添加到 user.pk 中,以确保对于 POSIX 用户来说,这"
"个数字不会太低。默认值为 2000以确保我们不会与本地用户的 uidNumber 发生冲突"
#: authentik/providers/ldap/models.py
msgid ""
@@ -1597,19 +1687,21 @@ msgid ""
"Default is 4000 to ensure that we don't collide with local groups or users "
"primary groups gidNumber"
msgstr ""
"起始 gidNumbers这个数字会被添加到从 group.pk 生成的数字中,以确保对于 POSIX 用户来说,这个数字不会太低。默认值为 "
"4000以确保我们不会与本地群组或用户主组的 gidNumber 发生冲突"
"起始 gidNumbers这个数字会被添加到从 group.pk 生成的数字中,以确保对于 "
"POSIX 用户来说,这个数字不会太低。默认值为 4000以确保我们不会与本地群组或用"
"户主组的 gidNumber 发生冲突"
#: authentik/providers/ldap/models.py authentik/providers/radius/models.py
msgid ""
"When enabled, code-based multi-factor authentication can be used by "
"appending a semicolon and the TOTP code to the password. This should only be"
" enabled if all users that will bind to this provider have a TOTP device "
"appending a semicolon and the TOTP code to the password. This should only be "
"enabled if all users that will bind to this provider have a TOTP device "
"configured, as otherwise a password may incorrectly be rejected if it "
"contains a semicolon."
msgstr ""
"启用时,可以通过在密码后添加分号和 TOTP 代码来使用基于代码的多因素身份验证。仅在所有绑定到此提供程序的用户都已配置 TOTP "
"设备的情况下才应该启用,否则密码可能会因为包含分号而被错误地拒绝。"
"启用时,可以通过在密码后添加分号和 TOTP 代码来使用基于代码的多因素身份验证。"
"仅在所有绑定到此提供程序的用户都已配置 TOTP 设备的情况下才应该启用,否则密码"
"可能会因为包含分号而被错误地拒绝。"
#: authentik/providers/ldap/models.py
msgid "LDAP Provider"
@@ -1652,7 +1744,9 @@ msgstr "基于用户的电子邮箱。建议在 UPN 方法上使用。"
msgid ""
"Based on the User's UPN, only works if user has a 'upn' attribute set. Use "
"this method only if you have different UPN and Mail domains."
msgstr "基于用户的 UPN仅当用户设置了 “upn” 属性时才有效。仅当您有不同的 UPN 和 Mail 域时才使用此方法。"
msgstr ""
"基于用户的 UPN仅当用户设置了 “upn” 属性时才有效。仅当您有不同的 UPN 和 "
"Mail 域时才使用此方法。"
#: authentik/providers/oauth2/models.py
msgid "Confidential"
@@ -1736,8 +1830,8 @@ msgstr "客户端使用的作用域"
#: authentik/providers/oauth2/models.py
msgid ""
"Description shown to the user when consenting. If left empty, the user won't"
" be informed."
"Description shown to the user when consenting. If left empty, the user won't "
"be informed."
msgstr "同意授权时向用户显示的描述。如果留空,则不会告知用户。"
#: authentik/providers/oauth2/models.py
@@ -1754,8 +1848,8 @@ msgstr "客户端类型"
#: authentik/providers/oauth2/models.py
msgid ""
"Confidential clients are capable of maintaining the confidentiality of their"
" credentials. Public clients are incapable"
"Confidential clients are capable of maintaining the confidentiality of their "
"credentials. Public clients are incapable"
msgstr "机密客户端有能力维护其凭据的机密性。公开客户端无此能力。"
#: authentik/providers/oauth2/models.py
@@ -1790,21 +1884,26 @@ msgstr "在 id_token 中包含声明"
#: authentik/providers/oauth2/models.py
msgid ""
"Include User claims from scopes in the id_token, for applications that don't"
" access the userinfo endpoint."
msgstr "对于不访问 userinfo 端点的应用程序,将来自作用域的用户声明包含在 id_token 中。"
"Include User claims from scopes in the id_token, for applications that don't "
"access the userinfo endpoint."
msgstr ""
"对于不访问 userinfo 端点的应用程序,将来自作用域的用户声明包含在 id_token "
"中。"
#: authentik/providers/oauth2/models.py
msgid ""
"Access codes not valid on or after current time + this value (Format: "
"hours=1;minutes=2;seconds=3)."
msgstr "从当前时间经过多久时或之后访问代码无效格式hours=1;minutes=2;seconds=3"
msgstr ""
"从当前时间经过多久时或之后,访问代码无效(格式:"
"hours=1;minutes=2;seconds=3。"
#: authentik/providers/oauth2/models.py
msgid ""
"Tokens not valid on or after current time + this value (Format: "
"hours=1;minutes=2;seconds=3)."
msgstr "从当前时间经过多久时或之后令牌无效格式hours=1;minutes=2;seconds=3"
msgstr ""
"从当前时间经过多久时或之后令牌无效格式hours=1;minutes=2;seconds=3。"
#: authentik/providers/oauth2/models.py
msgid ""
@@ -1841,8 +1940,7 @@ msgstr "用于加密令牌的密钥。如果设置,则令牌会被加密,并
#: authentik/providers/oauth2/models.py
msgid ""
"Any JWT signed by the JWK of the selected source can be used to "
"authenticate."
"Any JWT signed by the JWK of the selected source can be used to authenticate."
msgstr "任何由选定来源的 JWK 签发的 JWT 都可以用于身份验证。"
#: authentik/providers/oauth2/models.py
@@ -1901,14 +1999,6 @@ msgstr "OAuth2 刷新令牌"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2 刷新令牌"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "设备令牌"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "设备令牌"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr "向注销的客户端发送反向通道注销请求"
@@ -1967,13 +2057,17 @@ msgstr "内部主机 SSL 验证"
msgid ""
"Enable support for forwardAuth in traefik and nginx auth_request. Exclusive "
"with internal_host."
msgstr "在 traefik 和 nginx auth_request 中启用对 ForwardAuth 的支持。排除 internal_host。"
msgstr ""
"在 traefik 和 nginx auth_request 中启用对 ForwardAuth 的支持。排除 "
"internal_host。"
#: authentik/providers/proxy/models.py
msgid ""
"Regular expressions for which authentication is not required. Each new line "
"is interpreted as a new Regular Expression."
msgstr "用于描述何处不需要身份验证的正则表达式。每个新行都被解释为一个新的正则表达式。"
msgstr ""
"用于描述何处不需要身份验证的正则表达式。每个新行都被解释为一个新的正则表达"
"式。"
#: authentik/providers/proxy/models.py
msgid ""
@@ -1987,8 +2081,7 @@ msgstr "设置 HTTP-Basic 身份验证"
#: authentik/providers/proxy/models.py
msgid ""
"Set a custom HTTP-Basic Authentication header based on values from "
"authentik."
"Set a custom HTTP-Basic Authentication header based on values from authentik."
msgstr "根据来自 authentik 的值设置自定义 HTTP-Basic 身份验证标头。"
#: authentik/providers/proxy/models.py
@@ -1997,9 +2090,11 @@ msgstr "HTTP-Basic 用户名密钥"
#: authentik/providers/proxy/models.py
msgid ""
"User/Group Attribute used for the user part of the HTTP-Basic Header. If not"
" set, the user's Email address is used."
msgstr "用于 HTTP-Basic 标头用户名部分的用户/组属性。如果未设置,则使用用户的电子邮件地址。"
"User/Group Attribute used for the user part of the HTTP-Basic Header. If not "
"set, the user's Email address is used."
msgstr ""
"用于 HTTP-Basic 标头用户名部分的用户/组属性。如果未设置,则使用用户的电子邮件"
"地址。"
#: authentik/providers/proxy/models.py
msgid "HTTP-Basic Password Key"
@@ -2026,7 +2121,9 @@ msgstr "终止代理前哨的会话。"
msgid ""
"Determines how long a session lasts. Default of 0 means that the sessions "
"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)"
msgstr "确定会话持续多长时间。默认值为 0 表示会话持续到浏览器关闭为止。格式hours=-1;minutes=-2;seconds=-3"
msgstr ""
"确定会话持续多长时间。默认值为 0 表示会话持续到浏览器关闭为止。(格式:"
"hours=-1;minutes=-2;seconds=-3"
#: authentik/providers/rac/models.py
msgid "When set to true, connection tokens will be deleted upon disconnect."
@@ -2081,7 +2178,9 @@ msgid ""
"List of CIDRs (comma-separated) that clients can connect from. A more "
"specific CIDR will match before a looser one. Clients connecting from a non-"
"specified CIDR will be dropped."
msgstr "允许客户端连接的 CIDR 列表(逗号分隔)。严格的 CIDR 会在宽松的之前匹配。来自 CIDR 范围外的客户端连接将会被丢弃。"
msgstr ""
"允许客户端连接的 CIDR 列表(逗号分隔)。严格的 CIDR 会在宽松的之前匹配。来自 "
"CIDR 范围外的客户端连接将会被丢弃。"
#: authentik/providers/radius/models.py
msgid "Radius Provider"
@@ -2185,25 +2284,30 @@ msgid ""
"empty, the AuthnContextClassRef will be set based on which authentication "
"methods the user used to authenticate."
msgstr ""
"配置如何创建 AuthnContextClassRef 值。留空时AuthnContextClassRef 会基于用户使用的身份验证方式设置。"
"配置如何创建 AuthnContextClassRef 值。留空时AuthnContextClassRef 会基于用户"
"使用的身份验证方式设置。"
#: authentik/providers/saml/models.py
msgid ""
"Assertion valid not before current time + this value (Format: "
"hours=-1;minutes=-2;seconds=-3)."
msgstr "从当前时间经过多久时或之后断言有效格式hours=-1;minutes=-2;seconds=-3"
msgstr ""
"从当前时间经过多久时或之后,断言有效(格式:"
"hours=-1;minutes=-2;seconds=-3。"
#: authentik/providers/saml/models.py
msgid ""
"Assertion not valid on or after current time + this value (Format: "
"hours=1;minutes=2;seconds=3)."
msgstr "从当前时间经过多久时或之后断言无效格式hours=1;minutes=2;seconds=3"
msgstr ""
"从当前时间经过多久时或之后断言无效格式hours=1;minutes=2;seconds=3。"
#: authentik/providers/saml/models.py
msgid ""
"Session not valid on or after current time + this value (Format: "
"hours=1;minutes=2;seconds=3)."
msgstr "从当前时间经过多久时或之后会话无效格式hours=1;minutes=2;seconds=3"
msgstr ""
"从当前时间经过多久时或之后会话无效格式hours=1;minutes=2;seconds=3。"
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "SHA1"
@@ -2261,7 +2365,9 @@ msgstr "DSA-SHA1"
msgid ""
"When selected, incoming assertion's Signatures will be validated against "
"this certificate. To allow unsigned Requests, leave on default."
msgstr "选中后,传入断言的签名将根据此证书进行验证。要允许未签名的请求,请保留默认值。"
msgstr ""
"选中后,传入断言的签名将根据此证书进行验证。要允许未签名的请求,请保留默认"
"值。"
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "Verification Certificate"
@@ -2277,10 +2383,12 @@ msgstr "签名密钥对"
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid ""
"When selected, incoming assertions are encrypted by the IdP using the public"
" key of the encryption keypair. The assertion is decrypted by the SP using "
"When selected, incoming assertions are encrypted by the IdP using the public "
"key of the encryption keypair. The assertion is decrypted by the SP using "
"the the private key."
msgstr "选择此选项后,传入的断言将由 IdP 使用加密密钥对的公钥进行加密。 SP 会使用私钥解密该断言。"
msgstr ""
"选择此选项后,传入的断言将由 IdP 使用加密密钥对的公钥进行加密。 SP 会使用私钥"
"解密该断言。"
#: authentik/providers/saml/models.py authentik/sources/saml/models.py
msgid "Encryption Keypair"
@@ -2510,7 +2618,9 @@ msgstr "向 kadmin 进行身份验证以进行同步的密码"
msgid ""
"Keytab to authenticate to kadmin for sync. Must be base64-encoded or in the "
"form TYPE:residual"
msgstr "向 kadmin 进行身份验证以进行同步的 Keytab。必须以 Base64 编码,或者形式为 TYPE:residual"
msgstr ""
"向 kadmin 进行身份验证以进行同步的 Keytab。必须以 Base64 编码,或者形式为 "
"TYPE:residual"
#: authentik/sources/kerberos/models.py
msgid ""
@@ -2606,8 +2716,8 @@ msgstr "服务器 URI"
#: authentik/sources/ldap/models.py
msgid ""
"Optionally verify the LDAP Server's Certificate against the CA Chain in this"
" keypair."
"Optionally verify the LDAP Server's Certificate against the CA Chain in this "
"keypair."
msgstr "可选,根据此密钥对中的 CA 链验证 LDAP 服务器的证书。"
#: authentik/sources/ldap/models.py
@@ -2682,7 +2792,9 @@ msgid ""
"Lookup group membership based on a user attribute instead of a group "
"attribute. This allows nested group resolution on systems like FreeIPA and "
"Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 Active Directory 等系统上支持嵌套组决策"
msgstr ""
"基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 Active Directory 等"
"系统上支持嵌套组决策"
#: authentik/sources/ldap/models.py
msgid ""
@@ -2773,8 +2885,7 @@ msgstr "请求令牌 URL"
#: authentik/sources/oauth/models.py
msgid ""
"URL used to request the initial token. This URL is only required for OAuth "
"1."
"URL used to request the initial token. This URL is only required for OAuth 1."
msgstr "用于请求初始令牌的 URL。只有 OAuth 1 才需要此网址。"
#: authentik/sources/oauth/models.py
@@ -2811,8 +2922,7 @@ msgstr ""
#: authentik/sources/oauth/models.py
msgid ""
"How to perform authentication during an authorization_code token request "
"flow"
"How to perform authentication during an authorization_code token request flow"
msgstr "在 authorization_code 令牌请求流程期间,如何执行身份验证"
#: authentik/sources/oauth/models.py
@@ -3082,12 +3192,12 @@ msgstr "如果您的 IDP 支持单点注销,则为可选 URL。"
msgid ""
"Allows authentication flows initiated by the IdP. This can be a security "
"risk, as no validation of the request ID is done."
msgstr "允许由 IdP 启动的身份验证流程。这可能存在安全风险,因为未对请求 ID 进行验证。"
msgstr ""
"允许由 IdP 启动的身份验证流程。这可能存在安全风险,因为未对请求 ID 进行验证。"
#: authentik/sources/saml/models.py
msgid ""
"NameID Policy sent to the IdP. Can be unset, in which case no Policy is "
"sent."
"NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent."
msgstr "发送给 IdP 的 NameID 策略。可以取消设置,此时不会发送任何策略。"
#: authentik/sources/saml/models.py
@@ -3100,12 +3210,11 @@ msgid ""
"your IDP uses the NameID Format 'transient', and the user doesn't log out "
"manually. (Format: hours=1;minutes=2;seconds=3)."
msgstr ""
"删除临时用户的时间偏移。这仅适用于您的 IDP 使用 NameID 格式 “transient” "
"且用户未手动注销的情况。格式hours=1;minutes=2;seconds=3。"
"删除临时用户的时间偏移。这仅适用于您的 IDP 使用 NameID 格式 “transient” 且用"
"户未手动注销的情况。格式hours=1;minutes=2;seconds=3。"
#: authentik/sources/saml/models.py
msgid ""
"Keypair used to sign outgoing Responses going to the Identity Provider."
msgid "Keypair used to sign outgoing Responses going to the Identity Provider."
msgstr "密钥对,用于签署发送给身份提供程序的传出响应。"
#: authentik/sources/saml/models.py
@@ -3303,11 +3412,13 @@ msgstr ""
#, python-format
msgid ""
"\n"
" If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
" If you did not request this code, please ignore this email. The code "
"above is valid for %(expires)s.\n"
" "
msgstr ""
"\n"
" 如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有效。\n"
" 如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有"
"效。\n"
" "
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
@@ -3328,7 +3439,8 @@ msgstr ""
#, python-format
msgid ""
"\n"
"If you did not request this code, please ignore this email. The code above is valid for %(expires)s.\n"
"If you did not request this code, please ignore this email. The code above "
"is valid for %(expires)s.\n"
msgstr ""
"\n"
"如果您没有请求此代码,请忽略此电子邮件。上面的代码在 %(expires)s 内有效。\n"
@@ -3336,9 +3448,11 @@ msgstr ""
#: authentik/stages/authenticator_sms/models.py
msgid ""
"When enabled, the Phone number is only used during enrollment to verify the "
"users authenticity. Only a hash of the phone number is saved to ensure it is"
" not reused in the future."
msgstr "启用时,电话号码仅在注册期间用于验证用户的真实性。仅保存电话号码的哈希,以确保将来不会重复使用。"
"users authenticity. Only a hash of the phone number is saved to ensure it is "
"not reused in the future."
msgstr ""
"启用时,电话号码仅在注册期间用于验证用户的真实性。仅保存电话号码的哈希,以确"
"保将来不会重复使用。"
#: authentik/stages/authenticator_sms/models.py
msgid "Optionally modify the payload being sent to custom providers."
@@ -3451,10 +3565,12 @@ msgstr "短信"
#: authentik/stages/authenticator_validate/models.py
msgid ""
"Stages used to configure Authenticator when user doesn't have any compatible"
" devices. After this configuration Stage passes, the user is not prompted "
"Stages used to configure Authenticator when user doesn't have any compatible "
"devices. After this configuration Stage passes, the user is not prompted "
"again."
msgstr "当用户没有任何兼容的设备时,用来配置身份验证器的阶段。此阶段通过后,将不再请求此用户。"
msgstr ""
"当用户没有任何兼容的设备时,用来配置身份验证器的阶段。此阶段通过后,将不再请"
"求此用户。"
#: authentik/stages/authenticator_validate/models.py
msgid "Device classes which can be used to authenticate"
@@ -3525,7 +3641,9 @@ msgid ""
"threshold, the stage will show an error message. When not enabled, the flow "
"will continue, but the data from the captcha will be available in the "
"context for policy decisions"
msgstr "启用时,如果接收到的验证码分数超出给定的阈值,此阶段将显示错误信息。未启用时,流程会继续,但来自验证码的数据可在上下文中用于策略决定。"
msgstr ""
"启用时,如果接收到的验证码分数超出给定的阈值,此阶段将显示错误信息。未启用"
"时,流程会继续,但来自验证码的数据可在上下文中用于策略决定。"
#: authentik/stages/captcha/models.py
msgid "Captcha Stage"
@@ -3619,7 +3737,8 @@ msgid ""
"attempts will be rate-limited. (Format: hours=1;minutes=2;seconds=3)."
msgstr ""
"近期帐户恢复尝试次数的时间窗口。如果在此期间尝试次数超过 "
"recovery_max_attempts则后续尝试将受到速率限制。格式hours=1;minutes=2;seconds=3"
"recovery_max_attempts则后续尝试将受到速率限制。格式"
"hours=1;minutes=2;seconds=3。"
#: authentik/stages/email/models.py
msgid "Activate users upon completion of stage."
@@ -3679,7 +3798,8 @@ msgstr "确认账户"
#, python-format
msgid ""
"\n"
" If that doesn't work, copy and paste the following link in your browser: %(url)s\n"
" If that doesn't work, copy and paste the following link in your browser: "
"%(url)s\n"
" "
msgstr ""
"\n"
@@ -3696,7 +3816,8 @@ msgstr "我们很高兴您能开始使用。首先,您需要确认您的账户
#, python-format
msgid ""
"\n"
" This email was sent from the notification transport <code>%(name)s</code>.\n"
" This email was sent from the notification transport <code>%(name)s</"
"code>.\n"
" "
msgstr ""
"\n"
@@ -3727,7 +3848,8 @@ msgstr ""
#: authentik/stages/email/templates/email/password_reset.html
msgid ""
"\n"
" You recently requested to change your password for your authentik account. Use the button below to set a new password.\n"
" You recently requested to change your password for your authentik "
"account. Use the button below to set a new password.\n"
" "
msgstr ""
"\n"
@@ -3738,17 +3860,20 @@ msgstr ""
#, python-format
msgid ""
"\n"
" If you did not request a password change, please ignore this email. The link above is valid for %(expires)s.\n"
" If you did not request a password change, please ignore this email. The "
"link above is valid for %(expires)s.\n"
" "
msgstr ""
"\n"
" 如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有效。\n"
" 如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有"
"效。\n"
" "
#: authentik/stages/email/templates/email/password_reset.txt
msgid ""
"\n"
"You recently requested to change your password for your authentik account. Use the link below to set a new password.\n"
"You recently requested to change your password for your authentik account. "
"Use the link below to set a new password.\n"
msgstr ""
"\n"
"您最近请求更改您的 authentik 账户密码。使用下面的链接设置新密码。\n"
@@ -3757,7 +3882,8 @@ msgstr ""
#, python-format
msgid ""
"\n"
"If you did not request a password change, please ignore this email. The link above is valid for %(expires)s.\n"
"If you did not request a password change, please ignore this email. The link "
"above is valid for %(expires)s.\n"
msgstr ""
"\n"
"如果您没有请求更改密码,请忽略此电子邮件。上面的链接在 %(expires)s 内有效。\n"
@@ -3769,17 +3895,20 @@ msgstr "authentik 测试电子邮件"
#: authentik/stages/email/templates/email/setup.html
msgid ""
"\n"
" This is a test email to inform you, that you've successfully configured authentik emails.\n"
" This is a test email to inform you, that you've "
"successfully configured authentik emails.\n"
" "
msgstr ""
"\n"
" 这是一封测试电子邮件,用于通知您已成功配置 authentik 电子邮件。\n"
" 这是一封测试电子邮件,用于通知您已成功配置 authentik 电子"
"邮件。\n"
" "
#: authentik/stages/email/templates/email/setup.txt
msgid ""
"\n"
"This is a test email to inform you, that you've successfully configured authentik emails.\n"
"This is a test email to inform you, that you've successfully configured "
"authentik emails.\n"
msgstr ""
"\n"
"这是一封测试电子邮件,用于通知您已成功配置 authentik 电子邮件。\n"
@@ -3803,7 +3932,9 @@ msgid ""
"When a valid username/email has been entered, and this option is enabled, "
"the user's username and avatar will be shown. Otherwise, the text that the "
"user entered will be shown"
msgstr "如果输入了有效的用户名/电子邮箱,并且启用了此选项,则会显示用户的用户名和头像。否则,将显示用户输入的文本"
msgstr ""
"如果输入了有效的用户名/电子邮箱,并且启用了此选项,则会显示用户的用户名和头"
"像。否则,将显示用户输入的文本"
#: authentik/stages/identification/models.py
msgid ""
@@ -3813,8 +3944,8 @@ msgstr "启用时,即使输入错误的用户信息,此阶段也会成功并
#: authentik/stages/identification/models.py
msgid ""
"Show the user the 'Remember me on this device' toggle, allowing repeat users"
" to skip straight to entering their password."
"Show the user the 'Remember me on this device' toggle, allowing repeat users "
"to skip straight to entering their password."
msgstr "向用户显示“在此设备上记住我”开关,允许相同用户直接跳过输入密码。"
#: authentik/stages/identification/models.py
@@ -3858,7 +3989,9 @@ msgid ""
"If this flag is set, this Stage will jump to the next Stage when no "
"Invitation is given. By default this Stage will cancel the Flow when no "
"invitation is given."
msgstr "如果设置了此标志,则当没有发出邀请时,此阶段将跳转到下一个阶段。默认情况下,当没有发出邀请时,此阶段将取消流程。"
msgstr ""
"如果设置了此标志,则当没有发出邀请时,此阶段将跳转到下一个阶段。默认情况下,"
"当没有发出邀请时,此阶段将取消流程。"
#: authentik/stages/invitation/models.py
msgid "Invitation Stage"
@@ -3916,7 +4049,9 @@ msgstr "选择用于测试密码的后端。"
msgid ""
"How many attempts a user has before the flow is canceled. To lock the user "
"out, use a reputation policy and a user_write stage."
msgstr "在取消流程之前,用户可以尝试多少次。要锁定用户,请使用信誉策略和 user_write 阶段。"
msgstr ""
"在取消流程之前,用户可以尝试多少次。要锁定用户,请使用信誉策略和 user_write "
"阶段。"
#: authentik/stages/password/models.py
msgid ""
@@ -3964,9 +4099,11 @@ msgstr "电子邮箱:电子邮箱类型的文本字段。"
#: authentik/stages/prompt/models.py
msgid ""
"Password: Masked input, multiple inputs of this type on the same prompt need"
" to be identical."
msgstr "密码:屏蔽显示输入内容,多个此类型的输入如果在同一个输入项下,则内容需要相同。"
"Password: Masked input, multiple inputs of this type on the same prompt need "
"to be identical."
msgstr ""
"密码:屏蔽显示输入内容,多个此类型的输入如果在同一个输入项下,则内容需要相"
"同。"
#: authentik/stages/prompt/models.py
msgid "Fixed choice field rendered as a group of radio buttons."
@@ -4007,14 +4144,18 @@ msgid ""
"Optionally provide a short hint that describes the expected input value. "
"When creating a fixed choice field, enable interpreting as expression and "
"return a list to return multiple choices."
msgstr "可选的简短提示,用来描述期望的输入值。在创建固定选项字段时,启用以表达式解释,并返回多个选项的列表。"
msgstr ""
"可选的简短提示,用来描述期望的输入值。在创建固定选项字段时,启用以表达式解"
"释,并返回多个选项的列表。"
#: authentik/stages/prompt/models.py
msgid ""
"Optionally pre-fill the input with an initial value. When creating a fixed "
"choice field, enable interpreting as expression and return a list to return "
"multiple default choices."
msgstr "可选的预设输入初始值。在创建固定选项字段时,启用以表达式解释,并返回多个默认选项的列表。"
msgstr ""
"可选的预设输入初始值。在创建固定选项字段时,启用以表达式解释,并返回多个默认"
"选项的列表。"
#: authentik/stages/prompt/models.py
msgid "Prompt"
@@ -4082,8 +4223,8 @@ msgid ""
"option. Default of 0 means that the remember me option will not be shown. "
"(Format: hours=-1;minutes=-2;seconds=-3)"
msgstr ""
"当用户选择“记住我”选项时,会话将会延长的时间。默认值 0 "
"表示不显示“记住我”选项。格式hours=-1;minutes=-2;seconds=-3"
"当用户选择“记住我”选项时,会话将会延长的时间。默认值 0 表示不显示“记住我”选"
"项。格式hours=-1;minutes=-2;seconds=-3"
#: authentik/stages/user_login/models.py
msgid ""
@@ -4091,8 +4232,8 @@ msgid ""
"expiry,to remember the device the user is logging in from. (Format: "
"hours=-1;minutes=-2;seconds=-3)"
msgstr ""
"当设置为非零值时authentik 将会以更长的过期时间保存 "
"Cookie以记住用户的登录设备。格式hours=-1;minutes=-2;seconds=-3"
"当设置为非零值时authentik 将会以更长的过期时间保存 Cookie以记住用户的登录"
"设备。格式hours=-1;minutes=-2;seconds=-3"
#: authentik/stages/user_login/models.py
msgid "User Login Stage"

Binary file not shown.

View File

@@ -14,14 +14,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-20 00:11+0000\n"
"POT-Creation-Date: 2025-12-01 15:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: 刘松, 2025\n"
"Language-Team: Chinese (Taiwan) (https://app.transifex.com/authentik/teams/119923/zh_TW/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_TW\n"
"Language: zh_Hant\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: authentik/admin/models.py
@@ -357,6 +357,12 @@ msgstr "來源的顯示名稱。"
msgid "Internal source name, used in URLs."
msgstr "用於網址的內部來源名稱。"
#: authentik/core/models.py
msgid ""
"When enabled, this source will be displayed as a prominent button on the "
"login page, instead of a small icon."
msgstr ""
#: authentik/core/models.py
msgid "Flow to use when authenticating existing users."
msgstr "認證已存在使用者時所使用的流程。"
@@ -385,7 +391,7 @@ msgstr "權杖"
msgid "Tokens"
msgstr "權杖"
#: authentik/core/models.py
#: authentik/core/models.py authentik/endpoints/connectors/agent/models.py
msgid "View token's key"
msgstr "檢視權杖金鑰"
@@ -455,6 +461,7 @@ msgid "Remove temporary users created by SAML Sources."
msgstr ""
#: authentik/core/templates/if/error.html
#: authentik/policies/templates/policies/denied.html
msgid "Go home"
msgstr "回到首頁"
@@ -486,6 +493,26 @@ msgstr "rsa"
msgid "ecdsa"
msgstr "ecdsa"
#: authentik/crypto/models.py
msgid "RSA"
msgstr ""
#: authentik/crypto/models.py
msgid "Elliptic Curve"
msgstr ""
#: authentik/crypto/models.py
msgid "DSA"
msgstr ""
#: authentik/crypto/models.py
msgid "Ed25519"
msgstr ""
#: authentik/crypto/models.py
msgid "Ed448"
msgstr ""
#: authentik/crypto/models.py
msgid "PEM-encoded Certificate data"
msgstr "PEM 編碼的憑證資料"
@@ -508,6 +535,104 @@ msgstr "憑證金鑰對"
msgid "Discover, import and update certificates from the filesystem."
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Selected platform not supported"
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Token is expired"
msgstr ""
#: authentik/endpoints/connectors/agent/api/connectors.py
msgid "Invalid token for connector"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Agent Connector"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Agent Connectors"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "裝置權杖"
#: authentik/endpoints/connectors/agent/models.py
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "裝置權杖"
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Enrollment Tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication token"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Device authentication tokens"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonce"
msgstr ""
#: authentik/endpoints/connectors/agent/models.py
msgid "Apple Nonces"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device"
msgstr "设备"
#: authentik/endpoints/models.py
msgid "Devices"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User binding"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device User bindings"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connection"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device connections"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshot"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device fact snapshots"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access group"
msgstr ""
#: authentik/endpoints/models.py
msgid "Device access groups"
msgstr ""
#: authentik/endpoints/tasks.py
msgid "Sync endpoints."
msgstr ""
#: authentik/enterprise/api.py
msgid "Enterprise is required to create/update this object."
msgstr "企業版才可建立/更新此物件。"
@@ -1112,10 +1237,22 @@ msgstr "流程權杖"
msgid "Flow Tokens"
msgstr "流程權杖"
#: authentik/flows/templates/if/flow.html
msgid "Site footer"
msgstr ""
#: authentik/flows/views/executor.py
msgid "Invalid next URL"
msgstr "無效的下一步網址"
#: authentik/lib/sync/outgoing/models.py
msgid "Controls the number of objects synced in a single task"
msgstr ""
#: authentik/lib/sync/outgoing/models.py
msgid "Timeout for synchronization of a single page"
msgstr ""
#: authentik/lib/sync/outgoing/models.py
msgid ""
"When enabled, provider will not modify or create objects in the remote "
@@ -1480,6 +1617,10 @@ msgstr "個人檔案圖片"
msgid "Not you?"
msgstr "不是您嗎?"
#: authentik/policies/templates/policies/denied.html
msgid "Error"
msgstr "错误"
#: authentik/policies/templates/policies/denied.html
msgid "Request has been denied."
msgstr "請求被拒。"
@@ -1828,14 +1969,6 @@ msgstr "OAuth2 更新權杖"
msgid "OAuth2 Refresh Tokens"
msgstr "OAuth2 更新權杖"
#: authentik/providers/oauth2/models.py
msgid "Device Token"
msgstr "裝置權杖"
#: authentik/providers/oauth2/models.py
msgid "Device Tokens"
msgstr "裝置權杖"
#: authentik/providers/oauth2/tasks.py
msgid "Send a back-channel logout request to the registered client"
msgstr ""
@@ -2048,16 +2181,6 @@ msgstr "無法詮釋資料匯入:{messages}"
msgid "ACS URL"
msgstr "ACS 網址"
#: authentik/providers/saml/models.py
msgid ""
"Value of the audience restriction field of the assertion. When left empty, "
"no audience restriction will be added."
msgstr "斷言的目標對象來源限制欄位的值。當未設定時將不會對任何目標對象進行限制。"
#: authentik/providers/saml/models.py
msgid "Also known as EntityID"
msgstr "也稱為 EntityID"
#: authentik/providers/saml/models.py
msgid "Service Provider Binding"
msgstr "服務供應商附加"
@@ -2068,6 +2191,16 @@ msgid ""
"Provider."
msgstr "這決定了 authentik 如何將回應發送回服務供應商。"
#: authentik/providers/saml/models.py
msgid ""
"Value of the audience restriction field of the assertion. When left empty, "
"no audience restriction will be added."
msgstr "斷言的目標對象來源限制欄位的值。當未設定時將不會對任何目標對象進行限制。"
#: authentik/providers/saml/models.py
msgid "Also known as EntityID"
msgstr "也稱為 EntityID"
#: authentik/providers/saml/models.py
msgid "SLS URL"
msgstr ""

Binary file not shown.

View File

@@ -130,12 +130,19 @@
}
}
@media (width < 998px) {
.navbar__item.navbar__link {
display: none;
}
}
.DocSearch-Button {
--docsearch-primary-color: var(--ifm-color-primary-darkest);
--docsearch-text-color: var(--ifm-navbar-link-color);
--docsearch-searchbox-shadow: unset;
--docsearch-searchbox-background: transparent;
--docsearch-searchbox-focus-background: var(--ifm-hover-overlay);
--docsearch-subtle-color: transparent;
--docsearch-muted-color: hsl(0 0% 85% / 1);
--docsearch-key-gradient: linear-gradient(
@@ -153,6 +160,14 @@
padding: var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal) !important;
padding-inline-end: calc(var(--ifm-navbar-item-padding-horizontal) * 1.25) !important;
/* TODO: Remove this after Docusaurus's CSS layers is stable. */
height: auto !important;
border-radius: 1rem !important;
&:hover {
--docsearch-searchbox-background: var(--ifm-hover-overlay);
}
.DocSearch-Button-Placeholder {
font-family: var(--ifm-heading-font-family);
color: var(--ifm-navbar-link-color);

View File

@@ -1,12 +1,12 @@
{
"name": "@goauthentik/docusaurus-config",
"version": "2.2.1",
"version": "2.2.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@goauthentik/docusaurus-config",
"version": "2.2.1",
"version": "2.2.2",
"license": "MIT",
"dependencies": {
"deepmerge-ts": "^7.1.5",
@@ -61,7 +61,7 @@
},
"../eslint-config": {
"name": "@goauthentik/eslint-config",
"version": "1.1.0",
"version": "1.1.1",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8759,40 +8759,40 @@
}
},
"node_modules/express": {
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"body-parser": "~1.20.3",
"content-disposition": "~0.5.4",
"content-type": "~1.0.4",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"cookie": "~0.7.1",
"cookie-signature": "~1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"finalhandler": "~1.3.1",
"fresh": "~0.5.2",
"http-errors": "~2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"on-finished": "~2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.12",
"path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"qs": "~6.14.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.2",
"send": "~0.19.0",
"serve-static": "~1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"statuses": "~2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
@@ -8842,6 +8842,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/express/node_modules/qs": {
"version": "6.14.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/express/node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "@goauthentik/docusaurus-config",
"version": "2.2.1",
"version": "2.2.2",
"description": "authentik's Docusaurus config",
"license": "MIT",
"scripts": {

View File

@@ -10,7 +10,7 @@ import { reactConfig } from "./lib/react-config.js";
import { typescriptConfig } from "./lib/typescript-config.js";
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import { defineConfig, globalIgnores } from "eslint/config";
import tseslint from "typescript-eslint";
// @ts-check
@@ -56,9 +56,7 @@ export function createESLintPackageConfig({
parserOptions = {},
} = {}) {
return defineConfig(
{
ignores: ignorePatterns,
},
globalIgnores(ignorePatterns),
{
languageOptions: {

View File

@@ -1,12 +1,12 @@
{
"name": "@goauthentik/eslint-config",
"version": "1.1.0",
"version": "1.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@goauthentik/eslint-config",
"version": "1.1.0",
"version": "1.1.1",
"license": "MIT",
"dependencies": {
"eslint": "^9.39.1",
@@ -45,7 +45,7 @@
},
"../prettier-config": {
"name": "@goauthentik/prettier-config",
"version": "3.2.0",
"version": "3.2.1",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@goauthentik/eslint-config",
"version": "1.1.0",
"version": "1.1.1",
"description": "authentik's ESLint config",
"license": "MIT",
"scripts": {

View File

@@ -47,7 +47,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
go build -o /go/proxy ./cmd/proxy
# Stage 3: Run
FROM ghcr.io/goauthentik/fips-debian:trixie-slim-fips@sha256:de70579f5610286c5f0824180eff168cfc85a2f8a81d9190a2c4f81f52dc6db7
FROM ghcr.io/goauthentik/fips-debian:trixie-slim-fips@sha256:c718f608885a76a8940700b0c9feab75b1c967e1c291adf52dcd3ad6f6a86a66
ARG VERSION
ARG GIT_BUILD_HASH

View File

@@ -31,7 +31,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
go build -o /go/radius ./cmd/radius
# Stage 2: Run
FROM ghcr.io/goauthentik/fips-debian:trixie-slim-fips@sha256:de70579f5610286c5f0824180eff168cfc85a2f8a81d9190a2c4f81f52dc6db7
FROM ghcr.io/goauthentik/fips-debian:trixie-slim-fips@sha256:c718f608885a76a8940700b0c9feab75b1c967e1c291adf52dcd3ad6f6a86a66
ARG VERSION
ARG GIT_BUILD_HASH

2
web/.gitignore vendored
View File

@@ -5,7 +5,7 @@
#region Locale
src/locales/*.ts
xliff/pseudo-LOCALE.xlf
xliff/pseudo[_-]LOCALE.xlf
### Node ###
# Logs

View File

@@ -3,22 +3,20 @@
"sourceLocale": "en",
"targetLocales": [
"cs_CZ",
"de",
"de_DE",
"en",
"es",
"fr",
"it",
"ja",
"ko",
"nl",
"pl",
"ru",
"tr",
"zh-CN",
"zh-Hans",
"zh-Hant",
"zh_TW",
"pseudo-LOCALE"
"es_ES",
"fr_FR",
"it_IT",
"ja_JP",
"ko_KR",
"nl_NL",
"pl_PL",
"ru_RU",
"tr_TR",
"zh_Hans",
"zh_Hant",
"pseudo_LOCALE"
],
"tsConfig": "./tsconfig.json",
"output": {

72
web/package-lock.json generated
View File

@@ -173,7 +173,6 @@
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0",
@@ -2448,7 +2447,6 @@
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"license": "MIT",
"peer": true,
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
@@ -3645,18 +3643,6 @@
}
}
},
"node_modules/@swagger-api/apidom-parser-adapter-yaml-1-2/node_modules/tree-sitter": {
"version": "0.22.4",
"resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.22.4.tgz",
"integrity": "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-addon-api": "^8.3.0",
"node-gyp-build": "^4.8.4"
}
},
"node_modules/@swagger-api/apidom-reference": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.0.0-rc.3.tgz",
@@ -3741,6 +3727,7 @@
"integrity": "sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==",
"hasInstallScript": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.25"
@@ -4070,8 +4057,7 @@
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@types/chai": {
"version": "5.2.3",
@@ -4446,6 +4432,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~7.16.0"
}
@@ -4464,6 +4451,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.2.2"
}
@@ -4554,6 +4542,7 @@
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.47.0.tgz",
"integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.47.0",
"@typescript-eslint/types": "8.47.0",
@@ -4777,6 +4766,7 @@
"resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.0.13.tgz",
"integrity": "sha512-oaRY+/pvwS4/sN2rE2aZh9jdli8EkXm5AidmXEbWRu2wW0omG9PmgChWCX2jsD9qRLQxXTSLl5oKezANNF6LnQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vitest/browser": "4.0.13",
"@vitest/mocker": "4.0.13",
@@ -5242,6 +5232,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -6023,6 +6014,7 @@
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
"integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@kurkle/color": "^0.3.0"
},
@@ -6054,6 +6046,7 @@
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz",
"integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@chevrotain/cst-dts-gen": "11.0.3",
"@chevrotain/gast": "11.0.3",
@@ -6080,6 +6073,7 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"license": "MIT",
"peer": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -6342,6 +6336,7 @@
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz",
"integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10"
}
@@ -6742,6 +6737,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
"peer": true,
"engines": {
"node": ">=12"
}
@@ -6902,6 +6898,7 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
@@ -7129,7 +7126,6 @@
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.2.tgz",
"integrity": "sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12.20"
},
@@ -7142,7 +7138,6 @@
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz",
"integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==",
"license": "MIT",
"peer": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
@@ -7205,8 +7200,7 @@
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/dompurify": {
"version": "3.3.0",
@@ -7495,6 +7489,7 @@
"integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==",
"hasInstallScript": true,
"license": "MIT",
"peer": true,
"bin": {
"esbuild": "bin/esbuild"
},
@@ -7603,6 +7598,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -8884,7 +8880,6 @@
"resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.1.1.tgz",
"integrity": "sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==",
"license": "MIT",
"peer": true,
"funding": {
"url": "https://github.com/fisker/git-hooks-list?sponsor=1"
}
@@ -10443,6 +10438,7 @@
"resolved": "https://registry.npmjs.org/lit/-/lit-3.3.1.tgz",
"integrity": "sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==",
"license": "BSD-3-Clause",
"peer": true,
"dependencies": {
"@lit/reactive-element": "^2.1.0",
"lit-element": "^4.2.0",
@@ -10723,7 +10719,6 @@
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"license": "MIT",
"peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -13146,6 +13141,7 @@
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
"integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"playwright-core": "1.56.1"
},
@@ -13261,6 +13257,7 @@
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -13295,7 +13292,6 @@
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -13310,7 +13306,6 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10"
},
@@ -13322,8 +13317,7 @@
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/prismjs": {
"version": "1.30.0",
@@ -13537,6 +13531,7 @@
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz",
"integrity": "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ramda"
@@ -13616,6 +13611,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -13625,6 +13621,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -14197,6 +14194,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
"integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -14779,15 +14777,13 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz",
"integrity": "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/sort-package-json": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.4.0.tgz",
"integrity": "sha512-97oFRRMM2/Js4oEA9LJhjyMlde+2ewpZQf53pgue27UkbEXfHJnDzHlUxQ/DWUkzqmp7DFwJp8D+wi/TYeQhpA==",
"license": "MIT",
"peer": true,
"dependencies": {
"detect-indent": "^7.0.1",
"detect-newline": "^4.0.1",
@@ -14922,6 +14918,7 @@
"resolved": "https://registry.npmjs.org/storybook/-/storybook-10.0.8.tgz",
"integrity": "sha512-vQMufKKA9TxgoEDHJv3esrqUkjszuuRiDkThiHxENFPdQawHhm2Dei+iwNRwH5W671zTDy9iRT9P1KDjcU5Iyw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.6.0",
@@ -15816,7 +15813,6 @@
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
"integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@pkgr/core": "^0.2.9"
},
@@ -16019,18 +16015,6 @@
"node": ">=6"
}
},
"node_modules/tree-sitter": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz",
"integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-addon-api": "^8.0.0",
"node-gyp-build": "^4.8.0"
}
},
"node_modules/tree-sitter-json": {
"version": "0.24.8",
"resolved": "https://registry.npmjs.org/tree-sitter-json/-/tree-sitter-json-0.24.8.tgz",
@@ -16261,6 +16245,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -16274,6 +16259,7 @@
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.47.0.tgz",
"integrity": "sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.47.0",
"@typescript-eslint/parser": "8.47.0",
@@ -16653,6 +16639,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz",
"integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==",
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -17184,6 +17171,7 @@
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.13.tgz",
"integrity": "sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vitest/expect": "4.0.13",
"@vitest/mocker": "4.0.13",

View File

@@ -28,7 +28,8 @@ import { RuntimeLitLocalizer } from "@lit/localize-tools/lib/modes/runtime.js";
//#region Setup
const missingMessagePattern = /([\w_-]+)\smessage\s(?:[\w_-]+)\sis\smissing/;
const missingMessagePattern = /([\w_-]+)\smessage\s(?:[\w_.-]+)\sis\smissing/;
const outdatedMessagePattern = /([\w_-]+)\smessage\s(?:[\w_.-]+)\sdoes\snot\sexist/;
const logger = ConsoleLogger.child({ name: "Locales" });
const localizeRules = readConfigFileAndWriteSchema(path.join(PackageRoot, "lit-localize.json"));
@@ -38,6 +39,12 @@ if (localizeRules.interchange.format !== "xliff") {
process.exit(1);
}
const { sourceLocale } = localizeRules;
localizeRules.targetLocales = localizeRules.targetLocales.filter((locale) => {
return locale !== sourceLocale;
});
const XLIFFPath = resolve(PackageRoot, localizeRules.interchange.xliffDir);
const EmittedLocalesDirectory = resolve(
@@ -46,7 +53,7 @@ const EmittedLocalesDirectory = resolve(
);
const targetLocales = localizeRules.targetLocales.filter((localeCode) => {
return localeCode !== "pseudo-LOCALE";
return localeCode !== "pseudo_LOCALE";
});
//#endregion
@@ -153,7 +160,12 @@ export async function generateLocaleModules() {
/**
* @type {Map<string, number>}
*/
const localeWarnings = new Map();
const missingTranslationWarnings = new Map();
/**
* @type {Map<string, number>}
*/
const outdatedTranslationWarnings = new Map();
const initialConsoleWarn = console.warn;
@@ -163,12 +175,26 @@ export async function generateLocaleModules() {
return;
}
const [, matchedLocale] = arg0.match(missingMessagePattern) || [];
const [, matchedMissingTranslation] = arg0.match(missingMessagePattern) || [];
if (matchedLocale) {
const count = localeWarnings.get(matchedLocale) || 0;
if (matchedMissingTranslation) {
const count = missingTranslationWarnings.get(matchedMissingTranslation) || 0;
localeWarnings.set(matchedLocale, count + 1);
missingTranslationWarnings.set(matchedMissingTranslation, count + 1);
logger.debug(arg0);
return;
}
const [, matchedOutdatedTranslation] = arg0.match(outdatedMessagePattern) || [];
if (matchedOutdatedTranslation) {
const count = outdatedTranslationWarnings.get(matchedOutdatedTranslation) || 0;
outdatedTranslationWarnings.set(matchedOutdatedTranslation, count + 1);
logger.debug(arg0);
return;
}
@@ -181,7 +207,7 @@ export async function generateLocaleModules() {
await localizer.build();
const report = Array.from(localeWarnings)
const missingTranslationsReport = Array.from(missingTranslationWarnings)
.filter(([, count]) => count)
.sort(([, totalsA], [, totalsB]) => {
return totalsB - totalsA;
@@ -189,7 +215,17 @@ export async function generateLocaleModules() {
.map(([locale, count]) => `${locale}: ${count.toLocaleString()}`)
.join("\n");
logger.info(`Missing translations:\n${report}`);
logger.info(`Missing translations:\n${missingTranslationsReport}`);
const outdatedTranslationsReport = Array.from(outdatedTranslationWarnings)
.filter(([, count]) => count)
.sort(([, totalsA], [, totalsB]) => {
return totalsB - totalsA;
})
.map(([locale, count]) => `${locale}: ${count.toLocaleString()}`)
.join("\n");
logger.info(`Outdated translations:\n${outdatedTranslationsReport}`);
localizer.assertTranslationsAreValid();

View File

@@ -23,7 +23,7 @@ import { makeFormatter } from "@lit/localize-tools/lib/formatters/index.js";
import { sortProgramMessages } from "@lit/localize-tools/lib/messages.js";
import { TransformLitLocalizer } from "@lit/localize-tools/lib/modes/transform.js";
const pseudoLocale = /** @type {Locale} */ ("pseudo-LOCALE");
const pseudoLocale = /** @type {Locale} */ ("pseudo_LOCALE");
const targetLocales = [pseudoLocale];
const __dirname = fileURLToPath(new URL(".", import.meta.url));

View File

@@ -1,5 +1,4 @@
import "#admin/AdminInterface/AboutModal";
import "#elements/ak-locale-context/ak-locale-context";
import "#elements/banner/EnterpriseStatusBanner";
import "#elements/banner/VersionBanner";
import "#elements/messages/MessageContainer";
@@ -162,54 +161,52 @@ export class AdminInterface extends WithCapabilitiesConfig(WithSession(Authentic
"pf-m-collapsed": !drawerOpen,
};
return html` <ak-locale-context>
<div class="pf-c-page">
<ak-page-navbar ?open=${this.sidebarOpen}>
<ak-version-banner></ak-version-banner>
<ak-enterprise-status interface="admin"></ak-enterprise-status>
</ak-page-navbar>
return html`<div class="pf-c-page">
<ak-page-navbar ?open=${this.sidebarOpen}>
<ak-version-banner></ak-version-banner>
<ak-enterprise-status interface="admin"></ak-enterprise-status>
</ak-page-navbar>
<ak-sidebar ?hidden=${!this.sidebarOpen} class="${classMap(sidebarClasses)}"
>${renderSidebarItems(createAdminSidebarEntries())}
${this.can(CapabilitiesEnum.IsEnterprise)
? renderSidebarItems(createAdminSidebarEnterpriseEntries())
: nothing}
</ak-sidebar>
<ak-sidebar ?hidden=${!this.sidebarOpen} class="${classMap(sidebarClasses)}"
>${renderSidebarItems(createAdminSidebarEntries())}
${this.can(CapabilitiesEnum.IsEnterprise)
? renderSidebarItems(createAdminSidebarEnterpriseEntries())
: nothing}
</ak-sidebar>
<div class="pf-c-page__drawer">
<div class="pf-c-drawer ${classMap(drawerClasses)}">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<ak-router-outlet
role="presentation"
class="pf-c-page__main"
tabindex="-1"
id="main-content"
defaultUrl="/administration/overview"
.routes=${ROUTES}
>
</ak-router-outlet>
</div>
<div class="pf-c-page__drawer">
<div class="pf-c-drawer ${classMap(drawerClasses)}">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<ak-router-outlet
role="presentation"
class="pf-c-page__main"
tabindex="-1"
id="main-content"
defaultUrl="/administration/overview"
.routes=${ROUTES}
>
</ak-router-outlet>
</div>
<ak-notification-drawer
class="pf-c-drawer__panel pf-m-width-33 ${this
.notificationDrawerOpen
? ""
: "display-none"}"
?hidden=${!this.notificationDrawerOpen}
></ak-notification-drawer>
<ak-api-drawer
class="pf-c-drawer__panel pf-m-width-33 ${this.apiDrawerOpen
? ""
: "display-none"}"
?hidden=${!this.apiDrawerOpen}
></ak-api-drawer>
<ak-about-modal></ak-about-modal>
</div>
<ak-notification-drawer
class="pf-c-drawer__panel pf-m-width-33 ${this.notificationDrawerOpen
? ""
: "display-none"}"
?hidden=${!this.notificationDrawerOpen}
></ak-notification-drawer>
<ak-api-drawer
class="pf-c-drawer__panel pf-m-width-33 ${this.apiDrawerOpen
? ""
: "display-none"}"
?hidden=${!this.apiDrawerOpen}
></ak-api-drawer>
<ak-about-modal></ak-about-modal>
</div>
</div></div
></ak-locale-context>`;
</div>
</div>
</div>`;
}
}

View File

@@ -75,7 +75,7 @@ export class BrandForm extends ModelForm<Brand, string> {
<ak-switch-input
name="_default"
label=${msg("Sign assertions")}
label=${msg("Default")}
?checked=${this.instance?._default ?? false}
help=${msg("Use this brand for each domain that doesn't have a dedicated brand.")}
>

View File

@@ -4,11 +4,10 @@ import {
LocaleMiddleware,
LoggingMiddleware,
} from "#common/api/middleware";
import { EVENT_LOCALE_REQUEST } from "#common/constants";
import { globalAK } from "#common/global";
import { SentryMiddleware } from "#common/sentry/middleware";
import { Config, Configuration, CoreApi, CurrentBrand, RootApi } from "@goauthentik/api";
import { Config, Configuration, CurrentBrand, RootApi } from "@goauthentik/api";
let globalConfigPromise: Promise<Config> | undefined = Promise.resolve(globalAK().config);
export function config(): Promise<Config> {
@@ -35,34 +34,6 @@ export function brandSetFavicon(brand: CurrentBrand) {
});
}
export function brandSetLocale(brand: CurrentBrand) {
if (brand.defaultLocale === "") {
return;
}
console.debug("authentik/locale: setting locale from brand default");
window.dispatchEvent(
new CustomEvent(EVENT_LOCALE_REQUEST, {
composed: true,
bubbles: true,
detail: { locale: brand.defaultLocale },
}),
);
}
let globalBrandPromise: Promise<CurrentBrand> | undefined = Promise.resolve(globalAK().brand);
export function brand(): Promise<CurrentBrand> {
if (!globalBrandPromise) {
globalBrandPromise = new CoreApi(DEFAULT_CONFIG)
.coreBrandsCurrentRetrieve()
.then((brand) => {
brandSetFavicon(brand);
brandSetLocale(brand);
return brand;
});
}
return globalBrandPromise;
}
export const DEFAULT_CONFIG = new Configuration({
basePath: `${globalAK().api.base}api/v3`,
middleware: [

View File

@@ -35,7 +35,6 @@ export const EVENT_API_DRAWER_TOGGLE = "ak-api-drawer-toggle";
export const EVENT_FLOW_INSPECTOR_TOGGLE = "ak-flow-inspector-toggle";
export const EVENT_WS_MESSAGE = "ak-ws-message";
export const EVENT_FLOW_ADVANCE = "ak-flow-advance";
export const EVENT_LOCALE_CHANGE = "ak-locale-change";
export const EVENT_LOCALE_REQUEST = "ak-locale-request";
export const EVENT_REQUEST_POST = "ak-request-post";
export const EVENT_MESSAGE = "ak-message";

View File

@@ -0,0 +1,147 @@
import { type allLocales, sourceLocale } from "../../../locale-codes.js";
import type { LocaleModule } from "@lit/localize";
import { msg } from "@lit/localize";
export type TargetLocale = (typeof allLocales)[number];
/**
* A dummy locale module representing the source locale (English).
*
* @remarks
* This is used to satisfy the return type of {@linkcode LocaleLoaderRecord}
* for the source locale, which does not need to be loaded.
*/
const sourceTargetModule: LocaleModule = {
templates: {},
};
/**
* A record mapping locale codes to their respective human-readable labels.
*
* @remarks
* These are thunked functions to allow for localization via `msg()`.
*/
export const LocaleLabelRecord: Record<TargetLocale, () => string> = {
[sourceLocale]: () => msg("English"),
pseudo_LOCALE: () => msg("Pseudolocale (for testing)"),
cs_CZ: () => msg("Czech"),
de_DE: () => msg("German"),
es_ES: () => msg("Spanish"),
fr_FR: () => msg("French"),
it_IT: () => msg("Italian"),
ja_JP: () => msg("Japanese"),
ko_KR: () => msg("Korean"),
nl_NL: () => msg("Dutch"),
pl_PL: () => msg("Polish"),
ru_RU: () => msg("Russian"),
tr_TR: () => msg("Turkish"),
zh_Hans: () => msg("Chinese (simplified)"),
zh_Hant: () => msg("Chinese (traditional)"),
};
/**
* A tuple representing a locale label and its corresponding code.
*/
export type LocaleOption = [label: string, code: TargetLocale];
/**
* Format the locale options for use in a user-facing element.
*
* @param locales locales argument for locale-sensitive sorting.
* @param collatorOptions Optional collator options for locale-sensitive sorting.
* @returns An array of locale options sorted by their labels.
*/
export function formatLocaleOptions(
locales?: Intl.LocalesArgument,
collatorOptions?: Intl.CollatorOptions,
): LocaleOption[] {
const options = Object.entries(LocaleLabelRecord)
.map(([code, label]) => {
return [label(), code];
})
.sort(([aLabel], [bLabel]) => aLabel.localeCompare(bLabel, locales, collatorOptions));
return options as LocaleOption[];
}
/**
* A record mapping locale codes to their respective module loaders.
*
* @remarks
* The `import` statements **must** reference a locale module path,
* as this is how ESBuild identifies which files to include in the build.
*/
export const LocaleLoaderRecord: Record<TargetLocale, () => Promise<LocaleModule>> = {
[sourceLocale]: () => Promise.resolve(sourceTargetModule),
pseudo_LOCALE: () => import("#locales/pseudo_LOCALE"),
cs_CZ: () => import("#locales/cs_CZ"),
de_DE: () => import("#locales/de_DE"),
es_ES: () => import("#locales/es_ES"),
fr_FR: () => import("#locales/fr_FR"),
it_IT: () => import("#locales/it_IT"),
ja_JP: () => import("#locales/ja_JP"),
ko_KR: () => import("#locales/ko_KR"),
nl_NL: () => import("#locales/nl_NL"),
pl_PL: () => import("#locales/pl_PL"),
ru_RU: () => import("#locales/ru_RU"),
tr_TR: () => import("#locales/tr_TR"),
zh_Hans: () => import("#locales/zh_Hans"),
zh_Hant: () => import("#locales/zh_Hant"),
};
/**
* A record mapping locale codes to their respective regex patterns.
*
* @remarks
* While this isn't too useful on its own, we use it to build the {@linkcode LocalePatternCodeMap}
* while ensuring that TypeScript can verify that all locale codes are covered.
*
* The matchers try to conform loosely to [RFC 5646](https://www.rfc-editor.org/rfc/rfc5646.txt),
* "Tags for the Identification of Languages."
* In practice, language tags have been seen using both hyphens and underscores.
*
* Chinese language (`zh` or _Zhongwen_) can have a subtag indicating script:
*
* - `Hans`: Simplified
* - `Hant`: Traditional
*
* Alternatively, the subtag can indicate a region with a predominant script.
* The fallback is simplified Chinese.
*/
export const LocalePatternRecord: Record<TargetLocale, RegExp> = {
[sourceLocale]: /^en([_-]|$)/i,
pseudo_LOCALE: /^pseudo/i,
cs_CZ: /^cs([_-]|$)/i,
de_DE: /^de([_-]|$)/i,
es_ES: /^es([_-]|$)/i,
fr_FR: /^fr([_-]|$)/i,
it_IT: /^it([_-]|$)/i,
ja_JP: /^ja([_-]|$)/i,
ko_KR: /^ko([_-]|$)/i,
nl_NL: /^nl([_-]|$)/i,
pl_PL: /^pl([_-]|$)/i,
ru_RU: /^ru([_-]|$)/i,
tr_TR: /^tr([_-]|$)/i,
/**
* Traditional Chinese.
*
* The region subtag is required.
*/
zh_Hant: /^zh[_-](TW|HK|MO|Hant)/i,
/**
* Simplified Chinese.
*
* The region subtag is optional.
*/
zh_Hans: /^zh([_-](CN|SG|MY|Hans)|$)/i,
};
/**
* A mapping of regex patterns to locale codes for matching user-supplied locale strings.
*
* @see {@linkcode LocalePatternRecord} for the source of this map.
*/
export const LocalePatternCodeMap = new Map<RegExp, TargetLocale>(
Object.entries(LocalePatternRecord).map(([code, pattern]) => [pattern, code as TargetLocale]),
);

View File

@@ -1,10 +0,0 @@
import type { LocaleModule } from "@lit/localize";
export type LocaleRow = [string, RegExp, () => string, () => Promise<LocaleModule>];
export type AkLocale = {
code: string;
match: RegExp;
label: () => string;
locale: () => Promise<LocaleModule>;
};

View File

@@ -0,0 +1,74 @@
import { sourceLocale } from "../../../locale-codes.js";
import { LocalePatternCodeMap, TargetLocale } from "#common/ui/locale/definitions";
export function getBestMatchLocale(locale: string): TargetLocale | null {
const [, localeCode] =
Iterator.from(LocalePatternCodeMap).find(([pattern]) => pattern.test(locale)) || [];
return localeCode ?? null;
}
/**
* Find the first supported locale from a list of candidates.
*
* @param candidates An array of locale strings to check.
* @returns The first supported locale code, or null if none found.
*
* @remarks
* This looks weird, but it's sensible: we have several candidates, and we want to find the first
* one that has a supported locale. Then, from *that*, we have to extract that first supported
* locale.
*/
export function findSupportedLocale(candidates: string[]): TargetLocale | null {
const candidate = candidates.find((candidate) => getBestMatchLocale(candidate));
return candidate ? getBestMatchLocale(candidate) : null;
}
/**
* Auto-detect the best locale to use from several sources.
*
* @param localeHint An optional locale code hint.
* @param fallbackLocaleCode An optional fallback locale code.
* @returns The best-matching supported locale code.
*
* @remarks
* The order of precedence is:
*
* 1. A `locale` URL parameter
* 2. A provided locale hint
* 3. The browser's navigator language
* 4. A provided fallback locale code
* 5. The source locale (English)
*/
export function autoDetectLanguage(localeHint?: string, fallbackLocaleCode?: string): TargetLocale {
let localeParam: string | null = null;
if (self.location) {
const searchParam = new URLSearchParams(self.location.search);
localeParam = searchParam.get("locale");
}
const candidates = [
localeParam,
localeHint,
self.navigator?.language,
fallbackLocaleCode,
].filter((item): item is string => !!item);
const firstSupportedLocale = findSupportedLocale(candidates);
if (!firstSupportedLocale) {
console.debug(`authentik/locale: Falling back to source locale`, {
sourceLocale,
localeHint,
fallbackLocaleCode,
candidates,
});
return sourceLocale;
}
return firstSupportedLocale;
}

View File

@@ -1,5 +1,4 @@
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_LOCALE_REQUEST } from "#common/constants";
import { isResponseErrorLike } from "#common/errors/network";
import { UIConfig, UserDisplay } from "#common/ui/config";
@@ -85,23 +84,6 @@ export async function me(requestInit?: RequestInit): Promise<SessionUser> {
return new CoreApi(DEFAULT_CONFIG)
.coreUsersMeRetrieve(requestInit)
.then((nextSession) => {
const locale: string | undefined = nextSession.user.settings.locale;
if (locale) {
console.debug(`authentik/locale: Activating user's configured locale '${locale}'`);
window.dispatchEvent(
new CustomEvent(EVENT_LOCALE_REQUEST, {
composed: true,
bubbles: true,
detail: { locale },
}),
);
}
return nextSession;
})
.catch(async (error: unknown) => {
if (isResponseErrorLike(error)) {
const { response } = error;

View File

@@ -4,6 +4,7 @@ import { applyDocumentTheme, createUIThemeEffect } from "#common/theme";
import { AKElement } from "#elements/Base";
import { BrandingContextController } from "#elements/controllers/BrandContextController";
import { ConfigContextController } from "#elements/controllers/ConfigContextController";
import { LocaleContextController } from "#elements/controllers/LocaleContextController";
import { ModalOrchestrationController } from "#elements/controllers/ModalOrchestrationController";
/**
@@ -13,10 +14,11 @@ export abstract class Interface extends AKElement {
constructor() {
super();
const { config, brand } = globalAK();
const { config, brand, locale } = globalAK();
createUIThemeEffect(applyDocumentTheme);
this.addController(new LocaleContextController(this, locale));
this.addController(new ConfigContextController(this, config));
this.addController(new BrandingContextController(this, brand));
this.addController(new ModalOrchestrationController());

View File

@@ -1,52 +0,0 @@
import "./ak-locale-context.js";
import { EVENT_LOCALE_REQUEST } from "#common/constants";
import { customEvent } from "#elements/utils/customEvents";
import { localized, msg } from "@lit/localize";
import { html, LitElement } from "lit";
import { customElement } from "lit/decorators.js";
export default {
title: "Elements / Shell / Locale Context",
};
@localized()
@customElement("ak-locale-demo-component")
export class AKLocaleDemoComponent extends LitElement {
render() {
return html`<span>${msg("Everything is ok.")}</span>`;
}
}
@localized()
@customElement("ak-locale-sensitive-demo-component")
export class AKLocaleSensitiveDemoComponent extends LitElement {
render() {
return html`<p>${msg("Everything is ok.")}</p>`;
}
}
export const InFrench = () =>
html`<div style="padding: 4em">
<ak-locale-context locale="fr"
><ak-locale-demo-component
>Everything is not ok.</ak-locale-demo-component
></ak-locale-context
>
</div>`;
export const SwitchingBackAndForth = () => {
let lang = "en";
window.setInterval(() => {
lang = lang === "en" ? "fr" : "en";
window.dispatchEvent(customEvent(EVENT_LOCALE_REQUEST, { locale: lang }));
}, 1000);
return html`<div style="padding: 4em">
<ak-locale-context locale="fr">
<ak-locale-sensitive-demo-component></ak-locale-sensitive-demo-component
></ak-locale-context>
</div>`;
};

View File

@@ -1,104 +0,0 @@
import type { LocaleGetter, LocaleSetter } from "./configureLocale.js";
import { initializeLocalization } from "./configureLocale.js";
import { autoDetectLanguage, DEFAULT_LOCALE, getBestMatchLocale } from "./helpers.js";
import { EVENT_LOCALE_CHANGE, EVENT_LOCALE_REQUEST } from "#common/constants";
import { globalAK } from "#common/global";
import { AKElement } from "#elements/Base";
import { customEvent } from "#elements/utils/customEvents";
import { customElement, property } from "lit/decorators.js";
/**
* A component to manage your locale settings.
*
* ## Details
*
* This component exists to take a locale setting from several different places, find the
* appropriate locale file in our catalog of locales, and set the lit-localization context
* appropriately. If that works, it sends off an event saying so.
*
* @element ak-locale-context
* @slot - The content which consumes this context
* @fires ak-locale-change - When a valid locale has been swapped in
*/
@customElement("ak-locale-context")
export class LocaleContext extends AKElement {
protected createRenderRoot(): HTMLElement | DocumentFragment {
return this;
}
/// @attribute The text representation of the current locale */
@property({ attribute: true, type: String, useDefault: true })
public locale = globalAK().locale || DEFAULT_LOCALE;
/// @attribute The URL parameter to look for (if any)
@property({ attribute: true, type: String, useDefault: true })
public param = "locale";
getLocale: LocaleGetter;
setLocale: LocaleSetter;
constructor(code = DEFAULT_LOCALE) {
super();
this.notifyApplication = this.notifyApplication.bind(this);
this.updateLocaleHandler = this.updateLocaleHandler.bind(this);
try {
const [getLocale, setLocale] = initializeLocalization();
this.getLocale = getLocale;
this.setLocale = setLocale;
this.setLocale(code).then(() => {
window.setTimeout(this.notifyApplication, 0);
});
} catch (e) {
throw new Error(`Developer error: Must have only one locale context per session: ${e}`);
}
}
connectedCallback() {
super.connectedCallback();
this.updateLocale();
window.addEventListener(EVENT_LOCALE_REQUEST, this.updateLocaleHandler as EventListener);
}
disconnectedCallback() {
window.removeEventListener(EVENT_LOCALE_REQUEST, this.updateLocaleHandler as EventListener);
super.disconnectedCallback();
}
updateLocaleHandler(ev: CustomEvent<{ locale: string }>) {
console.debug("authentik/locale: Locale update request received.");
this.updateLocale(ev.detail.locale);
}
updateLocale(requestedLocale: string | undefined = undefined) {
const localeRequest = autoDetectLanguage(requestedLocale, this.locale);
const locale = getBestMatchLocale(localeRequest);
if (!locale) {
console.warn(`authentik/locale: failed to find locale for code ${localeRequest}`);
return;
}
locale.locale().then(() => {
console.debug(`authentik/locale: Setting Locale to ${locale.label()} (${locale.code})`);
this.setLocale(locale.code).then(() => {
window.setTimeout(this.notifyApplication, 0);
});
});
}
notifyApplication() {
// You will almost never have cause to catch this event. Lit's own `@localized()` decorator
// works just fine for almost every use case.
this.dispatchEvent(customEvent(EVENT_LOCALE_CHANGE));
}
}
export default LocaleContext;
declare global {
interface HTMLElementTagNameMap {
"ak-locale-context": LocaleContext;
}
}

View File

@@ -1,39 +0,0 @@
import { sourceLocale, targetLocales } from "../../locale-codes.js";
import { getBestMatchLocale } from "./helpers.js";
import { configureLocalization } from "@lit/localize";
type LocaleGetter = ReturnType<typeof configureLocalization>["getLocale"];
type LocaleSetter = ReturnType<typeof configureLocalization>["setLocale"];
// Internal use only.
//
// This is where the lit-localization module is initialized with our loader, which associates our
// collection of locales with its getter and setter functions.
let getLocale: LocaleGetter | undefined = undefined;
let setLocale: LocaleSetter | undefined = undefined;
export function initializeLocalization(): [LocaleGetter, LocaleSetter] {
if (getLocale && setLocale) {
return [getLocale, setLocale];
}
({ getLocale, setLocale } = configureLocalization({
sourceLocale,
targetLocales,
loadLocale: async (locale: string) => {
const localeDef = getBestMatchLocale(locale);
if (!localeDef) {
console.warn(`Unrecognized locale: ${localeDef}`);
return Promise.reject("");
}
return localeDef.locale();
},
}));
return [getLocale, setLocale];
}
export default initializeLocalization;
export type { LocaleGetter, LocaleSetter };

View File

@@ -1,4 +0,0 @@
import { createContext } from "@lit/context";
export const localeContext = createContext<string>("locale");
export default localeContext;

View File

@@ -1,67 +0,0 @@
import { AkLocale, LocaleRow } from "./types.js";
import type { LocaleModule } from "@lit/localize";
import { msg } from "@lit/localize";
export const DEFAULT_FALLBACK = "en";
export const enLocale: LocaleModule = {
templates: {},
};
// NOTE: This table cannot be made any shorter, despite all the repetition of syntax. Bundlers look
// for the `import` #a *string target* for doing alias substitution, so putting
// the import in some sort of abstracting function doesn't work. The same is true for the `msg()`
// function, which `localize` uses to find strings for extraction and translation. Likewise,
// because this is a file-level table, the `msg()` must be thunked so that they're re-run when
// the user changes the locale.
// NOTE: The matchers try to conform loosely to [RFC
// 5646](https://www.rfc-editor.org/rfc/rfc5646.txt), "Tags for the Identification of Languages." In
// practice, language tags have been seen using both hyphens and underscores, and the Chinese
// language uses both "regional" and "script" suffixes. The regexes use the language and any region
// or script.
//
// Chinese locales usually (but not always) use the script rather than region suffix. The default
// (optional) fallback for Chinese (zh) is "Chinese (simplified)", which is why it has that odd
// regex syntax at the end which means "match zh as long as it's not followed by a [:word:] token";
// Traditional script and the Taiwanese are attempted first, and if neither matches, anything
// beginning with that generic "zh" is mapped to "Chinese (simplified)."
// - Code for Lit/Locale
// - Regex for matching user-supplied locale.
// - Text Label
// - Locale loader.
// prettier-ignore
const debug: LocaleRow = [
"pseudo-LOCALE", /^pseudo/i, () => msg("Pseudolocale (for testing)"), () => import("#locales/pseudo-LOCALE"),
];
// prettier-ignore
const LOCALE_TABLE: LocaleRow[] = [
["de", /^de([_-]|$)/i, () => msg("German"), () => import("#locales/de")],
["en", /^en([_-]|$)/i, () => msg("English"), () => Promise.resolve(enLocale)],
["es", /^es([_-]|$)/i, () => msg("Spanish"), () => import("#locales/es")],
["fr", /^fr([_-]|$)/i, () => msg("French"), () => import("#locales/fr")],
["it", /^it([_-]|$)/i, () => msg("Italian"), () => import("#locales/it")],
["ja", /^ja([_-]|$)/i, () => msg("Japanese"), () => import("#locales/ja")],
["ko", /^ko([_-]|$)/i, () => msg("Korean"), () => import("#locales/ko")],
["nl", /^nl([_-]|$)/i, () => msg("Dutch"), () => import("#locales/nl")],
["pl", /^pl([_-]|$)/i, () => msg("Polish"), () => import("#locales/pl")],
["ru", /^ru([_-]|$)/i, () => msg("Russian"), () => import("#locales/ru")],
["tr", /^tr([_-]|$)/i, () => msg("Turkish"), () => import("#locales/tr")],
["zh_TW", /^zh[_-]TW$/i, () => msg("Taiwanese Mandarin"), () => import("#locales/zh_TW")],
["zh-Hans", /^zh(\b|_)/i, () => msg("Chinese (simplified)"), () => import("#locales/zh-Hans")],
["zh-Hant", /^zh[_-](HK|Hant)/i, () => msg("Chinese (traditional)"), () => import("#locales/zh-Hant")],
debug
];
export const LOCALES: AkLocale[] = LOCALE_TABLE.map(([code, match, label, locale]) => ({
code,
match,
label,
locale,
}));
export default LOCALES;

View File

@@ -1,70 +0,0 @@
import { enLocale, LOCALES as RAW_LOCALES } from "./definitions.js";
import { AkLocale } from "./types.js";
import { globalAK } from "#common/global";
export const DEFAULT_LOCALE = "en";
export const EVENT_REQUEST_LOCALE = "ak-request-locale";
const TOMBSTONE = "⛼⛼tombstone⛼⛼";
// NOTE: This is the definition of the LOCALES table that most of the code uses. The 'definitions'
// file is relatively pure, but here we establish that we want the English locale to loaded when an
// application is first instantiated.
export const LOCALES = RAW_LOCALES.map((locale) =>
locale.code === "en" ? { ...locale, locale: async () => enLocale } : locale,
);
export function getBestMatchLocale(locale: string): AkLocale | null {
return LOCALES.find((l) => l.match.test(locale)) || null;
}
// This looks weird, but it's sensible: we have several candidates, and we want to find the first
// one that has a supported locale. Then, from *that*, we have to extract that first supported
// locale.
export function findSupportedLocale(candidates: string[]): AkLocale | null {
const candidate = candidates.find((candidate: string) => getBestMatchLocale(candidate));
return candidate ? getBestMatchLocale(candidate) : null;
}
export function localeCodeFromUrl(param = "locale") {
const url = new URL(window.location.href);
return url.searchParams.get(param) || "";
}
// Get all locales we can, in order
// - Global authentik settings (contains user settings)
// - URL parameter
// - A requested code passed in, if any
// - Navigator
// - Fallback (en)
const isLocaleCandidate = (v: unknown): v is string =>
typeof v === "string" && v !== "" && v !== TOMBSTONE;
export function autoDetectLanguage(userReq = TOMBSTONE, brandReq = TOMBSTONE): string {
const localeCandidates: string[] = [
localeCodeFromUrl("locale"),
userReq,
window.navigator?.language ?? TOMBSTONE,
brandReq,
globalAK()?.locale ?? TOMBSTONE,
DEFAULT_LOCALE,
].filter(isLocaleCandidate);
const firstSupportedLocale = findSupportedLocale(localeCandidates);
if (!firstSupportedLocale) {
console.debug(
`authentik/locale: No locale found for '[${localeCandidates}.join(',')]', falling back to ${DEFAULT_LOCALE}`,
);
return DEFAULT_LOCALE;
}
return firstSupportedLocale.code;
}
export default autoDetectLanguage;

View File

@@ -1,4 +0,0 @@
import LocaleContext from "./ak-locale-context.js";
export { LocaleContext };
export default LocaleContext;

View File

@@ -1,15 +0,0 @@
import type { LocaleModule } from "@lit/localize";
export type LocaleRow = [
code: string,
pattern: RegExp,
label: () => string,
loader: () => Promise<LocaleModule>,
];
export type AkLocale = {
code: string;
match: RegExp;
label: () => string;
locale: () => Promise<LocaleModule>;
};

View File

@@ -0,0 +1,164 @@
import { sourceLocale, targetLocales } from "../../locale-codes.js";
import { LocaleLabelRecord, LocaleLoaderRecord, TargetLocale } from "#common/ui/locale/definitions";
import { autoDetectLanguage } from "#common/ui/locale/utils";
import { kAKLocale, LocaleContext, LocaleMixin } from "#elements/mixins/locale";
import type { ReactiveElementHost } from "#elements/types";
import { ContextProvider } from "@lit/context";
import { configureLocalization } from "@lit/localize";
import type { ReactiveController } from "lit";
/**
* A controller that provides the application configuration to the element.
*/
export class LocaleContextController implements ReactiveController {
protected static DocumentObserverInit: MutationObserverInit = {
attributes: true,
attributeFilter: ["lang"],
attributeOldValue: true,
};
#log = console.debug.bind(console, `authentik/controller/locale`);
/**
* Attempts to apply the given locale code.
* @param nextLocale A user or agent preferred locale code.
*/
#applyLocale(nextLocale: TargetLocale) {
const currentLocale = this.#context.value.getLocale();
const label = LocaleLabelRecord[nextLocale]();
if (currentLocale === nextLocale) {
this.#log("Skipping locale update, already set to:", label);
return;
}
this.#context.value.setLocale(nextLocale);
this.#host.locale = nextLocale;
this.#log("Applied locale:", label);
}
// #region Attribute Observation
/**
* Synchronizes changes to the document's `lang` attribute to the locale context.
*
* @remarks
* While we don't expect the document's `lang` attribute to change outside of
* this controller, we observe it to respect a possible external change,
* such as from the user agent's language settings, or a browser extension which
* modifies the attribute.
*/
#attributeListener = (mutations: MutationRecord[]) => {
for (const mutation of mutations) {
if (mutation.type !== "attributes" || mutation.attributeName !== "lang") {
continue;
}
const attribute = {
previous: mutation.oldValue,
current: document.documentElement.lang,
};
this.#log("Detected document `lang` attribute change", attribute);
if (attribute.previous === attribute.current) {
this.#log("Skipping locale update, `lang` unchanged", attribute);
continue;
}
const nextLocale = autoDetectLanguage(attribute.current);
this.#applyLocale(nextLocale);
return;
}
};
#documentObserver = new MutationObserver(this.#attributeListener);
#connectDocumentObserver() {
this.#documentObserver.observe(
document.documentElement,
LocaleContextController.DocumentObserverInit,
);
}
#disconnectDocumentObserver() {
this.#documentObserver.disconnect();
}
//#endregion
//#region Lifecycle
/**
* Loads the locale module for the given locale code.
*
* @param _locale The locale code to load.
*
* @remarks
* This is used by `@lit/localize` to dynamically load locale modules,
* as well synchronizing the document's `lang` attribute.
*/
#loadLocale = (_locale: string) => {
// TypeScript cannot infer the type here, but Lit Localize will only call this
// function with one of the `targetLocales`.
const locale = _locale as TargetLocale;
const label = LocaleLabelRecord[locale]();
this.#log(`Loading "${label}" module...`);
const loader = LocaleLoaderRecord[locale];
this.#log(`Updating \`lang\` attribute to: \`${locale}\``);
// Prevent observation while we update the `lang` attribute...
this.#disconnectDocumentObserver();
document.documentElement.lang = locale;
this.#connectDocumentObserver();
return loader();
};
#host: ReactiveElementHost<LocaleMixin>;
#context: ContextProvider<LocaleContext>;
/**
* @param host The host element.
* @param localeHint The initial locale code to set.
*/
constructor(host: ReactiveElementHost<LocaleMixin>, localeHint?: string) {
this.#host = host;
const contextValue = configureLocalization({
sourceLocale,
targetLocales,
loadLocale: this.#loadLocale,
});
this.#context = new ContextProvider(this.#host, {
context: LocaleContext,
initialValue: contextValue,
});
this.#host[kAKLocale] = contextValue;
const nextLocale = autoDetectLanguage(localeHint);
if (nextLocale !== sourceLocale) {
this.#applyLocale(nextLocale);
}
}
public hostDisconnected() {
this.#documentObserver.disconnect();
}
//#endregion
}

View File

@@ -1,9 +1,11 @@
import type { APIResult } from "#common/api/responses";
import { EVENT_WS_MESSAGE } from "#common/constants";
import { isCausedByAbortError, parseAPIResponseError } from "#common/errors/network";
import { autoDetectLanguage } from "#common/ui/locale/utils";
import { me } from "#common/users";
import { AKConfigMixin, kAKConfig } from "#elements/mixins/config";
import { kAKLocale, type LocaleMixin } from "#elements/mixins/locale";
import { SessionContext, SessionMixin } from "#elements/mixins/session";
import type { ReactiveElementHost } from "#elements/types";
@@ -23,7 +25,7 @@ export class SessionContextController implements ReactiveController {
#log = console.debug.bind(console, `authentik/controller/session`);
#abortController: null | AbortController = null;
#host: ReactiveElementHost<SessionMixin & AKConfigMixin>;
#host: ReactiveElementHost<LocaleMixin & SessionMixin & AKConfigMixin>;
#context: ContextProvider<SessionContext>;
constructor(
@@ -49,6 +51,14 @@ export class SessionContextController implements ReactiveController {
signal: this.#abortController.signal,
})
.then((session) => {
const localeHint: string | undefined = session.user.settings.locale;
if (localeHint) {
const locale = autoDetectLanguage(localeHint);
this.#log(`Activating user's configured locale '${locale}'`);
this.#host[kAKLocale]?.setLocale(locale);
}
const config = this.#host[kAKConfig];
if (config?.errorReporting.sendPii) {

View File

@@ -0,0 +1,74 @@
import { TargetLocale } from "#common/ui/locale/definitions";
import { createMixin } from "#elements/types";
import { consume, createContext } from "@lit/context";
import type { configureLocalization } from "@lit/localize";
export type LocaleContextValue = ReturnType<typeof configureLocalization>;
export const kAKLocale = Symbol("kAKLocale");
/**
* The Lit context for the application configuration.
*
* @category Context
* @see {@linkcode LocaleMixin}
* @see {@linkcode WithLocale}
*/
export const LocaleContext = createContext<LocaleContextValue>(
Symbol.for("authentik-locale-context"),
);
export type LocaleContext = typeof LocaleContext;
/**
* A consumer that provides session information to the element.
*
* @category Mixin
* @see {@linkcode WithLocale}
*/
export interface LocaleMixin {
/**
* The locale context value.
*
* @internal
*/
readonly [kAKLocale]: Readonly<LocaleContextValue>;
/**
* The current locale code.
*/
locale: TargetLocale;
}
/**
* A mixin that provides locale information to the element.
*
* @category Mixin
*/
export const WithLocale = createMixin<LocaleMixin>(
({
// ---
SuperClass,
subscribe = true,
}) => {
abstract class LocaleProvider extends SuperClass implements LocaleMixin {
@consume({
context: LocaleContext,
subscribe,
})
public [kAKLocale]!: LocaleContextValue;
public get locale(): TargetLocale {
return this[kAKLocale].getLocale() as TargetLocale;
}
public set locale(value: TargetLocale) {
this[kAKLocale].setLocale(value);
}
}
return LocaleProvider;
},
);

View File

@@ -1,5 +1,4 @@
import "#elements/LoadingOverlay";
import "#elements/ak-locale-context/ak-locale-context";
import "#flow/components/ak-brand-footer";
import "#flow/components/ak-flow-card";
import "#flow/sources/apple/AppleLoginInit";

View File

@@ -2,6 +2,7 @@ import { pluckErrorDetail } from "#common/errors/network";
import { AKElement } from "#elements/Base";
import { intersectionObserver } from "#elements/decorators/intersection-observer";
import { WithLocale } from "#elements/mixins/locale";
import { FocusTarget } from "#elements/utils/focus";
import { ContextualFlowInfo, CurrentBrand, ErrorDetail } from "@goauthentik/api";
@@ -56,7 +57,7 @@ export interface ResponseErrorsChallenge {
export abstract class BaseStage<
Tin extends FlowInfoChallenge & PendingUserChallenge & ResponseErrorsChallenge,
Tout,
> extends AKElement {
> extends WithLocale(AKElement) {
static shadowRootOptions: ShadowRootInit = {
...LitElement.shadowRootOptions,
delegatesFocus: true,

View File

@@ -3,7 +3,6 @@ import "#flow/components/ak-flow-card";
import { pluckErrorDetail } from "#common/errors/network";
import autoDetectLanguage from "#elements/ak-locale-context/helpers";
import { akEmptyState } from "#elements/EmptyState";
import { ifPresent } from "#elements/utils/attributes";
import { ListenerController } from "#elements/utils/listenerController";
@@ -134,8 +133,6 @@ export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeRe
#captchaDocumentContainer?: HTMLDivElement;
#listenController = new ListenerController();
#locale: string | null = null;
//#endregion
//#region Getters/Setters
@@ -195,7 +192,7 @@ export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeRe
sitekey: this.challenge.siteKey,
callback: this.onTokenChange,
size: "invisible",
hl: this.#locale ?? undefined,
hl: this.locale,
}),
);
});
@@ -230,7 +227,7 @@ export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeRe
sitekey: this.challenge.siteKey,
callback: this.onTokenChange,
size: "invisible",
hl: this.#locale ?? undefined,
hl: this.locale,
}),
);
}
@@ -256,7 +253,7 @@ export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeRe
data-theme="${this.activeTheme}"
data-callback="callback"
data-size="flexible"
data-language=${ifPresent(this.#locale)}
data-language=${ifPresent(this.locale)}
></div>`;
};
@@ -375,8 +372,6 @@ export class CaptchaStage extends BaseStage<CaptchaChallenge, CaptchaChallengeRe
window.addEventListener("message", this.#messageListener, {
signal: this.#listenController.signal,
});
this.#locale = autoDetectLanguage();
}
public disconnectedCallback(): void {

View File

@@ -1,7 +1,8 @@
import "#elements/Divider";
import "#flow/components/ak-flow-card";
import { LOCALES } from "#elements/ak-locale-context/definitions";
import { formatLocaleOptions } from "#common/ui/locale/definitions";
import { CapabilitiesEnum, WithCapabilitiesConfig } from "#elements/mixins/capabilities";
import { AKFormErrors } from "#components/ak-field-errors";
@@ -214,16 +215,16 @@ ${prompt.initialValue}</textarea
</div> `;
})}`;
case PromptTypeEnum.AkLocale: {
const locales = this.can(CapabilitiesEnum.CanDebug)
? LOCALES
: LOCALES.filter((locale) => locale.code !== "debug");
const options = locales.map(
(locale) =>
html`<option
value=${locale.code}
?selected=${locale.code === prompt.initialValue}
>
${locale.code.toUpperCase()} - ${locale.label()}
let localeOptions = formatLocaleOptions();
if (!this.can(CapabilitiesEnum.CanDebug)) {
localeOptions = localeOptions.filter(([, code]) => code !== "pseudo-LOCALE");
}
const options = localeOptions.map(
([label, code]) =>
html`<option value=${code} ?selected=${code === prompt.initialValue}>
${label}
</option> `,
);

View File

@@ -12,21 +12,19 @@ export const sourceLocale = `en`;
*/
export const targetLocales = [
`cs_CZ`,
`de`,
`es`,
`fr`,
`it`,
`ja`,
`ko`,
`nl`,
`pl`,
`pseudo-LOCALE`,
`ru`,
`tr`,
`zh_TW`,
`zh-CN`,
`zh-Hans`,
`zh-Hant`,
`de_DE`,
`es_ES`,
`fr_FR`,
`it_IT`,
`ja_JP`,
`ko_KR`,
`nl_NL`,
`pl_PL`,
`pseudo_LOCALE`,
`ru_RU`,
`tr_TR`,
`zh_Hans`,
`zh_Hant`,
] as const;
/**
@@ -34,20 +32,18 @@ export const targetLocales = [
*/
export const allLocales = [
`cs_CZ`,
`de`,
`de_DE`,
`en`,
`es`,
`fr`,
`it`,
`ja`,
`ko`,
`nl`,
`pl`,
`pseudo-LOCALE`,
`ru`,
`tr`,
`zh_TW`,
`zh-CN`,
`zh-Hans`,
`zh-Hant`,
`es_ES`,
`fr_FR`,
`it_IT`,
`ja_JP`,
`ko_KR`,
`nl_NL`,
`pl_PL`,
`pseudo_LOCALE`,
`ru_RU`,
`tr_TR`,
`zh_Hans`,
`zh_Hant`,
] as const;

View File

@@ -1,6 +1,5 @@
// sort-imports-ignore
import "rapidoc";
import "#elements/ak-locale-context/index";
import styles from "./index.entrypoint.css";
@@ -61,51 +60,46 @@ export class APIBrowser extends WithBrandConfig(Interface) {
render(): TemplateResult {
return html`
<ak-locale-context>
<rapi-doc
part="rapi-doc"
spec-url=${ifDefined(this.schemaPath)}
heading-text=""
theme="light"
render-style="read"
default-schema-tab="schema"
primary-color="#fd4b2d"
nav-bg-color="#212427"
bg-color=${this.bgColor}
text-color=${this.textColor}
nav-text-color="#ffffff"
nav-hover-bg-color="#3c3f42"
nav-accent-color="#4f5255"
nav-hover-text-color="#ffffff"
use-path-in-nav-bar="true"
nav-item-spacing="relaxed"
allow-server-selection="false"
show-header="false"
allow-spec-url-load="false"
allow-spec-file-load="false"
show-method-in-nav-bar="as-colored-text"
@before-try=${(
e: CustomEvent<{
request: {
headers: Headers;
};
}>,
) => {
e.detail.request.headers.append(
CSRFHeaderName,
getCookie("authentik_csrf"),
);
}}
>
<div slot="nav-logo">
<img
alt="${msg("authentik Logo")}"
class="logo"
src="${themeImage(this.brandingLogo, this.activeTheme)}"
/>
</div>
</rapi-doc>
</ak-locale-context>
<rapi-doc
part="rapi-doc"
spec-url=${ifDefined(this.schemaPath)}
heading-text=""
theme="light"
render-style="read"
default-schema-tab="schema"
primary-color="#fd4b2d"
nav-bg-color="#212427"
bg-color=${this.bgColor}
text-color=${this.textColor}
nav-text-color="#ffffff"
nav-hover-bg-color="#3c3f42"
nav-accent-color="#4f5255"
nav-hover-text-color="#ffffff"
use-path-in-nav-bar="true"
nav-item-spacing="relaxed"
allow-server-selection="false"
show-header="false"
allow-spec-url-load="false"
allow-spec-file-load="false"
show-method-in-nav-bar="as-colored-text"
@before-try=${(
e: CustomEvent<{
request: {
headers: Headers;
};
}>,
) => {
e.detail.request.headers.append(CSRFHeaderName, getCookie("authentik_csrf"));
}}
>
<div slot="nav-logo">
<img
alt="${msg("authentik Logo")}"
class="logo"
src="${themeImage(this.brandingLogo, this.activeTheme)}"
/>
</div>
</rapi-doc>
`;
}
}

View File

@@ -55,11 +55,6 @@
--ak-user-interface--slant-m-dark: var(--pf-global--BackgroundColor--100);
}
ak-locale-context {
display: flex;
flex-direction: column;
}
.pf-c-drawer__main {
min-height: calc(100vh - 76px);
max-height: calc(100vh - 76px);

View File

@@ -1,5 +1,4 @@
import "#components/ak-nav-buttons";
import "#elements/ak-locale-context/ak-locale-context";
import "#elements/banner/EnterpriseStatusBanner";
import "#elements/buttons/ActionButton/ak-action-button";
import "#elements/messages/MessageContainer";
@@ -124,8 +123,7 @@ class UserInterfacePresentation extends WithBrandConfig(WithSession(AKElement))
const backgroundStyles = this.uiConfig.theme.background;
return html`<ak-locale-context>
<ak-enterprise-status interface="user"></ak-enterprise-status>
return html`<ak-enterprise-status interface="user"></ak-enterprise-status>
<div class="pf-c-page">
<div class="background-wrapper" style=${ifPresent(backgroundStyles)}>
${!backgroundStyles
@@ -179,8 +177,7 @@ class UserInterfacePresentation extends WithBrandConfig(WithSession(AKElement))
</div>
</div>
</div>
</div>
</ak-locale-context>`;
</div>`;
}
}

View File

@@ -3,13 +3,13 @@
* not yet been generated, or are missing.
*
* ```sh
* npm run build:locales
* npm run build-locales
* ```
*/
declare module "#locales/*" {
/**
* If you see this, try running `npm run build:locales` to generate locale files.
* If you see this, try running `npm run build-locales` to generate locale files.
*/
type MissingLocale = symbol & { readonly __brand?: never };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

9699
web/xliff/de_DE.xlf Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More