From 3f19aa259e1714bbf9edb0679cbde54e77e7cc3c Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Fri, 31 Mar 2023 23:21:03 +0800 Subject: [PATCH 01/11] feat(cli): translation sync command to create missing files or translate untranslated phrases across all existing languages --- packages/cli/package.json | 1 + packages/cli/src/commands/translate/create.ts | 86 +++---------------- packages/cli/src/commands/translate/index.ts | 2 + packages/cli/src/commands/translate/sync.ts | 50 +++++++++++ packages/cli/src/commands/translate/utils.ts | 84 ++++++++++++++++++ pnpm-lock.yaml | 16 ++++ 6 files changed, 163 insertions(+), 76 deletions(-) create mode 100644 packages/cli/src/commands/translate/sync.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index cb953d864..d160dd41d 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -60,6 +60,7 @@ "nanoid": "^4.0.0", "ora": "^6.1.2", "p-limit": "^4.0.0", + "p-queue": "^7.3.4", "p-retry": "^5.1.2", "pg-protocol": "^1.6.0", "roarr": "^7.11.0", diff --git a/packages/cli/src/commands/translate/create.ts b/packages/cli/src/commands/translate/create.ts index 60cafd8c3..d02eedcbf 100644 --- a/packages/cli/src/commands/translate/create.ts +++ b/packages/cli/src/commands/translate/create.ts @@ -1,84 +1,12 @@ -import { existsSync } from 'node:fs'; -import fs from 'node:fs/promises'; -import path from 'node:path'; - -import { isLanguageTag, type LanguageTag } from '@logto/language-kit'; +import { isLanguageTag } from '@logto/language-kit'; import { isBuiltInLanguageTag as isPhrasesBuiltInLanguageTag } from '@logto/phrases'; import { isBuiltInLanguageTag as isPhrasesUiBuiltInLanguageTag } from '@logto/phrases-ui'; -import { conditionalString, type Optional } from '@silverhand/essentials'; import type { CommandModule } from 'yargs'; import { log } from '../../utils.js'; import { inquireInstancePath } from '../connector/utils.js'; -import { createOpenaiApi, translate } from './openai.js'; -import { baseLanguage, readBaseLocaleFiles } from './utils.js'; - -const createFullTranslation = async ( - instancePath: Optional, - packageName: 'phrases' | 'phrases-ui', - languageTag: LanguageTag -) => { - const directory = path.join( - await inquireInstancePath(instancePath), - 'packages', - packageName, - 'src/locales' - ); - const files = await readBaseLocaleFiles(directory); - - log.info( - 'Found ' + - String(files.length) + - ' file' + - conditionalString(files.length !== 1 && 's') + - ' in ' + - packageName + - ' to translate' - ); - - const openai = createOpenaiApi(); - - /* eslint-disable no-await-in-loop */ - for (const file of files) { - const relativePath = path.relative(path.join(directory, baseLanguage.toLowerCase()), file); - const targetPath = path.join(directory, languageTag.toLowerCase(), relativePath); - - const getTranslationPath = async () => { - if (existsSync(targetPath)) { - const currentContent = await fs.readFile(targetPath, 'utf8'); - - if (currentContent.includes('// UNTRANSLATED')) { - return targetPath; - } - - log.info(`Target path ${targetPath} exists and has no untranslated mark, skipping`); - - return; - } - - return file; - }; - - const translationPath = await getTranslationPath(); - - if (!translationPath) { - continue; - } - - log.info(`Translating ${translationPath}`); - const result = await translate(openai, languageTag, translationPath); - - if (!result) { - log.error(`Unable to translate ${translationPath}`); - } - - await fs.mkdir(path.parse(targetPath).dir, { recursive: true }); - await fs.writeFile(targetPath, result); - log.succeed(`Translated ${targetPath}`); - } - /* eslint-enable no-await-in-loop */ -}; +import { createFullTranslation } from './utils.js'; const create: CommandModule<{ path?: string }, { path?: string; 'language-tag': string }> = { command: ['create ', 'c'], @@ -94,15 +22,21 @@ const create: CommandModule<{ path?: string }, { path?: string; 'language-tag': log.error('Invalid language tag. Run `logto translate list-tags` to see available list.'); } + const instancePath = await inquireInstancePath(inputPath); + if (isPhrasesBuiltInLanguageTag(languageTag)) { log.info(languageTag + ' is a built-in tag of phrases, updating untranslated phrases'); } - await createFullTranslation(inputPath, 'phrases', languageTag); + await createFullTranslation({ instancePath, packageName: 'phrases', languageTag }); if (isPhrasesUiBuiltInLanguageTag(languageTag)) { log.info(languageTag + ' is a built-in tag of phrases-ui, updating untranslated phrases'); } - await createFullTranslation(inputPath, 'phrases-ui', languageTag); + await createFullTranslation({ + instancePath, + packageName: 'phrases-ui', + languageTag, + }); }, }; diff --git a/packages/cli/src/commands/translate/index.ts b/packages/cli/src/commands/translate/index.ts index 1a9bfee70..d302ead0f 100644 --- a/packages/cli/src/commands/translate/index.ts +++ b/packages/cli/src/commands/translate/index.ts @@ -3,6 +3,7 @@ import type { CommandModule } from 'yargs'; import create from './create.js'; import listTags from './list-tags.js'; +import sync from './sync.js'; const translate: CommandModule = { command: ['translate', 't'], @@ -16,6 +17,7 @@ const translate: CommandModule = { }) .command(create) .command(listTags) + .command(sync) .demandCommand(1), handler: noop, }; diff --git a/packages/cli/src/commands/translate/sync.ts b/packages/cli/src/commands/translate/sync.ts new file mode 100644 index 000000000..928fe5300 --- /dev/null +++ b/packages/cli/src/commands/translate/sync.ts @@ -0,0 +1,50 @@ +import { languages } from '@logto/language-kit'; +import { isBuiltInLanguageTag as isPhrasesBuiltInLanguageTag } from '@logto/phrases'; +import { isBuiltInLanguageTag as isPhrasesUiBuiltInLanguageTag } from '@logto/phrases-ui'; +import PQueue from 'p-queue'; +import type { CommandModule } from 'yargs'; + +import { inquireInstancePath } from '../connector/utils.js'; + +import { type CreateFullTranslation, baseLanguage, createFullTranslation } from './utils.js'; + +const sync: CommandModule<{ path?: string }, { path?: string }> = { + command: ['sync'], + describe: 'Translate all untranslated phrases.', + handler: async ({ path: inputPath }) => { + const queue = new PQueue({ concurrency: 5 }); + const instancePath = await inquireInstancePath(inputPath); + + for (const languageTag of Object.keys(languages)) { + if (languageTag === baseLanguage) { + continue; + } + + const baseOptions = { + instancePath, + verbose: false, + queue, + } satisfies Partial; + + if (isPhrasesBuiltInLanguageTag(languageTag)) { + void createFullTranslation({ + ...baseOptions, + packageName: 'phrases', + languageTag, + }); + } + + if (isPhrasesUiBuiltInLanguageTag(languageTag)) { + void createFullTranslation({ + ...baseOptions, + packageName: 'phrases-ui', + languageTag, + }); + } + } + + await queue.onIdle(); + }, +}; + +export default sync; diff --git a/packages/cli/src/commands/translate/utils.ts b/packages/cli/src/commands/translate/utils.ts index 7bc0eb831..e2ea17e7c 100644 --- a/packages/cli/src/commands/translate/utils.ts +++ b/packages/cli/src/commands/translate/utils.ts @@ -1,10 +1,15 @@ +import { existsSync } from 'node:fs'; import fs from 'node:fs/promises'; import path from 'node:path'; import { type LanguageTag } from '@logto/language-kit'; +import { conditionalString } from '@silverhand/essentials'; +import PQueue from 'p-queue'; import { log } from '../../utils.js'; +import { createOpenaiApi, translate } from './openai.js'; + export const baseLanguage = 'en' satisfies LanguageTag; export const readLocaleFiles = async (directory: string): Promise => { @@ -33,3 +38,82 @@ export const readBaseLocaleFiles = async (directory: string): Promise return readLocaleFiles(enDirectory); }; + +export type CreateFullTranslation = { + instancePath: string; + packageName: 'phrases' | 'phrases-ui'; + languageTag: LanguageTag; + verbose?: boolean; + queue?: PQueue; +}; + +export const createFullTranslation = async ({ + instancePath, + packageName, + languageTag, + verbose = true, + queue = new PQueue({ concurrency: 5 }), +}: CreateFullTranslation) => { + const directory = path.join(instancePath, 'packages', packageName, 'src/locales'); + const files = await readBaseLocaleFiles(directory); + + if (verbose) { + log.info( + 'Found ' + + String(files.length) + + ' file' + + conditionalString(files.length !== 1 && 's') + + ' in ' + + packageName + + ' to translate' + ); + } + + const openai = createOpenaiApi(); + + /* eslint-disable no-await-in-loop */ + for (const file of files) { + const basePath = path.relative(path.join(directory, baseLanguage.toLowerCase()), file); + const targetPath = path.join(directory, languageTag.toLowerCase(), basePath); + + const getTranslationPath = async () => { + if (existsSync(targetPath)) { + const currentContent = await fs.readFile(targetPath, 'utf8'); + + if (currentContent.includes('// UNTRANSLATED')) { + return targetPath; + } + + if (verbose) { + log.info(`Target path ${targetPath} exists and has no untranslated mark, skipping`); + } + + return; + } + + return file; + }; + + const translationPath = await getTranslationPath(); + + if (!translationPath) { + continue; + } + + void queue.add(async () => { + log.info(`Translating ${translationPath}`); + const result = await translate(openai, languageTag, translationPath); + + if (!result) { + log.error(`Unable to translate ${translationPath}`); + } + + await fs.mkdir(path.parse(targetPath).dir, { recursive: true }); + await fs.writeFile(targetPath, result); + log.succeed(`Translated ${targetPath}`); + }); + } + /* eslint-enable no-await-in-loop */ + + return queue.onIdle(); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 427a75b52..2503545d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,6 +135,9 @@ importers: p-limit: specifier: ^4.0.0 version: 4.0.0 + p-queue: + specifier: ^7.3.4 + version: 7.3.4 p-retry: specifier: ^5.1.2 version: 5.1.2 @@ -11876,6 +11879,14 @@ packages: type-fest: 3.5.2 dev: false + /p-queue@7.3.4: + resolution: {integrity: sha512-esox8CWt0j9EZECFvkFl2WNPat8LN4t7WWeXq73D9ha0V96qPRufApZi4ZhPwXAln1uVVal429HVVKPa2X0yQg==} + engines: {node: '>=12'} + dependencies: + eventemitter3: 4.0.7 + p-timeout: 5.1.0 + dev: false + /p-retry@5.1.2: resolution: {integrity: sha512-couX95waDu98NfNZV+i/iLt+fdVxmI7CbrrdC2uDWfPdUAApyxT4wmDlyOtR5KtTDmkDO0zDScDjDou9YHhd9g==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -11884,6 +11895,11 @@ packages: retry: 0.13.1 dev: false + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + dev: false + /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} From 736d6d212b1ba898d13f9ddf9f25e009735ae009 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Fri, 31 Mar 2023 23:22:46 +0800 Subject: [PATCH 02/11] chore: add changeset --- .changeset/seven-dolphins-hammer.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/seven-dolphins-hammer.md diff --git a/.changeset/seven-dolphins-hammer.md b/.changeset/seven-dolphins-hammer.md new file mode 100644 index 000000000..a723a90f7 --- /dev/null +++ b/.changeset/seven-dolphins-hammer.md @@ -0,0 +1,5 @@ +--- +"@logto/cli": minor +--- + +`logto translate sync` to create missing files or translate untranslated phrases across all existing languages From 4c2c786aeb30724c14cf07dffbc6da4eb8eaeb14 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Sat, 1 Apr 2023 01:53:59 +0800 Subject: [PATCH 03/11] feat(phrases): add it translation --- packages/phrases-ui/src/index.ts | 3 + packages/phrases-ui/src/locales/it/action.ts | 29 +++++ .../phrases-ui/src/locales/it/demo-app.ts | 5 + .../phrases-ui/src/locales/it/description.ts | 61 +++++++++ packages/phrases-ui/src/locales/it/error.ts | 23 ++++ packages/phrases-ui/src/locales/it/index.ts | 21 +++ packages/phrases-ui/src/locales/it/input.ts | 10 ++ .../phrases-ui/src/locales/it/secondary.ts | 6 + packages/phrases/src/index.ts | 3 + .../phrases/src/locales/it/errors/auth.ts | 13 ++ .../src/locales/it/errors/connector.ts | 40 ++++++ .../phrases/src/locales/it/errors/entity.ts | 8 ++ .../phrases/src/locales/it/errors/guard.ts | 9 ++ .../phrases/src/locales/it/errors/index.ts | 39 ++++++ .../src/locales/it/errors/localization.ts | 7 + packages/phrases/src/locales/it/errors/log.ts | 5 + .../phrases/src/locales/it/errors/oidc.ts | 20 +++ .../phrases/src/locales/it/errors/password.ts | 6 + .../phrases/src/locales/it/errors/request.ts | 6 + .../phrases/src/locales/it/errors/role.ts | 11 ++ .../phrases/src/locales/it/errors/scope.ts | 6 + .../phrases/src/locales/it/errors/session.ts | 26 ++++ .../locales/it/errors/sign-in-experiences.ts | 23 ++++ .../phrases/src/locales/it/errors/storage.ts | 7 + .../phrases/src/locales/it/errors/swagger.ts | 7 + .../phrases/src/locales/it/errors/user.ts | 33 +++++ .../locales/it/errors/verification-code.ts | 13 ++ packages/phrases/src/locales/it/index.ts | 11 ++ .../admin-console/api-resource-details.ts | 32 +++++ .../admin-console/api-resources.ts | 15 +++ .../admin-console/application-details.ts | 51 ++++++++ .../translation/admin-console/applications.ts | 53 ++++++++ .../it/translation/admin-console/cloud.ts | 121 ++++++++++++++++++ .../translation/admin-console/components.ts | 14 ++ .../admin-console/connector-details.ts | 35 +++++ .../translation/admin-console/connectors.ts | 91 +++++++++++++ .../it/translation/admin-console/contact.ts | 22 ++++ .../it/translation/admin-console/dashboard.ts | 21 +++ .../it/translation/admin-console/errors.ts | 25 ++++ .../it/translation/admin-console/general.ts | 56 ++++++++ .../translation/admin-console/get-started.ts | 35 +++++ .../it/translation/admin-console/index.ts | 62 +++++++++ .../translation/admin-console/log-details.ts | 18 +++ .../it/translation/admin-console/logs.ts | 13 ++ .../it/translation/admin-console/menu.ts | 13 ++ .../translation/admin-console/permissions.ts | 12 ++ .../it/translation/admin-console/profile.ts | 82 ++++++++++++ .../translation/admin-console/role-details.ts | 51 ++++++++ .../it/translation/admin-console/roles.ts | 24 ++++ .../admin-console/session-expired.ts | 8 ++ .../admin-console/sign-in-exp/index.ts | 88 +++++++++++++ .../admin-console/sign-in-exp/others.ts | 48 +++++++ .../sign-in-exp/sign-up-and-sign-in.ts | 58 +++++++++ .../translation/admin-console/tab-sections.ts | 9 ++ .../it/translation/admin-console/tabs.ts | 16 +++ .../translation/admin-console/user-details.ts | 66 ++++++++++ .../it/translation/admin-console/users.ts | 21 +++ .../it/translation/admin-console/welcome.ts | 8 ++ .../src/locales/it/translation/demo-app.ts | 13 ++ .../src/locales/it/translation/index.ts | 11 ++ .../src/locales/it/translation/oidc.ts | 5 + 61 files changed, 1648 insertions(+) create mode 100644 packages/phrases-ui/src/locales/it/action.ts create mode 100644 packages/phrases-ui/src/locales/it/demo-app.ts create mode 100644 packages/phrases-ui/src/locales/it/description.ts create mode 100644 packages/phrases-ui/src/locales/it/error.ts create mode 100644 packages/phrases-ui/src/locales/it/index.ts create mode 100644 packages/phrases-ui/src/locales/it/input.ts create mode 100644 packages/phrases-ui/src/locales/it/secondary.ts create mode 100644 packages/phrases/src/locales/it/errors/auth.ts create mode 100644 packages/phrases/src/locales/it/errors/connector.ts create mode 100644 packages/phrases/src/locales/it/errors/entity.ts create mode 100644 packages/phrases/src/locales/it/errors/guard.ts create mode 100644 packages/phrases/src/locales/it/errors/index.ts create mode 100644 packages/phrases/src/locales/it/errors/localization.ts create mode 100644 packages/phrases/src/locales/it/errors/log.ts create mode 100644 packages/phrases/src/locales/it/errors/oidc.ts create mode 100644 packages/phrases/src/locales/it/errors/password.ts create mode 100644 packages/phrases/src/locales/it/errors/request.ts create mode 100644 packages/phrases/src/locales/it/errors/role.ts create mode 100644 packages/phrases/src/locales/it/errors/scope.ts create mode 100644 packages/phrases/src/locales/it/errors/session.ts create mode 100644 packages/phrases/src/locales/it/errors/sign-in-experiences.ts create mode 100644 packages/phrases/src/locales/it/errors/storage.ts create mode 100644 packages/phrases/src/locales/it/errors/swagger.ts create mode 100644 packages/phrases/src/locales/it/errors/user.ts create mode 100644 packages/phrases/src/locales/it/errors/verification-code.ts create mode 100644 packages/phrases/src/locales/it/index.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/api-resource-details.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/api-resources.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/application-details.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/applications.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/cloud.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/components.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/connector-details.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/connectors.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/contact.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/dashboard.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/errors.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/general.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/get-started.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/index.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/log-details.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/logs.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/menu.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/permissions.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/profile.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/role-details.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/roles.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/session-expired.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/index.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/others.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/tab-sections.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/tabs.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/user-details.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/users.ts create mode 100644 packages/phrases/src/locales/it/translation/admin-console/welcome.ts create mode 100644 packages/phrases/src/locales/it/translation/demo-app.ts create mode 100644 packages/phrases/src/locales/it/translation/index.ts create mode 100644 packages/phrases/src/locales/it/translation/oidc.ts diff --git a/packages/phrases-ui/src/index.ts b/packages/phrases-ui/src/index.ts index a00ee021f..2955f84da 100644 --- a/packages/phrases-ui/src/index.ts +++ b/packages/phrases-ui/src/index.ts @@ -7,6 +7,7 @@ import de from './locales/de/index.js'; import en from './locales/en/index.js'; import es from './locales/es/index.js'; import fr from './locales/fr/index.js'; +import it from './locales/it/index.js'; import ja from './locales/ja/index.js'; import ko from './locales/ko/index.js'; import ptBR from './locales/pt-br/index.js'; @@ -27,6 +28,7 @@ export const builtInLanguages = [ 'en', 'es', 'fr', + 'it', 'ja', 'ko', 'pt-PT', @@ -54,6 +56,7 @@ const resource: Resource = { en, es, fr, + it, ja, ko, 'pt-PT': ptPT, diff --git a/packages/phrases-ui/src/locales/it/action.ts b/packages/phrases-ui/src/locales/it/action.ts new file mode 100644 index 000000000..c034e6c91 --- /dev/null +++ b/packages/phrases-ui/src/locales/it/action.ts @@ -0,0 +1,29 @@ +const action = { + sign_in: 'Accedi', + continue: 'Continua', + create_account: 'Crea account', + create_account_without_linking: 'Crea account senza collegare', + create: 'Crea', + enter_passcode: 'Inserisci il codice di verifica', + confirm: 'Conferma', + cancel: 'Annulla', + save_password: 'Salva password', + bind: 'Collega con {{address}}', + bind_and_continue: 'Collega e continua', + back: 'Torna indietro', + nav_back: 'Indietro', + agree: 'Accetto', + got_it: 'Capito', + sign_in_with: 'Continua con {{name}}', + forgot_password: 'Hai dimenticato la password?', + switch_to: 'Passa a {{method}}', + sign_in_via_passcode: 'Accedi con il codice di verifica', + sign_in_via_password: 'Accedi con la password', + change: 'Cambia {{method}}', + link_another_email: 'Collega un altro indirizzo email', + link_another_phone: 'Collega un altro numero di telefono', + link_another_email_or_phone: 'Collega un altro indirizzo email o numero di telefono', + show_password: 'Mostra password', +}; + +export default action; diff --git a/packages/phrases-ui/src/locales/it/demo-app.ts b/packages/phrases-ui/src/locales/it/demo-app.ts new file mode 100644 index 000000000..fe771be5e --- /dev/null +++ b/packages/phrases-ui/src/locales/it/demo-app.ts @@ -0,0 +1,5 @@ +const demo_app = { + notification: "Suggerimento: crea prima un account per testare l'esperienza di accesso.", +}; + +export default demo_app; diff --git a/packages/phrases-ui/src/locales/it/description.ts b/packages/phrases-ui/src/locales/it/description.ts new file mode 100644 index 000000000..c823bed22 --- /dev/null +++ b/packages/phrases-ui/src/locales/it/description.ts @@ -0,0 +1,61 @@ +const description = { + email: 'email', + phone_number: 'numero di telefono', + username: 'username', + reminder: 'Promemoria', + not_found: '404 Non trovato', + agree_with_terms: 'Ho letto e accetto i ', + agree_with_terms_modal: 'Per procedere, si prega di accettare i .', + terms_of_use: 'Termini di utilizzo', + sign_in: 'Accedi', + privacy_policy: 'Informativa sulla privacy', + create_account: 'Crea account', + or: 'o', + and: 'e', + enter_passcode: 'Il codice di verifica è stato inviato alla tua {{address}} {{target}}', + passcode_sent: 'Il codice di verifica è stato inviato di nuovo', + resend_after_seconds: 'Inviare di nuovo dopo {{seconds}} secondi', + resend_passcode: 'Inviare nuovamente il codice di verifica', + create_account_id_exists: "L'account con {{type}} {{value}} già esiste, vuoi accedere?", + link_account_id_exists: "L'account con {{type}} {{value}} è già esistente. Vuoi collegarlo?", + sign_in_id_does_not_exist: + "L'account con {{type}} {{value}} non esiste, vuoi creare un nuovo account?", + sign_in_id_does_not_exist_alert: "L'account con {{type}} {{value}} non esiste.", + create_account_id_exists_alert: + "L'account {{type}} {{value}} è collegato ad un altro account. Prova con un altro {{type}}.", + social_identity_exist: + "L'{{type}} {{value}} è collegato ad un altro account. Prova con un altro {{type}}.", + bind_account_title: 'Collega o crea un account', + social_create_account: 'Puoi creare un nuovo account.', + social_link_email: "Puoi collegare un'altra email", + social_link_phone: 'Puoi collegare un altro telefono', + social_link_email_or_phone: "Puoi collegare un'altra email o telefono", + social_bind_with_existing: 'Abbiamo trovato un account correlato, puoi collegarlo direttamente.', + reset_password: 'Resetta la password', + reset_password_description: + 'Inserisci il {{types, list(type: disjunction;)}} associato al tuo account, e ti invieremo il codice di verifica per resettare la password.', + new_password: 'Nuova password', + set_password: 'Imposta una password', + password_changed: 'Password cambiata', + no_account: 'Ancora nessun account? ', + have_account: 'Hai già un account?', + enter_password: 'Inserisci la password', + enter_password_for: 'Accedi con la password per {{method}} {{value}}', + enter_username: 'Imposta username', + enter_username_description: + "L'username è un'alternativa per l'accesso. L'username deve contenere solo lettere, numeri e trattini bassi.", + link_email: 'Collega emails', + link_phone: 'Collega telefono', + link_email_or_phone: 'Collega email o telefono', + link_email_description: "Per maggiore sicurezza, collega la tua email all'account.", + link_phone_description: "Per maggiore sicurezza, collega il tuo telefono all'account.", + link_email_or_phone_description: + "Per maggiore sicurezza, collega la tua email o il tuo telefono all'account.", + continue_with_more_information: + "Per maggiore sicurezza, completa i dettagli dell'account qui sotto.", + create_your_account: 'Crea il tuo account', + sign_in_to_your_account: 'Accedi al tuo account', + no_region_code_found: 'Nessun codice di regione trovato', +}; + +export default description; diff --git a/packages/phrases-ui/src/locales/it/error.ts b/packages/phrases-ui/src/locales/it/error.ts new file mode 100644 index 000000000..57e8d9163 --- /dev/null +++ b/packages/phrases-ui/src/locales/it/error.ts @@ -0,0 +1,23 @@ +const error = { + general_required: `{{types, list(type: disjunction;)}} è richiesto`, + general_invalid: `Il {{types, list(type: disjunction;)}} non è valido`, + username_required: 'Username è richiesto', + password_required: 'La password è richiesta', + username_exists: 'Username esiste già', + username_should_not_start_with_number: "L'username non dovrebbe iniziare con un numero", + username_invalid_charset: "L'username dovrebbe contenere solo lettere, numeri o underscore.", + invalid_email: "L'email non è valida", + invalid_phone: 'Il numero di telefono non è valido', + password_min_length: 'La password richiede un minimo di {{min}} caratteri', + invalid_password: + 'La password richiede un minimo di {{min}} caratteri e contiene una combinazione di lettere, numeri e simboli.', + passwords_do_not_match: 'Le password non corrispondono. Per favore prova di nuovo.', + invalid_passcode: 'Il codice di verifica non è valido', + invalid_connector_auth: "L'autorizzazione è invalida", + invalid_connector_request: 'I dati del connettore non sono validi', + unknown: 'Errore sconosciuto. Si prega di riprovare più tardi.', + invalid_session: 'Sessione non trovata. Si prega di tornare indietro e accedere di nuovo.', + timeout: 'Timeout della richiesta. Si prega di riprovare più tardi.', +}; + +export default error; diff --git a/packages/phrases-ui/src/locales/it/index.ts b/packages/phrases-ui/src/locales/it/index.ts new file mode 100644 index 000000000..8142b5458 --- /dev/null +++ b/packages/phrases-ui/src/locales/it/index.ts @@ -0,0 +1,21 @@ +import { type LocalePhrase } from '../../types.js'; + +import action from './action.js'; +import demo_app from './demo-app.js'; +import description from './description.js'; +import error from './error.js'; +import input from './input.js'; +import secondary from './secondary.js'; + +const it: LocalePhrase = Object.freeze({ + translation: { + input, + secondary, + action, + description, + error, + demo_app, + }, +}); + +export default it; diff --git a/packages/phrases-ui/src/locales/it/input.ts b/packages/phrases-ui/src/locales/it/input.ts new file mode 100644 index 000000000..4e847d0f0 --- /dev/null +++ b/packages/phrases-ui/src/locales/it/input.ts @@ -0,0 +1,10 @@ +const input = { + username: 'Nome utente', + password: 'Password', + email: 'Email', + phone_number: 'Numero di telefono', + confirm_password: 'Conferma password', + search_region_code: 'Codice regione di ricerca', +}; + +export default input; diff --git a/packages/phrases-ui/src/locales/it/secondary.ts b/packages/phrases-ui/src/locales/it/secondary.ts new file mode 100644 index 000000000..621c82a4d --- /dev/null +++ b/packages/phrases-ui/src/locales/it/secondary.ts @@ -0,0 +1,6 @@ +const secondary = { + social_bind_with: + 'Già un account? Accedi per collegare {{methods, list(type: disjunction;)}} con la tua identità sociale.', +}; + +export default secondary; diff --git a/packages/phrases/src/index.ts b/packages/phrases/src/index.ts index 21c5fca5a..3b5789d12 100644 --- a/packages/phrases/src/index.ts +++ b/packages/phrases/src/index.ts @@ -7,6 +7,7 @@ import de from './locales/de/index.js'; import en from './locales/en/index.js'; import es from './locales/es/index.js'; import fr from './locales/fr/index.js'; +import it from './locales/it/index.js'; import ja from './locales/ja/index.js'; import ko from './locales/ko/index.js'; import ptBR from './locales/pt-br/index.js'; @@ -27,6 +28,7 @@ export const builtInLanguages = [ 'en', 'es', 'fr', + 'it', 'ja', 'ko', 'pt-BR', @@ -66,6 +68,7 @@ const resource: Resource = { en, es, fr, + it, ja, ko, 'pt-BR': ptBR, diff --git a/packages/phrases/src/locales/it/errors/auth.ts b/packages/phrases/src/locales/it/errors/auth.ts new file mode 100644 index 000000000..abf03904c --- /dev/null +++ b/packages/phrases/src/locales/it/errors/auth.ts @@ -0,0 +1,13 @@ +const auth = { + authorization_header_missing: 'Header Autorizzazione mancante.', + authorization_token_type_not_supported: 'Tipo di autorizzazione non supportato.', + unauthorized: 'Non autorizzato. Controlla le credenziali e il loro ambito.', + forbidden: "Vietato. Controlla i ruoli e le autorizzazioni dell'utente.", + expected_role_not_found: + "Ruolo atteso non trovato. Controlla i ruoli e le autorizzazioni dell'utente.", + jwt_sub_missing: 'Manca il valore `sub` in JWT.', + require_re_authentication: + "È necessaria una nuova autenticazione per eseguire un'azione protetta.", +}; + +export default auth; diff --git a/packages/phrases/src/locales/it/errors/connector.ts b/packages/phrases/src/locales/it/errors/connector.ts new file mode 100644 index 000000000..1ee61f08b --- /dev/null +++ b/packages/phrases/src/locales/it/errors/connector.ts @@ -0,0 +1,40 @@ +const connector = { + general: 'Si è verificato un errore nel connettore: {{errorDescription}}', + not_found: 'Impossibile trovare un connettore disponibile per il tipo: {{type}}.', + not_enabled: 'Il connettore non è abilitato.', + invalid_metadata: 'I metadati del connettore non sono validi.', + invalid_config_guard: 'La guardia di configurazione del connettore non è valida.', + unexpected_type: 'Il tipo di connettore è inaspettato.', + invalid_request_parameters: 'La richiesta contiene parametri di input errati.', + insufficient_request_parameters: 'La richiesta potrebbe mancare di alcuni parametri di input.', + invalid_config: 'La configurazione del connettore non è valida.', + invalid_response: 'La risposta del connettore non è valida.', + template_not_found: + 'Impossibile trovare il modello corretto nella configurazione del connettore.', + not_implemented: '{{method}}: non è stato ancora implementato.', + social_invalid_access_token: 'Il token di accesso del connettore non è valido.', + invalid_auth_code: 'Il codice di autenticazione del connettore non è valido.', + social_invalid_id_token: 'Il token ID del connettore non è valido.', + authorization_failed: "Il processo di autorizzazione dell'utente non è riuscito.", + social_auth_code_invalid: + 'Impossibile ottenere il token di accesso, controllare il codice di autorizzazione.', + more_than_one_sms: 'Il numero di connettori SMS è maggiore di 1.', + more_than_one_email: 'Il numero di connettori email è maggiore di 1.', + more_than_one_connector_factory: + 'Trovate più fabbriche di connettori (con id {{connectorIds}}), è possibile disinstallare quelle non necessarie.', + db_connector_type_mismatch: "C'è un connettore nel DB che non corrisponde al tipo.", + not_found_with_connector_id: + "Impossibile trovare il connettore con l'id connettore standard fornito.", + multiple_instances_not_supported: + "Non è possibile creare più di un'istanza con il connettore standard selezionato.", + invalid_type_for_syncing_profile: + 'È possibile sincronizzare solo il profilo utente con i connettori social.', + can_not_modify_target: "Non è possibile modificare il 'target' del connettore.", + should_specify_target: "Si dovrebbe specificare il 'target'.", + multiple_target_with_same_platform: + 'Non è possibile avere più connettori social con lo stesso target e piattaforma.', + cannot_overwrite_metadata_for_non_standard_connector: + "I 'metadati' di questo connettore non possono essere sovrascritti.", +}; + +export default connector; diff --git a/packages/phrases/src/locales/it/errors/entity.ts b/packages/phrases/src/locales/it/errors/entity.ts new file mode 100644 index 000000000..6e7b6bac8 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/entity.ts @@ -0,0 +1,8 @@ +const entity = { + create_failed: 'Impossibile creare {{name}}.', + not_exists: '{{name}} non esiste.', + not_exists_with_id: '{{name}} con ID `{{id}}` non esiste.', + not_found: 'La risorsa non esiste.', +}; + +export default entity; diff --git a/packages/phrases/src/locales/it/errors/guard.ts b/packages/phrases/src/locales/it/errors/guard.ts new file mode 100644 index 000000000..afa29c383 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/guard.ts @@ -0,0 +1,9 @@ +const guard = { + invalid_input: 'La richiesta {{type}} non è valida.', + invalid_pagination: 'Il valore di paginazione della richiesta non è valido.', + can_not_get_tenant_id: "Impossibile ottenere l'ID dell'inquilino dalla richiesta.", + file_size_exceeded: 'Dimensione del file superata.', + mime_type_not_allowed: 'Il tipo MIME non è consentito.', +}; + +export default guard; diff --git a/packages/phrases/src/locales/it/errors/index.ts b/packages/phrases/src/locales/it/errors/index.ts new file mode 100644 index 000000000..c3f5e05ec --- /dev/null +++ b/packages/phrases/src/locales/it/errors/index.ts @@ -0,0 +1,39 @@ +import auth from './auth.js'; +import connector from './connector.js'; +import entity from './entity.js'; +import guard from './guard.js'; +import localization from './localization.js'; +import log from './log.js'; +import oidc from './oidc.js'; +import password from './password.js'; +import request from './request.js'; +import role from './role.js'; +import scope from './scope.js'; +import session from './session.js'; +import sign_in_experiences from './sign-in-experiences.js'; +import storage from './storage.js'; +import swagger from './swagger.js'; +import user from './user.js'; +import verification_code from './verification-code.js'; + +const errors = { + request, + auth, + guard, + oidc, + user, + password, + session, + connector, + verification_code, + sign_in_experiences, + localization, + swagger, + entity, + log, + role, + scope, + storage, +}; + +export default errors; diff --git a/packages/phrases/src/locales/it/errors/localization.ts b/packages/phrases/src/locales/it/errors/localization.ts new file mode 100644 index 000000000..e6a874679 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/localization.ts @@ -0,0 +1,7 @@ +const localization = { + cannot_delete_default_language: + '{{languageTag}} è impostato come la tua lingua predefinita e non può essere eliminato.', + invalid_translation_structure: "Schemi di dati non validi. Controlla l'input e riprova.", +}; + +export default localization; diff --git a/packages/phrases/src/locales/it/errors/log.ts b/packages/phrases/src/locales/it/errors/log.ts new file mode 100644 index 000000000..3015950ff --- /dev/null +++ b/packages/phrases/src/locales/it/errors/log.ts @@ -0,0 +1,5 @@ +const log = { + invalid_type: 'Il tipo di registro non è valido.', +}; + +export default log; diff --git a/packages/phrases/src/locales/it/errors/oidc.ts b/packages/phrases/src/locales/it/errors/oidc.ts new file mode 100644 index 000000000..519d25c34 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/oidc.ts @@ -0,0 +1,20 @@ +const oidc = { + aborted: "L'utente finale ha annullato l'interazione.", + invalid_scope: 'La scope {{scope}} non è supportata.', + invalid_scope_plural: 'Le scope {{scopes}} non sono supportate.', + invalid_token: 'Token non valido fornito.', + invalid_client_metadata: 'Metadata client non valide fornite.', + insufficient_scope: 'Token di accesso senza la scope richiesta {{scopes}}.', + invalid_request: 'La richiesta non è valida.', + invalid_grant: 'La richiesta di grant non è valida.', + invalid_redirect_uri: + '`redirect_uri` non corrisponde a nessuno degli `redirect_uris` registrati dal client.', + access_denied: 'Accesso negato.', + invalid_target: 'Indicatore di risorsa non valido.', + unsupported_grant_type: 'Tipo di `grant_type` richiesto non supportato.', + unsupported_response_mode: 'Modalità di risposta `response_mode` richiesta non supportata.', + unsupported_response_type: 'Tipo di risposta `response_type` richiesto non supportato.', + provider_error: 'Errore interno OIDC: {{message}}.', +}; + +export default oidc; diff --git a/packages/phrases/src/locales/it/errors/password.ts b/packages/phrases/src/locales/it/errors/password.ts new file mode 100644 index 000000000..3b19e0b37 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/password.ts @@ -0,0 +1,6 @@ +const password = { + unsupported_encryption_method: 'Il metodo di crittografia {{name}} non è supportato.', + pepper_not_found: 'Pepper password non trovato. Per favore controlla le tue env di core.', +}; + +export default password; diff --git a/packages/phrases/src/locales/it/errors/request.ts b/packages/phrases/src/locales/it/errors/request.ts new file mode 100644 index 000000000..c655231e1 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/request.ts @@ -0,0 +1,6 @@ +const request = { + invalid_input: "L'input non è valido. {{details}}", + general: 'Si è verificato un errore nella richiesta.', +}; + +export default request; diff --git a/packages/phrases/src/locales/it/errors/role.ts b/packages/phrases/src/locales/it/errors/role.ts new file mode 100644 index 000000000..502cd469f --- /dev/null +++ b/packages/phrases/src/locales/it/errors/role.ts @@ -0,0 +1,11 @@ +const role = { + name_in_use: 'Il nome di ruolo {{name}} è già in uso', + scope_exists: "L'identificatore di ambito {{scopeId}} è già stato aggiunto a questo ruolo", + user_exists: "L'identificatore di utente {{userId}} è già stato aggiunto a questo ruolo", + default_role_missing: + 'Alcuni dei nomi di ruolo predefiniti non esistono nel database, assicurati di creare prima i ruoli', + internal_role_violation: + 'Potresti cercare di aggiornare o eliminare un ruolo interno che è vietato da Logto. Se stai creando un nuovo ruolo, prova un altro nome che non inizi con "#internal:". ', +}; + +export default role; diff --git a/packages/phrases/src/locales/it/errors/scope.ts b/packages/phrases/src/locales/it/errors/scope.ts new file mode 100644 index 000000000..d74d6dfa0 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/scope.ts @@ -0,0 +1,6 @@ +const scope = { + name_exists: 'Il nome dello scope {{name}} è già in uso', + name_with_space: 'Il nome dello scope non può contenere spazi.', +}; + +export default scope; diff --git a/packages/phrases/src/locales/it/errors/session.ts b/packages/phrases/src/locales/it/errors/session.ts new file mode 100644 index 000000000..9fee446b8 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/session.ts @@ -0,0 +1,26 @@ +const session = { + not_found: 'Sessione non trovata. Torna indietro e accedi nuovamente.', + invalid_credentials: 'Account o password non corretti. Controlla le tue credenziali.', + invalid_sign_in_method: 'Metodo di accesso corrente non disponibile.', + invalid_connector_id: 'Impossibile trovare un connettore disponibile con ID {{connectorId}}.', + insufficient_info: 'Informazioni di accesso insufficienti.', + connector_id_mismatch: "L'ID del connettore non corrisponde con il record della sessione.", + connector_session_not_found: + 'Sessione del connettore non trovata. Torna indietro e accedi nuovamente.', + verification_session_not_found: + 'La verifica non è stata completata con successo. Riavvia il processo di verifica e riprova.', + verification_expired: + 'La connessione è scaduta. Verifica di nuovo per garantire la sicurezza del tuo account.', + unauthorized: 'Accedi prima di procedere.', + unsupported_prompt_name: 'Nome del prompt non supportato.', + forgot_password_not_enabled: 'Recupero password non abilitato.', + verification_failed: + 'La verifica non è stata completata con successo. Riavvia il processo di verifica e riprova.', + connector_validation_session_not_found: + 'Sessione del connettore per la convalida del token non trovata.', + identifier_not_found: 'Identificativo utente non trovato. Torna indietro e accedi nuovamente.', + interaction_not_found: + 'Sessione di interazione non trovata. Torna indietro e avvia la sessione nuovamente.', +}; + +export default session; diff --git a/packages/phrases/src/locales/it/errors/sign-in-experiences.ts b/packages/phrases/src/locales/it/errors/sign-in-experiences.ts new file mode 100644 index 000000000..ac43ed6bf --- /dev/null +++ b/packages/phrases/src/locales/it/errors/sign-in-experiences.ts @@ -0,0 +1,23 @@ +const sign_in_experiences = { + empty_content_url_of_terms_of_use: + 'URL di contenuto "Termini di utilizzo" vuoto. Si prega di aggiungere l\'URL del contenuto se "Termini di utilizzo" è abilitato.', + empty_social_connectors: + 'Connettori social vuoti. Si prega di aggiungere connettori social abilitati quando il metodo di accesso social è abilitato.', + enabled_connector_not_found: '{{type}} conettore abilitato non trovato.', + not_one_and_only_one_primary_sign_in_method: + "Deve esserci un solo metodo di accesso principale. Si prega di verificare l'input.", + username_requires_password: + "Deve abilitare impostazione di una password per l'identificatore di registrazione dell'username.", + passwordless_requires_verify: + "Deve abilitare la verifica per l'identificatore di registrazione tramite email/telefono.", + miss_sign_up_identifier_in_sign_in: + "I metodi di accesso devono contenere l'identificatore di registrazione.", + password_sign_in_must_be_enabled: + 'Il metodo di accesso con password deve essere abilitato quando è richiesta la creazione di una password nella registrazione.', + code_sign_in_must_be_enabled: + 'Il metodo di accesso con codice di verifica deve essere abilitato quando non è richiesta una password nella registrazione.', + unsupported_default_language: 'Questa lingua - {{language}} non è supportata al momento.', + at_least_one_authentication_factor: 'Devi selezionare almeno un fattore di autenticazione.', +}; + +export default sign_in_experiences; diff --git a/packages/phrases/src/locales/it/errors/storage.ts b/packages/phrases/src/locales/it/errors/storage.ts new file mode 100644 index 000000000..7c75b8b72 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/storage.ts @@ -0,0 +1,7 @@ +const storage = { + not_configured: 'Provider di archiviazione non configurato.', + missing_parameter: 'Parametro mancante {{parameter}} per il provider di archiviazione.', + upload_error: 'Impossibile caricare il file sul provider di archiviazione.', +}; + +export default storage; diff --git a/packages/phrases/src/locales/it/errors/swagger.ts b/packages/phrases/src/locales/it/errors/swagger.ts new file mode 100644 index 000000000..11bf3af16 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/swagger.ts @@ -0,0 +1,7 @@ +const swagger = { + invalid_zod_type: 'Tipo Zod non valido. Controllare la configurazione di guardia del percorso.', + not_supported_zod_type_for_params: + 'Tipo Zod non supportato per i parametri. Controllare la configurazione di guardia del percorso.', +}; + +export default swagger; diff --git a/packages/phrases/src/locales/it/errors/user.ts b/packages/phrases/src/locales/it/errors/user.ts new file mode 100644 index 000000000..44c435de5 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/user.ts @@ -0,0 +1,33 @@ +const user = { + username_already_in_use: 'Questo nome utente è già in uso.', + email_already_in_use: 'Questa email è associata ad un account esistente.', + phone_already_in_use: 'Questo numero di telefono è associato ad un account esistente.', + invalid_email: 'Indirizzo email non valido.', + invalid_phone: 'Numero di telefono non valido.', + email_not_exist: "L'indirizzo email non è stato ancora registrato.", + phone_not_exist: 'Il numero di telefono non è stato ancora registrato.', + identity_not_exist: "L'account social non è stato ancora registrato.", + identity_already_in_use: "L'account social è stato associato ad un account esistente.", + social_account_exists_in_profile: 'Hai già associato questo account social.', + cannot_delete_self: 'Non puoi eliminarti da solo.', + sign_up_method_not_enabled: 'Questo metodo di registrazione non è abilitato.', + sign_in_method_not_enabled: 'Questo metodo di accesso non è abilitato.', + same_password: 'La nuova password non può essere uguale alla vecchia password.', + password_required_in_profile: 'È necessario impostare una password prima di accedere.', + new_password_required_in_profile: 'È necessario impostare una nuova password.', + password_exists_in_profile: 'La password esiste già nel tuo profilo.', + username_required_in_profile: 'È necessario impostare un nome utente prima di accedere.', + username_exists_in_profile: 'Il nome utente esiste già nel tuo profilo.', + email_required_in_profile: "È necessario aggiungere un'indirizzo email prima di accedere.", + email_exists_in_profile: 'Il tuo profilo è già associato ad un indirizzo email.', + phone_required_in_profile: 'È necessario aggiungere un numero di telefono prima di accedere.', + phone_exists_in_profile: 'Il tuo profilo è già associato ad un numero di telefono.', + email_or_phone_required_in_profile: + 'È necessario aggiungere un indirizzo email o un numero di telefono prima di accedere.', + suspended: 'Questo account è stato sospeso.', + user_not_exist: "L'utente con {{ identifier }} non esiste.", + missing_profile: 'È necessario fornire informazioni aggiuntive prima di accedere.', + role_exists: "L'ID ruolo {{roleId}} è già stato aggiunto a questo utente", +}; + +export default user; diff --git a/packages/phrases/src/locales/it/errors/verification-code.ts b/packages/phrases/src/locales/it/errors/verification-code.ts new file mode 100644 index 000000000..469713489 --- /dev/null +++ b/packages/phrases/src/locales/it/errors/verification-code.ts @@ -0,0 +1,13 @@ +const verification_code = { + phone_email_empty: "Entrambi il telefono e l'e-mail sono vuoti.", + not_found: 'Codice di verifica non trovato. Si prega di inviare il codice di verifica per primo.', + phone_mismatch: + 'Telefono non corrispondente. Si prega di richiedere un nuovo codice di verifica.', + email_mismatch: 'Email non corrispondente. Si prega di richiedere un nuovo codice di verifica.', + code_mismatch: 'Codice di verifica non valido.', + expired: 'Il codice di verifica è scaduto. Si prega di richiedere un nuovo codice di verifica.', + exceed_max_try: + 'Superata la limitazione dei tentativi di codice di verifica. Si prega di richiedere un nuovo codice di verifica.', +}; + +export default verification_code; diff --git a/packages/phrases/src/locales/it/index.ts b/packages/phrases/src/locales/it/index.ts new file mode 100644 index 000000000..3eb0a2dba --- /dev/null +++ b/packages/phrases/src/locales/it/index.ts @@ -0,0 +1,11 @@ +import type { LocalePhrase } from '../../types.js'; + +import errors from './errors/index.js'; +import translation from './translation/index.js'; + +const it: LocalePhrase = Object.freeze({ + translation, + errors, +}); + +export default it; diff --git a/packages/phrases/src/locales/it/translation/admin-console/api-resource-details.ts b/packages/phrases/src/locales/it/translation/admin-console/api-resource-details.ts new file mode 100644 index 000000000..821259ea2 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/api-resource-details.ts @@ -0,0 +1,32 @@ +const api_resource_details = { + page_title: 'Dettagli delle risorse API', + back_to_api_resources: 'Torna alle risorse API', + settings_tab: 'Impostazioni', + permissions_tab: 'Autorizzazioni', + settings: 'Impostazioni', + settings_description: + "Le risorse API, anche note come Indicatori di Risorse, indicano i servizi o le risorse di destinazione da richiedere, di solito una variabile di formato URI che rappresenta l'identità della risorsa.", + token_expiration_time_in_seconds: 'Tempo di scadenza del token (in secondi)', + token_expiration_time_in_seconds_placeholder: 'Inserisci il tempo di scadenza del tuo token', + delete_description: + 'Questa azione non può essere annullata. Eliminerà definitivamente la risorsa API. Per favore, inserisci il nome della risorsa api {{name}} per confermare.', + enter_your_api_resource_name: 'Inserisci il nome della tua risorsa API', + api_resource_deleted: 'La risorsa API {{name}} è stata eliminata con successo', + permission: { + create_button: 'Crea autorizzazione', + create_title: 'crea autorizzazione', + create_subtitle: 'Definire le autorizzazioni (ambiti) necessarie per questa API.', + confirm_create: 'Crea autorizzazione', + name: 'Nome autorizzazione', + name_placeholder: 'lettura:risorsa', + forbidden_space_in_name: "Il nome dell'autorizzazione non deve contenere spazi.", + description: 'Descrizione', + description_placeholder: 'In grado di leggere le risorse', + permission_created: "L'autorizzazione {{name}} è stata creata con successo", + delete_description: + "Se questa autorizzazione viene eliminata, l'utente che aveva questa autorizzazione perderà l'accesso concessogli tramite di essa.", + deleted: 'L\'autorizzazione "{{name}}" è stata eliminata con successo!', + }, +}; + +export default api_resource_details; diff --git a/packages/phrases/src/locales/it/translation/admin-console/api-resources.ts b/packages/phrases/src/locales/it/translation/admin-console/api-resources.ts new file mode 100644 index 000000000..6cc4457f3 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/api-resources.ts @@ -0,0 +1,15 @@ +const api_resources = { + page_title: 'Risorse API', + title: 'Risorse API', + subtitle: 'Definisci API che le tue applicazioni autorizzate possono utilizzare', + create: 'Crea risorsa API', + api_name: 'Nome API', + api_name_placeholder: "Inserisci il nome dell'API", + api_identifier: 'Identificatore API', + api_identifier_tip: + "L'identificatore univoco della risorsa API. Deve essere un URI assoluto e non ha componenti di frammento (#). Corrisponde al parametro risorsa in OAuth 2.0.", + api_resource_created: 'La risorsa API {{name}} è stata creata con successo', + api_identifier_placeholder: 'https://tuo-identificatore-api/', +}; + +export default api_resources; diff --git a/packages/phrases/src/locales/it/translation/admin-console/application-details.ts b/packages/phrases/src/locales/it/translation/admin-console/application-details.ts new file mode 100644 index 000000000..2787dae46 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/application-details.ts @@ -0,0 +1,51 @@ +const application_details = { + page_title: "Dettagli dell'applicazione", + back_to_applications: 'Torna alle applicazioni', + check_guide: 'Verifica guida', + settings: 'Impostazioni', + settings_description: + 'Le applicazioni vengono utilizzate per identificare le tue applicazioni in Logto per OIDC, esperienza di accesso, registri di controllo, ecc.', + advanced_settings: 'Impostazioni avanzate', + advanced_settings_description: + "Le impostazioni avanzate includono termini correlati all'OIDC. Puoi consultare il Endpoint Token per ulteriori informazioni.", + application_name: "Nome dell'applicazione", + application_name_placeholder: 'La mia app', + description: 'Descrizione', + description_placeholder: 'Inserisci la descrizione della tua applicazione', + authorization_endpoint: 'Authorization Endpoint', + authorization_endpoint_tip: + "L'endpoint per effettuare l'autenticazione e l'autorizzazione. Viene utilizzato per la connessione OpenID autenticazione.", + application_id: 'ID Applicazione', + application_id_tip: + 'L\'identificatore univoco dell\'applicazione generato normalmente da Logto. Sta anche per "client_id" in OpenID Connect.', + application_secret: 'App Segreta', + redirect_uri: 'URI di reindirizzamento', + redirect_uris: 'URI di reindirizzamento', + redirect_uri_placeholder: 'https://il-tuo-sito-web.com/la-tua-app', + redirect_uri_placeholder_native: 'io.logto://callback', + redirect_uri_tip: + 'Il URI di reindirizzamento dopo il login di un utente (sia riuscito che non). Vedi OpenID Connect autenticazione richiesta per ulteriori informazioni.', + post_sign_out_redirect_uri: 'URI di reindirizzamento post disconnessione', + post_sign_out_redirect_uris: 'URI di reindirizzamento post disconnessione', + post_sign_out_redirect_uri_placeholder: 'https://your.website.com/home', + post_sign_out_redirect_uri_tip: + "Il URI di reindirizzamento dopo la disconnessione dell'utente (facoltativo). Potrebbe non avere alcun effetto pratico in alcuni tipi di app.", + cors_allowed_origins: 'Origini consentite CORS', + cors_allowed_origins_placeholder: 'https://il-tuo-sito-web.com', + cors_allowed_origins_tip: + 'Per impostazione predefinita, saranno consentite tutte le origini degli URI di reindirizzamento. Di solito non è richiesta alcuna azione per questo campo. Vedi la documentazione MDN per informazioni dettagliate.', + id_token_expiration: 'Scadenza token ID', + refresh_token_expiration: 'Scadenza token di aggiornamento', + token_endpoint: 'Endpoint del token', + user_info_endpoint: 'Endpoint delle informazioni utente', + enable_admin_access: "Abilita l'accesso amministratore", + enable_admin_access_label: + "Abilita o disabilita l'accesso all'API di gestione. Una volta abilitato, puoi utilizzare i token di accesso per chiamare l'API di gestione a nome di questa applicazione.", + delete_description: + "Questa azione non può essere annullata. Eliminerà definitivamente l'applicazione. Inserisci il nome dell'applicazione {{name}} per confermare.", + enter_your_application_name: 'Inserisci il nome della tua applicazione', + application_deleted: "L'applicazione {{name}} è stata eliminata con successo", + redirect_uri_required: 'Devi inserire almeno un URI di reindirizzamento', +}; + +export default application_details; diff --git a/packages/phrases/src/locales/it/translation/admin-console/applications.ts b/packages/phrases/src/locales/it/translation/admin-console/applications.ts new file mode 100644 index 000000000..39eb8dd48 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/applications.ts @@ -0,0 +1,53 @@ +const applications = { + page_title: 'Applicazioni', + title: 'Applicazioni', + subtitle: + "Configura l'autenticazione Logto per la tua applicazione nativa, a singola pagina, macchina-to-macchina o tradizionale", + create: 'Crea Applicazione', + application_name: 'Nome applicazione', + application_name_placeholder: 'La mia App', + application_description: 'Descrizione applicazione', + application_description_placeholder: 'Inserisci la descrizione della tua applicazione', + select_application_type: 'Seleziona un tipo di applicazione', + no_application_type_selected: 'Non hai ancora selezionato alcun tipo di applicazione', + application_created: + "L'applicazione {{name}} è stata creata con successo! \nOra completa le impostazioni della tua applicazione.", + app_id: 'ID App', + type: { + native: { + title: 'App Nativa', + subtitle: "Un'applicazione che viene eseguita in un ambiente nativo", + description: 'E.g., applicazione iOS, applicazione Android', + }, + spa: { + title: 'Applicazione a Singola Pagina', + subtitle: + "Un'applicazione che viene eseguita in un browser web e aggiorna dinamicamente i dati in maniera localizzata", + description: 'E.g., applicazione React DOM, applicazione Vue', + }, + traditional: { + title: 'Web Tradizionale', + subtitle: "Un'applicazione che renderizza e aggiorna le pagine solo attraverso il server web", + description: 'E.g., Next.js, PHP', + }, + machine_to_machine: { + title: 'Macchina-to-Macchina', + subtitle: "Un'app (solitamente un servizio) che comunica direttamente con le risorse", + description: 'E.g., servizio backend', + }, + }, + guide: { + get_sample_file: 'Scarica Esempio', + header_description: + 'Segui la guida passo passo per integrare la tua applicazione o clicca il pulsante corretto per scaricare il nostro progetto di esempio', + title: "L'applicazione è stata creata con successo", + subtitle: + 'Ora segui i passi di seguito per completare le impostazioni della tua app. Seleziona il tipo di SDK per continuare.', + description_by_sdk: "Questa guida rapida illustra come integrare Logto in un'app {{sdk}}", + }, + placeholder_title: 'Seleziona un tipo di applicazione per continuare', + placeholder_description: + "Logto utilizza un'entità applicazione per OIDC per aiutarti in compiti come l'identificazione delle tue app, la gestione dell'accesso e la creazione di registri di audit.", +}; + +export default applications; diff --git a/packages/phrases/src/locales/it/translation/admin-console/cloud.ts b/packages/phrases/src/locales/it/translation/admin-console/cloud.ts new file mode 100644 index 000000000..b772a8519 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/cloud.ts @@ -0,0 +1,121 @@ +const cloud = { + welcome: { + page_title: 'Benvenuto', + title: 'Benvenuto e creiamo insieme la tua anteprima di Logto Cloud', + description: + 'Che tu sia un utente open-source o cloud, fai un tour della vetrina e scopri il valore completo di Logto. Cloud preview serve anche come versione preliminare di Logto Cloud.', + project_field: 'Sto usando Logto per', + project_options: { + personal: 'Progetto personale', + company: 'Progetto aziendale', + }, + deployment_type_field: 'Preferisci open-source o cloud?', + deployment_type_options: { + open_source: 'Open-Source', + cloud: 'Cloud', + }, + }, + about: { + page_title: "Un po' di te", + title: "Un po' di te per rendere unica la tua esperienza Logto", + description: + 'Facciamo diventare la tua esperienza Logto unica conoscendoti meglio. Le tue informazioni sono al sicuro con noi.', + title_field: 'La tua posizione', + title_options: { + developer: 'Sviluppatore', + team_lead: 'Team Lead', + ceo: 'CEO', + cto: 'CTO', + product: 'Prodotto', + others: 'Altro', + }, + company_name_field: "Nome dell'azienda", + company_name_placeholder: 'Acme.co', + company_size_field: "Dimensione dell'azienda", + company_options: { + size_1: '1', + size_2_49: '2-49', + size_50_199: '50-199', + size_200_999: '200-999', + size_1000_plus: '1000+', + }, + reason_field: 'Mi sto iscrivendo perché', + reason_options: { + passwordless: 'Ricerca di autenticazione senza password e UI kit', + efficiency: 'Scoperta di infrastrutture di identità preconfezionate', + access_control: "Controllo dell'accesso degli utenti in base ai ruoli e alle responsabilità", + multi_tenancy: 'Ricerca di strategie per un prodotto multi-tenancy', + enterprise: 'Ricerca di soluzioni SSO per la preparazione aziendale', + others: 'Altro', + }, + }, + congrats: { + page_title: 'Guadagna crediti in anticipo', + title: 'Fantastiche notizie! Sei qualificato per guadagnare i primi crediti di Logto Cloud!', + description: + "Non perdere l'occasione di usufruire di una sottoscrizione gratuita di Logto Cloud per 60 giorni dopo il lancio ufficiale! Contatta subito il team di Logto per saperne di più.", + check_out_button: 'Guarda la anteprima dal vivo', + email_us_title: 'Scrivici una email per offerta speciale e dettagli di prezzo', + email_us_description: 'Ottieni prezzi esclusivi per risparmiare denaro', + email_us_button: 'Invia email', + join_description: + 'Entra nel nostro {{link}} pubblico per connetterti e chattare con altri sviluppatori.', + discord_link: 'canale discord', + enter_admin_console: 'Entra in Logto Cloud Preview', + }, + gift: { + title: 'Utilizza Logto Cloud gratuitamente per 60 giorni. Unisciti ai primi.', + description: + 'Prenota una sessione individuale con il nostro team per ottenere crediti anticipati.', + reserve_title: 'Prenota il tuo tempo con il team Logto', + reserve_description: 'Il credito è disponibile solo previa valutazione.', + book_button: 'Prenota', + email_us_title: 'Scrivici una email', + email_us_description: 'Contattaci per una offerta speciale e dettagli di prezzo.', + email_us_button: 'Invia', + }, + sie: { + page_title: "Personalizza l'esperienza di accesso", + title: 'Personalizziamo insieme la tua esperienza di accesso', + inspire: { + title: 'Crea esempi coinvolgenti', + description: + 'Ti senti incerto riguardo l\'esperienza di accesso? Fai clic su "Ispirami" e lascia che la magia accada!', + inspire_me: 'Ispirami', + }, + logo_field: "Logo dell'app", + color_field: 'Colore del brand', + identifier_field: 'Identificativo', + identifier_options: { + email: 'Email', + phone: 'Telefono', + user_name: 'Nome utente', + }, + authn_field: 'Autenticazione', + authn_options: { + password: 'Password', + verification_code: 'Codice di verifica', + }, + social_field: 'Accesso tramite social', + finish_and_done: 'Termina e completato', + preview: { + mobile_tab: 'Mobile', + web_tab: 'Web', + }, + connectors: { + unlocked_later: 'Sbloccato in seguito', + unlocked_later_tip: + 'Una volta completato il processo di onboarding e inserito il prodotto, avrai accesso a ancora più metodi di accesso tramite social.', + notice: + 'Si prega di evitare di utilizzare il connettore demo per scopi di produzione. Una volta completati i test, cancellare gentilmente il connettore demo e configurare il proprio connettore con le proprie credenziali.', + }, + }, + broadcast: '📣 Sei in Logto Cloud (Preview)', + socialCallback: { + title: 'Accesso effettuato con successo', + description: + "Hai effettuato l'accesso con successo utilizzando il tuo account social. Per garantire integrazione senza problemi e accesso a tutte le funzionalità di Logto, ti consigliamo di procedere alla configurazione del tuo connettore social.", + }, +}; + +export default cloud; diff --git a/packages/phrases/src/locales/it/translation/admin-console/components.ts b/packages/phrases/src/locales/it/translation/admin-console/components.ts new file mode 100644 index 000000000..5bd97b12b --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/components.ts @@ -0,0 +1,14 @@ +const components = { + uploader: { + action_description: 'Trascina e rilascia o cerca', + uploading: 'Caricamento in corso...', + image_limit: + 'Carica immagini sotto i {{size, number}}KB, solo {{extensions, list(style: narrow; type: conjunction;)}}.', + error_upload: 'Qualcosa è andato storto. Caricamento fallito.', + error_file_size: 'Il file è troppo grande. Carica un file sotto i {{size, number}}KB.', + error_file_type: + 'Formato file non supportato. Sono accettati solo formati {{extensions, list(style: narrow; type: conjunction;)}}.', + }, +}; + +export default components; diff --git a/packages/phrases/src/locales/it/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/it/translation/admin-console/connector-details.ts new file mode 100644 index 000000000..8f485a62c --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/connector-details.ts @@ -0,0 +1,35 @@ +const connector_details = { + page_title: 'Dettagli del connettore', + back_to_connectors: 'Torna ai connettori', + check_readme: 'Verifica README', + settings: 'Impostazioni generali', + settings_description: + "I connettori svolgono un ruolo critico in Logto. Grazie al loro aiuto, Logto consente agli utenti finali di utilizzare la registrazione o l'accesso senza password e le capacità di accedere tramite account social.", + parameter_configuration: 'Configurazione dei parametri', + test_connection: 'Test di connessione', + save_error_empty_config: 'Inserisci la configurazione', + send: 'Invia', + send_error_invalid_format: 'Input non valido', + edit_config_label: 'Inserisci il tuo JSON qui', + test_email_sender: 'Prova il tuo connettore per email', + test_sms_sender: 'Prova il tuo connettore per SMS', + test_email_placeholder: 'john.doe@example.com', + test_sms_placeholder: '+1 555-123-4567', + test_message_sent: 'Messaggio di prova inviato', + test_sender_description: + 'Logto utilizza il modello "Generico" per i test. Riceverai un messaggio se il tuo connettore è correttamente configurato.', + options_change_email: 'Cambia connettore per email', + options_change_sms: 'Cambia connettore per SMS', + connector_deleted: 'Il connettore è stato eliminato con successo', + type_email: 'Connettore per email', + type_sms: 'Connettore per SMS', + type_social: 'Connettore social', + in_used_social_deletion_description: + "Questo connettore è in uso nella tua esperienza di accesso. Eliminandolo, l'esperienza di accesso di verrà eliminata nelle impostazioni dell'esperienza di accesso. Dovrai riconfigurarlo se decidi di aggiungerlo di nuovo.", + in_used_passwordless_deletion_description: + 'Questo {{name}} è in uso nella tua esperienza di accesso. Eliminandolo, la tua esperienza di accesso non funzionerà correttamente fino a quando non risolverai il conflitto. Dovrai riconfigurarlo se decidi di aggiungerlo di nuovo.', + deletion_description: + 'Stai rimuovendo questo connettore. Non può essere annullato e dovrai riconfigurarlo se decidi di aggiungerlo di nuovo.', +}; + +export default connector_details; diff --git a/packages/phrases/src/locales/it/translation/admin-console/connectors.ts b/packages/phrases/src/locales/it/translation/admin-console/connectors.ts new file mode 100644 index 000000000..bc6d6f335 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/connectors.ts @@ -0,0 +1,91 @@ +const connectors = { + page_title: 'Connettori', + title: 'Connettori', + subtitle: + 'Imposta i connettori per abilitare una esperienza di accesso senza password e tramite social media', + create: 'Aggiungi connettore sociale', + config_sie_notice: 'Hai impostato i connettori. Assicurati di configurarli in {{link}}.', + config_sie_link_text: 'esperienza di accesso', + tab_email_sms: 'Connettori email e SMS', + tab_social: 'Connettori social', + connector_name: 'Nome del connettore', + demo_tip: + 'Il numero massimo di messaggi consentiti per questo connettore demo è limitato a 100 e non è consigliato per il deployment in un ambiente di produzione.', + social_demo_tip: + 'Il connettore demo è progettato esclusivamente per scopi di dimostrazione e non è consigliato per il deployment in un ambiente di produzione.', + connector_type: 'Tipo', + connector_status: 'Esperienza di accesso', + connector_status_in_use: 'In uso', + connector_status_not_in_use: 'Non in uso', + not_in_use_tip: { + content: + 'Non in uso significa che la tua esperienza di accesso non ha utilizzato questo metodo di accesso. {{link}} per aggiungere questo metodo di accesso. ', + go_to_sie: 'Vai all’esperienza di accesso', + }, + placeholder_title: 'Connettore sociale', + placeholder_description: + 'Logto ha fornito molti connettori di accesso condivisi tramite i social media, frattanto puoi creare il tuo usando i protocolli standard.', + save_and_done: 'Salva e Completa', + type: { + email: 'Connettore email', + sms: 'Connettore SMS', + social: 'Connettore sociale', + }, + setup_title: { + email: 'Imposta connettore email', + sms: 'Imposta connettore SMS', + social: 'Aggiungi connettore sociale', + }, + guide: { + subtitle: 'Una guida passo passo per configurare il tuo connettore', + general_setting: 'Impostazioni generali', + parameter_configuration: 'Configurazione dei parametri', + test_connection: 'Prova la connessione', + name: 'Nome per il pulsante di accesso tramite social media', + name_placeholder: 'Inserisci il nome per il pulsante di accesso tramite social media', + name_tip: + 'Il nome del pulsante del connettore verrà visualizzato come "Continua con {{name}}." Presta attenzione alla lunghezza del nome in caso risulti troppo lungo.', + logo: 'URL del logo per il pulsante di accesso tramite social media', + logo_placeholder: 'https://your.cdn.domain/logo.png', + logo_tip: + "L'immagine del logo verrà mostrata sul connettore. Otteni un link di immagine pubblicamente accessibile e inserisci qui il link.", + logo_dark: 'URL del logo per il pulsante di accesso tramite social media (modalità scura)', + logo_dark_placeholder: 'https://your.cdn.domain/logo.png', + logo_dark_tip: + 'Imposta il logo del tuo connettore per la modalità scura dopo averla abilitata nell’esperienza di accesso nel Console dell’Amministratore.', + logo_dark_collapse: 'Comprimi', + logo_dark_show: 'Mostra le impostazioni del logo per la modalità scura', + target: 'Nome del provider di identità', + target_placeholder: 'Inserisci il nome del provider di identità del connettore', + target_tip: + 'Il valore del "Nome IdP" può essere una stringa di identificatore univoco per distinguere le identità social. Questa impostazione non può essere cambiata dopo la costruzione del connettore.', + target_tooltip: + "'Nome IdP' nei connettori social di Logto si riferisce alla 'fonte' delle tue identità social media. Nel design di Logto, non accettiamo lo stesso 'Nome IdP' di una piattaforma specifica per evitare conflitti. Devi fare molta attenzione prima di aggiungere un connettore, poiché NON PUOI cambiarne il valore una volta creato. Scopri di più.", + target_conflict: + 'Il nome IdP inserito corrisponde al connettore nome esistente. L’utilizzo dello stesso nome IdP potrebbe causare un comportamento di accesso imprevisto in cui gli utenti possono accedere allo stesso account tramite due connettori diversi.', + target_conflict_line2: + 'Se desideri sostituire il connettore corrente con lo stesso provider di identità e consentire agli utenti precedenti di accedere senza registrarsi nuovamente, elimina il connettore nome e crea un nuovo connettore con lo stesso "Nome IdP".', + target_conflict_line3: + 'Se desideri connetterti a un provider di identità diverso, modifica il "Nome IdP" e procedi.', + config: 'Inserisci il tuo JSON di configurazione', + sync_profile: 'Sincronizza le informazioni del profilo', + sync_profile_only_at_sign_up: 'Sincronizza solo al momento della registrazione', + sync_profile_each_sign_in: 'Effettua sempre una sincronizzazione ad ogni accesso', + sync_profile_tip: + 'Sincronizza il profilo di base dal provider social, ad esempio i nomi degli utenti e le loro immagini del profilo.', + callback_uri: 'URI di callback', + callback_uri_description: + "Anche chiamato URI di reindirizzamento, è l'URI in Logto dove gli utenti verranno rimandati dopo l'autorizzazione tramite social media, copia e incollalo nella pagina di configurazione del provider social media.", + }, + platform: { + universal: 'Universale', + web: 'Web', + native: 'Native', + }, + add_multi_platform: 'supporta più piattaforme, seleziona una piattaforma per continuare', + drawer_title: 'Guida per il connettore', + drawer_subtitle: 'Segui le istruzioni per integrare il tuo connettore', + unknown: 'Connettore sconosciuto', +}; + +export default connectors; diff --git a/packages/phrases/src/locales/it/translation/admin-console/contact.ts b/packages/phrases/src/locales/it/translation/admin-console/contact.ts new file mode 100644 index 000000000..5ecfa7109 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/contact.ts @@ -0,0 +1,22 @@ +const contatto = { + title: 'Contattaci', + description: + 'Unisciti alla nostra comunità per fornire feedback, chiedere aiuto e condividere le tue idee con altri sviluppatori', + discord: { + title: 'Canale Discord', + description: 'Unisciti al nostro canale pubblico per chattare con altri sviluppatori', + button: 'Unisciti', + }, + github: { + title: 'GitHub', + description: 'Crea un problema e invialo su GitHub', + button: 'Apri', + }, + email: { + title: 'Invia email', + description: 'Invia una email per ulteriori informazioni e supporto', + button: 'Invia', + }, +}; + +export default contatto; diff --git a/packages/phrases/src/locales/it/translation/admin-console/dashboard.ts b/packages/phrases/src/locales/it/translation/admin-console/dashboard.ts new file mode 100644 index 000000000..9fecffe4b --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/dashboard.ts @@ -0,0 +1,21 @@ +const dashboard = { + page_title: 'Dashboard', + title: 'Dashboard', + description: 'Ottieni una panoramica sulle prestazioni della tua app', + total_users: 'Totale utenti', + total_users_tip: 'Totale utenti', + new_users_today: 'Nuovi utenti oggi', + new_users_today_tip: 'Il numero di nuovi utenti registrati sulle tue app oggi', + new_users_7_days: 'Nuovi utenti negli ultimi 7 giorni', + new_users_7_days_tip: 'Il numero di nuovi utenti registrati sulle tue app negli ultimi 7 giorni', + daily_active_users: 'Utenti attivi giornalieri', + daily_active_users_tip: 'Il numero di utenti unici che hanno scambiato token sulle tue app oggi', + weekly_active_users: 'Utenti attivi settimanali', + weekly_active_users_tip: + 'Il numero di utenti unici che hanno scambiato token sulle tue app negli ultimi 7 giorni', + monthly_active_users: 'Utenti attivi mensili', + monthly_active_users_tip: + 'Il numero di utenti unici che hanno scambiato token sulle tue app negli ultimi 30 giorni', +}; + +export default dashboard; diff --git a/packages/phrases/src/locales/it/translation/admin-console/errors.ts b/packages/phrases/src/locales/it/translation/admin-console/errors.ts new file mode 100644 index 000000000..862e071db --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/errors.ts @@ -0,0 +1,25 @@ +const errors = { + something_went_wrong: 'Oops! Si è verificato un errore.', + page_not_found: 'Pagina non trovata', + unknown_server_error: 'Si è verificato un errore del server sconosciuto', + empty: 'Nessun dato', + missing_total_number: 'Impossibile trovare Total-Number negli header di risposta', + invalid_uri_format: 'Formato URI non valido', + invalid_origin_format: 'Formato origine URI non valido', + invalid_json_format: 'Formato JSON non valido', + invalid_error_message_format: 'Il formato del messaggio di errore non è valido.', + required_field_missing: 'Inserisci {{field}}', + required_field_missing_plural: 'Devi inserire almeno un {{field}}', + more_details: 'Ulteriori dettagli', + username_pattern_error: + 'Il nome utente dovrebbe contenere solo lettere, numeri, o trattini bassi e non dovrebbe iniziare con un numero.', + password_pattern_error: + 'La password richiede un minimo di {{min}} caratteri e contiene una combinazione di lettere, numeri e simboli.', + insecure_contexts: 'I contesti non sicuri (non HTTPS) non sono supportati.', + unexpected_error: 'Si è verificato un errore inaspettato.', + not_found: '404 non trovato', + create_internal_role_violation: + "Stai creando un nuovo ruolo interno che è proibito da Logto. Prova un altro nome che non inizi con '#internal:'.", +}; + +export default errors; diff --git a/packages/phrases/src/locales/it/translation/admin-console/general.ts b/packages/phrases/src/locales/it/translation/admin-console/general.ts new file mode 100644 index 000000000..178009975 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/general.ts @@ -0,0 +1,56 @@ +const general = { + placeholder: 'Segnaposto', + skip: 'Salta', + next: 'Avanti', + back: 'Indietro', + retry: 'Riprova', + done: 'Fatto', + search: 'Cerca', + search_placeholder: 'Cerca', + clear_result: 'Cancella risultati', + save: 'Salva', + save_changes: 'Salva modifiche', + saved: 'Salvato!', + discard: 'Elimina', + loading: 'Caricamento...', + redirecting: 'Redirezione...', + add: 'Aggiungi', + added: 'Aggiunto', + cancel: 'Annulla', + confirm: 'Conferma', + check_out: 'Checkout', + create: 'Crea', + set_up: 'Imposta', + customize: 'Personalizza', + enable: 'Abilita', + reminder: 'Promemoria', + delete: 'Elimina', + more_options: 'PIÙ OPZIONI', + close: 'Chiudi', + copy: 'Copia', + copying: 'Copiare', + copied: 'Copiato', + required: 'Obbligatorio', + add_another: 'Aggiungi un altro', + deletion_confirmation: 'Sei sicuro di voler eliminare questo {{title}}?', + settings_nav: 'Impostazioni', + unsaved_changes_warning: + 'Hai apportato alcune modifiche. Sei sicuro di voler lasciare questa pagina?', + leave_page: 'Lascia pagina', + stay_on_page: 'Rimani sulla pagina', + type_to_search: 'Digita per cercare', + got_it: 'Capito', + continue: 'Continua', + page_info: '{{min, number}}-{{max, number}} di {{total, number}}', + learn_more: 'Scopri di più', + tab_errors: '{{count, number}} errori', + skip_for_now: 'Salta per ora', + remove: 'Rimuovi', + visit: 'Visita', + join: 'Unisciti', + try_now: 'Prova ora', + multiple_form_field: '(Multiplo)', + demo: 'Demo', +}; + +export default general; diff --git a/packages/phrases/src/locales/it/translation/admin-console/get-started.ts b/packages/phrases/src/locales/it/translation/admin-console/get-started.ts new file mode 100644 index 000000000..0540f7da2 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/get-started.ts @@ -0,0 +1,35 @@ +const get_started = { + page_title: 'Inizia', + progress: 'Guida per iniziare: {{completed}}/{{total}}', + progress_dropdown_title: 'Alcune cose che puoi fare...', + title: 'Esplora per avere successo', + subtitle_part1: 'Alcune cose che puoi fare per ottenere rapidamente il valore di Logto', + subtitle_part2: 'Sono un professionista e ho completato tutti i passaggi.', + hide_this: 'Nascondi questo', + confirm_message: + 'Sei sicuro di voler nascondere questa pagina? Questa azione non può essere annullata.', + check_preview_title: "Controlla l'anteprima dal vivo", + check_preview_subtitle: 'Prova subito Logto sign-in per vedere come funziona', + integration_title: 'Crea ed integra la tua applicazione', + integration_subtitle: + "Configura l'autenticazione di Logto per la tua applicazione nativa, single page, machine to machine o tradizionale", + custom_sie_title: "Personalizza l'esperienza di accesso", + custom_sie_subtitle: 'Sblocca una vasta gamma di scenari con le impostazioni avanzate', + passwordless_title: "Scala l'accesso senza password aggiungendo i tuoi connettori", + passwordless_subtitle: + "Prova l'accesso senza password e abilita un'esperienza sicura e priva di attriti per i tuoi clienti", + community_title: 'Unisciti alla nostra community su Discord', + community_subtitle: 'Entra nel nostro canale pubblico per parlare con altri sviluppatori', + management_api_title: 'Interagisci con la Management API', + management_api_subtitle: + 'Collega direttamente il tuo sistema di autenticazione alla nostra Management API', + further_readings_title: 'Ulteriori letture', + further_readings_subtitle: + 'Consulta la nostra documentazione passo-passo basata su scenari senza concetti noiosi', + add_rbac_title: + 'Aggiungi il controllo degli accessi basati sui ruoli per proteggere le tue risorse', + add_rbac_subtitle: + "Controlla le tue risorse attraverso l'autorizzazione basata su ruoli scalabile per utilizzi diversi.", +}; + +export default get_started; diff --git a/packages/phrases/src/locales/it/translation/admin-console/index.ts b/packages/phrases/src/locales/it/translation/admin-console/index.ts new file mode 100644 index 000000000..07500c9e5 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/index.ts @@ -0,0 +1,62 @@ +import api_resource_details from './api-resource-details.js'; +import api_resources from './api-resources.js'; +import application_details from './application-details.js'; +import applications from './applications.js'; +import cloud from './cloud.js'; +import components from './components.js'; +import connector_details from './connector-details.js'; +import connectors from './connectors.js'; +import contact from './contact.js'; +import dashboard from './dashboard.js'; +import errors from './errors.js'; +import general from './general.js'; +import get_started from './get-started.js'; +import log_details from './log-details.js'; +import logs from './logs.js'; +import menu from './menu.js'; +import permissions from './permissions.js'; +import profile from './profile.js'; +import role_details from './role-details.js'; +import roles from './roles.js'; +import session_expired from './session-expired.js'; +import sign_in_exp from './sign-in-exp/index.js'; +import tab_sections from './tab-sections.js'; +import tabs from './tabs.js'; +import user_details from './user-details.js'; +import users from './users.js'; +import welcome from './welcome.js'; + +const admin_console = { + title: 'Admin Console', + admin_user: 'Admin', + system_app: 'System', + menu, + general, + errors, + tab_sections, + tabs, + applications, + application_details, + api_resources, + api_resource_details, + connectors, + connector_details, + get_started, + users, + user_details, + contact, + sign_in_exp, + dashboard, + logs, + log_details, + session_expired, + welcome, + roles, + role_details, + permissions, + cloud, + profile, + components, +}; + +export default admin_console; diff --git a/packages/phrases/src/locales/it/translation/admin-console/log-details.ts b/packages/phrases/src/locales/it/translation/admin-console/log-details.ts new file mode 100644 index 000000000..3c24634fe --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/log-details.ts @@ -0,0 +1,18 @@ +const log_details = { + page_title: 'Dettagli registro di verifica', + back_to_logs: 'Torna ai log di verifica', + back_to_user: 'Torna a {{name}}', + success: 'Successo', + failed: 'Fallito', + event_key: 'Chiave evento', + application: 'Applicazione', + ip_address: 'Indirizzo IP', + user: 'Utente', + log_id: 'ID registro', + time: 'Tempo', + user_agent: 'User agent', + tab_details: 'Dettagli', + raw_data: 'Dati grezzi', +}; + +export default log_details; diff --git a/packages/phrases/src/locales/it/translation/admin-console/logs.ts b/packages/phrases/src/locales/it/translation/admin-console/logs.ts new file mode 100644 index 000000000..3eee38b63 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/logs.ts @@ -0,0 +1,13 @@ +const logs = { + page_title: 'Log di Audit', + title: 'Log di Audit', + subtitle: + 'Visualizza i dati di registro degli eventi di autenticazione effettuati dai tuoi utenti', + event: 'Evento', + user: 'Utente', + application: 'Applicazione', + time: 'Tempo', + filter_by: 'Filtra per', +}; + +export default logs; diff --git a/packages/phrases/src/locales/it/translation/admin-console/menu.ts b/packages/phrases/src/locales/it/translation/admin-console/menu.ts new file mode 100644 index 000000000..e275d09b2 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/menu.ts @@ -0,0 +1,13 @@ +const menu = { + profile: 'Profilo', + language: 'Lingua', + appearance: { + label: 'Aspetto', + light: 'Modalità chiaro', + dark: 'Modalità scuro', + system: 'Sincronizza con sistema', + }, + sign_out: 'Esci', +}; + +export default menu; diff --git a/packages/phrases/src/locales/it/translation/admin-console/permissions.ts b/packages/phrases/src/locales/it/translation/admin-console/permissions.ts new file mode 100644 index 000000000..fb8005a4f --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/permissions.ts @@ -0,0 +1,12 @@ +const permissions = { + search_placeholder: 'Cerca per nome API o permesso', + search_placeholder_without_api: 'Cerca per nome permesso', + name_column: 'Permesso', + description_column: 'Descrizione', + api_column: 'API', + placeholder_title: 'Permesso', + placeholder_description: + "Il permesso si riferisce all'autorizzazione per accedere ad una risorsa (la chiamiamo risorsa API).", +}; + +export default permissions; diff --git a/packages/phrases/src/locales/it/translation/admin-console/profile.ts b/packages/phrases/src/locales/it/translation/admin-console/profile.ts new file mode 100644 index 000000000..c52a80b33 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/profile.ts @@ -0,0 +1,82 @@ +const profile = { + page_title: 'Impostazioni Account', + title: 'Impostazioni Account', + description: + 'Cambia le tue impostazioni account e gestisci le tue informazioni personali qui per garantire la sicurezza del tuo account.', + settings: { + title: 'IMPOSTAZIONI PROFILO', + profile_information: 'Informazioni profilo', + avatar: 'Avatar', + name: 'Nome', + username: 'Nome utente', + }, + link_account: { + title: 'COLLEGA ACCOUNT', + email_sign_in: 'Accesso con email', + email: 'Email', + social_sign_in: 'Accesso con social media', + link_email: 'Collega email', + link_email_subtitle: "Collega la tua email per accedere o per recuperare l'account.", + email_required: "L'email è obbligatoria", + invalid_email: 'Indirizzo email non valido', + identical_email_address: "L'indirizzo email inserito è identico a quello corrente", + anonymous: 'Anonimo', + }, + password: { + title: 'PASSWORD E SICUREZZA', + password: 'Password', + password_setting: 'Impostazione password', + new_password: 'Nuova password', + confirm_password: 'Conferma password', + enter_password: 'Inserisci la tua password', + enter_password_subtitle: 'Verifica che sia tu per proteggere la sicurezza del tuo account.', + set_password: 'Imposta password', + verify_via_password: 'Verifica tramite password', + show_password: 'Mostra password', + required: 'La password è obbligatoria', + min_length: 'La password deve contenere almeno {{min}} caratteri', + do_not_match: 'Le password non corrispondono. Riprova.', + }, + code: { + enter_verification_code: 'Inserisci il codice di verifica', + enter_verification_code_subtitle: + 'Il codice di verifica è stato inviato a {{target}}', + verify_via_code: 'Verifica tramite codice di verifica', + resend: 'Invia nuovamente il codice di verifica', + resend_countdown: 'Invia nuovamente in {{countdown}} secondi', + }, + delete_account: { + title: 'ELIMINA ACCOUNT', + label: 'Elimina account', + description: + 'Eliminando il tuo account, verranno rimossi tutti i tuoi dati personali, le informazioni utente, la configurazione. Questa operazione non può essere annullata.', + button: 'Elimina account', + dialog_paragraph_1: + "Ci dispiace sapere che desideri eliminare il tuo account. L'eliminazione dell'account rimuoverà permanentemente tutti i dati, inclusi le informazioni utente, i log e le impostazioni, e questa azione non può essere annullata. Quindi assicurati di eseguire il backup di eventuali dati importanti prima di procedere.", + dialog_paragraph_2: + "Per procedere con il processo di eliminazione dell'account, invia un'email al nostro team di supporto all'indirizzo {{mail}} con l'oggetto \"Richiesta di eliminazione account\". Ti assisteremo e ci assicureremo che tutti i tuoi dati siano correttamente eliminati dal nostro sistema.", + dialog_paragraph_3: + 'Grazie per aver scelto Logto Cloud. Se hai ulteriori domande o dubbi, non esitare a contattarci.', + }, + set: 'Imposta', + change: 'Cambia', + link: 'Collega', + unlink: 'Scollega', + not_set: 'Non impostato', + change_avatar: 'Cambia avatar', + change_name: 'Cambia nome', + change_username: 'Cambia nome utente', + set_name: 'Imposta nome', + email_changed: 'Email modificata!', + password_changed: 'Password modificata!', + updated: '{{target}} aggiornato!', + linked: '{{target}} collegato!', + unlinked: '{{target}} scollegato!', + email_exists_reminder: + "Questa email {{email}} è associata a un account esistente. Collega un'altra email qui.", + unlink_confirm_text: 'Sì, scollega', + unlink_reminder: + "Gli utenti non potranno più accedere tramite l'account se lo scolleghi. Sicuro di procedere?", +}; + +export default profile; diff --git a/packages/phrases/src/locales/it/translation/admin-console/role-details.ts b/packages/phrases/src/locales/it/translation/admin-console/role-details.ts new file mode 100644 index 000000000..321c0aad0 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/role-details.ts @@ -0,0 +1,51 @@ +const role_details = { + back_to_roles: 'Torna ai Ruoli', + identifier: 'Identificatore', + delete_description: + 'Ciò cancellerà anche i permessi associati a questo ruolo dagli utenti coinvolti e cancellerà la corrispondenza tra ruoli, utenti e permessi.', + role_deleted: '{{name}} è stato cancellato con successo!', + settings_tab: 'Impostazioni', + users_tab: 'Utenti', + permissions_tab: 'Permessi', + settings: 'Impostazioni', + settings_description: + "I ruoli sono un raggruppamento di autorizzazioni che possono essere assegnate agli utenti. Forniscono anche un modo per aggregare le autorizzazioni definite per diverse API, rendendo più efficiente l'aggiunta, la rimozione o la regolazione delle autorizzazioni rispetto all'assegnazione individuale agli utenti.", + field_name: 'Nome', + field_description: 'Descrizione', + permission: { + assign_button: 'Assegna permessi', + assign_title: 'Assegna permessi', + assign_subtitle: + 'Assegna autorizzazioni a questo ruolo. Il ruolo acquisirà le autorizzazioni aggiunte e gli utenti con questo ruolo erediteranno queste autorizzazioni.', + assign_form_field: 'Assegna permessi', + added_text_one: '{{count, number}} permesso aggiunto', + added_text_other: '{{count, number}} autorizzazioni aggiunte', + api_permission_count_one: '{{count, number}} permesso', + api_permission_count_other: '{{count, number}} autorizzazioni', + confirm_assign: 'Assegna permessi', + permission_assigned: + 'Le autorizzazioni selezionate sono state assegnate con successo a questo ruolo', + deletion_description: + "Se questa autorizzazione viene rimossa, l'utente interessato con questo ruolo perderà l'accesso garantito da questa autorizzazione.", + permission_deleted: 'La permissione "{{name}}" è stata rimossa con successo da questo ruolo', + empty: 'Nessuna autorizzazione disponibile', + }, + users: { + assign_button: 'Assegna utenti', + name_column: 'Utente', + app_column: 'App', + latest_sign_in_column: 'Ultimo accesso', + delete_description: + "Resterà nella tua raccolta di utenti ma perderà l'autorizzazione per questo ruolo.", + deleted: '{{name}} è stato rimosso con successo da questo ruolo', + assign_title: 'Assegna utenti', + assign_subtitle: + 'Assegna utenti a questo ruolo. Trova utenti appropriati cercando nome, email, telefono o ID utente.', + assign_users_field: 'Assegna utenti', + confirm_assign: 'Assegna utenti', + users_assigned: 'Gli utenti selezionati sono stati assegnati con successo a questo ruolo', + empty: 'Nessun utente disponibile', + }, +}; + +export default role_details; diff --git a/packages/phrases/src/locales/it/translation/admin-console/roles.ts b/packages/phrases/src/locales/it/translation/admin-console/roles.ts new file mode 100644 index 000000000..8d5790c73 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/roles.ts @@ -0,0 +1,24 @@ +const roles = { + page_title: 'Ruoli', + title: 'Ruoli', + subtitle: + "I ruoli includono le autorizzazioni che determinano ciò che un utente può fare. RBAC utilizza i ruoli per dare agli utenti l'accesso alle risorse necessarie per specifiche azioni.", + create: 'Crea Ruolo', + role_name: 'Ruolo', + role_description: 'Descrizione', + role_name_placeholder: 'Inserisci il nome del tuo ruolo', + role_description_placeholder: 'Inserisci la descrizione del tuo ruolo', + assigned_users: 'Utenti assegnati', + assign_permissions: 'Assegna autorizzazioni', + create_role_title: 'Crea Ruolo', + create_role_description: + 'Crea e gestisci ruoli per le tue applicazioni. I ruoli contengono collezioni di autorizzazioni e possono essere assegnati agli utenti.', + create_role_button: 'Crea Ruolo', + role_created: 'Il ruolo {{name}} è stato creato con successo!', + search: 'Cerca per nome, descrizione o ID del ruolo', + placeholder_title: 'Ruoli', + placeholder_description: + 'I ruoli sono un raggruppamento di autorizzazioni che possono essere assegnati agli utenti. Assicurati di aggiungere le autorizzazioni prima di creare i ruoli.', +}; + +export default roles; diff --git a/packages/phrases/src/locales/it/translation/admin-console/session-expired.ts b/packages/phrases/src/locales/it/translation/admin-console/session-expired.ts new file mode 100644 index 000000000..ba5de7670 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/session-expired.ts @@ -0,0 +1,8 @@ +const session_expired = { + title: 'La sessione è scaduta', + subtitle: + 'La tua sessione potrebbe essere scaduta e sei stato disconnesso. Clicca il pulsante qui sotto per accedere di nuovo alla console di amministrazione.', + button: 'Accedi di nuovo', +}; + +export default session_expired; diff --git a/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/index.ts b/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/index.ts new file mode 100644 index 000000000..7d95d5a05 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/index.ts @@ -0,0 +1,88 @@ +import others from './others.js'; +import sign_up_and_sign_in from './sign-up-and-sign-in.js'; + +const sign_in_exp = { + page_title: 'Esperienza di accesso', + title: 'Esperienza di accesso', + description: + "Personalizza l'interfaccia di accesso per abbinarla al tuo marchio e visualizzala in tempo reale", + tabs: { + branding: 'Marchio', + sign_up_and_sign_in: 'Registrazione e accesso', + others: 'Altri', + }, + welcome: { + title: "Personalizza l'esperienza di accesso", + description: + 'Inizia subito con la configurazione del tuo primo accesso. Questa guida ti guiderà attraverso tutte le impostazioni necessarie.', + get_started: 'Inizia', + apply_remind: + "Si prega di notare che l'esperienza di accesso verrà applicata a tutte le applicazioni in questo account.", + }, + color: { + title: 'COLORE', + primary_color: 'Colore del marchio', + dark_primary_color: 'Colore del marchio (scuro)', + dark_mode: 'Abilita modalità scura', + dark_mode_description: + "La tua app avrà un tema modalità scura generato automaticamente in base al tuo colore del marchio e all'algoritmo Logto. Sei libero di personalizzare.", + dark_mode_reset_tip: 'Ricalcola il colore della modalità scura in base al colore del marchio.', + reset: 'Ricalcola', + }, + branding: { + title: 'AREA DI BRANDIZZO', + ui_style: 'Stile', + favicon: 'Favicon', + logo_image_url: "URL dell'immagine del logo dell'app", + logo_image_url_placeholder: 'https://your.cdn.domain/logo.png', + dark_logo_image_url: "URL dell'immagine del logo dell'app (scuro)", + dark_logo_image_url_placeholder: 'https://your.cdn.domain/logo-dark.png', + logo_image: "Logo dell'app", + dark_logo_image: "Logo dell'app (scuro)", + logo_image_error: "Logo dell'app: {{error}}", + favicon_error: 'Favicon: {{error}}', + }, + custom_css: { + title: 'CSS personalizzato', + css_code_editor_title: 'Personalizza la tua interfaccia utente con CSS personalizzato', + css_code_editor_description1: "Guarda l'esempio di CSS personalizzato.", + css_code_editor_description2: '{{link}}', + css_code_editor_description_link_content: 'Ulteriori informazioni', + css_code_editor_content_placeholder: + 'Inserisci il tuo CSS personalizzato per adattare lo stile di qualsiasi cosa alle tue specifiche. Esprimi la tua creatività e fai risaltare la tua interfaccia utente.', + }, + sign_up_and_sign_in, + others, + setup_warning: { + no_connector_sms: + 'Nessun connettore SMS ancora configurato. Prima di completare la configurazione, gli utenti non saranno in grado di accedere con questo metodo. {{link}} in "Connettori"', + no_connector_email: + 'Nessun connettore email ancora configurato. Prima di completare la configurazione, gli utenti non saranno in grado di accedere con questo metodo. {{link}} in "Connettori"', + no_connector_social: + 'Nessun connettore sociale ancora configurato. Prima di completare la configurazione, gli utenti non saranno in grado di accedere con questo metodo. {{link}} in "Connettori"', + no_added_social_connector: + 'Hai configurato alcuni connettori sociali adesso. Assicurati di aggiungerne alcuni alla tua esperienza di accesso.', + setup_link: 'Configura', + }, + save_alert: { + description: + 'Stai implementando nuove procedure di accesso e registrazione. Tutti i tuoi utenti potrebbero essere influenzati dalla nuova configurazione. Sei sicuro di voler procedere con il cambiamento?', + before: 'Prima', + after: 'Dopo', + sign_up: 'Registrazione', + sign_in: 'Accesso', + social: 'Sociale', + }, + preview: { + title: 'Anteprima di accesso', + live_preview: 'Anteprima in diretta', + live_preview_tip: 'Salva per visualizzare le modifiche', + native: 'Nat', + desktop_web: 'Web desktop', + mobile_web: 'Web mobile', + desktop: 'Desktop', + mobile: 'Mobile', + }, +}; + +export default sign_in_exp; diff --git a/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/others.ts b/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/others.ts new file mode 100644 index 000000000..9471cec90 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/others.ts @@ -0,0 +1,48 @@ +const others = { + terms_of_use: { + title: 'TERMINI', + terms_of_use: "URL dei termini d'uso", + terms_of_use_placeholder: 'https://tuoi.termini.di.uso/', + privacy_policy: 'URL della politica sulla privacy', + privacy_policy_placeholder: 'https://tua.politica.sulla.privacy/', + }, + languages: { + title: 'LINGUE', + enable_auto_detect: 'Abilita rilevamento automatico', + description: + "Il software rileva l'impostazione di lingua dell'utente e passa alla lingua locale. Puoi aggiungere nuove lingue traducendo l'interfaccia utente dall'inglese a un'altra lingua.", + manage_language: 'Gestisci lingua', + default_language: 'Lingua predefinita', + default_language_description_auto: + "La lingua predefinita verrà utilizzata quando la lingua dell'utente rilevata non è coperta dalla libreria delle lingue attuali.", + default_language_description_fixed: + "Quando il rilevamento automatico è disattivato, l'unica lingua che il tuo software mostrerà è quella predefinita. Attivare il rilevamento automatico per l'estensione delle lingue.", + }, + manage_language: { + title: 'Gestisci lingua', + subtitle: + "Localizza l'esperienza del prodotto aggiungendo lingue e traduzioni. Il tuo contributo può essere impostato come lingua predefinita.", + add_language: 'Aggiungi lingua', + logto_provided: 'Logtogli forniti', + key: 'Chiave', + logto_source_values: 'Valori di origine Logtogli', + custom_values: 'Valori personalizzati', + clear_all_tip: 'Cancella tutti i valori', + unsaved_description: 'Le modifiche non saranno salvate se lasci la pagina senza salvare.', + deletion_tip: 'Elimina la lingua', + deletion_title: 'Vuoi eliminare la lingua aggiunta?', + deletion_description: + "Dopo l'eliminazione, i tuoi utenti non saranno più in grado di navigare in quella lingua.", + default_language_deletion_title: 'La lingua predefinita non può essere eliminata.', + default_language_deletion_description: + '{{language}} è impostata come tua lingua predefinita e non può essere eliminata.', + }, + advanced_options: { + title: 'OPZIONI AVANZATE', + enable_user_registration: 'Abilita registrazione utente', + enable_user_registration_description: + "Abilitare o impedire la registrazione degli utenti. Una volta disattivata, gli utenti possono ancora essere aggiunti nella console di amministrazione ma gli utenti non possono più creare account attraverso l'interfaccia di accesso.", + }, +}; + +export default others; diff --git a/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts b/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts new file mode 100644 index 000000000..2a8b76de2 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts @@ -0,0 +1,58 @@ +const sign_up_and_sign_in = { + identifiers_email: 'Indirizzo email', + identifiers_phone: 'Numero di telefono', + identifiers_username: 'Nome utente', + identifiers_email_or_sms: 'Indirizzo email o numero di telefono', + identifiers_none: 'Non applicabile', + and: 'e', + or: 'o', + sign_up: { + title: 'REGISTRATI', + sign_up_identifier: 'Identificatore di registrazione', + identifier_description: + "L'identificatore di registrazione è necessario per la creazione dell'account e deve essere incluso nella schermata di accesso.", + sign_up_authentication: "Impostazione dell'autenticazione per la registrazione", + authentication_description: + 'Tutte le azioni selezionate saranno obbligatorie per gli utenti per completare il flusso.', + set_a_password_option: 'Crea la tua password', + verify_at_sign_up_option: "Verifica all'atto della registrazione", + social_only_creation_description: + '(Questo si applica solo alla creazione di account con i social)', + }, + sign_in: { + title: 'ACCEDI', + sign_in_identifier_and_auth: "Identificatore e impostazioni di autenticazione per l'accesso", + description: + 'Gli utenti possono accedere utilizzando una qualsiasi delle opzioni disponibili. Regola il layout trascinando e rilasciando le opzioni sottostanti.', + add_sign_in_method: 'Aggiungi metodo di accesso', + password_auth: 'Password', + verification_code_auth: 'Codice di verifica', + auth_swap_tip: 'Scambia le opzioni sottostanti per determinare quale appare prima nel flusso.', + require_auth_factor: 'Devi selezionare almeno un fattore di autenticazione.', + }, + social_sign_in: { + title: 'ACCESSO CON I SOCIAL', + social_sign_in: 'Accesso ai social', + description: + "A seconda dell'identificatore obbligatorio che hai impostato, all'utente potrebbe essere chiesto di fornire un identificatore durante la registrazione tramite il connettore social.", + add_social_connector: 'Aggiungi connettore social', + set_up_hint: { + not_in_list: 'Non in lista?', + set_up_more: 'Imposta', + go_to: 'altri connettori social ora.', + }, + }, + tip: { + set_a_password: 'Un set unico di password per il tuo nome utente è un must.', + verify_at_sign_up: + 'Attualmente supportiamo solo la posta elettronica verificata. La tua base utenti potrebbe contenere un gran numero di indirizzi email di bassa qualità se non effettui la convalida.', + password_auth: + "Questo è essenziale poiché hai abilitato l'opzione di impostazione della password durante il processo di registrazione.", + verification_code_auth: + "Questo è essenziale poiché hai abilitato solo l'opzione di fornire un codice di verifica durante la registrazione. Se consenti l'impostazione della password durante il processo di registrazione, puoi deselezionare la casella.", + delete_sign_in_method: + 'Questo è essenziale in quanto hai selezionato {{identifier}} come identificatore obbligatorio.', + }, +}; + +export default sign_up_and_sign_in; diff --git a/packages/phrases/src/locales/it/translation/admin-console/tab-sections.ts b/packages/phrases/src/locales/it/translation/admin-console/tab-sections.ts new file mode 100644 index 000000000..2f938a224 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/tab-sections.ts @@ -0,0 +1,9 @@ +const tab_sections = { + overview: 'Panoramica', + resource_management: 'Gestione delle Risorse', + user_management: 'Gestione Utenti', + access_control: 'Controllo Accessi', + help_and_support: 'Aiuto e Supporto', +}; + +export default tab_sections; diff --git a/packages/phrases/src/locales/it/translation/admin-console/tabs.ts b/packages/phrases/src/locales/it/translation/admin-console/tabs.ts new file mode 100644 index 000000000..49d695a8c --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/tabs.ts @@ -0,0 +1,16 @@ +const tabs = { + get_started: 'Iniziare', + dashboard: 'Dashboard', + applications: 'Applicazioni', + api_resources: 'Risorse API', + sign_in_experience: 'Esperienza di accesso', + connectors: 'Connettori', + users: 'Gestione utenti', + audit_logs: 'Registri di verifica', + roles: 'Ruoli', + docs: 'Documenti', + contact_us: 'Contattaci', + settings: 'Impostazioni', +}; + +export default tabs; diff --git a/packages/phrases/src/locales/it/translation/admin-console/user-details.ts b/packages/phrases/src/locales/it/translation/admin-console/user-details.ts new file mode 100644 index 000000000..637d60b8a --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/user-details.ts @@ -0,0 +1,66 @@ +const user_details = { + page_title: 'Dettagli utente', + back_to_users: 'Torna alla gestione utenti', + created_title: 'Questo utente è stato creato con successo', + created_guide: "Puoi inviare le seguenti informazioni di accesso all'utente", + created_username: 'Nome utente:', + created_password: 'Password:', + menu_delete: 'Elimina', + delete_description: + "Questa azione non può essere annullata. Eliminerai l'utente in modo permanente.", + deleted: "L'utente è stato eliminato con successo", + reset_password: { + reset_password: 'Resetta la password', + title: 'Sei sicuro di voler reimpostare la password?', + content: + "Questa azione non può essere annullata. Questo reimposterà le informazioni di accesso dell'utente.", + congratulations: "L'utente è stato reimpostato", + new_password: 'Nuova password:', + }, + tab_settings: 'Impostazioni', + tab_roles: 'Ruoli', + tab_logs: 'Log utente', + settings: 'Impostazioni', + settings_description: + "Ogni utente ha un profilo contenente tutte le informazioni dell'utente. È composto da dati di base, identità sociali e dati personalizzati.", + field_email: 'Email principale', + field_phone: 'Telefono principale', + field_username: 'Nome utente', + field_name: 'Nome', + field_avatar: "URL dell'immagine dell'avatar", + field_avatar_placeholder: 'https://il-tuo-dominio.cdn/avatar.png', + field_custom_data: 'Dati personalizzati', + field_custom_data_tip: + "Ulteriori informazioni sull'utente non elencate nelle proprietà utente predefinite, come il colore e la lingua preferiti dall'utente.", + field_connectors: 'Connessioni sociali', + custom_data_invalid: 'I dati personalizzati devono essere un oggetto JSON valido', + connectors: { + connectors: 'Connettori', + user_id: 'ID utente', + remove: 'Rimuovi', + not_connected: "L'utente non è connesso a nessun connettore sociale", + deletion_confirmation: + "Stai rimuovendo l'identità esistente . Sei sicuro di voler procedere?", + }, + suspended: 'Sospeso', + roles: { + name_column: 'Ruolo', + description_column: 'Descrizione', + assign_button: 'Assegna ruoli', + delete_description: + 'Questa azione rimuoverà questo ruolo da questo utente. Il ruolo stesso esisterà ancora, ma non sarà più associato a questo utente.', + deleted: '{{nome}} è stato rimosso con successo da questo utente.', + assign_title: 'Assegna ruoli a {{nome}}', + assign_subtitle: 'Autorizza {{nome}} uno o più ruoli', + assign_role_field: 'Assegna ruoli', + role_search_placeholder: 'Cerca per nome ruolo', + added_text: '{{value, number}} aggiunti', + assigned_user_count: '{{value, number}} utenti', + confirm_assign: 'Assegna ruoli', + role_assigned: 'Ruolo(ruoli) assegnati con successo', + search: 'Cerca per nome ruolo, descrizione o ID', + empty: 'Nessun ruolo disponibile', + }, +}; + +export default user_details; diff --git a/packages/phrases/src/locales/it/translation/admin-console/users.ts b/packages/phrases/src/locales/it/translation/admin-console/users.ts new file mode 100644 index 000000000..b991fddea --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/users.ts @@ -0,0 +1,21 @@ +const users = { + page_title: 'Gestione utenti', + title: 'Gestione utenti', + subtitle: + "Gestisci le identità degli utenti, inclusa la creazione di utenti, la modifica delle informazioni degli utenti, la visualizzazione dei log degli utenti, il ripristino delle password e l'eliminazione degli utenti", + create: 'Aggiungi utente', + user_name: 'Utente', + application_name: "Dall'applicazione", + latest_sign_in: 'Ultimo accesso', + create_form_username: 'Nome utente', + create_form_password: 'Password', + create_form_name: 'Nome completo', + unnamed: 'Senza nome', + search: 'Cerca per nome, email, telefono o nome utente', + check_user_detail: "Controlla i dettagli dell'utente", + placeholder_title: 'Gestione utenti', + placeholder_description: + "Ogni utente ha un profilo contenente tutte le informazioni dell'utente. È composto da dati di base, identità sociali e dati personalizzati.", +}; + +export default users; diff --git a/packages/phrases/src/locales/it/translation/admin-console/welcome.ts b/packages/phrases/src/locales/it/translation/admin-console/welcome.ts new file mode 100644 index 000000000..6bfc9e639 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/admin-console/welcome.ts @@ -0,0 +1,8 @@ +const welcome = { + title: 'Benvenuti alla Console di Amministrazione', + description: + "La console di amministrazione è un'app web per gestire Logto senza alcuna conoscenza di programmazione. Iniziamo creando un account. Con questo account, puoi gestire Logto da solo o per conto della tua azienda.", + create_account: 'Crea account', +}; + +export default welcome; diff --git a/packages/phrases/src/locales/it/translation/demo-app.ts b/packages/phrases/src/locales/it/translation/demo-app.ts new file mode 100644 index 000000000..ddc909c0a --- /dev/null +++ b/packages/phrases/src/locales/it/translation/demo-app.ts @@ -0,0 +1,13 @@ +const demo_app = { + title: "Hai effettuato l'accesso anteprima live con successo!", + subtitle: 'Ecco le tue informazioni di accesso:', + username: 'Nome utente: ', + user_id: 'ID utente: ', + sign_out: "Esci dall'anteprima live", + continue_explore: 'O continua ad esplorare', + customize_sign_in_experience: "Personalizza l'esperienza di accesso", + enable_passwordless: "Abilita l'accesso senza password", + add_social_connector: 'Aggiungi connettore social', +}; + +export default demo_app; diff --git a/packages/phrases/src/locales/it/translation/index.ts b/packages/phrases/src/locales/it/translation/index.ts new file mode 100644 index 000000000..d006e599f --- /dev/null +++ b/packages/phrases/src/locales/it/translation/index.ts @@ -0,0 +1,11 @@ +import admin_console from './admin-console/index.js'; +import demo_app from './demo-app.js'; +import oidc from './oidc.js'; + +const translation = { + admin_console, + demo_app, + oidc, +}; + +export default translation; diff --git a/packages/phrases/src/locales/it/translation/oidc.ts b/packages/phrases/src/locales/it/translation/oidc.ts new file mode 100644 index 000000000..f727bc1d9 --- /dev/null +++ b/packages/phrases/src/locales/it/translation/oidc.ts @@ -0,0 +1,5 @@ +const oidc = { + logout_success: 'Hai effettuato il logout correttamente.', +}; + +export default oidc; From ae6a5499361c576a61fab4ac5b7c7f947c06f332 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Sat, 1 Apr 2023 01:55:39 +0800 Subject: [PATCH 04/11] chore: add changeset --- .changeset/fluffy-masks-tap.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/fluffy-masks-tap.md diff --git a/.changeset/fluffy-masks-tap.md b/.changeset/fluffy-masks-tap.md new file mode 100644 index 000000000..28387b265 --- /dev/null +++ b/.changeset/fluffy-masks-tap.md @@ -0,0 +1,6 @@ +--- +"@logto/phrases": minor +"@logto/phrases-ui": minor +--- + +add it translation From 206fba2b57e3afa0f144d15ec93789b4f2bab627 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Sat, 1 Apr 2023 01:59:38 +0800 Subject: [PATCH 05/11] feat(phrases): add pl-PL translation --- .changeset/hungry-bears-complain.md | 6 + packages/phrases-ui/src/index.ts | 3 + .../phrases-ui/src/locales/pl-pl/action.ts | 29 +++++ .../phrases-ui/src/locales/pl-pl/demo-app.ts | 5 + .../src/locales/pl-pl/description.ts | 61 +++++++++ .../phrases-ui/src/locales/pl-pl/error.ts | 24 ++++ .../phrases-ui/src/locales/pl-pl/index.ts | 21 +++ .../phrases-ui/src/locales/pl-pl/input.ts | 10 ++ .../phrases-ui/src/locales/pl-pl/secondary.ts | 6 + packages/phrases/src/index.ts | 3 + .../phrases/src/locales/pl-pl/errors/auth.ts | 12 ++ .../src/locales/pl-pl/errors/connector.ts | 40 ++++++ .../src/locales/pl-pl/errors/entity.ts | 8 ++ .../phrases/src/locales/pl-pl/errors/guard.ts | 9 ++ .../phrases/src/locales/pl-pl/errors/index.ts | 39 ++++++ .../src/locales/pl-pl/errors/localization.ts | 8 ++ .../phrases/src/locales/pl-pl/errors/log.ts | 5 + .../phrases/src/locales/pl-pl/errors/oidc.ts | 20 +++ .../src/locales/pl-pl/errors/password.ts | 6 + .../src/locales/pl-pl/errors/request.ts | 6 + .../phrases/src/locales/pl-pl/errors/role.ts | 11 ++ .../phrases/src/locales/pl-pl/errors/scope.ts | 6 + .../src/locales/pl-pl/errors/session.ts | 25 ++++ .../pl-pl/errors/sign-in-experiences.ts | 22 ++++ .../src/locales/pl-pl/errors/storage.ts | 7 + .../src/locales/pl-pl/errors/swagger.ts | 7 + .../phrases/src/locales/pl-pl/errors/user.ts | 34 +++++ .../locales/pl-pl/errors/verification-code.ts | 12 ++ packages/phrases/src/locales/pl-pl/index.ts | 11 ++ .../admin-console/api-resource-details.ts | 32 +++++ .../admin-console/api-resources.ts | 15 +++ .../admin-console/application-details.ts | 51 ++++++++ .../translation/admin-console/applications.ts | 53 ++++++++ .../pl-pl/translation/admin-console/cloud.ts | 121 ++++++++++++++++++ .../translation/admin-console/components.ts | 15 +++ .../admin-console/connector-details.ts | 35 +++++ .../translation/admin-console/connectors.ts | 90 +++++++++++++ .../translation/admin-console/contact.ts | 22 ++++ .../translation/admin-console/dashboard.ts | 22 ++++ .../pl-pl/translation/admin-console/errors.ts | 25 ++++ .../translation/admin-console/general.ts | 55 ++++++++ .../translation/admin-console/get-started.ts | 34 +++++ .../pl-pl/translation/admin-console/index.ts | 62 +++++++++ .../translation/admin-console/log-details.ts | 18 +++ .../pl-pl/translation/admin-console/logs.ts | 13 ++ .../pl-pl/translation/admin-console/menu.ts | 13 ++ .../translation/admin-console/permissions.ts | 12 ++ .../translation/admin-console/profile.ts | 82 ++++++++++++ .../translation/admin-console/role-details.ts | 50 ++++++++ .../pl-pl/translation/admin-console/roles.ts | 24 ++++ .../admin-console/session-expired.ts | 8 ++ .../admin-console/sign-in-exp/index.ts | 88 +++++++++++++ .../admin-console/sign-in-exp/others.ts | 48 +++++++ .../sign-in-exp/sign-up-and-sign-in.ts | 58 +++++++++ .../translation/admin-console/tab-sections.ts | 9 ++ .../pl-pl/translation/admin-console/tabs.ts | 16 +++ .../translation/admin-console/user-details.ts | 63 +++++++++ .../pl-pl/translation/admin-console/users.ts | 21 +++ .../translation/admin-console/welcome.ts | 8 ++ .../src/locales/pl-pl/translation/demo-app.ts | 13 ++ .../src/locales/pl-pl/translation/index.ts | 11 ++ .../src/locales/pl-pl/translation/oidc.ts | 5 + 62 files changed, 1648 insertions(+) create mode 100644 .changeset/hungry-bears-complain.md create mode 100644 packages/phrases-ui/src/locales/pl-pl/action.ts create mode 100644 packages/phrases-ui/src/locales/pl-pl/demo-app.ts create mode 100644 packages/phrases-ui/src/locales/pl-pl/description.ts create mode 100644 packages/phrases-ui/src/locales/pl-pl/error.ts create mode 100644 packages/phrases-ui/src/locales/pl-pl/index.ts create mode 100644 packages/phrases-ui/src/locales/pl-pl/input.ts create mode 100644 packages/phrases-ui/src/locales/pl-pl/secondary.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/auth.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/connector.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/entity.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/guard.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/index.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/localization.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/log.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/oidc.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/password.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/request.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/role.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/scope.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/session.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/sign-in-experiences.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/storage.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/swagger.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/user.ts create mode 100644 packages/phrases/src/locales/pl-pl/errors/verification-code.ts create mode 100644 packages/phrases/src/locales/pl-pl/index.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/api-resource-details.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/api-resources.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/application-details.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/cloud.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/components.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/connector-details.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/connectors.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/contact.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/dashboard.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/errors.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/general.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/get-started.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/index.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/log-details.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/logs.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/menu.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/permissions.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/profile.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/role-details.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/session-expired.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/index.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/others.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/tab-sections.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/tabs.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/user-details.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/users.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/admin-console/welcome.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/demo-app.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/index.ts create mode 100644 packages/phrases/src/locales/pl-pl/translation/oidc.ts diff --git a/.changeset/hungry-bears-complain.md b/.changeset/hungry-bears-complain.md new file mode 100644 index 000000000..406a309e2 --- /dev/null +++ b/.changeset/hungry-bears-complain.md @@ -0,0 +1,6 @@ +--- +"@logto/phrases": minor +"@logto/phrases-ui": minor +--- + +add pl-PL translation diff --git a/packages/phrases-ui/src/index.ts b/packages/phrases-ui/src/index.ts index 2955f84da..0a9f8cac2 100644 --- a/packages/phrases-ui/src/index.ts +++ b/packages/phrases-ui/src/index.ts @@ -10,6 +10,7 @@ import fr from './locales/fr/index.js'; import it from './locales/it/index.js'; import ja from './locales/ja/index.js'; import ko from './locales/ko/index.js'; +import plPL from './locales/pl-pl/index.js'; import ptBR from './locales/pt-br/index.js'; import ptPT from './locales/pt-pt/index.js'; import ru from './locales/ru/index.js'; @@ -31,6 +32,7 @@ export const builtInLanguages = [ 'it', 'ja', 'ko', + 'pl-PL', 'pt-PT', 'pt-BR', 'ru', @@ -59,6 +61,7 @@ const resource: Resource = { it, ja, ko, + 'pl-PL': plPL, 'pt-PT': ptPT, 'pt-BR': ptBR, ru, diff --git a/packages/phrases-ui/src/locales/pl-pl/action.ts b/packages/phrases-ui/src/locales/pl-pl/action.ts new file mode 100644 index 000000000..64710de96 --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/action.ts @@ -0,0 +1,29 @@ +const action = { + sign_in: 'Zaloguj się', + continue: 'Kontynuuj', + create_account: 'Utwórz konto', + create_account_without_linking: 'Utwórz konto bez łączenia', + create: 'Utwórz', + enter_passcode: 'Wprowadź kod weryfikacyjny', + confirm: 'Potwierdź', + cancel: 'Anuluj', + save_password: 'Zapisz hasło', + bind: 'Połącz z {{address}}', + bind_and_continue: 'Połącz i kontynuuj', + back: 'Wróć', + nav_back: 'Wstecz', + agree: 'Zgadzam się', + got_it: 'Zrozumiałem', + sign_in_with: 'Kontynuuj z {{name}}', + forgot_password: 'Zapomniałeś hasła?', + switch_to: 'Przełącz na {{method}}', + sign_in_via_passcode: 'Zaloguj się za pomocą kodu weryfikacyjnego', + sign_in_via_password: 'Zaloguj się za pomocą hasła', + change: 'Zmień {{method}}', + link_another_email: 'Połącz inne konto email', + link_another_phone: 'Połącz inne konto telefoniczne', + link_another_email_or_phone: 'Połącz inne konto email lub telefoniczne', + show_password: 'Pokaż hasło', +}; + +export default action; diff --git a/packages/phrases-ui/src/locales/pl-pl/demo-app.ts b/packages/phrases-ui/src/locales/pl-pl/demo-app.ts new file mode 100644 index 000000000..0c61d2cc4 --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/demo-app.ts @@ -0,0 +1,5 @@ +const demo_app = { + notification: 'Wskazówka: Najpierw stwórz konto, aby przetestować proces logowania.', +}; + +export default demo_app; diff --git a/packages/phrases-ui/src/locales/pl-pl/description.ts b/packages/phrases-ui/src/locales/pl-pl/description.ts new file mode 100644 index 000000000..2666dce04 --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/description.ts @@ -0,0 +1,61 @@ +const opis = { + email: 'adres email', + phone_number: 'numer telefonu', + username: 'nazwa użytkownika', + reminder: 'Przypomnienie', + not_found: '404 Nie znaleziono', + agree_with_terms: 'Przeczytałem/am i zgadzam się z ', + agree_with_terms_modal: 'Do kontynuacji należy zaakceptować .', + terms_of_use: 'Warunki korzystania', + sign_in: 'Zaloguj się', + privacy_policy: 'Polityka prywatności', + create_account: 'Utwórz konto', + or: 'lub', + and: 'i', + enter_passcode: 'Kod weryfikacyjny został wysłany na twoje {{address}} {{target}}', + passcode_sent: 'Kod weryfikacyjny został wysłany ponownie', + resend_after_seconds: 'Wyślij ponownie po {{seconds}} sekundach', + resend_passcode: 'Wyślij kod weryfikacyjny ponownie', + create_account_id_exists: 'Konto z {{type}} {{value}} już istnieje. Czy chcesz się zalogować?', + link_account_id_exists: 'Konto z {{type}} {{value}} już istnieje. Czy chcesz je połączyć?', + sign_in_id_does_not_exist: + 'Konto z {{type}} {{value}} nie istnieje. Czy chcesz utworzyć nowe konto?', + sign_in_id_does_not_exist_alert: 'Konto z {{type}} {{value}} nie istnieje.', + create_account_id_exists_alert: + 'Konto z {{type}} {{value}} jest połączone z innym kontem. Spróbuj inny {{type}}.', + social_identity_exist: '{{type}} {{value}} jest połączony z innym kontem. Spróbuj inny {{type}}.', + bind_account_title: 'Połącz lub utwórz konto', + social_create_account: 'Możesz utworzyć nowe konto.', + social_link_email: 'Możesz połączyć kolejny adres email', + social_link_phone: 'Możesz połączyć kolejny numer telefonu', + social_link_email_or_phone: 'Możesz połączyć kolejny adres email lub numer telefonu', + social_bind_with_existing: 'Znaleźliśmy powiązane konto, możesz go połączyć bezpośrednio.', + reset_password: 'Zresetuj hasło', + reset_password_description: + 'Wpisz {{types, lista(type: złączonych;)}} związanego z twoim kontem, a wyślemy ci kod weryfikacyjny do zresetowania hasła.', + new_password: 'Nowe hasło', + set_password: 'Ustaw hasło', + password_changed: 'Hasło zmienione', + no_account: 'Nie masz jeszcze konta? ', + have_account: 'Masz już konto?', + enter_password: 'Wpisz hasło', + enter_password_for: 'Zaloguj się przy użyciu hasła do {{method}} {{value}}', + enter_username: 'Ustaw nazwę użytkownika', + enter_username_description: + 'Nazwa użytkownika jest alternatywną formą logowania. Nazwa użytkownika powinna zawierać tylko litery, cyfry i podkreślenia.', + link_email: 'Połącz adres email', + link_phone: 'Połącz numer telefonu', + link_email_or_phone: 'Połącz adres email lub numer telefonu', + link_email_description: 'Dla zwiększenia bezpieczeństwa, proszę połączyć konto z adresem e-mail.', + link_phone_description: + 'Dla zwiększenia bezpieczeństwa, proszę połączyć konto z numerem telefonu.', + link_email_or_phone_description: + 'Dla zwiększenia bezpieczeństwa, proszę połączyć konto z adresem e-mail lub numerem telefonu.', + continue_with_more_information: + 'Dla zwiększenia bezpieczeństwa, proszę uzupełnić poniższe informacje o koncie.', + create_your_account: 'Utwórz konto', + sign_in_to_your_account: 'Zaloguj się do swojego konta', + no_region_code_found: 'Nie znaleziono kodu regionu', +}; + +export default opis; diff --git a/packages/phrases-ui/src/locales/pl-pl/error.ts b/packages/phrases-ui/src/locales/pl-pl/error.ts new file mode 100644 index 000000000..aaf733ab8 --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/error.ts @@ -0,0 +1,24 @@ +const error = { + general_required: `{{types, list(type: disjunction;)}} jest wymagany`, + general_invalid: `{{types, list(type: disjunction;)}} jest nieprawidłowe`, + username_required: 'Nazwa użytkownika jest wymagana', + password_required: 'Hasło jest wymagane', + username_exists: 'Nazwa użytkownika już istnieje', + username_should_not_start_with_number: 'Nazwa użytkownika nie powinna zaczynać się od liczby', + username_invalid_charset: + 'Nazwa użytkownika powinna zawierać tylko litery, liczby lub podkreślenia.', + invalid_email: 'Nieprawidłowy adres e-mail', + invalid_phone: 'Nieprawidłowy numer telefonu', + password_min_length: 'Hasło wymaga minimum {{min}} znaków', + invalid_password: + 'Hasło wymaga minimum {{min}} znaków i zawiera kombinację liter, cyfr oraz symboli.', + passwords_do_not_match: 'Hasła nie pasują do siebie. Proszę spróbuj ponownie.', + invalid_passcode: 'Nieprawidłowy kod weryfikacyjny', + invalid_connector_auth: 'Nieprawidłowa autoryzacja', + invalid_connector_request: 'Nieprawidłowe dane konektora', + unknown: 'Nieznany błąd. Proszę spróbuj ponownie później.', + invalid_session: 'Sesja nie znaleziona. Proszę wróć i zaloguj się ponownie.', + timeout: 'Czas żądania upłynął. Proszę spróbuj ponownie później.', +}; + +export default error; diff --git a/packages/phrases-ui/src/locales/pl-pl/index.ts b/packages/phrases-ui/src/locales/pl-pl/index.ts new file mode 100644 index 000000000..497c0526b --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/index.ts @@ -0,0 +1,21 @@ +import { type LocalePhrase } from '../../types.js'; + +import action from './action.js'; +import demo_app from './demo-app.js'; +import description from './description.js'; +import error from './error.js'; +import input from './input.js'; +import secondary from './secondary.js'; + +const plPL: LocalePhrase = Object.freeze({ + translation: { + input, + secondary, + action, + description, + error, + demo_app, + }, +}); + +export default plPL; diff --git a/packages/phrases-ui/src/locales/pl-pl/input.ts b/packages/phrases-ui/src/locales/pl-pl/input.ts new file mode 100644 index 000000000..186047c1b --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/input.ts @@ -0,0 +1,10 @@ +const input = { + username: 'Nazwa użytkownika', + password: 'Hasło', + email: 'E-mail', + phone_number: 'Numer telefonu', + confirm_password: 'Potwierdź hasło', + search_region_code: 'Kod regionu wyszukiwania', +}; + +export default input; diff --git a/packages/phrases-ui/src/locales/pl-pl/secondary.ts b/packages/phrases-ui/src/locales/pl-pl/secondary.ts new file mode 100644 index 000000000..42f05d1c2 --- /dev/null +++ b/packages/phrases-ui/src/locales/pl-pl/secondary.ts @@ -0,0 +1,6 @@ +const secondary = { + social_bind_with: + 'Masz już konto? Zaloguj się, aby połączyć {{methods, list(type: disjunction;)}} z twoją tożsamością społeczną.', +}; + +export default secondary; diff --git a/packages/phrases/src/index.ts b/packages/phrases/src/index.ts index 3b5789d12..5e5e142e4 100644 --- a/packages/phrases/src/index.ts +++ b/packages/phrases/src/index.ts @@ -10,6 +10,7 @@ import fr from './locales/fr/index.js'; import it from './locales/it/index.js'; import ja from './locales/ja/index.js'; import ko from './locales/ko/index.js'; +import plPL from './locales/pl-pl/index.js'; import ptBR from './locales/pt-br/index.js'; import ptPT from './locales/pt-pt/index.js'; import ru from './locales/ru/index.js'; @@ -31,6 +32,7 @@ export const builtInLanguages = [ 'it', 'ja', 'ko', + 'pl-PL', 'pt-BR', 'pt-PT', 'ru', @@ -71,6 +73,7 @@ const resource: Resource = { it, ja, ko, + 'pl-PL': plPL, 'pt-BR': ptBR, 'pt-PT': ptPT, ru, diff --git a/packages/phrases/src/locales/pl-pl/errors/auth.ts b/packages/phrases/src/locales/pl-pl/errors/auth.ts new file mode 100644 index 000000000..d867c77b8 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/auth.ts @@ -0,0 +1,12 @@ +const auth = { + authorization_header_missing: 'Brak nagłówka autoryzacji', + authorization_token_type_not_supported: 'Nieobsługiwany typ autoryzacji', + unauthorized: 'Brak autoryzacji. Sprawdź swoje dane logowania i ich zakres.', + forbidden: 'Brak dostępu. Sprawdź swoje role użytkownika oraz uprawnienia.', + expected_role_not_found: + 'Nie znaleziono oczekiwanej roli. Sprawdź swoje role użytkownika oraz uprawnienia.', + jwt_sub_missing: 'Brak `sub` w JWT.', + require_re_authentication: 'Wymagane ponowne uwierzytelnienie, aby wykonać chronione działanie.', +}; + +export default auth; diff --git a/packages/phrases/src/locales/pl-pl/errors/connector.ts b/packages/phrases/src/locales/pl-pl/errors/connector.ts new file mode 100644 index 000000000..a7fc2fbc7 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/connector.ts @@ -0,0 +1,40 @@ +const connector = { + general: 'Wystąpił błąd włącznika: {{errorDescription}}', + not_found: 'Nie można znaleźć dostępnego łącznika dla typu: {{type}}.', + not_enabled: 'Łącznik nie jest włączony.', + invalid_metadata: 'Metadane łącznika są nieprawidłowe.', + invalid_config_guard: 'Ochrona konfiguracji łącznika jest nieprawidłowa.', + unexpected_type: 'Typ łącznika jest nieoczekiwany.', + invalid_request_parameters: + 'Żądanie jest z nieprawidłowym parametrem wejściowym/lub parametrami wejściowymi.', + insufficient_request_parameters: 'Żądanie może nie zawierać niektórych parametrów wejściowych.', + invalid_config: 'Konfiguracja łącznika jest nieprawidłowa.', + invalid_response: 'Odpowiedź łącznika jest nieprawidłowa.', + template_not_found: 'Nie można znaleźć poprawnego szablonu w konfiguracji łącznika.', + not_implemented: '{{method}}: jeszcze nie zaimplementowano.', + social_invalid_access_token: 'Token dostępu łącznika jest nieprawidłowy.', + invalid_auth_code: 'Kod autoryzacji łącznika jest nieprawidłowy.', + social_invalid_id_token: 'Token ID łącznika jest nieprawidłowy.', + authorization_failed: 'Proces autoryzacji użytkownika zakończył się niepowodzeniem.', + social_auth_code_invalid: + 'Nie udało się uzyskać tokenu dostępu, proszę sprawdzić kod autoryzacji.', + more_than_one_sms: 'Ilość łączników SMS jest większa niż 1.', + more_than_one_email: 'Ilość łączników e-mail jest większa niż 1.', + more_than_one_connector_factory: + 'Znaleziono wiele fabryk łączników (z id {{connectorIds}}), możesz odinstalować niepotrzebne.', + db_connector_type_mismatch: 'W bazie danych znajduje się łącznik, który nie pasuje do typu.', + not_found_with_connector_id: + 'Nie można odnaleźć łącznika o podanym standardowym identyfikatorze łącznika.', + multiple_instances_not_supported: + 'Nie można utworzyć wielu instancji z wybranym standardowym łącznikiem.', + invalid_type_for_syncing_profile: + 'Możesz tylko synchronizować profil użytkownika z łącznikami społecznościowymi.', + can_not_modify_target: "Nie można modyfikować 'target' łącznika.", + should_specify_target: "Powinieneś/nna/lno określić 'target'.", + multiple_target_with_same_platform: + "Nie można mieć wielu łączników społecznościowych z takim samym 'platforma i target'.", + cannot_overwrite_metadata_for_non_standard_connector: + 'Nie można nadpisać "metadata" tego łącznika, który nie należy do standardu.', +}; + +export default connector; diff --git a/packages/phrases/src/locales/pl-pl/errors/entity.ts b/packages/phrases/src/locales/pl-pl/errors/entity.ts new file mode 100644 index 000000000..b7cc21f25 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/entity.ts @@ -0,0 +1,8 @@ +const entity = { + create_failed: 'Nie udało się utworzyć {{name}}.', + not_exists: '{{name}} nie istnieje.', + not_exists_with_id: '{{name}} o identyfikatorze `{{id}}` nie istnieje.', + not_found: 'Zasób nie istnieje.', +}; + +export default entity; diff --git a/packages/phrases/src/locales/pl-pl/errors/guard.ts b/packages/phrases/src/locales/pl-pl/errors/guard.ts new file mode 100644 index 000000000..ee02fbee2 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/guard.ts @@ -0,0 +1,9 @@ +const guard = { + invalid_input: 'Żądanie {{type}} jest nieprawidłowe.', + invalid_pagination: 'Nieprawidłowa wartość paginacji żądania.', + can_not_get_tenant_id: 'Nie można pobrać identyfikatora najemcy z żądania.', + file_size_exceeded: 'Przekroczono rozmiar pliku.', + mime_type_not_allowed: 'Nie dozwolony typ MIME.', +}; + +export default guard; diff --git a/packages/phrases/src/locales/pl-pl/errors/index.ts b/packages/phrases/src/locales/pl-pl/errors/index.ts new file mode 100644 index 000000000..c3f5e05ec --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/index.ts @@ -0,0 +1,39 @@ +import auth from './auth.js'; +import connector from './connector.js'; +import entity from './entity.js'; +import guard from './guard.js'; +import localization from './localization.js'; +import log from './log.js'; +import oidc from './oidc.js'; +import password from './password.js'; +import request from './request.js'; +import role from './role.js'; +import scope from './scope.js'; +import session from './session.js'; +import sign_in_experiences from './sign-in-experiences.js'; +import storage from './storage.js'; +import swagger from './swagger.js'; +import user from './user.js'; +import verification_code from './verification-code.js'; + +const errors = { + request, + auth, + guard, + oidc, + user, + password, + session, + connector, + verification_code, + sign_in_experiences, + localization, + swagger, + entity, + log, + role, + scope, + storage, +}; + +export default errors; diff --git a/packages/phrases/src/locales/pl-pl/errors/localization.ts b/packages/phrases/src/locales/pl-pl/errors/localization.ts new file mode 100644 index 000000000..98a70a619 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/localization.ts @@ -0,0 +1,8 @@ +const localization = { + cannot_delete_default_language: + '{{languageTag}} jest ustawiony jako Twój język domyślny i nie można go usunąć.', + invalid_translation_structure: + 'Nieprawidłowe schematy danych. Sprawdź swoje dane wejściowe i spróbuj ponownie.', +}; + +export default localization; diff --git a/packages/phrases/src/locales/pl-pl/errors/log.ts b/packages/phrases/src/locales/pl-pl/errors/log.ts new file mode 100644 index 000000000..6c3c76337 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/log.ts @@ -0,0 +1,5 @@ +const log = { + invalid_type: 'Typ dziennika jest nieprawidłowy.', +}; + +export default log; diff --git a/packages/phrases/src/locales/pl-pl/errors/oidc.ts b/packages/phrases/src/locales/pl-pl/errors/oidc.ts new file mode 100644 index 000000000..6021fe73a --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/oidc.ts @@ -0,0 +1,20 @@ +const oidc = { + aborted: 'Koniec interakcji z użytkownikiem.', + invalid_scope: 'Zakres {{scope}} nie jest obsługiwany.', + invalid_scope_plural: 'Zakresy {{scopes}} nie są obsługiwane.', + invalid_token: 'Podano nieprawidłowy token.', + invalid_client_metadata: 'Podano nieprawidłowe metadane klienta.', + insufficient_scope: 'Brakujący zakres żądanego tokena dostępu {{scopes}}.', + invalid_request: 'Żądanie jest nieprawidłowe.', + invalid_grant: 'Żądanie przyznania jest nieprawidłowe.', + invalid_redirect_uri: + 'Adres URL `redirect_uri` nie pasuje do zarejestrowanych przez klienta `redirect_uris`.', + access_denied: 'Odmowa dostępu.', + invalid_target: 'Nieprawidłowy wskaźnik zasobów.', + unsupported_grant_type: 'Żądany typ `grant_type` nie jest obsługiwany.', + unsupported_response_mode: 'Żądany tryb `response_mode` nie jest obsługiwany.', + unsupported_response_type: 'Żądany typ `response_type` nie jest obsługiwany.', + provider_error: 'Wewnętrzny błąd OIDC: {{message}}.', +}; + +export default oidc; diff --git a/packages/phrases/src/locales/pl-pl/errors/password.ts b/packages/phrases/src/locales/pl-pl/errors/password.ts new file mode 100644 index 000000000..adc8e1bfd --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/password.ts @@ -0,0 +1,6 @@ +const password = { + unsupported_encryption_method: 'Metoda szyfrowania {{name}} nie jest obsługiwana.', + pepper_not_found: 'Nie znaleziono wartości pepper dla hasła. Sprawdź swoje zmienne środowiskowe.', +}; + +export default password; diff --git a/packages/phrases/src/locales/pl-pl/errors/request.ts b/packages/phrases/src/locales/pl-pl/errors/request.ts new file mode 100644 index 000000000..4195ccfc9 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/request.ts @@ -0,0 +1,6 @@ +const request = { + invalid_input: 'Nieprawidłowe dane wejściowe. {{details}}', + general: 'Wystąpił błąd żądania.', +}; + +export default request; diff --git a/packages/phrases/src/locales/pl-pl/errors/role.ts b/packages/phrases/src/locales/pl-pl/errors/role.ts new file mode 100644 index 000000000..514fe3e01 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/role.ts @@ -0,0 +1,11 @@ +const role = { + name_in_use: 'Ta nazwa roli {{name}} jest już w użyciu', + scope_exists: 'Identyfikator zakresu {{scopeId}} został już dodany do tej roli', + user_exists: 'Identyfikator użytkownika {{userId}} został już dodany do tej roli', + default_role_missing: + 'Niektóre z domyślnych nazw ról nie istnieją w bazie danych, upewnij się, że najpierw utworzysz role', + internal_role_violation: + 'Możesz próbować zaktualizować lub usunąć rolę wewnętrzną, co jest zabronione przez Logto. Jeśli tworzysz nową rolę, spróbuj innej nazwy, która nie zaczyna się od "#internal:".', +}; + +export default role; diff --git a/packages/phrases/src/locales/pl-pl/errors/scope.ts b/packages/phrases/src/locales/pl-pl/errors/scope.ts new file mode 100644 index 000000000..d3501a67b --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/scope.ts @@ -0,0 +1,6 @@ +const scope = { + name_exists: 'Nazwa zakresu {{name}} jest już używana', + name_with_space: 'Nazwa zakresu nie może zawierać spacji.', +}; + +export default scope; diff --git a/packages/phrases/src/locales/pl-pl/errors/session.ts b/packages/phrases/src/locales/pl-pl/errors/session.ts new file mode 100644 index 000000000..9c1beb291 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/session.ts @@ -0,0 +1,25 @@ +const session = { + not_found: 'Nie znaleziono sesji. Proszę wrócić i zalogować się ponownie.', + invalid_credentials: 'Niepoprawne konto lub hasło. Sprawdź swoje dane wejściowe.', + invalid_sign_in_method: 'Aktualna metoda logowania jest niedostępna.', + invalid_connector_id: 'Nie można znaleźć dostępnego łącznika o id {{connectorId}}.', + insufficient_info: 'Niewystarczające informacje do zalogowania.', + connector_id_mismatch: 'Id łącznika nie pasuje do rekordu sesji.', + connector_session_not_found: 'Nie znaleziono sesji łącznika. Proszę wróć i zaloguj ponownie.', + verification_session_not_found: + 'Weryfikacja nie powiodła się. Uruchom proces weryfikacji ponownie i spróbuj ponownie.', + verification_expired: + 'Połączenie wygasło. Zweryfikuj ponownie, aby zapewnić bezpieczeństwo Twojego konta.', + unauthorized: 'Proszę się najpierw zalogować.', + unsupported_prompt_name: 'Nieobsługiwana nazwa podpowiedzi.', + forgot_password_not_enabled: 'Odzyskiwanie hasła nie jest włączone.', + verification_failed: + 'Weryfikacja nie powiodła się. Uruchom proces weryfikacji ponownie i spróbuj ponownie.', + connector_validation_session_not_found: 'Nie znaleziono sesji łącznika dla weryfikacji tokena.', + identifier_not_found: + 'Nie znaleziono identyfikatora użytkownika. Proszę wróć i zaloguj się ponownie.', + interaction_not_found: + 'Nie znaleziono sesji interakcji. Proszę wróć i rozpocznij sesję ponownie.', +}; + +export default session; diff --git a/packages/phrases/src/locales/pl-pl/errors/sign-in-experiences.ts b/packages/phrases/src/locales/pl-pl/errors/sign-in-experiences.ts new file mode 100644 index 000000000..b798e3729 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/sign-in-experiences.ts @@ -0,0 +1,22 @@ +const sign_in_experiences = { + empty_content_url_of_terms_of_use: + 'Pusty adres URL zawartości "Regulaminu". Proszę dodać adres URL zawartości, jeśli funkcja "Regulamin" jest włączona.', + empty_social_connectors: + 'Brak skojarzonych kont społecznościowych. Proszę dodać skojarzone konta społecznościowe, gdy metoda logowania za pomocą sieci społecznościowej jest włączona.', + enabled_connector_not_found: 'Nie znaleziono aktywowanego łącznika typu {{type}}.', + not_one_and_only_one_primary_sign_in_method: + 'Musi istnieć jedna i tylko jedna podstawowa metoda logowania. Proszę sprawdzić swoje dane wejściowe.', + username_requires_password: + 'Należy włączyć ustawienie hasła dla identyfikatora rejestracji nazwy użytkownika.', + passwordless_requires_verify: + 'Należy włączyć weryfikację dla identyfikatora rejestracji adresu e-mail/telefonu.', + miss_sign_up_identifier_in_sign_in: 'Metody logowania muszą zawierać identyfikator rejestracji.', + password_sign_in_must_be_enabled: + 'Logowanie za pomocą hasła musi być włączone, gdy w rejestracji wymagane jest ustawienie hasła.', + code_sign_in_must_be_enabled: + 'Logowanie za pomocą kodu weryfikacyjnego musi być włączone, gdy w rejestracji nie jest wymagane ustawienie hasła.', + unsupported_default_language: 'Ten język - {{language}} nie jest obecnie obsługiwany.', + at_least_one_authentication_factor: 'Musisz wybrać co najmniej jeden czynnik uwierzytelniający.', +}; + +export default sign_in_experiences; diff --git a/packages/phrases/src/locales/pl-pl/errors/storage.ts b/packages/phrases/src/locales/pl-pl/errors/storage.ts new file mode 100644 index 000000000..d3b14a4ca --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/storage.ts @@ -0,0 +1,7 @@ +const storage = { + not_configured: 'Nie skonfigurowano dostawcy magazynu.', + missing_parameter: 'Brak parametru {{parameter}} dla dostawcy magazynu.', + upload_error: 'Nie udało się przesłać pliku do dostawcy magazynu.', +}; + +export default storage; diff --git a/packages/phrases/src/locales/pl-pl/errors/swagger.ts b/packages/phrases/src/locales/pl-pl/errors/swagger.ts new file mode 100644 index 000000000..c4d03ac69 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/swagger.ts @@ -0,0 +1,7 @@ +const swagger = { + invalid_zod_type: 'Nieprawidłowy typ Zod. Sprawdź konfigurację straży routy.', + not_supported_zod_type_for_params: + 'Nieobsługiwany typ Zod dla parametrów. Sprawdź konfigurację straży routy.', +}; + +export default swagger; diff --git a/packages/phrases/src/locales/pl-pl/errors/user.ts b/packages/phrases/src/locales/pl-pl/errors/user.ts new file mode 100644 index 000000000..dc4e29f3e --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/user.ts @@ -0,0 +1,34 @@ +const user = { + username_already_in_use: 'Nazwa użytkownika jest już zajęta.', + email_already_in_use: 'Ten email jest już powiązany z istniejącym kontem.', + phone_already_in_use: 'Ten numer telefonu jest już powiązany z istniejącym kontem.', + invalid_email: 'Nieprawidłowy adres email.', + invalid_phone: 'Nieprawidłowy numer telefonu.', + email_not_exist: 'Podany adres email nie został jeszcze zarejestrowany.', + phone_not_exist: 'Podany numer telefonu nie został jeszcze zarejestrowany.', + identity_not_exist: 'Konto społecznościowe nie zostało jeszcze zarejestrowane.', + identity_already_in_use: 'Konto społecznościowe zostało już powiązane z istniejącym kontem.', + social_account_exists_in_profile: + 'To konto społecznościowe zostało już powiązane z Twoim profilem.', + cannot_delete_self: 'Nie możesz usunąć swojego konta.', + sign_up_method_not_enabled: 'Rejestracja tym sposobem jest wyłączona.', + sign_in_method_not_enabled: 'Logowanie tym sposobem jest wyłączone.', + same_password: 'Nowe hasło nie może być takie samo jak stare hasło.', + password_required_in_profile: 'Musisz ustawić hasło przed zalogowaniem.', + new_password_required_in_profile: 'Musisz ustawić nowe hasło.', + password_exists_in_profile: 'Hasło już istnieje w Twoim profilu.', + username_required_in_profile: 'Musisz ustawić nazwę użytkownika przed zalogowaniem.', + username_exists_in_profile: 'Nazwa użytkownika już istnieje w Twoim profilu.', + email_required_in_profile: 'Musisz dodać adres email przed zalogowaniem.', + email_exists_in_profile: 'Twój profil jest już powiązany z adresem email.', + phone_required_in_profile: 'Musisz dodać numer telefonu przed zalogowaniem.', + phone_exists_in_profile: 'Twój profil jest już powiązany z numerem telefonu.', + email_or_phone_required_in_profile: + 'Musisz dodać adres email lub numer telefonu przed zalogowaniem.', + suspended: 'To konto jest zawieszone.', + user_not_exist: 'Użytkownik z identyfikatorem {{ identifier }} nie istnieje.', + missing_profile: 'Musisz podać dodatkowe informacje przed zalogowaniem.', + role_exists: 'Identyfikator roli {{roleId}} jest już dodany do tego użytkownika', +}; + +export default user; diff --git a/packages/phrases/src/locales/pl-pl/errors/verification-code.ts b/packages/phrases/src/locales/pl-pl/errors/verification-code.ts new file mode 100644 index 000000000..83fee9271 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/errors/verification-code.ts @@ -0,0 +1,12 @@ +const verification_code = { + phone_email_empty: 'Oba pola telefonu i emaila są puste.', + not_found: 'Nie znaleziono kodu weryfikacyjnego. Proszę najpierw wysłać kod weryfikacyjny.', + phone_mismatch: 'Niepoprawny numer telefonu. Proszę poprosić o nowy kod weryfikacyjny.', + email_mismatch: 'Niepoprawny adres email. Proszę poprosić o nowy kod weryfikacyjny.', + code_mismatch: 'Nieprawidłowy kod weryfikacyjny.', + expired: 'Kod weryfikacyjny wygasł. Proszę poprosić o nowy kod weryfikacyjny.', + exceed_max_try: + 'Osiągnięto limit prób kodu weryfikacyjnego. Proszę poprosić o nowy kod weryfikacyjny.', +}; + +export default verification_code; diff --git a/packages/phrases/src/locales/pl-pl/index.ts b/packages/phrases/src/locales/pl-pl/index.ts new file mode 100644 index 000000000..ad3241b65 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/index.ts @@ -0,0 +1,11 @@ +import type { LocalePhrase } from '../../types.js'; + +import errors from './errors/index.js'; +import translation from './translation/index.js'; + +const plPL: LocalePhrase = Object.freeze({ + translation, + errors, +}); + +export default plPL; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/api-resource-details.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/api-resource-details.ts new file mode 100644 index 000000000..88b49cbdd --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/api-resource-details.ts @@ -0,0 +1,32 @@ +const api_resource_details = { + page_title: 'Szczegóły zasobów API', + back_to_api_resources: 'Powróć do zasobów API', + settings_tab: 'Ustawienia', + permissions_tab: 'Uprawnienia', + settings: 'Ustawienia', + settings_description: + 'Zasoby API, tzw. wskaźniki zasobów, wskazują na usługi lub zasoby docelowe, które mają być żądane, zwykle w zmiennej formatu URI reprezentującej tożsamość zasobu.', + token_expiration_time_in_seconds: 'Czas wygaśnięcia tokenu (w sekundach)', + token_expiration_time_in_seconds_placeholder: 'Wprowadź czas wygaśnięcia tokenu', + delete_description: + 'Tej akcji nie można cofnąć. Spowoduje to trwałe usunięcie zasobu API. Wpisz nazwę zasobu API {{name}}, aby potwierdzić.', + enter_your_api_resource_name: 'Wprowadź nazwę swojego zasobu API', + api_resource_deleted: 'Zasób API {{name}} został pomyślnie usunięty', + permission: { + create_button: 'Utwórz uprawnienie', + create_title: 'Utwórz uprawnienie', + create_subtitle: 'Zdefiniuj uprawnienia (zakresy) wymagane przez to API.', + confirm_create: 'Utwórz uprawnienie', + name: 'Nazwa uprawnienia', + name_placeholder: 'ready:resource', + forbidden_space_in_name: 'Nazwa uprawnienia nie może zawierać spacji.', + description: 'Opis', + description_placeholder: 'Możliwość odczytu zasobów', + permission_created: 'Uprawnienie {{name}} zostało pomyślnie utworzone', + delete_description: + 'Jeśli to uprawnienie zostanie usunięte, użytkownik, który miał to uprawnienie, straci dostęp przyznany przez nie.', + deleted: 'Uprawnienie "{{name}}" zostało pomyślnie usunięte!', + }, +}; + +export default api_resource_details; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/api-resources.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/api-resources.ts new file mode 100644 index 000000000..f54576cbc --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/api-resources.ts @@ -0,0 +1,15 @@ +const api_resources = { + page_title: 'Zasoby API', + title: 'Zasoby API', + subtitle: 'Definiuj API, z których korzystać mogą twoje autoryzowane aplikacje', + create: 'Utwórz zasób API', + api_name: 'Nazwa API', + api_name_placeholder: 'Wprowadź nazwę swojego API', + api_identifier: 'Identyfikator API', + api_identifier_tip: + 'Unikalny identyfikator zasobu API. Musi to być bezwzględny adres URI bez składnika fragmentu (#). Jest równy parametrowi zasobu w standardzie OAuth 2.0.', + api_resource_created: 'Zasób API {{name}} został pomyślnie utworzony', + api_identifier_placeholder: 'https://identyfikator-twojego-api/', +}; + +export default api_resources; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/application-details.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/application-details.ts new file mode 100644 index 000000000..ed6efbf6e --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/application-details.ts @@ -0,0 +1,51 @@ +const application_details = { + page_title: 'Szczegóły aplikacji', + back_to_applications: 'Powrót do Aplikacji', + check_guide: 'Sprawdź przewodnik', + settings: 'Ustawienia', + settings_description: + 'Aplikacje są używane do identyfikowania Twoich aplikacji w Logto dla OIDC, doświadczenia logowania, dzienników audytowych itp.', + advanced_settings: 'Zaawansowane ustawienia', + advanced_settings_description: + 'Zaawansowane ustawienia obejmują związane z OIDC terminy. Możesz sprawdzić punkt końcowy Token dla bardziej szczegółowych informacji.', + application_name: 'Nazwa aplikacji', + application_name_placeholder: 'Moja aplikacja', + description: 'Opis', + description_placeholder: 'Wpisz opis swojej aplikacji', + authorization_endpoint: 'Endpoint autoryzacji', + authorization_endpoint_tip: + 'Endpoint wykorzystywany do autentykacji i autoryzacji. Używany jest dla OpenID Connect Autentykacji.', + application_id: 'ID aplikacji', + application_id_tip: + 'Unikalny identyfikator aplikacji, który jest zwykle generowany przez Logto. Oznacza również „client_id” w OpenID Connect.', + application_secret: 'Tajny kod aplikacji', + redirect_uri: 'Adres URL przekierowania', + redirect_uris: 'Adresy URL przekierowania', + redirect_uri_placeholder: 'https://twoja.strona.com/aplikacja', + redirect_uri_placeholder_native: 'io.logto://callback', + redirect_uri_tip: + 'Adres URL, na który użytkownik jest przekierowywany po zalogowaniu się (zarówno pozytywnym, jak i negatywnym). Zobacz OpenID Connect AuthRequest po więcej informacji.', + post_sign_out_redirect_uri: 'Adres URL przekierowania po wylogowaniu', + post_sign_out_redirect_uris: 'Adresy URL przekierowania po wylogowaniu', + post_sign_out_redirect_uri_placeholder: 'https://twoja.strona.com/strona-startowa', + post_sign_out_redirect_uri_tip: + 'Adres URL, na który użytkownik jest przekierowywany po wylogowaniu (opcjonalnie). W niektórych rodzajach aplikacji może nie mieć to praktycznego wpływu.', + cors_allowed_origins: 'Dozwolone źródła CORS', + cors_allowed_origins_placeholder: 'https://twoja.strona.com', + cors_allowed_origins_tip: + 'Domyślnie dozwolone będą wszystkie źródła z adresów URL przekierowania. Zazwyczaj nie wymaga to żadnych działań. Zobacz dokumentację MDN dla szczegółowych informacji.', + id_token_expiration: 'Ważność ID Token', + refresh_token_expiration: 'Ważność Token odświeżania', + token_endpoint: 'Endpoint Tokena', + user_info_endpoint: 'Endpoint Informacji o użytkowniku', + enable_admin_access: 'Włącz dostęp administratora', + enable_admin_access_label: + 'Włącz lub wyłącz dostęp do interfejsu API zarządzania. Po włączeniu możesz używać tokenów dostępu do wywoływania interfejsu API zarządzania w imieniu tej aplikacji.', + delete_description: + 'Ta operacja nie może zostać cofnięta. Skutkuje ona trwałym usunięciem aplikacji. Aby potwierdzić, wpisz nazwę aplikacji {{name}}.', + enter_your_application_name: 'Wpisz nazwę swojej aplikacji', + application_deleted: 'Aplikacja {{name}} została pomyślnie usunięta', + redirect_uri_required: 'Musisz wpisać co najmniej jeden adres URL przekierowania', +}; + +export default application_details; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts new file mode 100644 index 000000000..54e876969 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts @@ -0,0 +1,53 @@ +const applications = { + page_title: 'Applications', + title: 'Applications', + subtitle: + 'Set up Logto authentication for your native, single page, machine to machine, or traditional application', + create: 'Create Application', + application_name: 'Application name', + application_name_placeholder: 'My App', + application_description: 'Application description', + application_description_placeholder: 'Enter your application description', + select_application_type: 'Select an application type', + no_application_type_selected: 'You haven’t selected any application type yet', + application_created: + 'The application {{name}} has been successfully created! \nNow finish your application settings.', + app_id: 'App ID', + type: { + native: { + title: 'Native App', + subtitle: 'An app that runs in a native environment', + description: 'E.g., iOS app, Android app', + }, + spa: { + title: 'Single Page App', + subtitle: 'An app that runs in a web browser and dynamically updates data in place', + description: 'E.g., React DOM app, Vue app', + }, + traditional: { + title: 'Traditional Web', + subtitle: 'An app that renders and updates pages by the web server alone', + description: 'E.g., Next.js, PHP', + }, + machine_to_machine: { + title: 'Machine-to-Machine', + subtitle: 'An app (usually a service) that directly talks to resources', + description: 'E.g., Backend service', + }, + }, + guide: { + get_sample_file: 'Get Sample', + header_description: + 'Follow a step by step guide to integrate your application or click the right button to get our sample project', + title: 'The application has been successfully created', + subtitle: + 'Now follow the steps below to finish your app settings. Please select the SDK type to continue.', + description_by_sdk: + 'This quick start guide demonstrates how to integrate Logto into {{sdk}} app', + }, + placeholder_title: 'Select an application type to continue', + placeholder_description: + 'Logto uses an application entity for OIDC to help with tasks such as identifying your apps, managing sign-in, and creating audit logs.', +}; + +export default applications; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/cloud.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/cloud.ts new file mode 100644 index 000000000..19ee22fab --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/cloud.ts @@ -0,0 +1,121 @@ +const cloud = { + welcome: { + page_title: 'Witaj', + title: 'Witaj i stwórz własny podgląd chmury Logto', + description: + 'Nie ważne czy jesteś użytkownikiem open-source czy chmury, przejdź przez prezentacje i doświadcz pełnej wartości Logto. Podgląd chmury serwuje również jako wstępna wersja chmury Logto.', + project_field: 'Używam Logto do', + project_options: { + personal: 'Projektu osobistego', + company: 'Projektu firmowego', + }, + deployment_type_field: 'Wolisz open-source czy chmurę?', + deployment_type_options: { + open_source: 'Open-Source', + cloud: 'Chmura', + }, + }, + about: { + page_title: 'Trochę o Tobie', + title: 'Trochę o Tobie', + description: + 'Stwórz indywidualne wrażenia z Logto dzięki naszej wiedzy na temat Ciebie. Twoje informacje są bezpieczne u nas.', + title_field: 'Twój tytuł', + title_options: { + developer: 'Developer', + team_lead: 'Team Lead', + ceo: 'CEO', + cto: 'CTO', + product: 'Product', + others: 'Inne', + }, + company_name_field: 'Nazwa firmy', + company_name_placeholder: 'Acme.co', + company_size_field: 'Jak wielka jest Twoja firma?', + company_options: { + size_1: '1', + size_2_49: '2-49', + size_50_199: '50-199', + size_200_999: '200-999', + size_1000_plus: '1000+', + }, + reason_field: 'Rejestruję się, ponieważ', + reason_options: { + passwordless: 'Szukam uwierzytelnienia bez hasła i zestawu interfejsów użytkownika', + efficiency: 'Szukam infrastruktury tożsamości out-of-the-box', + access_control: 'Kontroluj dostęp użytkowników na podstawie ról i odpowiedzialności', + multi_tenancy: 'Szukam strategii dla produktu multi-mandantowego', + enterprise: 'Szukam rozwiązań SSO dla gotowości przedsiębiorstwa', + others: 'Inne', + }, + }, + congrats: { + page_title: 'Zarób wczesne kredyty', + title: 'Wspaniała wiadomość! Kwalifikujesz się do zyskania wczesnego kredytu na chmurę Logto!', + description: + 'Nie przegap szansy na bezpłatną 60-dniową subskrypcję na chmurę Logto po jej oficjalnym uruchomieniu! Skontaktuj się z zespołem Logto, aby dowiedzieć się więcej.', + check_out_button: 'Zobacz podgląd na żywo', + email_us_title: + 'Napisz do nas maila w celu uzyskania oferty specjalnej i szczegółów dotyczących ceny', + email_us_description: 'Uzyskaj wyłączną ofertę cenową na oszczędność pieniędzy', + email_us_button: 'Wyślij e-mail', + join_description: + 'Dołącz do naszej publicznej {{link}}, aby połączyć się i rozmawiać z innymi deweloperami.', + discord_link: 'kanał discord', + enter_admin_console: 'Wejdź do podglądu chmury Logto', + }, + gift: { + title: 'Używaj Logto Cloud za darmo przez 60 dni. Dołącz do pionierów już teraz!', + description: 'Zarezerwuj spotkanie z naszym zespołem i zdobądź wczesny kredyt.', + reserve_title: 'Zarezerwuj swój czas z zespołem Logto', + reserve_description: 'Kredyt przysługuje tylko raz po ocenie.', + book_button: 'Rezerwuj', + email_us_title: 'Napisz do nas', + email_us_description: 'Skontaktuj się z nami, aby otrzymać ofertę specjalną i szczegóły cen.', + email_us_button: 'Wyślij', + }, + sie: { + page_title: 'Dostosuj doświadczenie logowania', + title: 'Najpierw dostosuj swoje doświadczenie logowania', + inspire: { + title: 'Stwórz przykłady', + description: + 'Nie jesteś pewien swojego doświadczenia logowania? Kliknij "Zainspiruj mnie" i pozwól, żeby magia się stała!', + inspire_me: 'Zainspiruj mnie', + }, + logo_field: 'Logo aplikacji', + color_field: 'Kolor marki', + identifier_field: 'Identyfikator', + identifier_options: { + email: 'E-mail', + phone: 'Telefon', + user_name: 'Nazwa użytkownika', + }, + authn_field: 'Uwierzytelnianie', + authn_options: { + password: 'Hasło', + verification_code: 'Kod weryfikacyjny', + }, + social_field: 'Logowanie społecznościowe', + finish_and_done: 'Skończone i gotowe', + preview: { + mobile_tab: 'Mobilny', + web_tab: 'Sieć', + }, + connectors: { + unlocked_later: 'Zostanie odblokowane później', + unlocked_later_tip: + 'Po ukończeniu procesu wprowadzenia do użytku i wejściu do produktu będziesz mieć dostęp do jeszcze większej liczby metod logowania społecznościowego.', + notice: + 'Prosimy, unikaj korzystania z demo konektora do celów produkcyjnych. Po zakończeniu testów, uprzejmie usuń demokonwerter i skonfiguruj swój własny konektor z własnymi poświadczeniami.', + }, + }, + broadcast: '📣 Jesteś w Logto Cloud (Podgląd)', + socialCallback: { + title: 'Zalogowałeś się pomyślnie', + description: + 'Zalogowałeś się pomyślnie używając swojego konta społecznościowego. Aby zapewnić bezproblemową integrację i dostęp do wszystkich funkcji Logto, zalecamy przejście do konfiguracji własnego konektora społecznościowego.', + }, +}; + +export default cloud; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/components.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/components.ts new file mode 100644 index 000000000..e7dc053b0 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/components.ts @@ -0,0 +1,15 @@ +const components = { + uploader: { + action_description: 'Przeciągnij i upuść lub przeszukaj', + uploading: 'Wysyłanie...', + image_limit: + 'Wyślij obraz o rozmiarze mniejszym niż {{size, number}}KB, tylko w formacie {{extensions, list(style: narrow; type: conjunction;)}}.', + error_upload: 'Coś poszło nie tak. Nie udało się wysłać pliku.', + error_file_size: + 'Plik jest zbyt duży. Wyślij plik o rozmiarze mniejszym niż {{size, number}}KB.', + error_file_type: + 'Ten typ pliku nie jest obsługiwany. Obsługiwane formaty to {{extensions, list(style: narrow; type: conjunction;)}}.', + }, +}; + +export default components; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/connector-details.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/connector-details.ts new file mode 100644 index 000000000..80cec9894 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/connector-details.ts @@ -0,0 +1,35 @@ +const connector_details = { + page_title: 'Szczegóły konektora', + back_to_connectors: 'Powrót do konektorów', + check_readme: 'Sprawdź README', + settings: 'Ustawienia ogólne', + settings_description: + 'Konektory odgrywają kluczową rolę w Logto. Dzięki nim, Logto umożliwia użytkownikom końcowym korzystanie z rejestracji lub logowania bez hasła oraz możliwości logowania się za pomocą kont społecznościowych.', + parameter_configuration: 'Konfiguracja parametru', + test_connection: 'Testuj połączenie', + save_error_empty_config: 'Proszę wprowadzić konfigurację', + send: 'Wyślij', + send_error_invalid_format: 'Nieprawidłowy format danych wejściowych', + edit_config_label: 'Wprowadź swoje dane JSON tutaj', + test_email_sender: 'Wypróbuj konektor e-mail', + test_sms_sender: 'Wypróbuj konektor SMS', + test_email_placeholder: 'jan.kowalski@example.com', + test_sms_placeholder: '+48 123-456-789', + test_message_sent: 'Wiadomość testowa została wysłana', + test_sender_description: + 'Logto używa szablonu "Ogólny" do testów. Otrzymasz wiadomość, jeśli twój konektor jest prawidłowo skonfigurowany.', + options_change_email: 'Zmień konektor e-mail', + options_change_sms: 'Zmień konektor SMS', + connector_deleted: 'Konektor został pomyślnie usunięty', + type_email: 'Konektor e-mail', + type_sms: 'Konektor SMS', + type_social: 'Konektor społecznościowy', + in_used_social_deletion_description: + 'Ten konektor jest używany w Twoim procesie logowania. Usunięcie spowoduje usunięcie doświadczenia logowania w ustawieniach doświadczenia logowania. Będziesz musiał go ponownie skonfigurować, jeśli zdecydujesz się go dodać z powrotem.', + in_used_passwordless_deletion_description: + 'Ten {{name}} jest używany w Twoim procesie logowania. Usunięcie spowoduje, że Twoje doświadczenie logowania nie będzie działać poprawnie, dopóki nie rozwiążesz konfliktu. Będziesz musiał go ponownie skonfigurować, jeśli zdecydujesz się go dodać z powrotem.', + deletion_description: + 'Usuwasz ten konektor. Nie można tego cofnąć, będziesz musiał go ponownie skonfigurować, jeśli zdecydujesz się go ponownie dodać.', +}; + +export default connector_details; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/connectors.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/connectors.ts new file mode 100644 index 000000000..fe5be2c1c --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/connectors.ts @@ -0,0 +1,90 @@ +const connectors = { + page_title: 'Łączniki', + title: 'Łączniki', + subtitle: 'Skonfiguruj łączniki, aby umożliwić bezhasłowe i społecznościowe logowanie', + create: 'Dodaj łącznik społecznościowy', + config_sie_notice: 'Ustawiono łączniki. Upewnij się, że skonfigurowałeś to w {{link}}.', + config_sie_link_text: 'doświadczenie logowania', + tab_email_sms: 'Łączniki e-mail i SMS', + tab_social: 'Łączniki społecznościowe', + connector_name: 'Nazwa łącznika', + demo_tip: + 'Maksymalna liczba wiadomości dozwolona dla tego Łącznika demonstracyjnego wynosi 100 i nie jest zalecana do wdrożenia w środowisku produkcyjnym.', + social_demo_tip: + 'Łącznik demonstracyjny został zaprojektowany wyłącznie dla celów demonstracyjnych i nie jest zalecany do wdrożenia w środowisku produkcyjnym.', + connector_type: 'Typ', + connector_status: 'Doświadczenie logowania', + connector_status_in_use: 'W użyciu', + connector_status_not_in_use: 'Nie w użyciu', + not_in_use_tip: { + content: + 'Nie w użyciu oznacza, że Twoje doświadczenie logowania nie użyło tej metody logowania. {{link}} aby dodać tę metodę logowania.', + go_to_sie: 'Przejdź do doświadczenia logowania', + }, + placeholder_title: 'Łącznik społecznościowy', + placeholder_description: + 'Logto dostarczył wiele powszechnie używanych łączników społecznościowych, tymczasem możesz utworzyć własne z wykorzystaniem standardowych protokołów.', + save_and_done: 'Zapisz i zakończ', + type: { + email: 'Łącznik e-mail', + sms: 'Łącznik SMS', + social: 'Łącznik społecznościowy', + }, + setup_title: { + email: 'Skonfiguruj łącznik e-mail', + sms: 'Skonfiguruj łącznik SMS', + social: 'Dodaj łącznik społecznościowy', + }, + guide: { + subtitle: 'Przewodnik krok po kroku do konfiguracji Twojego łącznika', + general_setting: 'Ustawienia ogólne', + parameter_configuration: 'Konfiguracja parametrów', + test_connection: 'Testuj połączenie', + name: 'Nazwa przycisku logowania społecznościowego', + name_placeholder: 'Wpisz nazwę przycisku logowania społecznościowego', + name_tip: + 'Nazwa przycisku łącznika będzie wyświetlana jako "Kontynuuj z {{name}}." Uwzględnij długość nazwy, gdyż może stać się zbyt długa.', + logo: 'Logo URL łącznika społecznościowego', + logo_placeholder: 'https://your.cdn.domain/logo.png', + logo_tip: + 'Obraz logo zostanie wyświetlony na łączniku. Uzyskaj publicznie dostępny link do obrazu i wklej tutaj link.', + logo_dark: 'Logo URL łącznika społecznościowego (tryb ciemny)', + logo_dark_placeholder: 'https://your.cdn.domain/logo.png', + logo_dark_tip: + 'Ustaw logo łącznika dla trybu ciemnego po jego włączeniu w Doświadczeniu logowania w Konsoli Admina.', + logo_dark_collapse: 'Zwiń', + logo_dark_show: 'Pokaż ustawienia logo dla trybu ciemnego', + target: 'Nazwa dostawcy tożsamości', + target_placeholder: 'Wpisz nazwę dostawcy tożsamości łącznika', + target_tip: + 'Wartość „Nazwy dostawcy tożsamości” może być unikalnym ciągiem identyfikującym, który odróżnia Twoje tożsamości społecznościowe. Po utworzeniu łącznika nie możesz go zmienić.', + target_tooltip: + '„Nazwa dostawcy tożsamości” w łącznikach społecznościowych Logto odnosi się do "źródła" Twoich tożsamości społecznościowych. W projektowaniu Logto nie akceptujemy tych samych „Nazw dostawców tożsamości” konkretnej platformy, aby uniknąć konfliktów. Powinieneś bardzo uważać przed dodaniem łącznika, ponieważ NIE MOŻESZ zmienić jego wartości po utworzeniu. Dowiedz się więcej.', + target_conflict: + 'Wprowadzona nazwa IdP pasuje do istniejącego łącznika nazwa. Użycie tej samej nazwy IdP może spowodować nieoczekiwane zachowanie logowania, gdzie użytkownicy mogą uzyskać dostęp do tego samego konta za pośrednictwem dwóch różnych łączników.', + target_conflict_line2: + 'Jeśli chcesz zastąpić aktualny łącznik tym samym dostawcą tożsamości i umożliwić poprzednim użytkownikom logowanie bez rejestracji ponownie, usuń łącznik nazwa i utwórz nowy z tą samą „Nazwą dostawcy tożsamości”.', + target_conflict_line3: + 'Jeśli chcesz połączyć się z innym dostawcą tożsamości, zmodyfikuj „Nazwę dostawcy tożsamości” i kontynuuj.', + config: 'Wprowadź swój JSON konfiguracji', + sync_profile: 'Synchronizuj informacje profilowe', + sync_profile_only_at_sign_up: 'Synchronizuj tylko podczas rejestracji', + sync_profile_each_sign_in: 'Zawsze wykonaj synchronizację przy każdym logowaniu', + sync_profile_tip: + 'Synchronizuje podstawowy profil z dostawcy usług społecznościowych, takie jak nazwy użytkowników i ich awatary.', + callback_uri: 'URI zwrotu (Callback)', + callback_uri_description: + 'Nazywany także URI przekierowania, to URI w Logto, do którego użytkownicy zostaną przesłani po autoryzacji społecznej; skopiuj i wklej na stronie konfiguracyjnej dostawcy usług społecznościowych.', + }, + platform: { + universal: 'Uniwersalny', + web: 'Web', + native: 'Natywny', + }, + add_multi_platform: 'obsługuje wiele platform, wybierz platformę, aby kontynuować', + drawer_title: 'Poradnik łącznika', + drawer_subtitle: 'Postępuj zgodnie z instrukcjami, aby zintegrować swój łącznik', + unknown: 'Nieznany Łącznik', +}; + +export default connectors; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/contact.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/contact.ts new file mode 100644 index 000000000..62aac8b49 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/contact.ts @@ -0,0 +1,22 @@ +const contact = { + title: 'Skontaktuj się z nami', + description: + 'Dołącz do naszej społeczności, żeby dać opinię, poprosić o pomoc i podzielić się swoimi myślami z innymi developerami', + discord: { + title: 'Kanał Discord', + description: 'Dołącz do naszego publicznego kanału, żeby rozmawiać z innymi developerami', + button: 'Dołącz', + }, + github: { + title: 'GitHub', + description: 'Utwórz problem i wyślij na GitHub', + button: 'Otwórz', + }, + email: { + title: 'Wyślij e-mail', + description: 'Wyślij nam e-maila dla dalszych informacji i pomocy', + button: 'Wyślij', + }, +}; + +export default contact; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/dashboard.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/dashboard.ts new file mode 100644 index 000000000..123818af6 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/dashboard.ts @@ -0,0 +1,22 @@ +const dashboard = { + page_title: 'Panel', + title: 'Panel', + description: 'Przegląd wydajności Twojej aplikacji', + total_users: 'Wszyscy użytkownicy', + total_users_tip: 'Wszyscy użytkownicy', + new_users_today: 'Nowi użytkownicy dzisiaj', + new_users_today_tip: 'Liczba nowych użytkowników zarejestrowanych dzisiaj', + new_users_7_days: 'Nowi użytkownicy w ciągu ostatnich 7 dni', + new_users_7_days_tip: 'Liczba nowych użytkowników zarejestrowanych w ciągu ostatnich 7 dni', + daily_active_users: 'Dziennie aktywni użytkownicy', + daily_active_users_tip: + 'Liczba unikalnych użytkowników wymieniających tokeny na Twojej aplikacji dziś', + weekly_active_users: 'Tygodniowo aktywni użytkownicy', + weekly_active_users_tip: + 'Liczba unikalnych użytkowników wymieniających tokeny na Twojej aplikacji w ciągu ostatnich 7 dni', + monthly_active_users: 'Miesięcznie aktywni użytkownicy', + monthly_active_users_tip: + 'Liczba unikalnych użytkowników wymieniających tokeny na Twojej aplikacji w ciągu ostatnich 30 dni', +}; + +export default dashboard; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/errors.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/errors.ts new file mode 100644 index 000000000..21ed21e5c --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/errors.ts @@ -0,0 +1,25 @@ +const errors = { + something_went_wrong: 'Ups! Coś poszło nie tak.', + page_not_found: 'Nie znaleziono strony', + unknown_server_error: 'Wystąpił nieznany błąd serwera', + empty: 'Brak danych', + missing_total_number: 'Nie można znaleźć wartości Total-Number w nagłówkach odpowiedzi', + invalid_uri_format: 'Nieprawidłowy format URI', + invalid_origin_format: 'Nieprawidłowy format pochodzenia URI', + invalid_json_format: 'Nieprawidłowy format JSON', + invalid_error_message_format: 'Nieprawidłowy format komunikatu błędu.', + required_field_missing: 'Wpisz {{field}}', + required_field_missing_plural: 'Musisz wprowadzić przynajmniej jeden {{field}}', + more_details: 'Więcej szczegółów', + username_pattern_error: + 'Nazwa użytkownika powinna zawierać tylko litery, cyfry lub znak podkreślenia i nie powinna zaczynać się od cyfry.', + password_pattern_error: + 'Hasło wymaga minimum {{min}} znaków i zawiera kombinację liter, cyfr i symboli.', + insecure_contexts: 'Nieobsługiwane są niebezpieczne konteksty (non-HTTPS).', + unexpected_error: 'Wystąpił nieoczekiwany błąd.', + not_found: '404 nie znaleziono', + create_internal_role_violation: + 'Tworzysz nową wewnętrzną rolę, co jest zabronione przez Logto. Spróbuj użyć innego nazwy, która nie zaczyna się od "# internal:".', +}; + +export default errors; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/general.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/general.ts new file mode 100644 index 000000000..7a13d9136 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/general.ts @@ -0,0 +1,55 @@ +const general = { + placeholder: 'Miejsce na tekst', + skip: 'Pomiń', + next: 'Dalej', + back: 'Wstecz', + retry: 'Spróbuj ponownie', + done: 'Gotowe', + search: 'Szukaj', + search_placeholder: 'Szukaj', + clear_result: 'Wyczyść Wyniki', + save: 'Zapisz', + save_changes: 'Zapisz zmiany', + saved: 'Zapisane!', + discard: 'Porzuć', + loading: 'Trwa ładowanie...', + redirecting: 'Przekierowywanie...', + add: 'Dodaj', + added: 'Dodano', + cancel: 'Anuluj', + confirm: 'Potwierdź', + check_out: 'Zapłać i wyjdź', + create: 'Stwórz', + set_up: 'Skonfiguruj', + customize: 'Dostosuj', + enable: 'Włącz', + reminder: 'Przypomnienie', + delete: 'Usuń', + more_options: 'WIĘCEJ OPCJI', + close: 'Zamknij', + copy: 'Kopiuj', + copying: 'Kopiowanie', + copied: 'Skopiowano', + required: 'Wymagane', + add_another: 'Dodaj kolejny', + deletion_confirmation: 'Czy na pewno chcesz usunąć {{title}}?', + settings_nav: 'Ustawienia', + unsaved_changes_warning: 'Wprowadzono zmiany. Czy na pewno chcesz opuścić tę stronę?', + leave_page: 'Opuść stronę', + stay_on_page: 'Pozostań na stronie', + type_to_search: 'Szukaj', + got_it: 'Zrozumiałe(a)m', + continue: 'Kontynuuj', + page_info: '{{min, number}}-{{max, number}} z {{total, number}}', + learn_more: 'Dowiedz się więcej', + tab_errors: '{{count, number}} błędów', + skip_for_now: 'Pomiń na teraz', + remove: 'Usuń', + visit: 'Odwiedź', + join: 'Dołącz', + try_now: 'Wypróbuj teraz', + multiple_form_field: '(Wiele)', + demo: 'Demo', +}; + +export default general; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/get-started.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/get-started.ts new file mode 100644 index 000000000..2b09a4358 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/get-started.ts @@ -0,0 +1,34 @@ +const get_started = { + page_title: 'Rozpocznij', + progress: 'Przewodnik rozpoczęcia: {{completed}}/{{total}}', + progress_dropdown_title: 'Kilka rzeczy, które możesz zrobić...', + title: 'Coś do odkrycia, aby pomóc ci odnieść sukces', + subtitle_part1: 'Kilka rzeczy, które możesz zrobić, aby szybko osiągnąć wartość Logto', + subtitle_part2: 'Jestem ekspertem i ukończyłem wszystkie etapy.', + hide_this: 'Ukryj to', + confirm_message: 'Jesteś pewny, że chcesz ukryć tę stronę? Tej czynności nie można cofnąć.', + check_preview_title: 'Sprawdź podgląd na żywo', + check_preview_subtitle: + 'Wypróbuj teraz doświadczenie Logto przy logowaniu, aby zobaczyć, jak działa', + integration_title: 'Utwórz i zintegruj swoją aplikację', + integration_subtitle: + 'Skonfiguruj uwierzytelnianie Logto dla swojej aplikacji natywnej, jednostronicowej, maszynowej lub tradycyjnej', + custom_sie_title: 'Dostosuj doświadczenie logowania', + custom_sie_subtitle: 'Odblokuj szeroki zakres scenariuszy za pomocą zaawansowanych ustawień', + passwordless_title: 'Skaluj logowanie bez hasła, dodając własne łączniki', + passwordless_subtitle: + 'Spróbuj logowania bez hasła i zapewnij swoim klientom bezpieczne i bezproblemowe doświadczenie', + community_title: 'Dołącz do naszej społeczności Discord', + community_subtitle: 'Dołącz do naszego publicznego kanału, aby porozmawiać z innymi deweloperami', + management_api_title: 'Interakcja z API zarządzania', + management_api_subtitle: + 'Bezpośrednio połącz swój system uwierzytelniający z naszym API zarządzania', + further_readings_title: 'Dalsza lektura', + further_readings_subtitle: + 'Sprawdź nasze krok po kroku, oparte na scenariuszach dokumenty bez nużących pojęć', + add_rbac_title: 'Dodaj kontrolę dostępu opartą na rolach, aby chronić swoje zasoby', + add_rbac_subtitle: + 'Kontroluj swoje zasoby poprzez skalowalną autoryzację ról dla różnorodnych przypadków użycia.', +}; + +export default get_started; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/index.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/index.ts new file mode 100644 index 000000000..8ffecb483 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/index.ts @@ -0,0 +1,62 @@ +import api_resource_details from './api-resource-details.js'; +import api_resources from './api-resources.js'; +import application_details from './application-details.js'; +import applications from './applications.js'; +import cloud from './cloud.js'; +import components from './components.js'; +import connector_details from './connector-details.js'; +import connectors from './connectors.js'; +import contact from './contact.js'; +import dashboard from './dashboard.js'; +import errors from './errors.js'; +import general from './general.js'; +import get_started from './get-started.js'; +import log_details from './log-details.js'; +import logs from './logs.js'; +import menu from './menu.js'; +import permissions from './permissions.js'; +import profile from './profile.js'; +import role_details from './role-details.js'; +import roles from './roles.js'; +import session_expired from './session-expired.js'; +import sign_in_exp from './sign-in-exp/index.js'; +import tab_sections from './tab-sections.js'; +import tabs from './tabs.js'; +import user_details from './user-details.js'; +import users from './users.js'; +import welcome from './welcome.js'; + +const admin_console = { + title: '관리자 콘솔', + admin_user: '관리자', + system_app: '시스템', + menu, + general, + errors, + tab_sections, + tabs, + applications, + application_details, + api_resources, + api_resource_details, + connectors, + connector_details, + get_started, + users, + user_details, + contact, + sign_in_exp, + dashboard, + logs, + log_details, + session_expired, + welcome, + roles, + role_details, + permissions, + cloud, + profile, + components, +}; + +export default admin_console; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/log-details.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/log-details.ts new file mode 100644 index 000000000..b371db4ce --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/log-details.ts @@ -0,0 +1,18 @@ +const log_details = { + page_title: 'Szczegóły dziennika audytu', + back_to_logs: 'Powróć do dziennika audytu', + back_to_user: 'Powróć do {{name}}', + success: 'Sukces', + failed: 'Niepowodzenie', + event_key: 'Klucz zdarzenia', + application: 'Aplikacja', + ip_address: 'Adres IP', + user: 'Użytkownik', + log_id: 'ID dziennika', + time: 'Czas', + user_agent: 'Użytkownik agent', + tab_details: 'Szczegóły', + raw_data: 'Surowe dane', +}; + +export default log_details; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/logs.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/logs.ts new file mode 100644 index 000000000..162fac76b --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/logs.ts @@ -0,0 +1,13 @@ +const logs = { + page_title: 'Dziennik audytu', + title: 'Dziennik audytu', + subtitle: + 'Wyświetl dane dziennika dotyczące zdarzeń uwierzytelnienia dokonywanych przez Twoich użytkowników', + event: 'Zdarzenie', + user: 'Użytkownik', + application: 'Aplikacja', + time: 'Czas', + filter_by: 'Filtruj według', +}; + +export default logs; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/menu.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/menu.ts new file mode 100644 index 000000000..de8bbdac8 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/menu.ts @@ -0,0 +1,13 @@ +const menu = { + profile: 'Profil', + language: 'Język', + appearance: { + label: 'Wygląd', + light: 'Tryb jasny', + dark: 'Tryb ciemny', + system: 'Synchronizuj z systemem', + }, + sign_out: 'Wyloguj się', +}; + +export default menu; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/permissions.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/permissions.ts new file mode 100644 index 000000000..00cdb7b51 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/permissions.ts @@ -0,0 +1,12 @@ +const permissions = { + search_placeholder: 'Szukaj według API lub nazwy uprawnienia', + search_placeholder_without_api: 'Szukaj według nazwy uprawnienia', + name_column: 'Uprawnienie', + description_column: 'Opis', + api_column: 'API', + placeholder_title: 'Uprawnienie', + placeholder_description: + 'Uprawnienie odnosi się do autoryzacji dostępu do zasobu (nazywamy go zasobem API).', +}; + +export default permissions; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/profile.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/profile.ts new file mode 100644 index 000000000..6151bf7ef --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/profile.ts @@ -0,0 +1,82 @@ +const profile = { + page_title: 'Ustawienia konta', + title: 'Ustawienia konta', + description: + 'Zmień swoje ustawienia konta i zarządzaj swoimi danymi osobistymi tutaj, aby zapewnić bezpieczeństwo Twojego konta.', + settings: { + title: 'USTAWIENIA PROFILU', + profile_information: 'Informacje o profilu', + avatar: 'Awatar', + name: 'Nazwa', + username: 'Nazwa użytkownika', + }, + link_account: { + title: 'POŁĄCZ KONTO', + email_sign_in: 'Zaloguj się przez e-mail', + email: 'Email', + social_sign_in: 'Zaloguj się przez media społecznościowe', + link_email: 'Połącz email', + link_email_subtitle: 'Połącz swój email, aby się zalogować lub pomóc w odzyskiwaniu konta.', + email_required: 'Email jest wymagany', + invalid_email: 'Nieprawidłowy adres email', + identical_email_address: 'Adres email jest taki sam jak obecny', + anonymous: 'Anonimowy', + }, + password: { + title: 'HASŁO I BEZPIECZEŃSTWO', + password: 'Hasło', + password_setting: 'Ustawienia hasła', + new_password: 'Nowe hasło', + confirm_password: 'Potwierdź hasło', + enter_password: 'Wprowadź hasło', + enter_password_subtitle: 'Zweryfikuj, czy to Ty, aby chronić bezpieczeństwo swojego konta.', + set_password: 'Ustaw hasło', + verify_via_password: 'Zweryfikuj za pomocą hasła', + show_password: 'Pokaż hasło', + required: 'Hasło jest wymagane', + min_length: 'Hasło wymaga co najmniej {{min}} znaków.', + do_not_match: 'Hasła nie pasują do siebie. Spróbuj ponownie.', + }, + code: { + enter_verification_code: 'Wprowadź kod weryfikacyjny', + enter_verification_code_subtitle: + 'Kod weryfikacyjny został wysłany na adres {{target}}', + verify_via_code: 'Zweryfikuj za pomocą kodu weryfikacyjnego', + resend: 'Wyślij ponownie kod weryfikacyjny', + resend_countdown: 'Wyślij ponownie za {{countdown}} sekund', + }, + delete_account: { + title: 'USUŃ KONTO', + label: 'Usuń konto', + description: + 'Usunięcie twojego konta spowoduje usunięcie wszystkich twoich danych osobistych, danych użytkownika i konfiguracji. Ta operacja nie może być cofnięta.', + button: 'Usuń konto', + dialog_paragraph_1: + 'Żałujemy, że chcesz usunąć swoje konto. Usunięcie twojego konta spowoduje trwałe usunięcie wszystkich danych, w tym informacji o użytkowniku, logów i ustawień, i ta operacja nie może być cofnięta. Przed dokonaniem tej operacji zalecamy wykonanie kopii zapasowych ważnych danych.', + dialog_paragraph_2: + 'Aby przejść do procesu usuwania konta, wyślij email do naszego zespołu wsparcia na adres {{mail}} z tematem "Żądanie usunięcia konta". Pomożemy Ci i zapewnimy, że wszystkie twoje dane zostaną poprawnie usunięte z naszego systemu.', + dialog_paragraph_3: + 'Dziękujemy za wybranie chmury Logto. Jeśli masz jakieś dodatkowe pytania lub wątpliwości, skontaktuj się z nami.', + }, + set: 'Ustaw', + change: 'Zmień', + link: 'Połącz', + unlink: 'Odłącz', + not_set: 'Nie ustawione', + change_avatar: 'Zmień awatar', + change_name: 'Zmień nazwę', + change_username: 'Zmień nazwę użytkownika', + set_name: 'Ustaw nazwę', + email_changed: 'Adres email został zmieniony!', + password_changed: 'Hasło zostało zmienione!', + updated: '{{target}} zaktualizowane!', + linked: '{{target}} połączone!', + unlinked: '{{target}} rozłączone!', + email_exists_reminder: + 'Ten adres e-mail {{email}} jest powiązany z istniejącym kontem. Połącz inny e-mail tutaj.', + unlink_confirm_text: 'Tak, odłącz', + unlink_reminder: + 'Użytkownicy nie będą mogli się zalogować z kontem , jeśli je odłączysz. Czy na pewno chcesz kontynuować?', +}; + +export default profile; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/role-details.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/role-details.ts new file mode 100644 index 000000000..48809fb1d --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/role-details.ts @@ -0,0 +1,50 @@ +const role_details = { + back_to_roles: 'Powrót do ról', + identifier: 'Identyfikator', + delete_description: + 'Usunięcie tej roli usunie uprawnienia z nią związanymi od użytkowników i usunie odwzorowanie między rolami, użytkownikami i uprawnieniami.', + role_deleted: '{{name}} został pomyślnie usunięty!', + settings_tab: 'Ustawienia', + users_tab: 'Użytkownicy', + permissions_tab: 'Uprawnienia', + settings: 'Ustawienia', + settings_description: + 'Role to grupowanie uprawnień, które mogą być przypisywane do użytkowników. Zapewniają również sposób agregacji uprawnień zdefiniowanych dla różnych interfejsów API, co umożliwia bardziej efektywne dodawanie, usuwanie lub modyfikowanie uprawnień w porównaniu z przypisywaniem ich do użytkowników indywidualnie.', + field_name: 'Nazwa', + field_description: 'Opis', + permission: { + assign_button: 'Przypisz uprawnienia', + assign_title: 'Przypisz uprawnienia', + assign_subtitle: + 'Przypisz uprawnienia do tej roli. Rola zyska dodane uprawnienia, a użytkownicy z tą rolą odziedziczą te uprawnienia.', + assign_form_field: 'Przypisz uprawnienia', + added_text_one: '{{count, number}} uprawnienie dodane', + added_text_other: '{{count, number}} uprawnień dodanych', + api_permission_count_one: '{{count, number}} uprawnienie', + api_permission_count_other: '{{count, number}} uprawnień', + confirm_assign: 'Przypisz uprawnienia', + permission_assigned: 'Wybrane uprawnienia zostały pomyślnie przypisane do tej roli', + deletion_description: + 'Jeśli to uprawnienie zostanie usunięte, dotknięty użytkownik z tą rolą straci dostęp przyznany przez to uprawnienie.', + permission_deleted: 'Uprawnienie "{{name}}" zostało pomyślnie usunięte z tej roli', + empty: 'Brak dostępnych uprawnień', + }, + users: { + assign_button: 'Przydziel użytkowników', + name_column: 'Użytkownik', + app_column: 'Aplikacja', + latest_sign_in_column: 'Ostatnie logowanie', + delete_description: + 'Osoba pozostanie w bazie użytkowników, ale straci autoryzację dla tej roli.', + deleted: '{{name}} został pomyślnie usunięty z tej roli', + assign_title: 'Przydziel użytkowników', + assign_subtitle: + 'Przydziel użytkowników do tej roli. Znajdź odpowiednich użytkowników, wyszukując po nazwie, adresie e-mail, numerze telefonu lub identyfikatorze użytkownika.', + assign_users_field: 'Przydziel użytkowników', + confirm_assign: 'Przydziel użytkowników', + users_assigned: 'Wybrani użytkownicy zostali pomyślnie przypisani do tej roli', + empty: 'Brak dostępnych użytkowników', + }, +}; + +export default role_details; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts new file mode 100644 index 000000000..b10412628 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/roles.ts @@ -0,0 +1,24 @@ +const roles = { + page_title: 'Role', + title: 'Role', + subtitle: + 'Role zawiera uprawnienia określające, co użytkownik może robić. RBAC wykorzystuje role do udostępniania użytkownikom zasobów do określonych działań.', + create: 'Utwórz rolę', + role_name: 'Rola', + role_description: 'Opis', + role_name_placeholder: 'Wprowadź nazwę swojej roli', + role_description_placeholder: 'Wprowadź opis swojej roli', + assigned_users: 'Przypisani użytkownicy', + assign_permissions: 'Przypisz uprawnienia', + create_role_title: 'Utwórz rolę', + create_role_description: + 'Utwórz i zarządzaj rolami dla swoich aplikacji. Role zawierają zbiory uprawnień i mogą być przypisywane użytkownikom.', + create_role_button: 'Utwórz rolę', + role_created: 'Rola {{name}} została pomyślnie utworzona!', + search: 'Wyszukaj po nazwie roli, opisie lub identyfikatorze', + placeholder_title: 'Role', + placeholder_description: + 'Role są grupowaniem uprawnień, które mogą być przypisywane użytkownikom. Upewnij się, że najpierw dodasz uprawnienie, zanim utworzysz role.', +}; + +export default roles; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/session-expired.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/session-expired.ts new file mode 100644 index 000000000..c22e6fe90 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/session-expired.ts @@ -0,0 +1,8 @@ +const session_expired = { + title: 'Sesja wygasła', + subtitle: + 'Twoja sesja mogła wygasnąć i zostałeś odłączony. Kliknij poniższy przycisk, aby ponownie się zalogować do konsoli administracyjnej.', + button: 'Zaloguj się ponownie', +}; + +export default session_expired; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/index.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/index.ts new file mode 100644 index 000000000..7ade3e8de --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/index.ts @@ -0,0 +1,88 @@ +import others from './others.js'; +import sign_up_and_sign_in from './sign-up-and-sign-in.js'; + +const sign_in_exp = { + page_title: 'Doświadczenie logowania', + title: 'Doświadczenie logowania', + description: + 'Dostosuj interfejs logowania, aby pasował do Twojej marki i wyświetlaj w czasie rzeczywistym', + tabs: { + branding: 'Marka', + sign_up_and_sign_in: 'Rejestracja i logowanie', + others: 'Inne', + }, + welcome: { + title: 'Dostosuj swoje doświadczenie logowania', + description: + 'Szybkie uruchomienie Twojego pierwszego logowania. Ten przewodnik po krokach przeprowadzi Cię przez wszystkie niezbędne ustawienia.', + get_started: 'Rozpocznij', + apply_remind: + 'Należy pamiętać, że doświadczenie logowania będzie stosowane do wszystkich aplikacji w tej sekcji.', + }, + color: { + title: 'KOLOR', + primary_color: 'Kolor marki', + dark_primary_color: 'Kolor marki (ciemny)', + dark_mode: 'Włącz tryb ciemny', + dark_mode_description: + 'Twoja aplikacja będzie miała automatycznie wygenerowany szablon trybu ciemnego na podstawie koloru marki i algorytmu Logto. Możesz go swobodnie dostosować.', + dark_mode_reset_tip: 'Przelicz kolor trybu ciemnego na podstawie koloru marki.', + reset: 'Przelicz', + }, + branding: { + title: 'OPCJE BRANDINGU', + ui_style: 'Styl', + favicon: 'Favicon', + logo_image_url: 'Adres URL obrazka logo aplikacji', + logo_image_url_placeholder: 'https://twoja.domena.cdn/logo.png', + dark_logo_image_url: 'Adres URL obrazka logo aplikacji (Ciemny)', + dark_logo_image_url_placeholder: 'https://twoja.domena.cdn/logo-ciemny.png', + logo_image: 'Logo aplikacji', + dark_logo_image: 'Logo aplikacji (Ciemny)', + logo_image_error: 'Logo aplikacji: {{error}}', + favicon_error: 'Favicon: {{error}}', + }, + custom_css: { + title: 'Niestandardowe CSS', + css_code_editor_title: 'Dostosuj swój interfejs użytkownika niestandardowym CSS', + css_code_editor_description1: 'Zobacz przykład niestandardowego CSS.', + css_code_editor_description2: '{{link}}', + css_code_editor_description_link_content: 'Dowiedz się więcej', + css_code_editor_content_placeholder: + 'Wprowadź swoje niestandardowe CSS, aby dostosować style czegokolwiek do swoich dokładnych specyfikacji. Wyraź swoją kreatywność i wyróżnij swój interfejs użytkownika.', + }, + sign_up_and_sign_in, + others, + setup_warning: { + no_connector_sms: + 'Nie ustawiono jeszcze łącznika SMS. Przed zakończeniem konfiguracji użytkownicy nie będą mogli się zalogować przy użyciu tej metody. {{link}} w sekcji „Łączniki“', + no_connector_email: + 'Nie ustawiono jeszcze łącznika e-mail. Przed zakończeniem konfiguracji użytkownicy nie będą mogli się zalogować przy użyciu tej metody. {{link}} w sekcji „Łączniki“', + no_connector_social: + 'Nie ustawiono jeszcze łącznika społecznościowego. Przed zakończeniem konfiguracji użytkownicy nie będą mogli się zalogować przy użyciu tej metody. {{link}} w sekcji„Łączniki"', + no_added_social_connector: + 'Skonfigurowałeś teraz kilka łączników społecznościowych. Upewnij się, że dodano niektóre z nich do Twojego doświadczenia logowania.', + setup_link: 'Konfiguracja', + }, + save_alert: { + description: + 'Wdrażasz nowe procedury logowania i rejestracji. Wszyscy Twoi użytkownicy mogą być dotknięci nową konfiguracją. Czy na pewno zdecydowałeś się na zmiany?', + before: 'Przed', + after: 'Po', + sign_up: 'Rejestracja', + sign_in: 'Logowanie', + social: 'Społecznościowy', + }, + preview: { + title: 'Podgląd logowania', + live_preview: 'Podgląd na żywo', + live_preview_tip: 'Zapisz, aby obejrzeć zmiany', + native: 'Aplikacja natywna', + desktop_web: 'Wersja desktopowa', + mobile_web: 'Wersja mobilna', + desktop: 'Komputer', + mobile: 'Telefon', + }, +}; + +export default sign_in_exp; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/others.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/others.ts new file mode 100644 index 000000000..12c264384 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/others.ts @@ -0,0 +1,48 @@ +const others = { + terms_of_use: { + title: 'WARUNKI', + terms_of_use: 'URL warunków użytkowania', + terms_of_use_placeholder: 'https://twoje.warunki.użytkowania/', + privacy_policy: 'URL polityki prywatności', + privacy_policy_placeholder: 'https://twoja.polityka.prywatności/', + }, + languages: { + title: 'JĘZYKI', + enable_auto_detect: 'Włącz wykrywanie automatyczne', + description: + 'Twoje oprogramowanie wykrywa ustawienia językowe użytkownika i przełącza się na język lokalny. Możesz dodać nowe języki, tłumacząc interfejs użytkownika z angielskiego na inny język.', + manage_language: 'Zarządzanie językiem', + default_language: 'Domyślny język', + default_language_description_auto: + 'Domyślny język będzie używany, gdy wykryty język użytkownika nie będzie objęty w bieżącej bibliotece językowej.', + default_language_description_fixed: + 'Gdy wykrywanie automatyczne jest wyłączone, jedynym językiem, który będzie wyświetlał się w twoim oprogramowaniu, jest język domyślny. Włącz wykrywanie automatyczne, aby rozszerzyć język.', + }, + manage_language: { + title: 'Zarządzanie językiem', + subtitle: + 'Lokalizuj doświadczenie użytkownika przez dodawanie języków i tłumaczeń. Twoje tłumaczenie może być ustawione jako domyślny język.', + add_language: 'Dodaj język', + logto_provided: 'Logto dostarczony', + key: 'Klucz', + logto_source_values: 'Logto źródłowe wartości', + custom_values: 'Własne wartości', + clear_all_tip: 'Wyczyść wszystkie wartości', + unsaved_description: + 'Zmiany nie zostaną zapisane, jeśli wyjdziecie z tej strony bez zapisywania.', + deletion_tip: 'Usuń język', + deletion_title: 'Czy chcesz usunąć dodany język?', + deletion_description: 'Po usunięciu użytkownicy nie będą mogli przeglądać w tym języku.', + default_language_deletion_title: 'Domyślny język nie może zostać usunięty.', + default_language_deletion_description: + '{{language}} jest ustawiony jako twój domyślny język i nie może być usunięty.', + }, + advanced_options: { + title: 'OPCJE ZAAWANSOWANE', + enable_user_registration: 'Włącz rejestrację użytkowników', + enable_user_registration_description: + 'Włącz lub wyłącz rejestrację użytkowników. Po wyłączeniu użytkownicy nadal mogą być dodawani w konsoli administracyjnej, ale nie mogą już zakładać kont za pomocą interfejsu logowania.', + }, +}; + +export default others; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts new file mode 100644 index 000000000..4e630a641 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/sign-in-exp/sign-up-and-sign-in.ts @@ -0,0 +1,58 @@ +const sign_up_and_sign_in = { + identifiers_email: 'Adres e-mail', + identifiers_phone: 'Numer telefonu', + identifiers_username: 'Nazwa użytkownika', + identifiers_email_or_sms: 'Adres e-mail lub numer telefonu', + identifiers_none: 'Nie dotyczy', + and: 'i', + or: 'lub', + sign_up: { + title: 'REJESTRACJA', + sign_up_identifier: 'Identyfikator rejestracji', + identifier_description: + 'Identyfikator rejestracji jest wymagany do utworzenia konta i musi być uwzględniony na ekranie logowania.', + sign_up_authentication: 'Ustawienia uwierzytelniania dla rejestracji', + authentication_description: + 'Wszystkie wybrane czynności będą obowiązkowe dla użytkowników, aby ukończyć proces rejestracji.', + set_a_password_option: 'Utwórz hasło', + verify_at_sign_up_option: 'Weryfikuj podczas rejestracji', + social_only_creation_description: '(Stosuje się tylko do tworzenia kont społecznościowych)', + }, + sign_in: { + title: 'LOGOWANIE', + sign_in_identifier_and_auth: 'Identyfikator i ustawienia uwierzytelniania dla logowania', + description: + 'Użytkownicy mogą się zalogować za pomocą dowolnej dostępnej opcji. Dostosuj układ, przeciągając i upuszczając poniżej opcji.', + add_sign_in_method: 'Dodaj metodę logowania', + password_auth: 'Hasło', + verification_code_auth: 'Kod weryfikacyjny', + auth_swap_tip: + 'Zamień poniższe opcje, aby określić, która pojawia się jako pierwsza w procesie.', + require_auth_factor: 'Musisz wybrać co najmniej jeden czynnik uwierzytelniający.', + }, + social_sign_in: { + title: 'LOGOWANIE SPOŁECZNOŚCIOWE', + social_sign_in: 'Logowanie społecznościowe', + description: + 'W zależności od obowiązkowego identyfikatora, którego ustawisz, użytkownik może zostać poproszony o podanie identyfikatora podczas rejestracji za pośrednictwem łącznika społecznościowego.', + add_social_connector: 'Dodaj łącznik społecznościowy', + set_up_hint: { + not_in_list: 'Nie ma na liście?', + set_up_more: 'Ustaw', + go_to: 'inne łączniki społecznościowe teraz.', + }, + }, + tip: { + set_a_password: 'Unikatowe hasło dla nazwy użytkownika jest konieczne.', + verify_at_sign_up: + 'Obecnie obsługujemy tylko weryfikowany adres e-mail. Twoja baza użytkowników może zawierać dużą liczbę adresów e-mail niskiej jakości, jeśli nie dokonasz walidacji.', + password_auth: + 'Jest to istotne, ponieważ umożliwiłeś opcję tworzenia hasła podczas procesu rejestracji.', + verification_code_auth: + 'Jest to istotne, ponieważ umożliwiłeś wyłącznie opcję podania kodu weryfikacyjnego podczas rejestracji. Możesz odznaczyć pole wyboru, gdy dozwolone jest ustawienie hasła podczas procesu rejestracji.', + delete_sign_in_method: + 'Jest to istotne, ponieważ wybrałeś {{identifier}} jako wymagany identyfikator.', + }, +}; + +export default sign_up_and_sign_in; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/tab-sections.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/tab-sections.ts new file mode 100644 index 000000000..b1ee68d1d --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/tab-sections.ts @@ -0,0 +1,9 @@ +const tab_sections = { + overview: 'Przegląd', + resource_management: 'Zarządzanie zasobami', + user_management: 'Zarządzanie użytkownikami', + access_control: 'Kontrola dostępu', + help_and_support: 'Pomoc i wsparcie', +}; + +export default tab_sections; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/tabs.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/tabs.ts new file mode 100644 index 000000000..b52900f05 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/tabs.ts @@ -0,0 +1,16 @@ +const tabs = { + get_started: 'Rozpocznij', + dashboard: 'Panel', + applications: 'Aplikacje', + api_resources: 'Zasoby API', + sign_in_experience: 'Doświadczenie przy logowaniu', + connectors: 'Konnektory', + users: 'Zarządzanie użytkownikami', + audit_logs: 'Dzienniki audytu', + roles: 'Role', + docs: 'Dokumentacja', + contact_us: 'Skontaktuj się z nami', + settings: 'Ustawienia', +}; + +export default tabs; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/user-details.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/user-details.ts new file mode 100644 index 000000000..63c813027 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/user-details.ts @@ -0,0 +1,63 @@ +const user_details = { + page_title: 'Szczegóły użytkownika', + back_to_users: 'Powrót do zarządzania użytkownikami', + created_title: 'Ten użytkownik został pomyślnie utworzony', + created_guide: 'Możesz wysłać następujące informacje o logowaniu do użytkownika', + created_username: 'Nazwa użytkownika:', + created_password: 'Hasło:', + menu_delete: 'Usuń', + delete_description: 'Tej akcji nie można cofnąć. Usunie to użytkownika na stałe.', + deleted: 'Użytkownik został pomyślnie usunięty', + reset_password: { + reset_password: 'Zresetuj hasło', + title: 'Czy na pewno chcesz zresetować hasło?', + content: 'Tej akcji nie można cofnąć. To zresetuje informacje o logowaniu użytkownika.', + congratulations: 'Ten użytkownik został zresetowany', + new_password: 'Nowe hasło:', + }, + tab_settings: 'Ustawienia', + tab_roles: 'Role', + tab_logs: 'Logi użytkownika', + settings: 'Ustawienia', + settings_description: + 'Każdy użytkownik ma profil zawierający wszystkie informacje o użytkowniku. Składa się on z podstawowych danych, tożsamości społecznościowych i niestandardowych danych.', + field_email: 'E-mail podstawowy', + field_phone: 'Telefon podstawowy', + field_username: 'Nazwa użytkownika', + field_name: 'Imię i nazwisko', + field_avatar: 'Adres URL obrazka awatara', + field_avatar_placeholder: 'https://twoja.domena/cdn/avatar.png', + field_custom_data: 'Dane niestandardowe', + field_custom_data_tip: + 'Dodatkowe informacje o użytkowniku niewymienione jako właściwości predefiniowane, takie jak preferowany przez użytkownika kolor i język.', + field_connectors: 'Połączenia społecznościowe', + custom_data_invalid: 'Nieprawidłowe dane niestandardowe JSON', + connectors: { + connectors: 'Połączenia', + user_id: 'Identyfikator użytkownika', + remove: 'Usuń', + not_connected: 'Użytkownik nie jest połączony z żadnym połączeniem społecznościowym', + deletion_confirmation: 'Usuwasz istniejącą tożsamość . Czy na pewno chcesz to zrobić?', + }, + suspended: 'Zawieszony', + roles: { + name_column: 'Rola', + description_column: 'Opis', + assign_button: 'Przypisz role', + delete_description: + 'Ta akcja usunie tę rolę z tego użytkownika. Rola nadal będzie istnieć, ale nie będzie już przypisana do tego użytkownika.', + deleted: '{{name}} został usunięty z tego użytkownika.', + assign_title: 'Przypisz role dla {{name}}', + assign_subtitle: 'Autoryzuj {{name}} jedną lub wiele ról', + assign_role_field: 'Przypisz role', + role_search_placeholder: 'Szukaj po nazwie roli', + added_text: '{{value, number}} dodanych', + assigned_user_count: '{{value, number}} użytkowników', + confirm_assign: 'Przypisz role', + role_assigned: 'Pomyślnie przypisano rolę(y)', + search: 'Szukaj po nazwie roli, opisie lub ID', + empty: 'Brak dostępnej roli', + }, +}; + +export default user_details; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/users.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/users.ts new file mode 100644 index 000000000..4c852492e --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/users.ts @@ -0,0 +1,21 @@ +const users = { + page_title: 'Zarządzanie użytkownikami', + title: 'Zarządzanie użytkownikami', + subtitle: + 'Zarządzaj tożsamościami użytkowników, w tym tworzeniem użytkowników, edycją informacji o użytkownikach, przeglądaniem dzienników użytkowników, resetowaniem hasła i usuwaniem użytkowników.', + create: 'Dodaj użytkownika', + user_name: 'Użytkownik', + application_name: 'Z aplikacji', + latest_sign_in: 'Najnowsze logowanie', + create_form_username: 'Nazwa użytkownika', + create_form_password: 'Hasło', + create_form_name: 'Imię i nazwisko', + unnamed: 'Bez nazwy', + search: 'Wyszukaj według nazwy, e-maila, numeru telefonu lub nazwy użytkownika', + check_user_detail: 'Sprawdź szczegóły użytkownika', + placeholder_title: 'Zarządzanie użytkownikami', + placeholder_description: + 'Każdy użytkownik ma profil zawierający wszystkie informacje o użytkowniku. Składa się z podstawowych danych, tożsamości społecznych i niestandardowych danych.', +}; + +export default users; diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/welcome.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/welcome.ts new file mode 100644 index 000000000..8367f805b --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/welcome.ts @@ -0,0 +1,8 @@ +const welcome = { + title: 'Witaj w konsoli administracyjnej', + description: + 'Konsola administracyjna to aplikacja internetowa umożliwiająca zarządzanie Logto bez wymagania znajomości kodowania. Najpierw załóż konto. Dzięki temu kontu możesz zarządzać Logto samodzielnie lub w imieniu swojej firmy.', + create_account: 'Załóż konto', +}; + +export default welcome; diff --git a/packages/phrases/src/locales/pl-pl/translation/demo-app.ts b/packages/phrases/src/locales/pl-pl/translation/demo-app.ts new file mode 100644 index 000000000..abf81e271 --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/demo-app.ts @@ -0,0 +1,13 @@ +const demo_app = { + title: 'Pomyślnie zalogowałeś się do podglądu na żywo!', + subtitle: 'Oto twoje informacje logowania:', + username: 'Nazwa użytkownika: ', + user_id: 'ID użytkownika: ', + sign_out: 'Wyloguj się z podglądu na żywo', + continue_explore: 'Lub kontynuuj przeglądanie', + customize_sign_in_experience: 'Dostosuj wrażenia z logowania', + enable_passwordless: 'Włącz logowanie bez hasła', + add_social_connector: 'Dodaj złącze społecznościowe', +}; + +export default demo_app; diff --git a/packages/phrases/src/locales/pl-pl/translation/index.ts b/packages/phrases/src/locales/pl-pl/translation/index.ts new file mode 100644 index 000000000..d006e599f --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/index.ts @@ -0,0 +1,11 @@ +import admin_console from './admin-console/index.js'; +import demo_app from './demo-app.js'; +import oidc from './oidc.js'; + +const translation = { + admin_console, + demo_app, + oidc, +}; + +export default translation; diff --git a/packages/phrases/src/locales/pl-pl/translation/oidc.ts b/packages/phrases/src/locales/pl-pl/translation/oidc.ts new file mode 100644 index 000000000..f50611fbf --- /dev/null +++ b/packages/phrases/src/locales/pl-pl/translation/oidc.ts @@ -0,0 +1,5 @@ +const oidc = { + logout_success: 'Pomyślnie zostałeś wylogowany.', +}; + +export default oidc; From fc08fb5575018f5dc7ad7ba6a57e2c9c9358b2d0 Mon Sep 17 00:00:00 2001 From: simeng-li Date: Mon, 3 Apr 2023 10:24:03 +0800 Subject: [PATCH 06/11] refactor(ui): refactor ui hooks and provider structure (#3647) * refactor(ui): refactor ui hooks and provider structure refactor ui hooks and provider structure * chore(ui): provide dependency precisely provide dependency precisely --- packages/ui/src/App.tsx | 158 ++++++------------ .../ui/src/Layout/LandingPageLayout/index.tsx | 2 +- .../AppBoundary}/hooks/use-color-theme.ts | 2 +- .../AppBoundary/hooks/use-custom-style.ts | 19 +++ .../AppBoundary/hooks/use-meta-data.ts | 31 ++++ .../AppBoundary}/hooks/use-theme.ts | 9 +- .../ui/src/Providers/AppBoundary/index.tsx | 32 +--- .../Providers/LoadingLayerProvider/index.tsx | 2 +- .../PageContextProvider/PageContext.tsx | 38 +++++ .../Providers/PageContextProvider/index.tsx | 66 ++++++++ .../PreviewProvider/index.tsx} | 70 ++++---- .../src/Providers/SettingsProvider/index.tsx | 23 +++ .../SignInExperienceProvider/index.tsx | 22 +++ .../ui/src/Providers/ToastProvider/index.tsx | 2 +- .../RenderWithPageContext/ContextProvider.tsx | 9 - .../SettingsProvider.tsx | 2 +- .../__mocks__/RenderWithPageContext/index.tsx | 13 +- .../src/components/LogtoSignature/index.tsx | 2 +- .../ui/src/containers/SocialLanding/index.tsx | 2 +- .../SocialSignInList/index.test.tsx | 6 +- .../index.tsx | 2 +- .../VerificationCode/index.test.tsx | 25 ++- .../use-resend-verification-code.ts | 6 +- packages/ui/src/hooks/use-api.ts | 2 +- packages/ui/src/hooks/use-error-handler.ts | 6 +- .../src/hooks/use-native-message-listener.ts | 6 +- packages/ui/src/hooks/use-page-context.ts | 77 --------- packages/ui/src/hooks/use-platform.ts | 2 +- .../use-required-profile-error-handler.ts | 6 +- packages/ui/src/hooks/use-sie.ts | 4 +- .../src/hooks/use-social-landing-handler.ts | 6 +- .../src/hooks/use-social-sign-in-listener.ts | 6 +- packages/ui/src/hooks/use-social.ts | 2 +- packages/ui/src/hooks/use-terms.ts | 2 +- packages/ui/src/hooks/use-toast.ts | 11 ++ packages/ui/src/pages/Consent/index.tsx | 2 +- packages/ui/src/pages/ErrorPage/index.tsx | 2 +- .../ForgotPasswordForm/index.test.tsx | 13 +- .../src/pages/ForgotPassword/index.test.tsx | 26 ++- packages/ui/src/pages/Register/index.test.tsx | 24 ++- packages/ui/src/pages/Register/index.tsx | 7 +- .../ui/src/pages/ResetPassword/index.test.tsx | 11 +- .../pages/ResetPassword/use-reset-password.ts | 6 +- .../IdentifierSignInForm/index.test.tsx | 7 +- .../SignIn/PasswordSignInForm/index.test.tsx | 5 +- packages/ui/src/pages/SignIn/index.test.tsx | 31 ++-- packages/ui/src/pages/SignIn/index.tsx | 7 +- .../PasswordForm/VerificationCodeLink.tsx | 6 +- .../src/pages/SignInPassword/index.test.tsx | 20 +-- .../ui/src/pages/SocialLanding/index.test.tsx | 13 +- .../pages/SocialLinkAccount/index.test.tsx | 46 +++-- .../pages/SocialSignInCallback/index.test.tsx | 13 +- .../src/pages/VerificationCode/index.test.tsx | 24 ++- 53 files changed, 495 insertions(+), 441 deletions(-) rename packages/ui/src/{ => Providers/AppBoundary}/hooks/use-color-theme.ts (96%) create mode 100644 packages/ui/src/Providers/AppBoundary/hooks/use-custom-style.ts create mode 100644 packages/ui/src/Providers/AppBoundary/hooks/use-meta-data.ts rename packages/ui/src/{ => Providers/AppBoundary}/hooks/use-theme.ts (74%) create mode 100644 packages/ui/src/Providers/PageContextProvider/PageContext.tsx create mode 100644 packages/ui/src/Providers/PageContextProvider/index.tsx rename packages/ui/src/{hooks/use-preview.ts => Providers/PreviewProvider/index.tsx} (54%) create mode 100644 packages/ui/src/Providers/SettingsProvider/index.tsx create mode 100644 packages/ui/src/Providers/SignInExperienceProvider/index.tsx delete mode 100644 packages/ui/src/__mocks__/RenderWithPageContext/ContextProvider.tsx delete mode 100644 packages/ui/src/hooks/use-page-context.ts create mode 100644 packages/ui/src/hooks/use-toast.ts diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index 9e4934f93..29983e1c1 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -1,13 +1,10 @@ -import { SignInMode } from '@logto/schemas'; -import { useEffect, useRef } from 'react'; -import { Route, Routes, BrowserRouter, Navigate } from 'react-router-dom'; +import { Route, Routes, BrowserRouter } from 'react-router-dom'; import AppLayout from './Layout/AppLayout'; import AppBoundary from './Providers/AppBoundary'; import LoadingLayerProvider from './Providers/LoadingLayerProvider'; -import usePageContext from './hooks/use-page-context'; -import usePreview from './hooks/use-preview'; -import initI18n from './i18n/init'; +import PageContextProvider from './Providers/PageContextProvider'; +import SettingsProvider from './Providers/SettingsProvider'; import Callback from './pages/Callback'; import Consent from './pages/Consent'; import Continue from './pages/Continue'; @@ -24,117 +21,68 @@ import SocialSignIn from './pages/SocialSignInCallback'; import Springboard from './pages/Springboard'; import VerificationCode from './pages/VerificationCode'; import { handleSearchParametersData } from './utils/search-parameters'; -import { getSignInExperienceSettings, setFavIcon } from './utils/sign-in-experience'; import './scss/normalized.scss'; handleSearchParametersData(); const App = () => { - const { context, Provider } = usePageContext(); - const { experienceSettings, setLoading, setExperienceSettings } = context; - const customCssRef = useRef(document.createElement('style')); - const [isPreview, previewConfig] = usePreview(context); - - useEffect(() => { - document.head.append(customCssRef.current); - }, []); - - useEffect(() => { - if (isPreview) { - // eslint-disable-next-line @silverhand/fp/no-mutation - customCssRef.current.textContent = previewConfig?.signInExperience.customCss ?? null; - - return; - } - - (async () => { - const settings = await getSignInExperienceSettings(); - - const { - customCss, - branding: { favicon }, - } = settings; - - // eslint-disable-next-line @silverhand/fp/no-mutation - customCssRef.current.textContent = customCss; - setFavIcon(favicon); - - // Note: i18n must be initialized ahead of page render - await initI18n(); - - // Init the page settings and render - setExperienceSettings(settings); - })(); - }, [isPreview, previewConfig, setExperienceSettings, setLoading]); - - if (!experienceSettings) { - return null; - } - - const isRegisterOnly = experienceSettings.signInMode === SignInMode.Register; - const isSignInOnly = experienceSettings.signInMode === SignInMode.SignIn; - return ( - - - - } /> - }> - } - /> - } /> + + + + + } /> + }> + } + /> + } /> - }> - {/* Sign-in */} - - : } - /> - } /> - } /> + }> + {/* Sign-in */} + + } /> + } /> + } /> + + + {/* Register */} + + } /> + } /> + + + {/* Forgot password */} + + } /> + } /> + + + {/* Passwordless verification code */} + } /> + + {/* Continue set up missing profile */} + + } /> + + + {/* Social sign-in pages */} + + } /> + } /> + + } /> - {/* Register */} - - : } - /> - } /> - - - {/* Forgot password */} - - } /> - } /> - - - {/* Passwordless verification code */} - } /> - - {/* Continue set up missing profile */} - - } /> - - - {/* Social sign-in pages */} - - } /> - } /> - - } /> + } /> - - } /> - - - - + + + + ); }; diff --git a/packages/ui/src/Layout/LandingPageLayout/index.tsx b/packages/ui/src/Layout/LandingPageLayout/index.tsx index bc29a4e94..da4301c41 100644 --- a/packages/ui/src/Layout/LandingPageLayout/index.tsx +++ b/packages/ui/src/Layout/LandingPageLayout/index.tsx @@ -3,8 +3,8 @@ import type { ReactNode } from 'react'; import { useContext } from 'react'; import type { TFuncKey } from 'react-i18next'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import BrandingHeader from '@/components/BrandingHeader'; -import { PageContext } from '@/hooks/use-page-context'; import { layoutClassNames } from '@/utils/consts'; import { getBrandingLogoUrl } from '@/utils/logo'; diff --git a/packages/ui/src/hooks/use-color-theme.ts b/packages/ui/src/Providers/AppBoundary/hooks/use-color-theme.ts similarity index 96% rename from packages/ui/src/hooks/use-color-theme.ts rename to packages/ui/src/Providers/AppBoundary/hooks/use-color-theme.ts index 879c355de..5fb4f4558 100644 --- a/packages/ui/src/hooks/use-color-theme.ts +++ b/packages/ui/src/Providers/AppBoundary/hooks/use-color-theme.ts @@ -3,7 +3,7 @@ import { Theme } from '@logto/schemas'; import color from 'color'; import { useEffect, useContext } from 'react'; -import { PageContext } from '@/hooks/use-page-context'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; const generateLightColorLibrary = (primaryColor: color) => ({ [`--color-brand-default`]: primaryColor.hex(), diff --git a/packages/ui/src/Providers/AppBoundary/hooks/use-custom-style.ts b/packages/ui/src/Providers/AppBoundary/hooks/use-custom-style.ts new file mode 100644 index 000000000..b0b98d3ed --- /dev/null +++ b/packages/ui/src/Providers/AppBoundary/hooks/use-custom-style.ts @@ -0,0 +1,19 @@ +import { useRef, useEffect, useContext } from 'react'; + +import PageContext from '@/Providers/PageContextProvider/PageContext'; + +const useCustomStyle = () => { + const customCssRef = useRef(document.createElement('style')); + const { experienceSettings } = useContext(PageContext); + + useEffect(() => { + document.head.append(customCssRef.current); + }, []); + + useEffect(() => { + // eslint-disable-next-line @silverhand/fp/no-mutation + customCssRef.current.textContent = experienceSettings?.customCss ?? null; + }, [experienceSettings?.customCss]); +}; + +export default useCustomStyle; diff --git a/packages/ui/src/Providers/AppBoundary/hooks/use-meta-data.ts b/packages/ui/src/Providers/AppBoundary/hooks/use-meta-data.ts new file mode 100644 index 000000000..b66ac2442 --- /dev/null +++ b/packages/ui/src/Providers/AppBoundary/hooks/use-meta-data.ts @@ -0,0 +1,31 @@ +import { conditionalString } from '@silverhand/essentials'; +import { useEffect, useContext } from 'react'; + +import PageContext from '@/Providers/PageContextProvider/PageContext'; +import { setFavIcon } from '@/utils/sign-in-experience'; + +import * as styles from '../index.module.scss'; + +// TODO: replace with react-helmet +const useMetaData = () => { + const { experienceSettings, theme, platform } = useContext(PageContext); + + // Set favicon + useEffect(() => { + setFavIcon(experienceSettings?.branding.favicon); + }, [experienceSettings?.branding.favicon]); + + // Set Theme Mode + useEffect(() => { + document.body.classList.remove(conditionalString(styles.light), conditionalString(styles.dark)); + document.body.classList.add(conditionalString(styles[theme])); + }, [theme]); + + // Apply Platform Style + useEffect(() => { + document.body.classList.remove('desktop', 'mobile'); + document.body.classList.add(platform === 'mobile' ? 'mobile' : 'desktop'); + }, [platform]); +}; + +export default useMetaData; diff --git a/packages/ui/src/hooks/use-theme.ts b/packages/ui/src/Providers/AppBoundary/hooks/use-theme.ts similarity index 74% rename from packages/ui/src/hooks/use-theme.ts rename to packages/ui/src/Providers/AppBoundary/hooks/use-theme.ts index aed64c344..5405d0d0b 100644 --- a/packages/ui/src/hooks/use-theme.ts +++ b/packages/ui/src/Providers/AppBoundary/hooks/use-theme.ts @@ -1,20 +1,19 @@ import { Theme } from '@logto/schemas'; import { useEffect, useContext } from 'react'; -import { PageContext } from './use-page-context'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; const darkThemeWatchMedia = window.matchMedia('(prefers-color-scheme: dark)'); const getThemeBySystemConfiguration = (): Theme => darkThemeWatchMedia.matches ? Theme.Dark : Theme.Light; -export default function useTheme(): Theme { - const { isPreview, experienceSettings, theme, setTheme } = useContext(PageContext); +export default function useTheme() { + const { isPreview, experienceSettings, setTheme } = useContext(PageContext); useEffect(() => { /** * Note: * In preview mode, the theme of the page is controlled by the preview options and does not follow system changes. - * The `usePreview` hook changes the theme of the page by calling the `setTheme` API of the `PageContext`. */ if (isPreview) { return; @@ -36,6 +35,4 @@ export default function useTheme(): Theme { darkThemeWatchMedia.removeEventListener('change', changeTheme); }; }, [experienceSettings, isPreview, setTheme]); - - return theme; } diff --git a/packages/ui/src/Providers/AppBoundary/index.tsx b/packages/ui/src/Providers/AppBoundary/index.tsx index 0693a4f87..39164d416 100644 --- a/packages/ui/src/Providers/AppBoundary/index.tsx +++ b/packages/ui/src/Providers/AppBoundary/index.tsx @@ -1,39 +1,25 @@ -import { conditionalString } from '@silverhand/essentials'; -import type { ReactNode } from 'react'; -import { useContext, useEffect } from 'react'; +import type { ReactElement } from 'react'; -import useColorTheme from '@/hooks/use-color-theme'; -import { PageContext } from '@/hooks/use-page-context'; -import useTheme from '@/hooks/use-theme'; +import useColorTheme from '@/Providers/AppBoundary/hooks/use-color-theme'; import ConfirmModalProvider from '../ConfirmModalProvider'; import IframeModalProvider from '../IframeModalProvider'; import ToastProvider from '../ToastProvider'; -import * as styles from './index.module.scss'; +import useCustomStyle from './hooks/use-custom-style'; +import useMetaData from './hooks/use-meta-data'; +import useTheme from './hooks/use-theme'; type Props = { - children: ReactNode; + children: ReactElement; }; const AppBoundary = ({ children }: Props) => { - // Set Primary Color useColorTheme(); - const theme = useTheme(); + useCustomStyle(); + useTheme(); - const { platform } = useContext(PageContext); - - // Set Theme Mode - useEffect(() => { - document.body.classList.remove(conditionalString(styles.light), conditionalString(styles.dark)); - document.body.classList.add(conditionalString(styles[theme])); - }, [theme]); - - // Apply Platform Style - useEffect(() => { - document.body.classList.remove('desktop', 'mobile'); - document.body.classList.add(platform === 'mobile' ? 'mobile' : 'desktop'); - }, [platform]); + useMetaData(); return ( diff --git a/packages/ui/src/Providers/LoadingLayerProvider/index.tsx b/packages/ui/src/Providers/LoadingLayerProvider/index.tsx index e04588215..cefd8d5ed 100644 --- a/packages/ui/src/Providers/LoadingLayerProvider/index.tsx +++ b/packages/ui/src/Providers/LoadingLayerProvider/index.tsx @@ -2,8 +2,8 @@ import { useContext } from 'react'; import { Outlet } from 'react-router-dom'; import { useDebouncedLoader } from 'use-debounced-loader'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import LoadingLayer from '@/components/LoadingLayer'; -import { PageContext } from '@/hooks/use-page-context'; const LoadingLayerProvider = () => { const { loading } = useContext(PageContext); diff --git a/packages/ui/src/Providers/PageContextProvider/PageContext.tsx b/packages/ui/src/Providers/PageContextProvider/PageContext.tsx new file mode 100644 index 000000000..d9b41fe7d --- /dev/null +++ b/packages/ui/src/Providers/PageContextProvider/PageContext.tsx @@ -0,0 +1,38 @@ +import { Theme } from '@logto/schemas'; +import { noop } from '@silverhand/essentials'; +import { createContext } from 'react'; +import { isMobile } from 'react-device-detect'; + +import type { SignInExperienceResponse, Platform } from '@/types'; + +export type PageContextType = { + theme: Theme; + toast: string; + loading: boolean; + platform: Platform; + termsAgreement: boolean; + experienceSettings: SignInExperienceResponse | undefined; + isPreview: boolean; + setTheme: React.Dispatch>; + setToast: React.Dispatch>; + setLoading: React.Dispatch>; + setPlatform: React.Dispatch>; + setTermsAgreement: React.Dispatch>; + setExperienceSettings: React.Dispatch>; +}; + +export default createContext({ + toast: '', + theme: Theme.Light, + loading: false, + platform: isMobile ? 'mobile' : 'web', + termsAgreement: false, + experienceSettings: undefined, + isPreview: false, + setTheme: noop, + setToast: noop, + setLoading: noop, + setPlatform: noop, + setTermsAgreement: noop, + setExperienceSettings: noop, +}); diff --git a/packages/ui/src/Providers/PageContextProvider/index.tsx b/packages/ui/src/Providers/PageContextProvider/index.tsx new file mode 100644 index 000000000..bcbaf80cd --- /dev/null +++ b/packages/ui/src/Providers/PageContextProvider/index.tsx @@ -0,0 +1,66 @@ +import { Theme } from '@logto/schemas'; +import { useState, useMemo } from 'react'; +import { isMobile } from 'react-device-detect'; +import { useSearchParams } from 'react-router-dom'; + +import type { SignInExperienceResponse, Platform } from '@/types'; + +import type { PageContextType } from './PageContext'; +import MainContext from './PageContext'; + +type Props = { + children: React.ReactNode; + preset?: Partial< + Pick< + PageContextType, + | 'theme' + | 'toast' + | 'loading' + | 'platform' + | 'termsAgreement' + | 'experienceSettings' + | 'isPreview' + > + >; +}; + +const PageContextProvider = ({ children, preset }: Props) => { + const [searchParameters] = useSearchParams(); + + const [loading, setLoading] = useState(preset?.loading ?? false); + const [toast, setToast] = useState(preset?.toast ?? ''); + const [theme, setTheme] = useState(preset?.theme ?? Theme.Light); + + const [platform, setPlatform] = useState( + preset?.platform ?? (isMobile ? 'mobile' : 'web') + ); + const [termsAgreement, setTermsAgreement] = useState(preset?.termsAgreement ?? false); + const [experienceSettings, setExperienceSettings] = useState< + SignInExperienceResponse | undefined + >(preset?.experienceSettings ?? undefined); + + const isPreview = searchParameters.get('preview') === 'true'; + + const pageContext = useMemo( + () => ({ + theme, + toast, + loading, + platform, + termsAgreement, + experienceSettings, + isPreview, + setTheme, + setLoading, + setToast, + setPlatform, + setTermsAgreement, + setExperienceSettings, + }), + [experienceSettings, isPreview, loading, platform, termsAgreement, theme, toast] + ); + + return {children}; +}; + +export default PageContextProvider; diff --git a/packages/ui/src/hooks/use-preview.ts b/packages/ui/src/Providers/PreviewProvider/index.tsx similarity index 54% rename from packages/ui/src/hooks/use-preview.ts rename to packages/ui/src/Providers/PreviewProvider/index.tsx index 36eaf4175..3c51b0763 100644 --- a/packages/ui/src/hooks/use-preview.ts +++ b/packages/ui/src/Providers/PreviewProvider/index.tsx @@ -1,37 +1,31 @@ import { ConnectorPlatform } from '@logto/schemas'; import { conditionalString } from '@silverhand/essentials'; -import { useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import * as styles from '@/Layout/AppLayout/index.module.scss'; -import type { Context } from '@/hooks/use-page-context'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import initI18n from '@/i18n/init'; import { changeLanguage } from '@/i18n/utils'; -import type { SignInExperienceResponse, PreviewConfig } from '@/types'; +import type { PreviewConfig, SignInExperienceResponse } from '@/types'; import { filterPreviewSocialConnectors } from '@/utils/social-connectors'; -const usePreview = (context: Context): [boolean, PreviewConfig?] => { +const PreviewProvider = () => { const [previewConfig, setPreviewConfig] = useState(); - const { isPreview, setExperienceSettings, setPlatform, setTheme } = context; + const { setTheme, setPlatform, setExperienceSettings } = useContext(PageContext); + // Fetch the preview config useEffect(() => { - if (!isPreview) { - return; - } - // Init i18n const i18nInit = initI18n(); // Block pointer event document.body.classList.add(conditionalString(styles.preview)); + // Listen to the message from the ancestor window const previewMessageHandler = async (event: MessageEvent) => { - // TODO: @simeng: we can check allowed origins via `/.well-known/endpoints` - // if (event.origin !== window.location.origin) { - // return; - // } - + // #event.data should be guarded at the provider's side if (event.data.sender === 'ac_preview') { - // #event.data should be guarded at the provider's side + // Wait for i18n to be initialized await i18nInit; // eslint-disable-next-line no-restricted-syntax @@ -44,17 +38,16 @@ const usePreview = (context: Context): [boolean, PreviewConfig?] => { return () => { window.removeEventListener('message', previewMessageHandler); }; - }, [isPreview]); + }, []); + // Set Experience settings useEffect(() => { - if (!isPreview || !previewConfig) { + if (!previewConfig) { return; } const { signInExperience: { socialConnectors, ...rest }, - mode, - platform, isNative, } = previewConfig; @@ -66,26 +59,33 @@ const usePreview = (context: Context): [boolean, PreviewConfig?] => { ), }; - (async () => { - setTheme(mode); - - setPlatform(platform); - - setExperienceSettings(experienceSettings); - })(); - }, [isPreview, previewConfig, setExperienceSettings, setPlatform, setTheme]); + setExperienceSettings(experienceSettings); + }, [previewConfig, setExperienceSettings]); + // Set Theme useEffect(() => { - if (!isPreview || !previewConfig?.language) { - return; + if (previewConfig?.mode) { + setTheme(previewConfig.mode); } + }, [previewConfig?.mode, setTheme]); - (async () => { - await changeLanguage(previewConfig.language); - })(); - }, [previewConfig?.language, isPreview]); + // Set Platform + useEffect(() => { + if (previewConfig?.platform) { + setPlatform(previewConfig.platform); + } + }, [previewConfig?.platform, setPlatform]); - return [isPreview, previewConfig]; + // Set Language + useEffect(() => { + if (previewConfig?.language) { + (async () => { + await changeLanguage(previewConfig.language); + })(); + } + }, [previewConfig?.language]); + + return null; }; -export default usePreview; +export default PreviewProvider; diff --git a/packages/ui/src/Providers/SettingsProvider/index.tsx b/packages/ui/src/Providers/SettingsProvider/index.tsx new file mode 100644 index 000000000..d9b8d867a --- /dev/null +++ b/packages/ui/src/Providers/SettingsProvider/index.tsx @@ -0,0 +1,23 @@ +import { useContext } from 'react'; + +import PageContext from '@/Providers/PageContextProvider/PageContext'; + +import PreviewProvider from '../PreviewProvider'; +import SignInExperienceProvider from '../SignInExperienceProvider'; + +type Props = { + children: React.ReactElement; +}; + +const SettingsProvider = ({ children }: Props) => { + const { isPreview, experienceSettings } = useContext(PageContext); + + return ( + <> + {isPreview ? : } + {experienceSettings ? children : null} + + ); +}; + +export default SettingsProvider; diff --git a/packages/ui/src/Providers/SignInExperienceProvider/index.tsx b/packages/ui/src/Providers/SignInExperienceProvider/index.tsx new file mode 100644 index 000000000..015f6659f --- /dev/null +++ b/packages/ui/src/Providers/SignInExperienceProvider/index.tsx @@ -0,0 +1,22 @@ +import { useContext, useEffect } from 'react'; + +import PageContext from '@/Providers/PageContextProvider/PageContext'; +import initI18n from '@/i18n/init'; +import { getSignInExperienceSettings } from '@/utils/sign-in-experience'; + +const SignInExperienceProvider = () => { + const { isPreview, setExperienceSettings } = useContext(PageContext); + + useEffect(() => { + (async () => { + const [settings] = await Promise.all([getSignInExperienceSettings(), initI18n()]); + + // Init the page settings and render + setExperienceSettings(settings); + })(); + }, [isPreview, setExperienceSettings]); + + return null; +}; + +export default SignInExperienceProvider; diff --git a/packages/ui/src/Providers/ToastProvider/index.tsx b/packages/ui/src/Providers/ToastProvider/index.tsx index 34fce7f1e..7a62977db 100644 --- a/packages/ui/src/Providers/ToastProvider/index.tsx +++ b/packages/ui/src/Providers/ToastProvider/index.tsx @@ -1,8 +1,8 @@ import type { ReactNode } from 'react'; import { useCallback, useContext } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import Toast from '@/components/Toast'; -import { PageContext } from '@/hooks/use-page-context'; type Props = { children: ReactNode; diff --git a/packages/ui/src/__mocks__/RenderWithPageContext/ContextProvider.tsx b/packages/ui/src/__mocks__/RenderWithPageContext/ContextProvider.tsx deleted file mode 100644 index 913de6140..000000000 --- a/packages/ui/src/__mocks__/RenderWithPageContext/ContextProvider.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import usePageContext from '@/hooks/use-page-context'; - -const ContextProvider = ({ children }: { children: React.ReactNode }) => { - const { context, Provider } = usePageContext(); - - return {children}; -}; - -export default ContextProvider; diff --git a/packages/ui/src/__mocks__/RenderWithPageContext/SettingsProvider.tsx b/packages/ui/src/__mocks__/RenderWithPageContext/SettingsProvider.tsx index 2a73e01d9..37d875c74 100644 --- a/packages/ui/src/__mocks__/RenderWithPageContext/SettingsProvider.tsx +++ b/packages/ui/src/__mocks__/RenderWithPageContext/SettingsProvider.tsx @@ -1,7 +1,7 @@ import type { ReactElement } from 'react'; import { useContext, useEffect } from 'react'; -import { PageContext } from '@/hooks/use-page-context'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import type { SignInExperienceResponse } from '@/types'; import { mockSignInExperienceSettings } from '../logto'; diff --git a/packages/ui/src/__mocks__/RenderWithPageContext/index.tsx b/packages/ui/src/__mocks__/RenderWithPageContext/index.tsx index fdec9cdba..a3a3e53df 100644 --- a/packages/ui/src/__mocks__/RenderWithPageContext/index.tsx +++ b/packages/ui/src/__mocks__/RenderWithPageContext/index.tsx @@ -1,15 +1,24 @@ import type { Queries, queries, RenderOptions } from '@testing-library/react'; import { render } from '@testing-library/react'; import type { ReactElement } from 'react'; +import { MemoryRouter } from 'react-router-dom'; -import ContextProvider from './ContextProvider'; +import PageContextProvider from '@/Providers/PageContextProvider'; const renderWithPageContext = < Q extends Queries = typeof queries, Container extends Element | DocumentFragment = HTMLElement >( ui: ReactElement, + memoryRouterProps: Parameters[0] = {}, options: RenderOptions = {} -) => render({ui}, options); +) => { + return render( + + {ui} + , + options + ); +}; export default renderWithPageContext; diff --git a/packages/ui/src/components/LogtoSignature/index.tsx b/packages/ui/src/components/LogtoSignature/index.tsx index 7eb5b77e1..1dca2af16 100644 --- a/packages/ui/src/components/LogtoSignature/index.tsx +++ b/packages/ui/src/components/LogtoSignature/index.tsx @@ -1,10 +1,10 @@ import { Theme } from '@logto/schemas'; import { useContext } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import LogtoLogtoDark from '@/assets/icons/logto-logo-dark.svg'; import LogtoLogoLight from '@/assets/icons/logto-logo-light.svg'; import LogtoLogoShadow from '@/assets/icons/logto-logo-shadow.svg'; -import { PageContext } from '@/hooks/use-page-context'; import * as styles from './index.module.scss'; diff --git a/packages/ui/src/containers/SocialLanding/index.tsx b/packages/ui/src/containers/SocialLanding/index.tsx index abcba8d49..bf48b9413 100644 --- a/packages/ui/src/containers/SocialLanding/index.tsx +++ b/packages/ui/src/containers/SocialLanding/index.tsx @@ -2,8 +2,8 @@ import { Theme } from '@logto/schemas'; import classNames from 'classnames'; import { useContext } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import { LoadingIcon } from '@/components/LoadingLayer'; -import { PageContext } from '@/hooks/use-page-context'; import * as styles from './index.module.scss'; diff --git a/packages/ui/src/containers/SocialSignInList/index.test.tsx b/packages/ui/src/containers/SocialSignInList/index.test.tsx index 1c4df09ab..4e3b8a83d 100644 --- a/packages/ui/src/containers/SocialSignInList/index.test.tsx +++ b/packages/ui/src/containers/SocialSignInList/index.test.tsx @@ -1,5 +1,3 @@ -import { MemoryRouter } from 'react-router-dom'; - import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; import { socialConnectors } from '@/__mocks__/logto'; @@ -10,9 +8,7 @@ describe('SocialSignInList', () => { it('Display connectors', () => { const { container } = renderWithPageContext( - - - + ); expect(container.querySelectorAll('button')).toHaveLength(socialConnectors.length); diff --git a/packages/ui/src/containers/TermsAndPrivacy/TermsAndPrivacyConfirmModalContent/index.tsx b/packages/ui/src/containers/TermsAndPrivacy/TermsAndPrivacyConfirmModalContent/index.tsx index 1933196c8..044cbc7ef 100644 --- a/packages/ui/src/containers/TermsAndPrivacy/TermsAndPrivacyConfirmModalContent/index.tsx +++ b/packages/ui/src/containers/TermsAndPrivacy/TermsAndPrivacyConfirmModalContent/index.tsx @@ -2,9 +2,9 @@ import { conditional } from '@silverhand/essentials'; import { useContext } from 'react'; import { useTranslation, Trans } from 'react-i18next'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import TermsLinks from '@/components/TermsLinks'; import type { ModalContentRenderProps } from '@/hooks/use-confirm-modal'; -import { PageContext } from '@/hooks/use-page-context'; const TermsAndPrivacyConfirmModalContent = ({ cancel }: ModalContentRenderProps) => { const { experienceSettings } = useContext(PageContext); diff --git a/packages/ui/src/containers/VerificationCode/index.test.tsx b/packages/ui/src/containers/VerificationCode/index.test.tsx index 01c76b6a2..2391595da 100644 --- a/packages/ui/src/containers/VerificationCode/index.test.tsx +++ b/packages/ui/src/containers/VerificationCode/index.test.tsx @@ -1,6 +1,5 @@ import { SignInIdentifier } from '@logto/schemas'; import { act, fireEvent, waitFor } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import { @@ -288,13 +287,11 @@ describe('', () => { })); const { container } = renderWithPageContext( - - - + ); const inputs = container.querySelectorAll('input'); @@ -323,13 +320,11 @@ describe('', () => { })); const { container } = renderWithPageContext( - - - + ); const inputs = container.querySelectorAll('input'); diff --git a/packages/ui/src/containers/VerificationCode/use-resend-verification-code.ts b/packages/ui/src/containers/VerificationCode/use-resend-verification-code.ts index 4bfc655d1..b493f0089 100644 --- a/packages/ui/src/containers/VerificationCode/use-resend-verification-code.ts +++ b/packages/ui/src/containers/VerificationCode/use-resend-verification-code.ts @@ -1,12 +1,12 @@ import { SignInIdentifier } from '@logto/schemas'; import { t } from 'i18next'; -import { useCallback, useContext } from 'react'; +import { useCallback } from 'react'; import { useTimer } from 'react-timer-hook'; import { sendVerificationCodeApi } from '@/apis/utils'; import useApi from '@/hooks/use-api'; import useErrorHandler from '@/hooks/use-error-handler'; -import { PageContext } from '@/hooks/use-page-context'; +import useToast from '@/hooks/use-toast'; import type { UserFlow } from '@/types'; export const timeRange = 59; @@ -23,7 +23,7 @@ const useResendVerificationCode = ( method: SignInIdentifier.Email | SignInIdentifier.Phone, target: string ) => { - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const { seconds, isRunning, restart } = useTimer({ autoStart: true, diff --git a/packages/ui/src/hooks/use-api.ts b/packages/ui/src/hooks/use-api.ts index 0dcc60154..b97000eee 100644 --- a/packages/ui/src/hooks/use-api.ts +++ b/packages/ui/src/hooks/use-api.ts @@ -1,7 +1,7 @@ import type { Nullable } from '@silverhand/essentials'; import { useCallback, useContext } from 'react'; -import { PageContext } from '@/hooks/use-page-context'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; const useApi = (api: (...args: Args) => Promise) => { const { setLoading } = useContext(PageContext); diff --git a/packages/ui/src/hooks/use-error-handler.ts b/packages/ui/src/hooks/use-error-handler.ts index de46d31f7..6a1ac05ee 100644 --- a/packages/ui/src/hooks/use-error-handler.ts +++ b/packages/ui/src/hooks/use-error-handler.ts @@ -1,10 +1,10 @@ import type { LogtoErrorCode } from '@logto/phrases'; import type { RequestErrorBody } from '@logto/schemas'; import { HTTPError, TimeoutError } from 'ky'; -import { useCallback, useContext } from 'react'; +import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { PageContext } from '@/hooks/use-page-context'; +import useToast from './use-toast'; export type ErrorHandlers = { [key in LogtoErrorCode]?: (error: RequestErrorBody) => void | Promise; @@ -15,7 +15,7 @@ export type ErrorHandlers = { const useErrorHandler = () => { const { t } = useTranslation(); - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const handleError = useCallback( async (error: unknown, errorHandlers?: ErrorHandlers) => { diff --git a/packages/ui/src/hooks/use-native-message-listener.ts b/packages/ui/src/hooks/use-native-message-listener.ts index 66671b977..5ee897b58 100644 --- a/packages/ui/src/hooks/use-native-message-listener.ts +++ b/packages/ui/src/hooks/use-native-message-listener.ts @@ -1,11 +1,11 @@ -import { useEffect, useContext } from 'react'; +import { useEffect } from 'react'; import { isNativeWebview } from '@/utils/native-sdk'; -import { PageContext } from './use-page-context'; +import useToast from './use-toast'; const useNativeMessageListener = () => { - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); // Monitor Native Error Message useEffect(() => { diff --git a/packages/ui/src/hooks/use-page-context.ts b/packages/ui/src/hooks/use-page-context.ts deleted file mode 100644 index 30141a36c..000000000 --- a/packages/ui/src/hooks/use-page-context.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Theme } from '@logto/schemas'; -import { noop } from '@silverhand/essentials'; -import { useState, useMemo, createContext } from 'react'; -import { isMobile } from 'react-device-detect'; - -import type { SignInExperienceResponse, Platform } from '@/types'; -import { parseQueryParameters } from '@/utils'; - -export type Context = { - theme: Theme; - toast: string; - loading: boolean; - platform: Platform; - termsAgreement: boolean; - experienceSettings: SignInExperienceResponse | undefined; - isPreview: boolean; - setTheme: React.Dispatch>; - setToast: React.Dispatch>; - setLoading: React.Dispatch>; - setPlatform: React.Dispatch>; - setTermsAgreement: React.Dispatch>; - setExperienceSettings: React.Dispatch>; -}; - -export const PageContext = createContext({ - toast: '', - theme: Theme.Light, - loading: false, - platform: isMobile ? 'mobile' : 'web', - termsAgreement: false, - experienceSettings: undefined, - isPreview: false, - setTheme: noop, - setToast: noop, - setLoading: noop, - setPlatform: noop, - setTermsAgreement: noop, - setExperienceSettings: noop, -}); - -const usePageContext = () => { - const [loading, setLoading] = useState(false); - const [toast, setToast] = useState(''); - const [theme, setTheme] = useState(Theme.Light); - const [platform, setPlatform] = useState(isMobile ? 'mobile' : 'web'); - const [experienceSettings, setExperienceSettings] = useState(); - const [termsAgreement, setTermsAgreement] = useState(false); - - const { preview } = parseQueryParameters(window.location.search); - const isPreview = preview === 'true'; - - const context = useMemo( - () => ({ - theme, - toast, - loading, - platform, - termsAgreement, - experienceSettings, - isPreview, - setTheme, - setLoading, - setToast, - setPlatform, - setTermsAgreement, - setExperienceSettings, - }), - [experienceSettings, isPreview, loading, platform, termsAgreement, theme, toast] - ); - - return { - context, - Provider: PageContext.Provider, - }; -}; - -export default usePageContext; diff --git a/packages/ui/src/hooks/use-platform.ts b/packages/ui/src/hooks/use-platform.ts index 33c95f828..b759ac9d4 100644 --- a/packages/ui/src/hooks/use-platform.ts +++ b/packages/ui/src/hooks/use-platform.ts @@ -1,6 +1,6 @@ import { useContext } from 'react'; -import { PageContext } from './use-page-context'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; const usePlatform = () => { const { platform } = useContext(PageContext); diff --git a/packages/ui/src/hooks/use-required-profile-error-handler.ts b/packages/ui/src/hooks/use-required-profile-error-handler.ts index 38f5e4a8f..0f79285bb 100644 --- a/packages/ui/src/hooks/use-required-profile-error-handler.ts +++ b/packages/ui/src/hooks/use-required-profile-error-handler.ts @@ -1,5 +1,5 @@ import { MissingProfile } from '@logto/schemas'; -import { useMemo, useContext } from 'react'; +import { useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { validate } from 'superstruct'; @@ -8,7 +8,7 @@ import { missingProfileErrorDataGuard } from '@/types/guard'; import { queryStringify } from '@/utils'; import type { ErrorHandlers } from './use-error-handler'; -import { PageContext } from './use-page-context'; +import useToast from './use-toast'; type Options = { replace?: boolean; @@ -17,7 +17,7 @@ type Options = { const useRequiredProfileErrorHandler = ({ replace, linkSocial }: Options = {}) => { const navigate = useNavigate(); - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const requiredProfileErrorHandler = useMemo( () => ({ diff --git a/packages/ui/src/hooks/use-sie.ts b/packages/ui/src/hooks/use-sie.ts index 56df2b9ab..05f1f9682 100644 --- a/packages/ui/src/hooks/use-sie.ts +++ b/packages/ui/src/hooks/use-sie.ts @@ -1,10 +1,9 @@ import { SignInIdentifier } from '@logto/schemas'; import { useContext } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import type { VerificationCodeIdentifier } from '@/types'; -import { PageContext } from './use-page-context'; - export const useSieMethods = () => { const { experienceSettings } = useContext(PageContext); const { identifiers, password, verify } = experienceSettings?.signUp ?? {}; @@ -20,7 +19,6 @@ export const useSieMethods = () => { socialConnectors: experienceSettings?.socialConnectors ?? [], signInMode: experienceSettings?.signInMode, forgotPassword: experienceSettings?.forgotPassword, - customCss: experienceSettings?.customCss, customContent: experienceSettings?.customContent, }; }; diff --git a/packages/ui/src/hooks/use-social-landing-handler.ts b/packages/ui/src/hooks/use-social-landing-handler.ts index 96a6026e1..fff8ad48b 100644 --- a/packages/ui/src/hooks/use-social-landing-handler.ts +++ b/packages/ui/src/hooks/use-social-landing-handler.ts @@ -1,15 +1,15 @@ -import { useContext, useState, useCallback } from 'react'; +import { useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { SearchParameters } from '@/types'; import { getSearchParameters } from '@/utils'; import { storeCallbackLink } from '@/utils/social-connectors'; -import { PageContext } from './use-page-context'; +import useToast from './use-toast'; const useSocialLandingHandler = () => { const [loading, setLoading] = useState(true); - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const { t } = useTranslation(); const { search } = window.location; diff --git a/packages/ui/src/hooks/use-social-sign-in-listener.ts b/packages/ui/src/hooks/use-social-sign-in-listener.ts index 288d64510..cfd4dd93c 100644 --- a/packages/ui/src/hooks/use-social-sign-in-listener.ts +++ b/packages/ui/src/hooks/use-social-sign-in-listener.ts @@ -1,6 +1,6 @@ import type { RequestErrorBody } from '@logto/schemas'; import { SignInMode } from '@logto/schemas'; -import { useEffect, useCallback, useContext, useMemo, useState } from 'react'; +import { useEffect, useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { validate } from 'superstruct'; @@ -13,14 +13,14 @@ import { stateValidation } from '@/utils/social-connectors'; import useApi from './use-api'; import useErrorHandler from './use-error-handler'; import type { ErrorHandlers } from './use-error-handler'; -import { PageContext } from './use-page-context'; import useRequiredProfileErrorHandler from './use-required-profile-error-handler'; import { useSieMethods } from './use-sie'; import useSocialRegister from './use-social-register'; import useTerms from './use-terms'; +import useToast from './use-toast'; const useSocialSignInListener = (connectorId?: string) => { - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const { signInMode } = useSieMethods(); const { t } = useTranslation(); const { termsValidation } = useTerms(); diff --git a/packages/ui/src/hooks/use-social.ts b/packages/ui/src/hooks/use-social.ts index 414e2c56d..6ec0383eb 100644 --- a/packages/ui/src/hooks/use-social.ts +++ b/packages/ui/src/hooks/use-social.ts @@ -1,13 +1,13 @@ import type { ConnectorMetadata } from '@logto/schemas'; import { useCallback, useContext } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import { getSocialAuthorizationUrl } from '@/apis/interaction'; import { getLogtoNativeSdk, isNativeWebview } from '@/utils/native-sdk'; import { generateState, storeState, buildSocialLandingUri } from '@/utils/social-connectors'; import useApi from './use-api'; import useErrorHandler from './use-error-handler'; -import { PageContext } from './use-page-context'; const useSocial = () => { const { experienceSettings, theme } = useContext(PageContext); diff --git a/packages/ui/src/hooks/use-terms.ts b/packages/ui/src/hooks/use-terms.ts index de81c7b1c..f250a945c 100644 --- a/packages/ui/src/hooks/use-terms.ts +++ b/packages/ui/src/hooks/use-terms.ts @@ -1,10 +1,10 @@ import { conditional } from '@silverhand/essentials'; import { useContext, useCallback, useMemo } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import TermsAndPrivacyConfirmModalContent from '@/containers/TermsAndPrivacy/TermsAndPrivacyConfirmModalContent'; import { useConfirmModal } from './use-confirm-modal'; -import { PageContext } from './use-page-context'; const useTerms = () => { const { termsAgreement, setTermsAgreement, experienceSettings } = useContext(PageContext); diff --git a/packages/ui/src/hooks/use-toast.ts b/packages/ui/src/hooks/use-toast.ts new file mode 100644 index 000000000..f8d73e3e4 --- /dev/null +++ b/packages/ui/src/hooks/use-toast.ts @@ -0,0 +1,11 @@ +import { useContext } from 'react'; + +import PageContext from '@/Providers/PageContextProvider/PageContext'; + +const useToast = () => { + const { toast, setToast } = useContext(PageContext); + + return { toast, setToast }; +}; + +export default useToast; diff --git a/packages/ui/src/pages/Consent/index.tsx b/packages/ui/src/pages/Consent/index.tsx index 588e3ccea..67274f7d9 100644 --- a/packages/ui/src/pages/Consent/index.tsx +++ b/packages/ui/src/pages/Consent/index.tsx @@ -1,11 +1,11 @@ import { conditional } from '@silverhand/essentials'; import { useEffect, useContext, useState } from 'react'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import { consent } from '@/apis/consent'; import { LoadingIcon } from '@/components/LoadingLayer'; import useApi from '@/hooks/use-api'; import useErrorHandler from '@/hooks/use-error-handler'; -import { PageContext } from '@/hooks/use-page-context'; import { getBrandingLogoUrl } from '@/utils/logo'; import * as styles from './index.module.scss'; diff --git a/packages/ui/src/pages/ErrorPage/index.tsx b/packages/ui/src/pages/ErrorPage/index.tsx index a375d3b96..894b667fb 100644 --- a/packages/ui/src/pages/ErrorPage/index.tsx +++ b/packages/ui/src/pages/ErrorPage/index.tsx @@ -4,10 +4,10 @@ import type { TFuncKey } from 'react-i18next'; import { useTranslation } from 'react-i18next'; import StaticPageLayout from '@/Layout/StaticPageLayout'; +import PageContext from '@/Providers/PageContextProvider/PageContext'; import EmptyStateDark from '@/assets/icons/empty-state-dark.svg'; import EmptyState from '@/assets/icons/empty-state.svg'; import NavBar from '@/components/NavBar'; -import { PageContext } from '@/hooks/use-page-context'; import * as styles from './index.module.scss'; diff --git a/packages/ui/src/pages/ForgotPassword/ForgotPasswordForm/index.test.tsx b/packages/ui/src/pages/ForgotPassword/ForgotPasswordForm/index.test.tsx index 515af9f34..aaedc015b 100644 --- a/packages/ui/src/pages/ForgotPassword/ForgotPasswordForm/index.test.tsx +++ b/packages/ui/src/pages/ForgotPassword/ForgotPasswordForm/index.test.tsx @@ -1,7 +1,6 @@ import { InteractionEvent, SignInIdentifier } from '@logto/schemas'; import { assert } from '@silverhand/essentials'; import { act, fireEvent, waitFor } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import { putInteraction, sendVerificationCode } from '@/apis/interaction'; @@ -33,13 +32,11 @@ describe('ForgotPasswordForm', () => { const renderForm = (defaultType: VerificationCodeIdentifier, defaultValue?: string) => renderWithPageContext( - - - + ); describe.each([ diff --git a/packages/ui/src/pages/ForgotPassword/index.test.tsx b/packages/ui/src/pages/ForgotPassword/index.test.tsx index 4033d8427..f784d51bd 100644 --- a/packages/ui/src/pages/ForgotPassword/index.test.tsx +++ b/packages/ui/src/pages/ForgotPassword/index.test.tsx @@ -1,7 +1,7 @@ import { SignInIdentifier } from '@logto/schemas'; import { Globals } from '@react-spring/web'; import { assert } from '@silverhand/essentials'; -import { MemoryRouter, useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -24,19 +24,17 @@ jest.mock('react-router-dom', () => ({ describe('ForgotPassword', () => { const renderPage = (settings?: SignInExperienceResponse['forgotPassword']) => renderWithPageContext( - - - - - + + + ); beforeAll(() => { diff --git a/packages/ui/src/pages/Register/index.test.tsx b/packages/ui/src/pages/Register/index.test.tsx index 7e231ccc9..275bee3b0 100644 --- a/packages/ui/src/pages/Register/index.test.tsx +++ b/packages/ui/src/pages/Register/index.test.tsx @@ -1,6 +1,6 @@ import type { SignUp } from '@logto/schemas'; import { SignInMode, SignInIdentifier } from '@logto/schemas'; -import { MemoryRouter } from 'react-router-dom'; +import { Route, Routes } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -17,9 +17,7 @@ describe('', () => { const renderRegisterPage = (settings?: Partial) => renderWithPageContext( - - - + ); @@ -59,8 +57,20 @@ describe('', () => { expect(queryByText('action.create_account')).toBeNull(); }); - test('render with sign-in only mode should return ErrorPage', () => { - const { queryByText } = renderRegisterPage({ signInMode: SignInMode.SignIn }); - expect(queryByText('description.not_found')).not.toBeNull(); + test('render with sign-in only mode should should redirect to the SignIn page', () => { + const { queryByText } = renderWithPageContext( + + + sign-in} /> + } /> + + , + { + initialEntries: ['/register'], + } + ); + expect(queryByText('sign-in')).not.toBeNull(); }); }); diff --git a/packages/ui/src/pages/Register/index.tsx b/packages/ui/src/pages/Register/index.tsx index 9e21665ae..6ccfd1235 100644 --- a/packages/ui/src/pages/Register/index.tsx +++ b/packages/ui/src/pages/Register/index.tsx @@ -1,5 +1,6 @@ import { SignInMode } from '@logto/schemas'; import { useTranslation } from 'react-i18next'; +import { Navigate } from 'react-router-dom'; import LandingPageLayout from '@/Layout/LandingPageLayout'; import Divider from '@/components/Divider'; @@ -17,10 +18,14 @@ const Register = () => { const { signUpMethods, socialConnectors, signInMode, signInMethods } = useSieMethods(); const { t } = useTranslation(); - if (!signInMode || signInMode === SignInMode.SignIn) { + if (!signInMode) { return ; } + if (signInMode === SignInMode.SignIn) { + return ; + } + return ( {signUpMethods.length > 0 && ( diff --git a/packages/ui/src/pages/ResetPassword/index.test.tsx b/packages/ui/src/pages/ResetPassword/index.test.tsx index 5305b0ab9..d73b0737d 100644 --- a/packages/ui/src/pages/ResetPassword/index.test.tsx +++ b/packages/ui/src/pages/ResetPassword/index.test.tsx @@ -1,5 +1,5 @@ import { act, waitFor, fireEvent } from '@testing-library/react'; -import { MemoryRouter, Routes, Route } from 'react-router-dom'; +import { Routes, Route } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import { setUserPassword } from '@/apis/interaction'; @@ -20,11 +20,10 @@ jest.mock('@/apis/interaction', () => ({ describe('ForgotPassword', () => { it('render forgot-password page properly', () => { const { queryByText, container } = renderWithPageContext( - - - } /> - - + + } /> + , + { initialEntries: ['/forgot-password'] } ); expect(container.querySelector('input[name="newPassword"]')).not.toBeNull(); diff --git a/packages/ui/src/pages/ResetPassword/use-reset-password.ts b/packages/ui/src/pages/ResetPassword/use-reset-password.ts index db754f8be..b9cf6bca7 100644 --- a/packages/ui/src/pages/ResetPassword/use-reset-password.ts +++ b/packages/ui/src/pages/ResetPassword/use-reset-password.ts @@ -1,4 +1,4 @@ -import { useMemo, useState, useContext, useCallback } from 'react'; +import { useMemo, useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -7,12 +7,12 @@ import useApi from '@/hooks/use-api'; import { useConfirmModal } from '@/hooks/use-confirm-modal'; import useErrorHandler from '@/hooks/use-error-handler'; import type { ErrorHandlers } from '@/hooks/use-error-handler'; -import { PageContext } from '@/hooks/use-page-context'; +import useToast from '@/hooks/use-toast'; const useResetPassword = () => { const { t } = useTranslation(); const navigate = useNavigate(); - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const { show } = useConfirmModal(); const [errorMessage, setErrorMessage] = useState(); diff --git a/packages/ui/src/pages/SignIn/IdentifierSignInForm/index.test.tsx b/packages/ui/src/pages/SignIn/IdentifierSignInForm/index.test.tsx index 268bf9f4d..c6cbe75d1 100644 --- a/packages/ui/src/pages/SignIn/IdentifierSignInForm/index.test.tsx +++ b/packages/ui/src/pages/SignIn/IdentifierSignInForm/index.test.tsx @@ -2,7 +2,6 @@ import type { SignIn } from '@logto/schemas'; import { SignInIdentifier } from '@logto/schemas'; import { assert } from '@silverhand/essentials'; import { fireEvent, act, waitFor } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import { mockSignInMethodSettingsTestCases } from '@/__mocks__/logto'; @@ -34,11 +33,7 @@ const email = 'foo@email.com'; const phone = '8573333333'; const renderForm = (signInMethods: SignIn['methods']) => - renderWithPageContext( - - - - ); + renderWithPageContext(); describe('IdentifierSignInForm', () => { afterEach(() => { diff --git a/packages/ui/src/pages/SignIn/PasswordSignInForm/index.test.tsx b/packages/ui/src/pages/SignIn/PasswordSignInForm/index.test.tsx index e6a0ba862..3fb6dccd1 100644 --- a/packages/ui/src/pages/SignIn/PasswordSignInForm/index.test.tsx +++ b/packages/ui/src/pages/SignIn/PasswordSignInForm/index.test.tsx @@ -2,7 +2,6 @@ import { SignInIdentifier } from '@logto/schemas'; import { assert } from '@silverhand/essentials'; import { fireEvent, waitFor } from '@testing-library/react'; import { act } from 'react-dom/test-utils'; -import { MemoryRouter } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -35,9 +34,7 @@ describe('UsernamePasswordSignInForm', () => { ) => renderWithPageContext( - - - + ); diff --git a/packages/ui/src/pages/SignIn/index.test.tsx b/packages/ui/src/pages/SignIn/index.test.tsx index 1783ad0c8..72148b302 100644 --- a/packages/ui/src/pages/SignIn/index.test.tsx +++ b/packages/ui/src/pages/SignIn/index.test.tsx @@ -1,5 +1,5 @@ import { SignInIdentifier, SignInMode } from '@logto/schemas'; -import { MemoryRouter } from 'react-router-dom'; +import { Route, Routes } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -11,13 +11,16 @@ jest.mock('i18next', () => ({ language: 'en', })); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useNavigate: () => jest.fn(), +})); + describe('', () => { const renderSignIn = (settings?: Partial) => renderWithPageContext( - - - + ); @@ -76,9 +79,7 @@ describe('', () => { test('renders with social as primary', async () => { const { container, queryByText } = renderWithPageContext( - - - + ); @@ -90,17 +91,21 @@ describe('', () => { expect(queryByText('description.privacy_policy')).not.toBeNull(); }); - test('render with register only mode should return ErrorPage', () => { + test('render with register only mode should redirect to the Register page', () => { const { queryByText } = renderWithPageContext( - - - - + + } /> + Register} /> + + , + { + initialEntries: ['/sign-in'], + } ); - expect(queryByText('description.not_found')).not.toBeNull(); + expect(queryByText('Register')).not.toBeNull(); }); }); diff --git a/packages/ui/src/pages/SignIn/index.tsx b/packages/ui/src/pages/SignIn/index.tsx index e7d03e915..83b1ce764 100644 --- a/packages/ui/src/pages/SignIn/index.tsx +++ b/packages/ui/src/pages/SignIn/index.tsx @@ -1,5 +1,6 @@ import { SignInMode } from '@logto/schemas'; import { useTranslation } from 'react-i18next'; +import { Navigate } from 'react-router-dom'; import LandingPageLayout from '@/Layout/LandingPageLayout'; import Divider from '@/components/Divider'; @@ -17,10 +18,14 @@ const SignIn = () => { const { signInMethods, signUpMethods, socialConnectors, signInMode } = useSieMethods(); const { t } = useTranslation(); - if (!signInMode || signInMode === SignInMode.Register) { + if (!signInMode) { return ; } + if (signInMode === SignInMode.Register) { + return ; + } + return (
diff --git a/packages/ui/src/pages/SignInPassword/PasswordForm/VerificationCodeLink.tsx b/packages/ui/src/pages/SignInPassword/PasswordForm/VerificationCodeLink.tsx index 5891e8cda..ee4496051 100644 --- a/packages/ui/src/pages/SignInPassword/PasswordForm/VerificationCodeLink.tsx +++ b/packages/ui/src/pages/SignInPassword/PasswordForm/VerificationCodeLink.tsx @@ -1,9 +1,9 @@ -import { useContext, useEffect } from 'react'; +import { useEffect } from 'react'; import SwitchIcon from '@/assets/icons/switch-icon.svg'; import TextLink from '@/components/TextLink'; -import { PageContext } from '@/hooks/use-page-context'; import useSendVerificationCode from '@/hooks/use-send-verification-code'; +import useToast from '@/hooks/use-toast'; import type { VerificationCodeIdentifier } from '@/types'; import { UserFlow } from '@/types'; @@ -14,7 +14,7 @@ type Props = { }; const VerificationCodeLink = ({ className, identifier, value }: Props) => { - const { setToast } = useContext(PageContext); + const { setToast } = useToast(); const { errorMessage, clearErrorMessage, onSubmit } = useSendVerificationCode( UserFlow.signIn, diff --git a/packages/ui/src/pages/SignInPassword/index.test.tsx b/packages/ui/src/pages/SignInPassword/index.test.tsx index 47012af52..bdf35e2b7 100644 --- a/packages/ui/src/pages/SignInPassword/index.test.tsx +++ b/packages/ui/src/pages/SignInPassword/index.test.tsx @@ -1,5 +1,5 @@ import { SignInIdentifier } from '@logto/schemas'; -import { MemoryRouter, useLocation } from 'react-router-dom'; +import { useLocation } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -20,16 +20,14 @@ describe('SignInPassword', () => { const renderPasswordSignInPage = (settings?: Partial) => renderWithPageContext( - - - - - + + + ); beforeEach(() => { diff --git a/packages/ui/src/pages/SocialLanding/index.test.tsx b/packages/ui/src/pages/SocialLanding/index.test.tsx index 08db5fbec..1da04cc47 100644 --- a/packages/ui/src/pages/SocialLanding/index.test.tsx +++ b/packages/ui/src/pages/SocialLanding/index.test.tsx @@ -1,5 +1,5 @@ import { waitFor } from '@testing-library/react'; -import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { Route, Routes } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -31,12 +31,11 @@ describe(`SocialLanding Page`, () => { renderWithPageContext( - - - } /> - - - + + } /> + + , + { initialEntries: ['/social/landing/github'] } ); await waitFor(() => { diff --git a/packages/ui/src/pages/SocialLinkAccount/index.test.tsx b/packages/ui/src/pages/SocialLinkAccount/index.test.tsx index 3702a33dd..725ee6268 100644 --- a/packages/ui/src/pages/SocialLinkAccount/index.test.tsx +++ b/packages/ui/src/pages/SocialLinkAccount/index.test.tsx @@ -1,5 +1,5 @@ import { SignInIdentifier } from '@logto/schemas'; -import { MemoryRouter, Route, Routes } from 'react-router-dom'; +import { Route, Routes } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -18,12 +18,11 @@ describe('SocialRegister', () => { it('render', () => { const { queryByText } = renderWithPageContext( - - - } /> - - - + + } /> + + , + { initialEntries: ['/social/link/github'] } ); expect(queryByText('description.bind_account_title')).not.toBeNull(); expect(queryByText('description.social_create_account')).not.toBeNull(); @@ -41,12 +40,11 @@ describe('SocialRegister', () => { }, }} > - - - } /> - - - + + } /> + + , + { initialEntries: ['/social/link/github'] } ); expect(queryByText('description.link_email')).not.toBeNull(); expect(queryByText('description.social_link_email')).not.toBeNull(); @@ -64,12 +62,11 @@ describe('SocialRegister', () => { }, }} > - - - } /> - - - + + } /> + + , + { initialEntries: ['/social/link/github'] } ); expect(queryByText('description.link_phone')).not.toBeNull(); expect(queryByText('description.social_link_phone')).not.toBeNull(); @@ -87,12 +84,11 @@ describe('SocialRegister', () => { }, }} > - - - } /> - - - + + } /> + + , + { initialEntries: ['/social/link/github'] } ); expect(queryByText('description.link_email_or_phone')).not.toBeNull(); expect(queryByText('description.social_link_email_or_phone')).not.toBeNull(); diff --git a/packages/ui/src/pages/SocialSignInCallback/index.test.tsx b/packages/ui/src/pages/SocialSignInCallback/index.test.tsx index ac8902b27..39c6a6653 100644 --- a/packages/ui/src/pages/SocialSignInCallback/index.test.tsx +++ b/packages/ui/src/pages/SocialSignInCallback/index.test.tsx @@ -1,5 +1,5 @@ import { waitFor } from '@testing-library/react'; -import { MemoryRouter, Route, Routes, useSearchParams } from 'react-router-dom'; +import { Route, Routes, useSearchParams } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -38,12 +38,11 @@ describe('SocialCallbackPage with code', () => { renderWithPageContext( - - - } /> - - - + + } /> + + , + { initialEntries: ['/sign-in/social/github'] } ); await waitFor(() => { diff --git a/packages/ui/src/pages/VerificationCode/index.test.tsx b/packages/ui/src/pages/VerificationCode/index.test.tsx index b29f56a5c..de8fb44e4 100644 --- a/packages/ui/src/pages/VerificationCode/index.test.tsx +++ b/packages/ui/src/pages/VerificationCode/index.test.tsx @@ -1,4 +1,4 @@ -import { Routes, Route, MemoryRouter } from 'react-router-dom'; +import { Routes, Route } from 'react-router-dom'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider'; @@ -15,13 +15,12 @@ jest.mock('react-router-dom', () => ({ describe('VerificationCode Page', () => { it('render properly', () => { const { queryByText } = renderWithPageContext( - - - - } /> - - - + + + } /> + + , + { initialEntries: ['/sign-in/verification-code'] } ); expect(queryByText('action.enter_passcode')).not.toBeNull(); @@ -30,11 +29,10 @@ describe('VerificationCode Page', () => { it('render with invalid flow', () => { const { queryByText } = renderWithPageContext( - - - } /> - - + + } /> + , + { initialEntries: ['/social/verification-code'] } ); expect(queryByText('action.enter_passcode')).toBeNull(); From 1c431e7a59f79559569af6464f71f6f09d13d769 Mon Sep 17 00:00:00 2001 From: simeng-li Date: Mon, 3 Apr 2023 10:24:50 +0800 Subject: [PATCH 07/11] feat(core): apply standard security headers 1/2 (#3590) * feat(core): add some basic security headers add some basic security headers * chore(core): add some comments add some comments * chore(core): update the refererPolicy configs update the refererPolicy configs * chore(core): update helmet middleware update helmet middleware * feat(core): add csp headers to the mainflow and ac http requests 2/2 (#3613) * feat(core): add csp headers to the mainflow requests add csp headers to the mainflow requests * chore(core): add ui and console security headers add ui and console security headers * fix(core): remove unused middleware remove unused middleware * fix(ui): set terms iframe sandbox set terms iframe sandbox allow same origin * fix(core): update security headers middleware update security headers middleware * chore(core): add changesets * chore(core): address rebase conflict address rebase conflict --- .changeset-staged/shiny-crabs-wink.md | 21 ++ .../ImageWithErrorFallback/index.tsx | 9 +- .../components/GithubRawImage/index.tsx | 1 + .../Uploader/ImageUploader/index.tsx | 2 +- packages/core/package.json | 1 + .../src/middleware/koa-security-headers.ts | 124 ++++++++++ packages/core/src/tenants/Tenant.ts | 4 + packages/shared/src/env/UrlSet.test.ts | 11 + packages/shared/src/env/UrlSet.ts | 4 + .../IframeModalProvider/IframeModal/index.tsx | 3 +- .../src/components/BrandingHeader/index.tsx | 2 +- .../components/Button/SocialLinkButton.tsx | 9 +- .../ui/src/containers/SocialLanding/index.tsx | 1 + packages/ui/src/pages/Consent/index.tsx | 4 +- pnpm-lock.yaml | 233 +++++++++++------- 15 files changed, 330 insertions(+), 99 deletions(-) create mode 100644 .changeset-staged/shiny-crabs-wink.md create mode 100644 packages/core/src/middleware/koa-security-headers.ts diff --git a/.changeset-staged/shiny-crabs-wink.md b/.changeset-staged/shiny-crabs-wink.md new file mode 100644 index 000000000..6f166ee6c --- /dev/null +++ b/.changeset-staged/shiny-crabs-wink.md @@ -0,0 +1,21 @@ +--- +"@logto/console": patch +"@logto/core": patch +"@logto/shared": patch +"@logto/ui": patch +--- + +Apply security headers + +Apply security headers to logto http request response using (helmetjs)[https://helmetjs.github.io/]. + +[x] crossOriginOpenerPolicy +[x] crossOriginEmbedderPolicy +[x] crossOriginResourcePolicy +[x] hidePoweredBy +[x] hsts +[x] ieNoOpen +[x] noSniff +[x] referrerPolicy +[x] xssFilter +[x] Content-Security-Policy diff --git a/packages/console/src/components/ImageWithErrorFallback/index.tsx b/packages/console/src/components/ImageWithErrorFallback/index.tsx index 9cd18b1a0..25f21a72b 100644 --- a/packages/console/src/components/ImageWithErrorFallback/index.tsx +++ b/packages/console/src/components/ImageWithErrorFallback/index.tsx @@ -39,7 +39,14 @@ function ImageWithErrorFallback({ return (
- {alt} + {alt}
); } diff --git a/packages/console/src/components/Markdown/components/GithubRawImage/index.tsx b/packages/console/src/components/Markdown/components/GithubRawImage/index.tsx index 08774860b..e1c42ed5f 100644 --- a/packages/console/src/components/Markdown/components/GithubRawImage/index.tsx +++ b/packages/console/src/components/Markdown/components/GithubRawImage/index.tsx @@ -27,6 +27,7 @@ function GithubRawImage({ src, alt }: HTMLProps) { src={`${githubRawUrlPrefix}${src}`} alt={alt} width={`${width}px`} + crossOrigin="anonymous" onLoad={onLoad} /> ); diff --git a/packages/console/src/components/Uploader/ImageUploader/index.tsx b/packages/console/src/components/Uploader/ImageUploader/index.tsx index 6d8d68c62..ed3533d85 100644 --- a/packages/console/src/components/Uploader/ImageUploader/index.tsx +++ b/packages/console/src/components/Uploader/ImageUploader/index.tsx @@ -26,7 +26,7 @@ export type Props = Omit & { function ImageUploader({ name, value, onDelete, ...rest }: Props) { return value ? (
- {name} + {name} { diff --git a/packages/core/package.json b/packages/core/package.json index 4af5da523..75b175649 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -56,6 +56,7 @@ "koa-body": "^5.0.0", "koa-compose": "^4.1.0", "koa-compress": "^5.1.0", + "koa-helmet": "^7.0.2", "koa-logger": "^3.2.1", "koa-mount": "^4.0.0", "koa-proxies": "^0.12.1", diff --git a/packages/core/src/middleware/koa-security-headers.ts b/packages/core/src/middleware/koa-security-headers.ts new file mode 100644 index 000000000..4e81b5578 --- /dev/null +++ b/packages/core/src/middleware/koa-security-headers.ts @@ -0,0 +1,124 @@ +import { defaultTenantId } from '@logto/schemas'; +import type { MiddlewareType } from 'koa'; +import helmet from 'koa-helmet'; + +import { EnvSet, AdminApps, getTenantEndpoint } from '#src/env-set/index.js'; + +/** + * Apply security headers to the response using koa-helmet + * @see https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html for recommended headers + * @see https://helmetjs.github.io/ for more details + * @returns koa middleware + */ + +export default function koaSecurityHeaders( + mountedApps: string[], + tenantId: string +): MiddlewareType { + type Middleware = MiddlewareType; + + type HelmetOptions = Parameters[0]; + + const { isProduction, isCloud, isMultiTenancy, adminUrlSet, cloudUrlSet } = EnvSet.values; + + const adminOrigins = adminUrlSet.origins; + const cloudOrigins = isCloud ? cloudUrlSet.origins : []; + const tenantEndpointOrigin = getTenantEndpoint( + isMultiTenancy ? tenantId : defaultTenantId, + EnvSet.values + ).origin; + const developmentOrigins = isProduction ? [] : ['ws:']; + + /** + * Default Applied rules: + * - crossOriginOpenerPolicy: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#cross-origin-opener-policy-coop + * - crossOriginResourcePolicy: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#cross-origin-resource-policy-corp + * - crossOriginEmbedderPolicy: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#cross-origin-embedder-policy-coep + * - hidePoweredBy: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-powered-by + * - hsts: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#strict-transport-security-hsts + * - ieNoOpen: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-download-options + * - noSniff: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-content-type-options + * - permittedCrossDomainPolicies: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-permitted-cross-domain-policies + * - referrerPolicy: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#referrer-policy + * - xssFilter: https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-xss-protection + * - originAgentCluster: https://whatpr.org/html/6214/origin.html#origin-keyed-agent-clusters + */ + + const basicSecurityHeaderSettings: HelmetOptions = { + contentSecurityPolicy: false, // Exclusively set per app + expectCt: false, // Not recommended, will be deprecated by modern browsers + dnsPrefetchControl: false, + referrerPolicy: { + policy: 'strict-origin-when-cross-origin', + }, + }; + + const mainFlowUiSecurityHeaderSettings: HelmetOptions = { + ...basicSecurityHeaderSettings, + // WARNING: high risk Need to allow self hosted terms of use page loaded in an iframe + frameguard: false, + // Alow loaded by console preview iframe + crossOriginResourcePolicy: { + policy: 'cross-origin', + }, + contentSecurityPolicy: { + useDefaults: true, + // Temporary set to report only to avoid breaking the app + reportOnly: true, + directives: { + imgSrc: ["'self'", 'data:', 'https:'], + connectSrc: ["'self'", ...adminOrigins, ...cloudOrigins, ...developmentOrigins], + // WARNING: high risk Need to allow self hosted terms of use page loaded in an iframe + frameSrc: ["'self'", 'https:'], + // Alow loaded by console preview iframe + frameAncestors: ["'self'", ...adminOrigins, ...cloudOrigins], + }, + }, + }; + + const consoleSecurityHeaderSettings: HelmetOptions = { + ...basicSecurityHeaderSettings, + // Guarded by CSP header bellow + frameguard: false, + contentSecurityPolicy: { + useDefaults: true, + // Temporary set to report only to avoid breaking the app + reportOnly: true, + directives: { + imgSrc: ["'self'", 'data:', 'https:'], + connectSrc: [ + "'self'", + tenantEndpointOrigin, + ...adminOrigins, + ...cloudOrigins, + ...developmentOrigins, + ], + // Allow Main Flow origin loaded in preview iframe + frameSrc: ["'self'", tenantEndpointOrigin], + }, + }, + }; + + const buildHelmetMiddleware: (options: HelmetOptions) => Middleware = (options) => + helmet(options); + + return async (ctx, next) => { + const requestPath = ctx.request.path; + + // Admin Console + if ( + requestPath.startsWith(`/${AdminApps.Console}`) || + requestPath.startsWith(`/${AdminApps.Welcome}`) + ) { + return buildHelmetMiddleware(consoleSecurityHeaderSettings)(ctx, next); + } + + // Route has been handled by one of mounted apps + if (mountedApps.some((app) => app !== '' && requestPath.startsWith(`/${app}`))) { + return buildHelmetMiddleware(basicSecurityHeaderSettings)(ctx, next); + } + + // Main flow UI + return buildHelmetMiddleware(mainFlowUiSecurityHeaderSettings)(ctx, next); + }; +} diff --git a/packages/core/src/tenants/Tenant.ts b/packages/core/src/tenants/Tenant.ts index 07c55e098..c01edd0c8 100644 --- a/packages/core/src/tenants/Tenant.ts +++ b/packages/core/src/tenants/Tenant.ts @@ -14,6 +14,7 @@ import koaConsoleRedirectProxy from '#src/middleware/koa-console-redirect-proxy. import koaErrorHandler from '#src/middleware/koa-error-handler.js'; import koaI18next from '#src/middleware/koa-i18next.js'; import koaOIDCErrorHandler from '#src/middleware/koa-oidc-error-handler.js'; +import koaSecurityHeaders from '#src/middleware/koa-security-headers.js'; import koaSlonikErrorHandler from '#src/middleware/koa-slonik-error-handler.js'; import koaSpaProxy from '#src/middleware/koa-spa-proxy.js'; import koaSpaSessionGuard from '#src/middleware/koa-spa-session-guard.js'; @@ -69,6 +70,7 @@ export default class Tenant implements TenantContext { app.use(koaConnectorErrorHandler()); app.use(koaI18next()); app.use(koaCompress()); + app.use(koaSecurityHeaders(mountedApps, id)); // Mount OIDC const provider = initOidc(id, envSet, queries, libraries); @@ -82,6 +84,7 @@ export default class Tenant implements TenantContext { libraries, envSet, }; + // Mount APIs app.use(mount('/api', initApis(tenantContext))); @@ -126,6 +129,7 @@ export default class Tenant implements TenantContext { this.provider = provider; const { isPathBasedMultiTenancy, adminUrlSet } = EnvSet.values; + this.run = isPathBasedMultiTenancy && // If admin URL Set is specified, consider that URL first diff --git a/packages/shared/src/env/UrlSet.test.ts b/packages/shared/src/env/UrlSet.test.ts index 37a2536b6..2348ddc2a 100644 --- a/packages/shared/src/env/UrlSet.test.ts +++ b/packages/shared/src/env/UrlSet.test.ts @@ -20,6 +20,10 @@ describe('UrlSet', () => { new URL('https://localhost:3001'), new URL('https://logto.mock'), ]); + expect(set1.origins).toStrictEqual([ + new URL('https://localhost:3001').origin, + new URL('https://logto.mock').origin, + ]); expect(set1.port).toEqual(3001); expect(set1.localhostUrl).toEqual(new URL('https://localhost:3001')); expect(set1.endpoint).toEqual(new URL('https://logto.mock')); @@ -30,6 +34,10 @@ describe('UrlSet', () => { new URL('http://localhost:3002/'), new URL('https://admin.logto.mock/'), ]); + expect(set2.origins).toStrictEqual([ + new URL('http://localhost:3002/').origin, + new URL('https://admin.logto.mock/').origin, + ]); expect(set2.port).toEqual(3002); expect(set2.localhostUrl).toEqual(new URL('http://localhost:3002')); expect(set2.endpoint).toEqual(new URL('https://admin.logto.mock')); @@ -44,6 +52,7 @@ describe('UrlSet', () => { const set1 = new UrlSet(false, 3001); expect(set1.deduplicated()).toStrictEqual([new URL('http://localhost:3001/')]); + expect(set1.origins).toStrictEqual([new URL('http://localhost:3001/').origin]); expect(set1.port).toEqual(3001); expect(set1.localhostUrl).toEqual(new URL('http://localhost:3001')); expect(set1.endpoint).toEqual(new URL('http://localhost:3001')); @@ -59,6 +68,7 @@ describe('UrlSet', () => { const set1 = new UrlSet(true, 3001); expect(set1.deduplicated()).toStrictEqual([new URL('https://logto.mock/logto')]); + expect(set1.origins).toStrictEqual([new URL('https://logto.mock/logto').origin]); expect(() => set1.port).toThrowError('Localhost has been disabled in this URL Set.'); expect(() => set1.localhostUrl).toThrowError('Localhost has been disabled in this URL Set.'); expect(set1.endpoint).toEqual(new URL('https://logto.mock/logto')); @@ -74,6 +84,7 @@ describe('UrlSet', () => { const set1 = new UrlSet(false, 3002, 'ADMIN_'); expect(set1.deduplicated()).toStrictEqual([]); + expect(set1.origins).toStrictEqual([]); expect(() => set1.port).toThrowError('Localhost has been disabled in this URL Set.'); expect(() => set1.localhostUrl).toThrowError('Localhost has been disabled in this URL Set.'); expect(() => set1.endpoint).toThrowError('No available endpoint in this URL Set.'); diff --git a/packages/shared/src/env/UrlSet.ts b/packages/shared/src/env/UrlSet.ts index fd269f3ac..a8fa29ef7 100644 --- a/packages/shared/src/env/UrlSet.ts +++ b/packages/shared/src/env/UrlSet.ts @@ -39,6 +39,10 @@ export default class UrlSet { ).map((value) => new URL(value)); } + public get origins(): string[] { + return this.deduplicated().map((url) => url.origin); + } + public get port(): number { if (this.isLocalhostDisabled) { throw new Error('Localhost has been disabled in this URL Set.'); diff --git a/packages/ui/src/Providers/IframeModalProvider/IframeModal/index.tsx b/packages/ui/src/Providers/IframeModalProvider/IframeModal/index.tsx index 5754277a5..3d50e461b 100644 --- a/packages/ui/src/Providers/IframeModalProvider/IframeModal/index.tsx +++ b/packages/ui/src/Providers/IframeModalProvider/IframeModal/index.tsx @@ -52,8 +52,7 @@ const IframeModal = ({ className, title = '', href = '', onClose }: ModalProps)