Compare commits

...

34 Commits

Author SHA1 Message Date
566dae8e2e Add French privacy policy and update project file
Added privacy-policy.fr-FR.html with detailed data protection info for signFLOW. Updated EnvelopeGenerator.Web.csproj to always copy this file to the output directory.
2026-02-13 14:50:37 +01:00
9763ff05cf Update localization injection in cookie consent partial
Replaced IStringLocalizer<SharedResource> with IStringLocalizer<Resource> for improved localization handling in _CookieConsentPartial.cshtml.
2026-02-13 14:44:18 +01:00
83f571b226 Add 2FA registration localization and update Reg.cshtml
Added resource entries for 2FA registration steps and instructions in de-DE, en-US, and fr-FR. Updated Reg.cshtml to use localized strings, replacing hardcoded text for improved internationalization.
2026-02-13 14:40:45 +01:00
95ea4db0a0 Add localization for protected doc UI strings
Added "DocumentProtected", "Password", and "Open" entries to de-DE, en-US, and fr-FR resource files. Updated Index.cshtml to use localized strings for the page title, password label, placeholder, and submit button, replacing hardcoded German text. This improves multilingual support for the protected document access page.
2026-02-13 14:24:15 +01:00
a2e68d275f Add localization for "Creator" and "Date" labels
Added "Creator" and "Date" resource strings to de-DE, en-US, and fr-FR resource files. Updated DebugEnvelopes.cshtml to use localized labels instead of hardcoded German text for creator and date fields.
2026-02-13 14:21:54 +01:00
41cf52fd41 Add localized expired session message to resources and view
Added "ConnectionValidityExpired" string to de-DE, en-US, and fr-FR resource files. Updated _Expired.cshtml to use localized title, header, and body messages for session expiration.
2026-02-13 14:19:42 +01:00
171ab508c5 Add localization for cookie consent modal
Added localized strings for the cookie consent modal in de-DE, en-US, and fr-FR resource files. Updated _CookieConsentPartial.cshtml to use these resources for the modal title, message, and accept button, enabling multilingual support. Injected IStringLocalizer to support string localization in the view.
2026-02-13 14:17:28 +01:00
924e39253a Localize envelope sharing UI and messages
Replaced hardcoded German text in the envelope sharing UI and JavaScript alerts with localized resource strings for German, English, and French. Added new translations for labels, prompts, and error/success messages. Improved internationalization and user experience by making the sharing feature fully language-aware.
2026-02-13 13:43:47 +01:00
aba68faa4d Add localized messages for document signing success
Added new resource strings for document signing success and confirmation messages in de-DE, en-US, and fr-FR. Updated EnvelopeSigned.cshtml to use these localized strings instead of hardcoded text.
2026-02-13 12:00:54 +01:00
f1ceaab70a Improve i18n for authenticator setup instructions
Added new resource strings (prefix, link, suffix) for authenticator app setup instructions in German, English, and French resource files. Updated EnvelopeLocked.cshtml to assemble the instruction dynamically using these localized parts, ensuring correct grammar and flexibility across supported languages.
2026-02-13 11:39:01 +01:00
f855c60be4 Localize "envelope expired" page and add resource keys
Added "DocumentSharingPeriodExpired" and "Expired" keys to de-DE, en-US, and fr-FR resource files. Updated EnvelopeExpired.cshtml to use localized strings for the title, heading, and message, enabling full internationalization of the expired envelope page.
2026-02-13 11:24:39 +01:00
8f9ca082e5 Add French (fr-FR) language config to appsettings.UI.json
Added a new entry for French (fr-FR) with FIClass "fi-fr" to the language configurations in appsettings.UI.json. This enables support for French localization.
2026-02-13 10:23:42 +01:00
deec1b1df5 Add French localization resource and project support
Added Resource.fr-FR.resx with French UI translations. Updated EnvelopeGenerator.Application.csproj to include the new resource and copy it to the output directory, enabling French language support in the application.
2026-02-13 10:19:44 +01:00
a982f48ef9 Improve culture cookie handling and localization responses
Refactored GetCulture to return null if cookie is missing or invalid, and added GetCultureOrDefault for fallback. Updated TestLocalizerController and CultureMiddleware to use new methods for more accurate culture detection. Localizer now returns only the localized string value.
2026-02-13 09:46:01 +01:00
297ab458c7 Replace Cultures with MultiCulture and update middleware order
Switched configuration and DI from Cultures to MultiCulture.
Adjusted middleware registration so CultureMiddleware runs after ExceptionHandlingMiddleware.
2026-02-12 17:16:47 +01:00
0e270e3182 Update Culture model and DI for non-nullable properties
Refactored Culture model to use required and non-nullable properties.
Removed nullable checks for Info in ShowEnvelope.cshtml.
Changed DI from Cultures to MultiCulture in _ViewImports.cshtml.
2026-02-12 17:16:36 +01:00
bcf55f7906 Update CultureMiddleware to use MultiCulture config
Replaced Cultures with MultiCulture in CultureMiddleware.cs.
Constructor now accepts IOptions<MultiCulture> for culture settings.
2026-02-12 17:15:34 +01:00
489b2d0917 Rename Cultures class to MultiCulture throughout codebase
Refactored all references from Cultures to MultiCulture in controllers and base classes. Updated the class definition in MultiCulture.cs to improve clarity and consistency in culture-related functionality. No functional changes were made.
2026-02-12 17:15:14 +01:00
63fbdc3bd5 Validate culture cookie against supported languages
Changed CultureMiddleware to check if the culture cookie value is in the list of supported languages, not just for null or empty. This ensures that only valid, supported culture values are accepted from the cookie; otherwise, the middleware falls back to Accept-Language or default logic.
2026-02-12 16:51:51 +01:00
aaf1f75aa7 Change Localize endpoint to use route parameter for key
The Localize endpoint in TestLocalizerController now accepts the "key" parameter as a route parameter instead of a query string. The method signature was updated to use [FromRoute], and the route template was modified to include "{key}". This changes the endpoint usage from /localize?key=de_DE to /localize/de_DE.
2026-02-12 16:42:49 +01:00
cdca639e4f Update culture handling and adjust middleware order
Changed GetCulture to return current UI culture if cookie is missing, ensuring a non-null result. Reordered middleware in Program.cs to run ExceptionHandlingMiddleware after CultureMiddleware.
2026-02-12 16:40:51 +01:00
ab57dd4cee Add endpoints for culture detection and improve cookie parsing
Added two endpoints to TestLocalizerController for retrieving culture from Accept-Language and user cookies. Enhanced GetCulture extension to parse and return the actual culture string from cookies. Updated usings for new extension methods.
2026-02-12 16:11:40 +01:00
745e9c7bfe Add GetCultureByAcceptLanguage extension for HttpContext
Introduced a new extension method, GetCultureByAcceptLanguage, in the WebExtensions class. This method parses the Accept-Language header from the HTTP request and returns the first valid CultureInfo, enabling detection of the user's preferred culture from browser settings.
2026-02-11 13:54:27 +01:00
670c8ed87c Improve culture selection using Accept-Language header
When no culture cookie is present, use the browser's Accept-Language
header to determine the user's preferred culture. This culture is
applied and stored in a cookie, enhancing localization by respecting
user preferences instead of always defaulting to the application's
default language.
2026-02-11 13:51:01 +01:00
91eb5d1e64 Make Culture lookup case-insensitive; add GetOrDefault()
Changed Culture indexer to use case-insensitive language matching.
Added GetOrDefault() to return a Culture or the default if not found.
2026-02-11 13:50:02 +01:00
9f59a17f63 Mark CreateAsync as obsolete; update Flag reference
Marked CreateAsync in ReadOnlyController as [Obsolete] to encourage use of MediatR. Simplified Flag.DataIntegrityIssue reference in EnvelopeMailService error handling.
2026-02-11 13:14:07 +01:00
2a0f7f99d6 Refactor EnvelopeMailService to use MediatR ISender
Replaces IAuthenticator with ISender in EnvelopeMailService, updates the constructor accordingly, and removes unused dependencies. Improves code readability and formatting, cleans up unused usings and redundant code, and aligns with the intended MediatR-based architecture. No functional changes to email sending logic.
2026-02-11 12:59:17 +01:00
ec674b6e80 Refactor TestEmailTemplateController to use MediatR
Replaced direct service dependency and base class inheritance with MediatR in TestEmailTemplateController. Updated the GetAll endpoint to use a MediatR query and removed obsolete code related to the previous service-based approach. This aligns the controller with CQRS/MediatR best practices.
2026-02-11 12:45:32 +01:00
10f23170fd Rename email template query methods for consistency
Renamed ReadEmailTemplateById and ReadEmailTemplateByType to ReadEmailTemplateAsync in ReadEmailTemplateQueryExtensions. This improves naming consistency and better reflects their asynchronous behavior. No changes to method signatures or functionality.
2026-02-11 12:08:26 +01:00
0ec823ec9e Add ISender extension methods for reading email templates
Introduced ReadEmailTemplateQueryExtensions with methods to fetch a single EmailTemplateDto by ID or type and language code. Added required using directive for EnvelopeGenerator.Application.Common.Extensions. These extensions streamline querying email templates via ISender.
2026-02-11 12:06:32 +01:00
06884fe809 Refactor Get method in EmailTemplateController
Simplified the Get method to always require a ReadEmailTemplateQuery and CancellationToken, delegating all queries to the mediator. Removed conditional logic for handling null or missing parameters. Updated XML documentation to reflect the new method signature.
2026-02-11 11:58:50 +01:00
c2d5bd65aa Refactor email template query to support multiple results
ReadEmailTemplateQuery now returns a collection of EmailTemplateDto, with optional filtering by Id, Type, and new LangCode property. Query handler updated to return all matching templates instead of a single result, and NotFoundException handling was removed.
2026-02-11 11:57:47 +01:00
cfcd43b0ed Make EmailTemplateDto mutable, add LangCode property
Changed EmailTemplateDto properties from init-only to mutable (get/set), removed 'required' from Name, and added a new LangCode property with a default value. Also updated using directives and added conditional compilation in EmailTemplate.cs for .NET Framework compatibility. No functional changes to EmailTemplate class.
2026-02-11 11:00:18 +01:00
f41199c389 Add LangCode property to EmailTemplate entity
Introduced a required LangCode property to the EmailTemplate entity, mapped to the LANG_CODE column in the database as varchar(5). This supports language-specific email templates.
2026-02-11 10:56:20 +01:00
35 changed files with 1139 additions and 276 deletions

View File

@@ -19,20 +19,20 @@ namespace EnvelopeGenerator.API.Controllers;
/// <remarks>
/// Initialisiert eine neue Instanz der <see cref="EmailTemplateController"/>-Klasse.
/// </remarks>
/// <param name="mapper">
/// <param name="repository">
/// Die AutoMapper-Instanz, die zum Zuordnen von Objekten verwendet wird.
/// <param name="mediator">
/// Die Mediator-Instanz, die zum Senden von Befehlen und Abfragen verwendet wird.
/// </param>
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = AuthPolicy.Sender)]
public class EmailTemplateController(IMapper mapper, IRepository<EmailTemplate> repository, IMediator mediator) : ControllerBase
public class EmailTemplateController(IMediator mediator) : ControllerBase
{
/// <summary>
/// Ruft E-Mail-Vorlagen basierend auf der angegebenen Abfrage ab.
/// Gibt alles zurück, wenn keine Id- oder Typ-Informationen eingegeben wurden.
/// </summary>
/// <param name="emailTemplate">Die Abfrageparameter zum Abrufen von E-Mail-Vorlagen.</param>
/// <param name="cancel"></param>
/// <returns>Gibt HTTP-Antwort zurück</returns>
/// <remarks>
/// Sample request:
@@ -43,18 +43,10 @@ public class EmailTemplateController(IMapper mapper, IRepository<EmailTemplate>
/// <response code="401">Wenn der Benutzer nicht authentifiziert ist.</response>
/// <response code="404">Wenn die gesuchte Abfrage nicht gefunden wird.</response>
[HttpGet]
public async Task<IActionResult> Get([FromQuery] ReadEmailTemplateQuery? emailTemplate = null)
public async Task<IActionResult> Get([FromQuery] ReadEmailTemplateQuery emailTemplate, CancellationToken cancel)
{
if (emailTemplate is null || (emailTemplate.Id is null && emailTemplate.Type is null))
{
var temps = await repository.Query.ToListAsync();
return Ok(mapper.Map<IEnumerable<EmailTemplateDto>>(temps));
}
else
{
var temp = await mediator.Send(emailTemplate);
return temp is null ? NotFound() : Ok(temp);
}
var result = await mediator.Send(emailTemplate, cancel);
return Ok(result);
}
/// <summary>

View File

@@ -38,6 +38,7 @@ public class ReadOnlyController : ControllerBase
/// <param name="createDto">Creation payload.</param>
[HttpPost]
[Authorize(Policy = AuthPolicy.Receiver)]
[Obsolete("Use MediatR")]
public async Task<IActionResult> CreateAsync([FromBody] EnvelopeReceiverReadOnlyCreateDto createDto)
{
var authReceiverMail = User.GetReceiverMailOfReceiver();

View File

@@ -13,25 +13,30 @@ public record EmailTemplateDto
/// <summary>
///
/// </summary>
public required string Name { get; init; }
public string Name { get; set; } = null!;
/// <summary>
/// Das Datum und die Uhrzeit, wann die Vorlage hinzugefügt wurde.
/// </summary>
public DateTime AddedWhen { get; init; }
public DateTime AddedWhen { get; set; }
/// <summary>
/// Der Inhalt (Body) der E-Mail-Vorlage. Kann null sein.
/// </summary>
public string? Body { get; init; }
public string? Body { get; set; }
/// <summary>
/// Der Betreff der E-Mail-Vorlage. Kann null sein.
/// </summary>
public string? Subject { get; init; }
public string? Subject { get; set; }
/// <summary>
/// Der Sprachcode der E-Mail-Vorlage.
/// </summary>
public string LangCode { get; set; } = null!;
/// <summary>
/// Das Datum und die Uhrzeit, wann die Vorlage zuletzt geändert wurde. Kann null sein.
/// </summary>
public DateTime? ChangedWhen { get; init; }
public DateTime? ChangedWhen { get; set; }
};

View File

@@ -6,6 +6,7 @@ using EnvelopeGenerator.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using EnvelopeGenerator.Domain.Constants;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Common.Extensions;
namespace EnvelopeGenerator.Application.EmailTemplates.Queries;
@@ -13,7 +14,7 @@ namespace EnvelopeGenerator.Application.EmailTemplates.Queries;
/// Stellt eine Abfrage dar, um eine E-Mail-Vorlage zu lesen.
/// Diese Klasse erbt von <see cref="IEmailTemplateQuery"/>.
/// </summary>
public record ReadEmailTemplateQuery : IEmailTemplateQuery, IRequest<EmailTemplateDto>
public record ReadEmailTemplateQuery : IEmailTemplateQuery, IRequest<IEnumerable<EmailTemplateDto>>
{
/// <summary>
/// Die eindeutige Kennung der E-Mail-Vorlage (optional).
@@ -34,12 +35,51 @@ public record ReadEmailTemplateQuery : IEmailTemplateQuery, IRequest<EmailTempla
/// 9 - DocumentRejected_REC_2 (für sonstige Empfänger): Mail an andere Empfänger (Brief), wenn das Dokument abgelehnt wird.
/// </summary>
public EmailTemplateType? Type { get; set; }
/// <summary>
///
/// </summary>
public string? LangCode { get; set; }
}
/// <summary>
///
/// </summary>
public class ReadEmailTemplateQueryHandler : IRequestHandler<ReadEmailTemplateQuery, EmailTemplateDto>
public static class ReadEmailTemplateQueryExtensions
{
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="id"></param>
/// <param name="langCode"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public static async Task<EmailTemplateDto?> ReadEmailTemplateAsync(this ISender sender, int id, string langCode, CancellationToken cancel = default)
{
var result = await sender.Send(new ReadEmailTemplateQuery { Id = id, LangCode = langCode }, cancel);
return result.FirstOrDefault();
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="type"></param>
/// <param name="langCode"></param>
/// <param name="cancel"></param>
/// <returns></returns>
public static async Task<EmailTemplateDto?> ReadEmailTemplateAsync(this ISender sender, EmailTemplateType type, string langCode, CancellationToken cancel = default)
{
var result = await sender.Send(new ReadEmailTemplateQuery { Type = type, LangCode = langCode }, cancel);
return result.FirstOrDefault();
}
}
/// <summary>
///
/// </summary>
public class ReadEmailTemplateQueryHandler : IRequestHandler<ReadEmailTemplateQuery, IEnumerable<EmailTemplateDto>>
{
private readonly IMapper _mapper;
@@ -65,14 +105,21 @@ public class ReadEmailTemplateQueryHandler : IRequestHandler<ReadEmailTemplateQu
/// <param name="cancel"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<EmailTemplateDto> Handle(ReadEmailTemplateQuery request, CancellationToken cancel)
public async Task<IEnumerable<EmailTemplateDto>> Handle(ReadEmailTemplateQuery request, CancellationToken cancel)
{
var query = request.Id is int id
? _repo.Query.Where(temp => temp.Id == id)
: _repo.Query.Where(temp => temp.Name == request.Type!.ToString());
var query = _repo.Query;
var entity = await query.FirstOrDefaultAsync(cancel) ?? throw new NotFoundException();
if (request.Id is int id)
query = query.Where(temp => temp.Id == id);
return _mapper.Map<EmailTemplateDto>(entity);
if (request.Type is EmailTemplateType type)
query = query.Where(temp => temp.Name == type.ToString());
if (request.LangCode is string langCode)
query = query.Where(temp => temp.LangCode == langCode);
var entity = await query.ToListAsync(cancel);
return _mapper.Map<IEnumerable<EmailTemplateDto>>(entity);
}
}

View File

@@ -63,6 +63,9 @@
<LastGenOutput>Model.Designer.cs</LastGenOutput>
<Generator>PublicResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Resources\Resource.fr-FR.resx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Update="Resources\Resource.de-DE.resx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>

View File

@@ -123,6 +123,9 @@
<data name="Back" xml:space="preserve">
<value>Zurück</value>
</data>
<data name="AuthenticatorSetup_Prefix" xml:space="preserve">
<value>Klicken Sie auf den</value>
</data>
<data name="Complete" xml:space="preserve">
<value>Abschließen</value>
</data>
@@ -144,6 +147,9 @@
<data name="DocSigned" xml:space="preserve">
<value>Dokument unterschrieben</value>
</data>
<data name="DocumentSharingPeriodExpired" xml:space="preserve">
<value>Der Zeitraum für die gemeinsame Nutzung von Dokumenten ist abgelaufen.</value>
</data>
<data name="en-US" xml:space="preserve">
<value>Englisch</value>
</data>
@@ -153,6 +159,9 @@
<data name="EnvelopeInfo2" xml:space="preserve">
<value>Erstellt am {0} von {1}. Sie können den Absender über &lt;span class="highlight highlight-envelope-info-2"&gt;&lt;a class="mail-link" href="mailto:{2}?subject={3}&amp;body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A"&gt;{6}&lt;/a&gt;&lt;/span&gt; kontaktieren.</value>
</data>
<data name="Expired" xml:space="preserve">
<value>Abgelaufen</value>
</data>
<data name="FiClass" xml:space="preserve">
<value>fi-de</value>
</data>
@@ -165,6 +174,9 @@
<data name="HomePageDescription" xml:space="preserve">
<value>Das digitale Unterschriftenportal ist eine Plattform, die entwickelt wurde, um Ihre Dokumente sicher zu unterschreiben und zu verwalten. Mit seiner benutzerfreundlichen Oberfläche können Sie Ihre Dokumente schnell hochladen, die Unterschriftsprozesse verfolgen und Ihre digitalen Unterschriftenanwendungen einfach durchführen. Dieses Portal beschleunigt Ihren Arbeitsablauf mit rechtlich gültigen Unterschriften und erhöht gleichzeitig die Sicherheit Ihrer Dokumente.</value>
</data>
<data name="AuthenticatorSetup_Link" xml:space="preserve">
<value>Link</value>
</data>
<data name="LocationWarning" xml:space="preserve">
<value>Bitte überprüfen Sie die Standortinformationen. Wenn sie falsch sind, korrigieren Sie diese bitte.</value>
</data>
@@ -264,4 +276,109 @@
<data name="WrongAccessCode" xml:space="preserve">
<value>Ungültiger Zugangscode.</value>
</data>
<data name="AuthenticatorSetup_Suffix" xml:space="preserve">
<value>um Ihre Authenticator-App einzurichten.</value>
</data>
<data name="DocumentSuccessfullySigned" xml:space="preserve">
<value>Dokument erfolgreich signiert!</value>
</data>
<data name="DocumentSignedConfirmationMessage" xml:space="preserve">
<value>Sie haben das Dokument signiert. Im Anschluss erhalten Sie eine schriftliche Bestätigung.</value>
</data>
<data name="Signatures" xml:space="preserve">
<value>Unterschriften</value>
</data>
<data name="EnterRecipientToShareDocument" xml:space="preserve">
<value>Geben Sie hier den Empfänger ein, mit welchem Sie das Dokument teilen wollen</value>
</data>
<data name="Email" xml:space="preserve">
<value>E-Mail</value>
</data>
<data name="ValidUntil" xml:space="preserve">
<value>Gültig bis</value>
</data>
<data name="ShrEnvInvalidEmailTitle" xml:space="preserve">
<value>Falsche Email</value>
</data>
<data name="ShrEnvInvalidEmailText" xml:space="preserve">
<value>Die E-Mail-Adresse ist ungültig. Bitte verwenden Sie das richtige Format, z. B.: user@mail.com.</value>
</data>
<data name="ShrEnvSentTitle" xml:space="preserve">
<value>Gesendet</value>
</data>
<data name="ShrEnvErrorTitle" xml:space="preserve">
<value>Fehler</value>
</data>
<data name="InvalidDateTitle" xml:space="preserve">
<value>Falsches Datum</value>
</data>
<data name="ShrEnvInvalidDateText" xml:space="preserve">
<value>Die E-Mail-Adresse ist ungültig. Bitte verwenden Sie das richtige Format, z. B.: user@mail.com.</value>
</data>
<data name="UnexpectedErrorTitle" xml:space="preserve">
<value>Unerwarteter Fehler</value>
</data>
<data name="ShrEnvOperationFailedText" xml:space="preserve">
<value>Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team.</value>
</data>
<data name="PrivacyNotice" xml:space="preserve">
<value>Datenschutzhinweis</value>
</data>
<data name="CookieConsentMessage" xml:space="preserve">
<value>Wir verwenden technisch notwendige Session Cookies. Diese Cookies sind für den ordnungsgemäßen Betrieb dieser Webseite von nöten und können aus diesm Grund nicht abgewählt werden. Es findet keine Übermittlung an Dritte statt.</value>
</data>
<data name="Accept" xml:space="preserve">
<value>Akzeptieren</value>
</data>
<data name="ConnectionValidityExpired" xml:space="preserve">
<value>Die Gültigkeitsdauer der Verbindung ist abgelaufen.</value>
</data>
<data name="Creator" xml:space="preserve">
<value>Ersteller</value>
</data>
<data name="Date" xml:space="preserve">
<value>Datum</value>
</data>
<data name="DocumentProtected" xml:space="preserve">
<value>Dokument geschützt</value>
</data>
<data name="Password" xml:space="preserve">
<value>Passwort</value>
</data>
<data name="Open" xml:space="preserve">
<value>Öffnen</value>
</data>
<data name="TfaRegistration" xml:space="preserve">
<value>2FA Registrierung</value>
</data>
<data name="Registration" xml:space="preserve">
<value>Registrierung</value>
</data>
<data name="PageVisibleUntil" xml:space="preserve">
<value>Diese Seite ist bis {0} sichtbar.</value>
</data>
<data name="Step1Download2faApplication" xml:space="preserve">
<value>Schritt 1 - Download einer 2FA Applikation</value>
</data>
<data name="Download2faAppInstruction" xml:space="preserve">
<value>Bitte nehmen Sie Ihr Smartphone zur Hand und laden eine Applikation herunter, die zur Zwei-Faktor-Authentifizierung (2FA) benutzt werden kann.</value>
</data>
<data name="Recommended2faApplications" xml:space="preserve">
<value>Folgende Applikationen empfehlen wir</value>
</data>
<data name="Step2ScanQrCode" xml:space="preserve">
<value>Schritt 2 - Scannen des QR-Codes</value>
</data>
<data name="ScanQrCodeInstruction" xml:space="preserve">
<value>Sobald Sie eine Zwei-Faktor-Authentifizierung App installiert haben, können Sie fortfahren und innerhalb der Applikation die Option zum Scannen eines QR-Codes suchen und bestätigen. Im Anschluss, sobald die Kamera freigegeben wurde, können Sie den QR-Code von uns scannen.</value>
</data>
<data name="Step3VerifyTheCode" xml:space="preserve">
<value>Schritt 3 - Verifizierung des Codes</value>
</data>
<data name="VerifyCodeInstructionMain" xml:space="preserve">
<value>Sie können nun in der Zwei-Faktor-Authentifizierung App einen Zahlencode zur Verifizierung des Vorganges ablesen. Bitte tragen Sie diesen Code in das unten aufgeführte Eingabefeld ein und Klicken auf</value>
</data>
<data name="VerifyCodeInstructionSubmit" xml:space="preserve">
<value>Senden</value>
</data>
</root>

View File

@@ -123,6 +123,9 @@
<data name="Back" xml:space="preserve">
<value>Back</value>
</data>
<data name="AuthenticatorSetup_Prefix" xml:space="preserve">
<value>Click the</value>
</data>
<data name="Complete" xml:space="preserve">
<value>Complete</value>
</data>
@@ -144,6 +147,9 @@
<data name="DocSigned" xml:space="preserve">
<value>Document signed</value>
</data>
<data name="DocumentSharingPeriodExpired" xml:space="preserve">
<value>The period for sharing documents has expired.</value>
</data>
<data name="en-US" xml:space="preserve">
<value>English</value>
</data>
@@ -153,6 +159,9 @@
<data name="EnvelopeInfo2" xml:space="preserve">
<value>Created on {0} by {1}. You can contact the sender via &lt;span class="highlight highlight-envelope-info-2"&gt;&lt;a class="mail-link" href="mailto:{2}?subject={3}&amp;body=Dear%20{4}%20{5},%0A%0A%0A"&gt;{6}&lt;/a&gt;&lt;/span&gt;.</value>
</data>
<data name="Expired" xml:space="preserve">
<value>Expired</value>
</data>
<data name="FiClass" xml:space="preserve">
<value>fi-us</value>
</data>
@@ -165,6 +174,9 @@
<data name="HomePageDescription" xml:space="preserve">
<value>The Digital Signature Portal is a platform developed for securely signing and managing your documents. With its user-friendly interface, you can quickly upload your documents, track the signing processes, and easily carry out your digital signature applications. This portal accelerates your workflow with legally valid signatures while enhancing the security of your documents.</value>
</data>
<data name="AuthenticatorSetup_Link" xml:space="preserve">
<value>link</value>
</data>
<data name="LocationWarning" xml:space="preserve">
<value>Please review the location information. If it is incorrect, kindly make the necessary corrections.</value>
</data>
@@ -264,4 +276,109 @@
<data name="WrongAccessCode" xml:space="preserve">
<value>Invalid access code.</value>
</data>
<data name="AuthenticatorSetup_Suffix" xml:space="preserve">
<value>to set up your authenticator app.</value>
</data>
<data name="DocumentSuccessfullySigned" xml:space="preserve">
<value>Document successfully signed!</value>
</data>
<data name="DocumentSignedConfirmationMessage" xml:space="preserve">
<value>You have signed the document. Afterwards, you will receive a written confirmation.</value>
</data>
<data name="Signatures" xml:space="preserve">
<value>Signatures</value>
</data>
<data name="EnterRecipientToShareDocument" xml:space="preserve">
<value>Enter the recipient you want to share the document with</value>
</data>
<data name="Email" xml:space="preserve">
<value>E-mail</value>
</data>
<data name="ValidUntil" xml:space="preserve">
<value>Valid until</value>
</data>
<data name="ShrEnvInvalidEmailTitle" xml:space="preserve">
<value>Invalid email</value>
</data>
<data name="ShrEnvInvalidEmailText" xml:space="preserve">
<value>The email address is invalid. Please use the correct format, e.g., user@mail.com.</value>
</data>
<data name="ShrEnvSentTitle" xml:space="preserve">
<value>Sent</value>
</data>
<data name="ShrEnvErrorTitle" xml:space="preserve">
<value>Error</value>
</data>
<data name="InvalidDateTitle" xml:space="preserve">
<value>Invalid date</value>
</data>
<data name="ShrEnvInvalidDateText" xml:space="preserve">
<value>The email address is invalid. Please use the correct format, e.g., user@mail.com.</value>
</data>
<data name="UnexpectedErrorTitle" xml:space="preserve">
<value>Unexpected error</value>
</data>
<data name="ShrEnvOperationFailedText" xml:space="preserve">
<value>The operation failed. Please contact the IT team.</value>
</data>
<data name="PrivacyNotice" xml:space="preserve">
<value>Privacy notice</value>
</data>
<data name="CookieConsentMessage" xml:space="preserve">
<value>We use technically necessary session cookies. These cookies are required for the proper operation of this website and therefore cannot be deselected. No data is transmitted to third parties.</value>
</data>
<data name="Accept" xml:space="preserve">
<value>Accept</value>
</data>
<data name="ConnectionValidityExpired" xml:space="preserve">
<value>The session has expired.</value>
</data>
<data name="Creator" xml:space="preserve">
<value>Creator</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="DocumentProtected" xml:space="preserve">
<value>Document protected</value>
</data>
<data name="Password" xml:space="preserve">
<value>Password</value>
</data>
<data name="Open" xml:space="preserve">
<value>Open</value>
</data>
<data name="TfaRegistration" xml:space="preserve">
<value>2FA Registration</value>
</data>
<data name="Registration" xml:space="preserve">
<value>Registration</value>
</data>
<data name="PageVisibleUntil" xml:space="preserve">
<value>This page is visible until {0}.</value>
</data>
<data name="Step1Download2faApplication" xml:space="preserve">
<value>Step 1 Download a 2FA application</value>
</data>
<data name="Download2faAppInstruction" xml:space="preserve">
<value>Please take your smartphone and download an application that can be used for two-factor authentication (2FA).</value>
</data>
<data name="Recommended2faApplications" xml:space="preserve">
<value>We recommend the following applications</value>
</data>
<data name="Step2ScanQrCode" xml:space="preserve">
<value>Step 2 Scan the QR code</value>
</data>
<data name="ScanQrCodeInstruction" xml:space="preserve">
<value>Once you have installed a two-factor authentication app, you can proceed and look for the option to scan a QR code within the application and confirm it. Then, once the camera is enabled, you can scan the QR code provided by us.</value>
</data>
<data name="Step3VerifyTheCode" xml:space="preserve">
<value>Step 3 Verify the code</value>
</data>
<data name="VerifyCodeInstructionMain" xml:space="preserve">
<value>You can now read a numeric code in the two-factor authentication app to verify the process. Please enter this code in the input field below and click</value>
</data>
<data name="VerifyCodeInstructionSubmit" xml:space="preserve">
<value>Submit</value>
</data>
</root>

View File

@@ -0,0 +1,384 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="and" xml:space="preserve">
<value>et</value>
</data>
<data name="Back" xml:space="preserve">
<value>Retour</value>
</data>
<data name="AuthenticatorSetup_Prefix" xml:space="preserve">
<value>Cliquez sur</value>
</data>
<data name="Complete" xml:space="preserve">
<value>Terminer</value>
</data>
<data name="Confirmation" xml:space="preserve">
<value>Confirmation</value>
</data>
<data name="Culture" xml:space="preserve">
<value>fr-FR</value>
</data>
<data name="de-DE" xml:space="preserve">
<value>Allemand</value>
</data>
<data name="DocProtected" xml:space="preserve">
<value>Document protégé</value>
</data>
<data name="DocRejected" xml:space="preserve">
<value>Document rejeté</value>
</data>
<data name="DocSigned" xml:space="preserve">
<value>Document signé</value>
</data>
<data name="DocumentSharingPeriodExpired" xml:space="preserve">
<value>La période de partage des documents a expiré.</value>
</data>
<data name="en-US" xml:space="preserve">
<value>Anglais</value>
</data>
<data name="EnvelopeInfo1" xml:space="preserve">
<value>Vous devez signer le processus {0}. &lt;span class="highlight highlight-envelope-info-1"&gt;Veuillez vérifier la page {1}&lt;/span&gt;.</value>
</data>
<data name="EnvelopeInfo2" xml:space="preserve">
<value>Créé le {0} par {1}. Vous pouvez contacter lexpéditeur via &lt;span class="highlight highlight-envelope-info-2"&gt;&lt;a class="mail-link" href="mailto:{2}?subject={3}&amp;body=Cher%20{4}%20{5},%0A%0A%0A"&gt;{6}&lt;/a&gt;&lt;/span&gt;.</value>
</data>
<data name="Expired" xml:space="preserve">
<value>Expiré</value>
</data>
<data name="FiClass" xml:space="preserve">
<value>fi-fr</value>
</data>
<data name="Finalize" xml:space="preserve">
<value>Finaliser</value>
</data>
<data name="Hello" xml:space="preserve">
<value>Bonjour</value>
</data>
<data name="HomePageDescription" xml:space="preserve">
<value>Le Portail de Signature Numérique est une plateforme développée pour signer et gérer vos documents en toute sécurité. Grâce à son interface conviviale, vous pouvez rapidement téléverser vos documents, suivre les processus de signature et effectuer facilement vos démarches de signature numérique. Ce portail accélère votre flux de travail avec des signatures juridiquement valides tout en renforçant la sécurité de vos documents.</value>
</data>
<data name="AuthenticatorSetup_Link" xml:space="preserve">
<value>lien</value>
</data>
<data name="LocationWarning" xml:space="preserve">
<value>Veuillez vérifier les informations de localisation. Si elles sont incorrectes, veuillez effectuer les corrections nécessaires.</value>
</data>
<data name="LockedBodyAccess" xml:space="preserve">
<value>Nous allons maintenant vous envoyer un code daccès à votre adresse e-mail enregistrée. Cela peut prendre quelques minutes !</value>
</data>
<data name="LockedBodyAuthenticator" xml:space="preserve">
<value>Veuillez saisir le TOTP fourni dans votre application Authenticator.</value>
</data>
<data name="LockedBodyAuthenticatorNew" xml:space="preserve">
<value>Nous avons envoyé le code QR à votre adresse e-mail. Votre code QR est valide jusquau {0}. Vous pouvez lutiliser pour toutes les enveloppes reçues à cette adresse e-mail.</value>
</data>
<data name="LockedBodySms" xml:space="preserve">
<value>Nous venons denvoyer le code daccès par SMS au numéro de téléphone que vous avez fourni.</value>
</data>
<data name="LockedCodeLabelAccess" xml:space="preserve">
<value>Code daccès</value>
</data>
<data name="LockedCodeLabelAuthenticator" xml:space="preserve">
<value>TOTP</value>
</data>
<data name="LockedCodeLabelSms" xml:space="preserve">
<value>Code SMS</value>
</data>
<data name="LockedFooterBodyAccess" xml:space="preserve">
<value>Veuillez vérifier votre boîte de réception, y compris le dossier spam. Vous pouvez également demander à lexpéditeur &lt;a class="mail-link" href="mailto:{0}?subject={1}&amp;body={2}" target="_blank"&gt;{0}&lt;/a&gt; de vous envoyer le code par un autre moyen.</value>
</data>
<data name="LockedFooterBodyAuthenticator" xml:space="preserve">
<value>Le nouveau code QR nest envoyé quune seule fois pour une période donnée et est enregistré dans votre application Authenticator une fois scanné. Il peut être utilisé pour toutes les enveloppes reçues à la même adresse e-mail jusquà son expiration. Si vous ne recevez pas le-mail contenant le code QR ou si vous le supprimez à la fois de le-mail et de lapplication Authenticator, veuillez contacter lexpéditeur.</value>
</data>
<data name="LockedFooterBodySms" xml:space="preserve">
<value>Vous pouvez demander à lexpéditeur de vérifier votre numéro de téléphone. Le numéro de téléphone doit être saisi avec lindicatif. Sinon, vous pouvez demander la suppression de la protection à deux facteurs.</value>
</data>
<data name="LockedFooterTitleAccess" xml:space="preserve">
<value>Vous navez pas reçu de code daccès ?</value>
</data>
<data name="LockedFooterTitleAuthenticator" xml:space="preserve">
<value>Vous navez pas reçu de code QR ?</value>
</data>
<data name="LockedFooterTitleSms" xml:space="preserve">
<value>Vous navez pas reçu de SMS ?</value>
</data>
<data name="LockedTitleAccess" xml:space="preserve">
<value>Le document nécessite un code daccès</value>
</data>
<data name="LockedTitleAuthenticator" xml:space="preserve">
<value>Authentification à 2 facteurs</value>
</data>
<data name="LockedTitleSms" xml:space="preserve">
<value>Authentification à 2 facteurs</value>
</data>
<data name="Privacy" xml:space="preserve">
<value>Confidentialité</value>
</data>
<data name="ReadOnlyMessage" xml:space="preserve">
<value>Transféré par {0}. Valable jusquau {1}.</value>
</data>
<data name="Reject" xml:space="preserve">
<value>Rejeter</value>
</data>
<data name="Rejection" xml:space="preserve">
<value>Rejet</value>
</data>
<data name="RejectionInfo1" xml:space="preserve">
<value>Ce processus de signature a été rejeté !</value>
</data>
<data name="RejectionInfo1_ext" xml:space="preserve">
<value>Processus annulé !</value>
</data>
<data name="RejectionInfo2" xml:space="preserve">
<value>Vous pouvez contacter {0}, &lt;a href="mailto:{1}?subject={2}&amp;body=Cher%20{0},%0A%0A%0A"&gt;{1}&lt;/a&gt; si nécessaire.</value>
</data>
<data name="RejectionInfo2_ext" xml:space="preserve">
<value>Le processus a été rejeté par lune des parties concernées. Vous pouvez contacter {0}, &lt;a href="mailto:{1}?subject={2}&amp;body=Cher%20{0},%0A%0A%0A"&gt;{1}&lt;/a&gt; si nécessaire.</value>
</data>
<data name="RejectionReasonQ" xml:space="preserve">
<value>Veuillez indiquer une raison :</value>
</data>
<data name="SigAgree" xml:space="preserve">
<value>En cliquant sur Finaliser, jaccepte que la signature affichée et soumise soit une représentation électronique de ma signature dans les cas où je lutilise sur des documents, y compris des contrats juridiquement contraignants.</value>
</data>
<data name="SignDoc" xml:space="preserve">
<value>Signer le document</value>
</data>
<data name="SigningProcessTitle" xml:space="preserve">
<value>Titre du processus de signature</value>
</data>
<data name="UnexpectedError" xml:space="preserve">
<value>Une erreur inattendue sest produite.</value>
</data>
<data name="ViewDoc" xml:space="preserve">
<value>Afficher le document</value>
</data>
<data name="WelcomeToTheESignPortal" xml:space="preserve">
<value>Bienvenue sur le portail eSign</value>
</data>
<data name="WrongAccessCode" xml:space="preserve">
<value>Code daccès invalide.</value>
</data>
<data name="AuthenticatorSetup_Suffix" xml:space="preserve">
<value>pour configurer votre application d'authentification.</value>
</data>
<data name="DocumentSuccessfullySigned" xml:space="preserve">
<value>Document signé avec succès!</value>
</data>
<data name="DocumentSignedConfirmationMessage" xml:space="preserve">
<value>Vous avez signé le document. Vous recevrez ensuite une confirmation écrite.</value>
</data>
<data name="Signatures" xml:space="preserve">
<value>Signatures</value>
</data>
<data name="EnterRecipientToShareDocument" xml:space="preserve">
<value>Saisissez ici le destinataire avec lequel vous souhaitez partager le document</value>
</data>
<data name="Email" xml:space="preserve">
<value>E-mail</value>
</data>
<data name="ValidUntil" xml:space="preserve">
<value>Valable jusqu'au</value>
</data>
<data name="ShrEnvInvalidEmailTitle" xml:space="preserve">
<value>E-mail incorrect</value>
</data>
<data name="ShrEnvInvalidEmailText" xml:space="preserve">
<value>L'adresse e-mail est invalide. Veuillez utiliser le format correct, par ex. : user@mail.com.</value>
</data>
<data name="ShrEnvSentTitle" xml:space="preserve">
<value>Envoyé</value>
</data>
<data name="ShrEnvErrorTitle" xml:space="preserve">
<value>Erreur</value>
</data>
<data name="InvalidDateTitle" xml:space="preserve">
<value>Date invalide</value>
</data>
<data name="ShrEnvInvalidDateText" xml:space="preserve">
<value>L'adresse e-mail est invalide. Veuillez utiliser le format correct, par ex. : user@mail.com.</value>
</data>
<data name="UnexpectedErrorTitle" xml:space="preserve">
<value>Erreur inattendue</value>
</data>
<data name="ShrEnvOperationFailedText" xml:space="preserve">
<value>L'opération a échoué. Veuillez contacter l'équipe informatique.</value>
</data>
<data name="PrivacyNotice" xml:space="preserve">
<value>Avis de confidentialité</value>
</data>
<data name="CookieConsentMessage" xml:space="preserve">
<value>Nous utilisons des cookies de session strictement nécessaires. Ces cookies sont indispensables au bon fonctionnement de ce site et ne peuvent donc pas être désactivés. Aucune donnée n'est transmise à des tiers.</value>
</data>
<data name="Accept" xml:space="preserve">
<value>Accepter</value>
</data>
<data name="ConnectionValidityExpired" xml:space="preserve">
<value>La durée de validité de la connexion est expirée.</value>
</data>
<data name="Creator" xml:space="preserve">
<value>Créateur</value>
</data>
<data name="Date" xml:space="preserve">
<value>Date</value>
</data>
<data name="DocumentProtected" xml:space="preserve">
<value>Document protégé</value>
</data>
<data name="Password" xml:space="preserve">
<value>Mot de passe</value>
</data>
<data name="Open" xml:space="preserve">
<value>Ouvrir</value>
</data>
<data name="TfaRegistration" xml:space="preserve">
<value>Enregistrement 2FA</value>
</data>
<data name="Registration" xml:space="preserve">
<value>Inscription</value>
</data>
<data name="PageVisibleUntil" xml:space="preserve">
<value>Cette page est visible jusqu'au {0}.</value>
</data>
<data name="Step1Download2faApplication" xml:space="preserve">
<value>Étape 1 Téléchargez une application 2FA</value>
</data>
<data name="Download2faAppInstruction" xml:space="preserve">
<value>Veuillez prendre votre smartphone et télécharger une application pouvant être utilisée pour lauthentification à deux facteurs (2FA).</value>
</data>
<data name="Recommended2faApplications" xml:space="preserve">
<value>Nous recommandons les applications suivantes</value>
</data>
<data name="Step2ScanQrCode" xml:space="preserve">
<value>Étape 2 Scannez le code QR</value>
</data>
<data name="ScanQrCodeInstruction" xml:space="preserve">
<value>Une fois que vous avez installé une application dauthentification à deux facteurs, vous pouvez continuer et chercher dans lapplication loption pour scanner un code QR et la confirmer. Ensuite, une fois la caméra activée, vous pourrez scanner le code QR fourni par nos soins.</value>
</data>
<data name="Step3VerifyTheCode" xml:space="preserve">
<value>Étape 3 Vérification du code</value>
</data>
<data name="VerifyCodeInstructionMain" xml:space="preserve">
<value>Vous pouvez maintenant lire un code numérique dans lapplication dauthentification à deux facteurs pour vérifier lopération. Veuillez saisir ce code dans le champ ci-dessous et cliquer sur</value>
</data>
<data name="VerifyCodeInstructionSubmit" xml:space="preserve">
<value>Envoyer</value>
</data>
</root>

View File

@@ -4,7 +4,6 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Configurations;
@@ -12,6 +11,7 @@ using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiverReadOnly;
using EnvelopeGenerator.Application.Common.Extensions;
using EnvelopeGenerator.Application.Common.Interfaces.Services;
using MediatR;
namespace EnvelopeGenerator.Application.Services;
@@ -21,40 +21,40 @@ namespace EnvelopeGenerator.Application.Services;
[Obsolete("Use MediatR")]
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
{
private readonly IEmailTemplateService _tempService;
private readonly IEnvelopeReceiverService _envRcvService;
private readonly DispatcherParams _dConfig;
private readonly IConfigService _configService;
private readonly Dictionary<string, string> _placeholders;
private readonly IAuthenticator _authenticator;
private readonly IEmailTemplateService _tempService;
private readonly IEnvelopeReceiverService _envRcvService;
private readonly DispatcherParams _dConfig;
private readonly IConfigService _configService;
private readonly Dictionary<string, string> _placeholders;
private readonly ISender _sender;
/// <summary>
///
/// </summary>
/// <param name="repository"></param>
/// <param name="mapper"></param>
/// <param name="tempService"></param>
/// <param name="envelopeReceiverService"></param>
/// <param name="dispatcherConfigOptions"></param>
/// <param name="configService"></param>
/// <param name="mailConfig"></param>
/// <param name="authenticator"></param>
public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, IAuthenticator authenticator) : base(repository, mapper)
/// <summary>
///
/// </summary>
/// <param name="repository"></param>
/// <param name="mapper"></param>
/// <param name="tempService"></param>
/// <param name="envelopeReceiverService"></param>
/// <param name="dispatcherConfigOptions"></param>
/// <param name="configService"></param>
/// <param name="mailConfig"></param>
/// <param name="sender"></param>
public EnvelopeMailService(IEmailOutRepository repository, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherParams> dispatcherConfigOptions, IConfigService configService, IOptions<MailParams> mailConfig, ISender sender) : base(repository, mapper)
{
_tempService = tempService;
_envRcvService = envelopeReceiverService;
_dConfig = dispatcherConfigOptions.Value;
_configService = configService;
_placeholders = new Dictionary<string, string>(mailConfig.Value.Placeholders);
_authenticator = authenticator;
_sender = sender;
}
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
{
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
{
if (accessCode is not null)
_placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode;
if(envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
if (envelopeReceiverDto?.Envelope is not null && envelopeReceiverDto.Receiver is not null)
{
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).ToEnvelopeKey();
var sigHost = await _configService.ReadDefaultSignatureHost();
@@ -64,7 +64,7 @@ private async Task<Dictionary<string, string>> CreatePlaceholders(string? access
}
return _placeholders;
}
}
private async Task<Dictionary<string, string>> CreatePlaceholders(EnvelopeReceiverReadOnlyDto? readOnlyDto = null)
{
@@ -81,18 +81,18 @@ private async Task<Dictionary<string, string>> CreatePlaceholders(string? access
return _placeholders;
}
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <param name="tempType"></param>
/// <param name="optionalPlaceholders"></param>
/// <returns></returns>
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <param name="tempType"></param>
/// <param name="optionalPlaceholders"></param>
/// <returns></returns>
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, EmailTemplateType tempType, Dictionary<string, object>? optionalPlaceholders = null)
{
var tempSerResult = await _tempService.ReadByNameAsync(tempType);
if (tempSerResult.IsFailed)
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, DigitalData.Core.Abstraction.Application.DTO.Flag.DataIntegrityIssue, $"The email cannot send because '{tempType}' template cannot found.");
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{tempType}' template cannot found.");
var temp = tempSerResult.Data;
var mail = new EmailOutCreateDto()
@@ -112,7 +112,7 @@ private async Task<Dictionary<string, string>> CreatePlaceholders(string? access
ReminderTypeId = _dConfig.ReminderTypeId,
SendingProfile = _dConfig.SendingProfile,
EntityId = null,
WfId = (int) EnvelopeStatus.MessageAccessCodeSent,
WfId = (int)EnvelopeStatus.MessageAccessCodeSent,
WfReference = null,
AddedWho = _dConfig.AddedWho,
EmailAttmt1 = _dConfig.EmailAttmt1
@@ -132,18 +132,18 @@ private async Task<Dictionary<string, string>> CreatePlaceholders(string? access
placeholders[oph.Key] = oph.Value.ToString() ?? "NULL";
//TODO: remove the requirement to add the models using reflections
return await CreateWithTemplateAsync(createDto: mail,placeholders: placeholders,
return await CreateWithTemplateAsync(createDto: mail, placeholders: placeholders,
dto, dto.Envelope.User!, dto.Envelope);
}
}
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <param name="optionalPlaceholders"></param>
/// <returns></returns>
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Dictionary<string, object>? optionalPlaceholders = null)
{
/// <summary>
///
/// </summary>
/// <param name="dto"></param>
/// <param name="optionalPlaceholders"></param>
/// <returns></returns>
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Dictionary<string, object>? optionalPlaceholders = null)
{
var tempSerResult = await _tempService.ReadByNameAsync(EmailTemplateType.DocumentShared);
if (tempSerResult.IsFailed)
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{EmailTemplateType.DocumentShared}' template cannot found.");
@@ -155,7 +155,7 @@ public async Task<DataResult<int>> SendAsync(EnvelopeReceiverReadOnlyDto dto, Di
EmailSubj = temp.Subject,
EmailBody = temp.Body,
//TODO: remove int casting when all
ReferenceId = (int) dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
ReferenceId = (int)dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
ReferenceString = dto.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
//receiver_name = receiver.name,
//receiver_access_code = receiver.access_code,

View File

@@ -1,9 +1,11 @@
using System;
using DigitalData.Core.Abstractions.Interfaces;
using DigitalData.Core.Abstractions.Interfaces;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using EnvelopeGenerator.Domain.Interfaces.Auditing;
#if NETFRAMEWORK
using System;
#endif
namespace EnvelopeGenerator.Domain.Entities
{
@@ -24,6 +26,10 @@ namespace EnvelopeGenerator.Domain.Entities
[Column("SUBJECT", TypeName = "nvarchar(512)")]
public string Subject { get; set; }
[Required]
[Column("LANG_CODE", TypeName = "varchar(5)")]
public string LangCode { get; set; }
[Required]
[Column("ADDED_WHEN", TypeName = "datetime")]
[DefaultValue("GETDATE()")]

View File

@@ -40,7 +40,7 @@ public class EnvelopeController : ViewControllerBase
private readonly IMediator _mediator;
[Obsolete("Use MediatR")]
public EnvelopeController(ILogger<EnvelopeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IAuthenticator authenticator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService, IMediator mediator) : base(logger, cultures, localizer)
public EnvelopeController(ILogger<EnvelopeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, MultiCulture cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService, IAuthenticator authenticator, IReceiverService receiverService, IEnvelopeSmsHandler envelopeSmsService, IMediator mediator) : base(logger, cultures, localizer)
{
_envRcvService = envelopeReceiverService;
_historyService = historyService;

View File

@@ -11,7 +11,7 @@ public class HomeController : ViewControllerBase
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration configuration, ILogger<HomeController> logger, Cultures cultures, IStringLocalizer<Resource> localizer) : base(logger, cultures, localizer)
public HomeController(IConfiguration configuration, ILogger<HomeController> logger, MultiCulture cultures, IStringLocalizer<Resource> localizer) : base(logger, cultures, localizer)
{
_configuration = configuration;
}

View File

@@ -14,9 +14,9 @@ namespace EnvelopeGenerator.Web.Controllers
private readonly IStringLocalizer<Resource> _localizer;
private readonly Cultures _cultures;
private readonly MultiCulture _cultures;
public LocalizationController(IStringLocalizer<Resource> localizer, Cultures cultures, ILogger<LocalizationController> logger)
public LocalizationController(IStringLocalizer<Resource> localizer, MultiCulture cultures, ILogger<LocalizationController> logger)
{
_localizer = localizer;
_cultures = cultures;

View File

@@ -26,7 +26,7 @@ public class TFARegController : ViewControllerBase
private readonly TFARegParams _params;
[Obsolete("Use MediatR")]
public TFARegController(ILogger<TFARegController> logger, Cultures cultures, IStringLocalizer<Resource> localizer, IEnvelopeReceiverService erService, IAuthenticator authenticator, IReceiverService receiverService, IOptions<TFARegParams> tfaRegParamsOptions) : base(logger, cultures, localizer)
public TFARegController(ILogger<TFARegController> logger, MultiCulture cultures, IStringLocalizer<Resource> localizer, IEnvelopeReceiverService erService, IAuthenticator authenticator, IReceiverService receiverService, IOptions<TFARegParams> tfaRegParamsOptions) : base(logger, cultures, localizer)
{
_envRcvService = erService;
_authenticator = authenticator;

View File

@@ -1,34 +1,22 @@
using DigitalData.Core.Abstraction.Application.DTO;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.AspNetCore.Mvc;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.Common.Dto;
using EnvelopeGenerator.Application.Common.Interfaces.Services;
using Microsoft.AspNetCore.Mvc;
using MediatR;
using EnvelopeGenerator.Application.EmailTemplates.Queries;
namespace EnvelopeGenerator.Web.Controllers.Test;
[Obsolete("Use MediatR")]
public class TestEmailTemplateController : TestControllerBase<IEmailTemplateService, EmailTemplateDto, EmailTemplate, int>
public class TestEmailTemplateController : ControllerBase
{
public TestEmailTemplateController(ILogger<TestEmailTemplateController> logger, IEmailTemplateService service) : base(logger, service)
private readonly IMediator _mediator;
public TestEmailTemplateController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
[Obsolete("Use MediatR")]
public virtual async Task<IActionResult> GetAll([FromQuery] string? tempType = null)
public virtual async Task<IActionResult> GetAll([FromQuery] ReadEmailTemplateQuery query, CancellationToken cancel)
{
return tempType is null
? await base.GetAll()
: await _service.ReadByNameAsync((EmailTemplateType)Enum.Parse(typeof(EmailTemplateType), tempType)).ThenAsync(
Success: Ok,
Fail: IActionResult (messages, notices) =>
{
_logger.LogNotice(notices);
return NotFound(messages);
});
var res = await _mediator.Send(query, cancel);
return Ok(res);
}
[NonAction]
public override Task<IActionResult> GetAll() => base.GetAll();
}

View File

@@ -1,9 +1,12 @@
using AngleSharp.Common;
using DigitalData.Core.API;
using EnvelopeGenerator.Application.Resources;
using EnvelopeGenerator.Web.Extensions;
using EnvelopeGenerator.Web.Models;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using System.Globalization;
namespace EnvelopeGenerator.Web.Controllers.Test
{
@@ -12,21 +15,30 @@ namespace EnvelopeGenerator.Web.Controllers.Test
public class TestLocalizerController : ControllerBase
{
private readonly IStringLocalizer _localizer;
private readonly Cultures _cultures;
private readonly MultiCulture _cultures;
public TestLocalizerController(IStringLocalizer<Resource> localizer, Cultures cultures)
public TestLocalizerController(IStringLocalizer<Resource> localizer, MultiCulture cultures)
{
_localizer = localizer;
_cultures = cultures;
}
[HttpGet]
public IActionResult Localize([FromQuery] string key = "de_DE") => Ok(_localizer[key]);
[HttpGet("{key}")]
public IActionResult Localize([FromRoute] string key) => Ok(_localizer[key].Value);
[HttpGet("fi-class")]
public IActionResult GetFIClass(string? lang = null) => lang is null ? Ok(_cultures.FIClasses) : Ok(_cultures[lang]?.FIClass);
[HttpGet("culture")]
public IActionResult GetCultures(string? lang = null) => lang is null ? Ok(_cultures) : Ok(_cultures[lang]);
[HttpGet("culture/accept-language")]
public IActionResult GetCultureByAcceptLanguage()
=> HttpContext.GetCultureByAcceptLanguage()?.Name is string culture
? Ok(culture)
: NotFound();
[HttpGet("culture/user")]
public IActionResult GetUserCulture() => Request.Cookies.GetCultureOrDefault() is string cult ? Ok(cult) : NotFound();
}
}

View File

@@ -8,10 +8,10 @@ namespace EnvelopeGenerator.Web.Controllers;
public class ViewControllerBase : Controller
{
protected readonly ILogger _logger;
protected readonly Cultures _cultures;
protected readonly MultiCulture _cultures;
protected readonly IStringLocalizer<Resource> _localizer;
public ViewControllerBase(ILogger logger, Cultures cultures, IStringLocalizer<Resource> localizer)
public ViewControllerBase(ILogger logger, MultiCulture cultures, IStringLocalizer<Resource> localizer)
{
_logger = logger;
_cultures = cultures;

View File

@@ -2203,6 +2203,9 @@
<Content Update="wwwroot\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\privacy-policy.fr-FR.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\privacy-policy.en-US.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@@ -3,8 +3,10 @@ using EnvelopeGenerator.Application.Common.Dto.Receiver;
using EnvelopeGenerator.Web.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using System.Globalization;
using System.Security.Claims;
namespace EnvelopeGenerator.Web.Extensions;
@@ -59,7 +61,14 @@ public static class WebExtensions
#region Cookie
public static string? GetCulture(this IRequestCookieCollection cookies)
=> cookies[CookieRequestCultureProvider.DefaultCookieName];
{
if (cookies[CookieRequestCultureProvider.DefaultCookieName] is string cookieValue)
return CookieRequestCultureProvider.ParseCookieValue(cookieValue)?.Cultures.FirstOrDefault().Value;
else
return null;
}
public static string GetCultureOrDefault(this IRequestCookieCollection cookies) => GetCulture(cookies) ?? CultureInfo.CurrentCulture.Name;
public static void SetCulture(this IResponseCookies cookies, string culture)
{
@@ -116,4 +125,31 @@ public static class WebExtensions
Body = "Bitte kontaktieren Sie das IT-Team."
});
#endregion
#region HttpContext
public static CultureInfo? GetCultureByAcceptLanguage(this HttpContext context)
{
var acceptLanguage = context.Request.Headers.AcceptLanguage.ToString();
if (string.IsNullOrWhiteSpace(acceptLanguage))
return null;
foreach (var value in acceptLanguage.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
var cultureName = value.Split(';', 2)[0];
if (string.IsNullOrWhiteSpace(cultureName))
continue;
try
{
return new CultureInfo(cultureName);
}
catch (CultureNotFoundException)
{
// ignore invalid cultures and continue
}
}
return null;
}
#endregion
}

View File

@@ -9,9 +9,9 @@ namespace EnvelopeGenerator.Web.Middleware;
public class CultureMiddleware
{
private readonly RequestDelegate _next;
private readonly Cultures _cultures;
private readonly MultiCulture _cultures;
public CultureMiddleware(RequestDelegate next, IOptions<Cultures> culturesOpt)
public CultureMiddleware(RequestDelegate next, IOptions<MultiCulture> culturesOpt)
{
_next = next;
_cultures = culturesOpt.Value;
@@ -19,14 +19,17 @@ public class CultureMiddleware
public async Task InvokeAsync(HttpContext context)
{
var cookieName = CookieRequestCultureProvider.DefaultCookieName;
var cookieValue = context.Request.Cookies[cookieName];
var cookieValue = context.Request.Cookies.GetCulture();
if (string.IsNullOrEmpty(cookieValue))
if (!_cultures.Languages.Contains(cookieValue))
{
context.Response.Cookies.SetCulture(_cultures.Default.Language);
CultureInfo.CurrentCulture = new CultureInfo(_cultures.Default.Language);
CultureInfo.CurrentUICulture = new CultureInfo(_cultures.Default.Language);
var requestCulture = context.GetCultureByAcceptLanguage()?.Name;
var culture = _cultures.GetOrDefault(requestCulture);
var cultureInfo = culture.Info ?? new CultureInfo(culture.Language);
context.Response.Cookies.SetCulture(culture.Language);
CultureInfo.CurrentCulture = cultureInfo;
CultureInfo.CurrentUICulture = cultureInfo;
}
await _next(context);

View File

@@ -4,15 +4,20 @@ namespace EnvelopeGenerator.Web.Models
{
public class Culture
{
private string _language = string.Empty;
public string Language { get => _language;
init {
private string _language = null!;
public required string Language
{
get => _language;
init
{
_language = value;
Info = new(value);
}
}
public string FIClass { get; init; } = string.Empty;
public CultureInfo? Info { get; init; }
public string FIClass { get; init; } = null!;
public CultureInfo Info { get; init; } = null!;
}
}

View File

@@ -1,6 +1,6 @@
namespace EnvelopeGenerator.Web.Models
{
public class Cultures : List<Culture>
public class MultiCulture : List<Culture>
{
public IEnumerable<string> Languages => this.Select(c => c.Language);
@@ -8,6 +8,8 @@
public Culture Default => this.First();
public Culture? this[string? language] => language is null ? null : this.Where(c => c.Language == language).FirstOrDefault();
public Culture GetOrDefault(string? language) => this[language] ?? Default;
public Culture? this[string? language] => language is null ? null : this.FirstOrDefault(c => string.Equals(c.Language, language, StringComparison.OrdinalIgnoreCase));
}
}

View File

@@ -165,8 +165,8 @@ try
});
// Register the FlagIconCssClass instance as a singleton
builder.Services.Configure<Cultures>(config.GetSection("Cultures"));
builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<Cultures>>().Value);
builder.Services.Configure<MultiCulture>(config.GetSection("Cultures"));
builder.Services.AddSingleton(sp => sp.GetRequiredService<IOptions<MultiCulture>>().Value);
// Register mail services
#pragma warning disable CS0618 // Type or member is obsolete
@@ -230,7 +230,7 @@ try
app.UseAuthentication();
app.UseAuthorization();
var cultures = app.Services.GetRequiredService<Cultures>();
var cultures = app.Services.GetRequiredService<MultiCulture>();
if (!cultures.Any())
throw new InvalidOperationException(@"Languages section is missing in the appsettings. Please configure like following.
Language is both a name of the culture and the name of the resx file such as Resource.de-DE.resx

View File

@@ -1,5 +1,5 @@
@{
ViewData["Title"] = "Abgelaufen";
ViewData["Title"] = _localizer["Expired"];
}
<div class="page container p-5">
<header class="text-center">
@@ -15,9 +15,9 @@
<path fill="#263238" d="M26.4,39.9c0-0.2,0-0.4,0.1-0.6s0.2-0.3,0.3-0.5s0.3-0.2,0.5-0.3s0.4-0.1,0.6-0.1s0.5,0,0.7,0.1 s0.4,0.2,0.5,0.3s0.2,0.3,0.3,0.5s0.1,0.4,0.1,0.6s0,0.4-0.1,0.6s-0.2,0.3-0.3,0.5s-0.3,0.2-0.5,0.3s-0.4,0.1-0.7,0.1 s-0.5,0-0.6-0.1s-0.4-0.2-0.5-0.3s-0.2-0.3-0.3-0.5S26.4,40.1,26.4,39.9z M29.2,36.8h-2.3L26.5,27h3L29.2,36.8z" />
</svg>
</div>
<h1>Abgelaufen!</h1>
<h1>@_localizer["Expired"]</h1>
</header>
<section class="text-center">
<p>Der Zeitraum für die gemeinsame Nutzung von Dokumenten ist abgelaufen.</p>
<p>@_localizer["DocumentSharingPeriodExpired"]</p>
</section>
</div>

View File

@@ -38,12 +38,12 @@
{
<section class="text-center">
<p class="m-0 p-0">
Klicken Sie auf den
@_localizer["AuthenticatorSetup_Prefix"]
<a class="icon-link m-0 p-0" href="/tfa/@envelopeKey" style="text-decoration: none;" target="_blank">
Link
@_localizer["AuthenticatorSetup_Link"]
<i class="bi bi-box-arrow-up-right"></i>
</a>
um Ihre Authenticator-App einzurichten.
@_localizer["AuthenticatorSetup_Suffix"]
</p>
</section>
}

View File

@@ -9,9 +9,9 @@
<path d="M15.354 3.354a.5.5 0 0 0-.708-.708L8 9.293 5.354 6.646a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l7-7z" />
</svg>
</div>
<h1>Dokument erfolgreich signiert!</h1>
<h1>@_localizer["DocumentSuccessfullySigned"]</h1>
</header>
<section class="text-center">
<p>Sie haben das Dokument signiert. Im Anschluss erhalten Sie eine schriftliche Bestätigung.</p>
<p>@_localizer["DocumentSignedConfirmationMessage"]</p>
</section>
</div>

View File

@@ -62,7 +62,7 @@
<div class="progress-container">
<div id="signed-count-bar" class="progress"></div>
<span class="progress-text">
<span id="signed-count">0</span>/<span id="signature-count">@signatureCount</span> Unterschriften
<span id="signed-count">0</span>/<span id="signature-count">@signatureCount</span> @_localizer["Signatures"]
</span>
</div>
}
@@ -86,7 +86,7 @@
<p>
<small class="text-body-secondary">
@Html.Raw(_localizer.EnvelopeInfo2().Format(
envelope?.AddedWhen.ToString(userCulture?.Info?.DateTimeFormat),
envelope?.AddedWhen.ToString(userCulture?.Info.DateTimeFormat),
$"{sender?.Prename} {sender?.Name}",
sender?.Email,
envelope?.Title,
@@ -104,16 +104,16 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<small class="modal-title text-body-secondary" id="shareBackdropLabel">Geben Sie hier den Empfänger ein, mit welchem Sie das Dokument teilen wollen:</small>
<small class="modal-title text-body-secondary" id="shareBackdropLabel">@_localizer["EnterRecipientToShareDocument"]:</small>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<span class="input-group-text">E-Mail</span>
<span class="input-group-text">@_localizer["Email"]</span>
<input type="text" class="form-control email-input" placeholder="user@mail.com" id="readonly-receiver-mail" aria-label="">
</div>
<div class="input-group">
<span class="input-group-text">Gültig bis</span>
<span class="input-group-text">@_localizer["ValidUntil"]</span>
<input type="date" name="expiration" class="form-control" lang="de" id="readonly-date-valid" onkeydown="return false;" onclick="this.showPicker()"
min="@DateTime.Today.AddDays(1).ToString("yyyy-MM-dd")"
max="@DateTime.Today.AddDays(90).ToString("yyyy-MM-dd")"
@@ -143,12 +143,23 @@
const receiverMail_value = receiverMail.value;
const dateValid_value = dateValid.value;
const shrEnvLocalizedTexts = {
invalidEmailTitle: '@_localizer["ShrEnvInvalidEmailTitle"]',
invalidEmailText: '@_localizer["ShrEnvInvalidEmailText"]',
invalidDateTitle: '@_localizer["ShrEnvInvalidDateTitle"]',
invalidDateText: '@_localizer["ShrEnvInvalidDateText"]',
sentTitle: '@_localizer["ShrEnvSentTitle"]',
errorTitle: '@_localizer["ShrEnvErrorTitle"]',
unexpectedErrorTitle: '@_localizer["UnexpectedErrorTitle"]',
operationFailedText: '@_localizer["ShrEnvOperationFailedText"]'
};
//check email
if (!receiverMail_value || receiverMail.classList.contains('is-invalid')) {
Swal.fire({
icon: "error",
title: "Falsche Email",
text: "Die E-Mail-Adresse ist ungültig. Bitte verwenden Sie das richtige Format, z. B.: user@mail.com."
title: shrEnvLocalizedTexts.invalidEmailTitle,
text: shrEnvLocalizedTexts.invalidEmailText
});
return;
}
@@ -158,8 +169,8 @@
if (new Date(dateValid_value) < tomorrow) {
Swal.fire({
icon: "error",
title: "Falsches Datum",
text: "Die Verteilung der Umschläge sollte mindestens einen Tag dauern."
title: shrEnvLocalizedTexts.invalidDateTitle,
text: shrEnvLocalizedTexts.invalidDateText
});
return;
}
@@ -168,23 +179,23 @@
.then(res => {
if (res.ok) {
Swal.fire({
title: "Gesendet",
title: shrEnvLocalizedTexts.sentTitle,
icon: "success"
});
}
else {
Swal.fire({
icon: "error",
title: `Fehler ${res.status}`,
text: "Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team."
title: `${shrEnvLocalizedTexts.errorTitle} ${res.status}`,
text: shrEnvLocalizedTexts.operationFailedText
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Unerwarteter Fehler",
text: "Der Vorgang ist fehlgeschlagen. Bitte wenden Sie sich an das IT-Team."
title: shrEnvLocalizedTexts.unexpectedErrorTitle,
text: shrEnvLocalizedTexts.operationFailedText
});
})
@@ -216,6 +227,6 @@
var documentBase64String = Convert.ToBase64String(documentBytes);
var envelopeKey = ViewData["EnvelopeKey"] as string;
@:document.addEventListener("DOMContentLoaded", async () => await new App("@envelopeKey", @Html.Raw(envelopeReceiverJson), B64ToBuff("@Html.Raw(documentBase64String)"), "@ViewData["PSPDFKitLicenseKey"]", "@userCulture?.Info?.TwoLetterISOLanguageName").init())
@:document.addEventListener("DOMContentLoaded", async () => await new App("@envelopeKey", @Html.Raw(envelopeReceiverJson), B64ToBuff("@Html.Raw(documentBase64String)"), "@ViewData["PSPDFKitLicenseKey"]", "@userCulture?.Info.TwoLetterISOLanguageName").init())
}
</script>

View File

@@ -1,4 +1,5 @@
@using Microsoft.AspNetCore.Http.Features
@inject IStringLocalizer<Resource> _localizer
@{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
@@ -13,13 +14,13 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="staticBackdropLabel">Datenschutzhinweis</h1>
<h1 class="modal-title fs-5" id="staticBackdropLabel">@_localizer["PrivacyNotice"]</h1>
</div>
<div class="modal-body">
Wir verwenden technisch notwendige Session Cookies. Diese Cookies sind für den ordnungsgemäßen Betrieb dieser Webseite von nöten und können aus diesm Grund nicht abgewählt werden. Es findet keine Übermittlung an Dritte statt.
@_localizer["CookieConsentMessage"]
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary accept-policy close" data-bs-dismiss="modal" data-cookie-string="@cookieString"><span aria-hidden="true">Accept</span></button>
<button type="button" class="btn btn-secondary accept-policy close" data-bs-dismiss="modal" data-cookie-string="@cookieString"><span aria-hidden="true">@_localizer["Accept"]</span></button>
</div>
</div>
</div>

View File

@@ -1,7 +1,7 @@
@{
ViewData["Title"] = "Abgelaufen";
var head = ViewData["Head"] as string ?? "Abgelaufen!";
var body = ViewData["Body"] as string ?? "Die Gültigkeitsdauer der Verbindung ist abgelaufen.";
ViewData["Title"] = _localizer["Expired"];
var head = ViewData["Head"] as string ?? _localizer["Expired"];
var body = ViewData["Body"] as string ?? _localizer["ConnectionValidityExpired"];
}
<div class="page container p-5">
<header class="text-center">

View File

@@ -1,6 +1,6 @@
@using System.Globalization
@{
ViewData["Title"] = "2FA Registrierung";
ViewData["Title"] = @_localizer["TfaRegistration"];
var totpQR64 = ViewData["TotpQR64"] as string;
var regDeadline = ViewData["RegDeadline"] is DateTime _dateTime ? _dateTime : throw new InvalidOperationException("RegDeadline is not added to view in Reg.cshtml view.");
}
@@ -13,23 +13,23 @@
</svg>
</div>
<h2 class="mb-0">2-Factor Authentication (2FA)</h2>
<h2>Registrierung</h2>
<h2>@_localizer["Registration"]</h2>
</header>
<section class="text-center">
<p class="p-0 m-0"> @string.Format("Diese Seite ist bis {0} sichtbar.", regDeadline.ToString("d. MMM, HH:mm", new CultureInfo("de-DE")))</p>
<p class="p-0 m-0"> @string.Format(@_localizer["PageVisibleUntil"], regDeadline.ToString("d. MMM, HH:mm", new CultureInfo("de-DE")))</p>
</section>
<section class="text-start mt-4">
<div class="accordion" id="tfaRegStep">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<p class="fw-bolder">Schritt 1 - Download einer 2FA Applikation</p>
<p class="fw-bolder">@_localizer["Step1Download2faApplication"]</p>
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" data-bs-parent="#tfaRegStep">
<div class="accordion-body">
<p class="text-wrap fw-medium">Bitte nehmen Sie Ihr Smartphone zur Hand und laden eine Applikation herunter, die zur Zwei-Faktor-Authentifizierung (2FA) benutzt werden kann.</p>
<p class="text-wrap fw-light">Folgende Applikationen empfehlen wir</p>
<p class="text-wrap fw-medium">@_localizer["Download2faAppInstruction"]</p>
<p class="text-wrap fw-light">@_localizer["Recommended2faApplications"]</p>
<ul class="list-group text-start">
<li class="list-group-item">
<a href="https://support.google.com/accounts/answer/1066447?hl=de&co=GENIE.Platform%3DAndroid" target="_blank" style="text-decoration: none;">
@@ -48,25 +48,25 @@
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
<p class="fw-bolder">Schritt 2 - Scannen des QR-Codes</p>
<p class="fw-bolder">@_localizer["Step2ScanQrCode"]</p>
</button>
</h2>
<div id="collapseTwo" class="accordion-collapse collapse" data-bs-parent="#tfaRegStep">
<div class="accordion-body">
<div class="text-center m-0 p-0"><img class="tfaQrCode" src="data:image/png;base64,@totpQR64"></div>
<p class="text-wrap fw-medium">Sobald Sie eine Zwei-Faktor-Authentifizierung App installiert haben, können Sie fortfahren und innerhalb der Applikation die Option zum Scannen eines QR-Codes suchen und bestätigen. Im Anschluss, sobald die Kamera freigegeben wurde, können Sie den QR-Code von uns scannen.</p>
<p class="text-wrap fw-medium">@_localizer["ScanQrCodeInstruction"]</p>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
<p class="fw-bolder">Schritt 3 - Verifizierung des Codes</p>
<p class="fw-bolder">@_localizer["Step3VerifyTheCode"]</p>
</button>
</h2>
<div id="collapseThree" class="accordion-collapse collapse" data-bs-parent="#tfaRegStep">
<div class="accordion-body">
<p class="text-wrap fw-medium">Sie können nun in der Zwei-Faktor-Authentifizierung App einen Zahlencode zur Verifizierung des Vorganges ablesen. Bitte tragen Sie diesen Code in das unten aufgeführte Eingabefeld ein und Klicken auf <samp>Absenden</samp>.</p>
<p class="text-wrap fw-medium">@_localizer["VerifyCodeInstructionMain"] <samp>@_localizer["VerifyCodeInstructionSubmit"]</samp>.</p>
</div>
</div>
</div>

View File

@@ -32,8 +32,8 @@
<section>
<article class="envelope">
<strong><a href="/EnvelopeKey/@encodeEnvelopeKey(envelope)">@envelope.Title</a></strong>
<div><strong>Ersteller</strong> @envelope.User.Email</div>
<div><strong>Datum</strong> @envelope.AddedWhen</div>
<div><strong>@_localizer["Creator"]</strong> @envelope.User.Email</div>
<div><strong>@_localizer["Date"]</strong> @envelope.AddedWhen</div>
</article>
</section>

View File

@@ -1,5 +1,5 @@
@{
ViewData["Title"] = "Dokument geschützt";
ViewData["Title"] = @_localizer["DocumentProtected"];
}
<div class="page container p-5">
@@ -23,12 +23,12 @@
<section>
<form id="form-access-code" class="form" method="post">
<div class="input">
<label class="visually-hidden" for="access_code">Passwort</label>
<input type="password" class="form-control" name="password" placeholder="Passwort" required="required">
<label class="visually-hidden" for="access_code">@_localizer["Password"]</label>
<input type="password" class="form-control" name="password" placeholder="@_localizer["Password"]" required="required">
</div>
<div class="button">
<button type="submit" class="btn btn-primary">Öffnen</button>
<button type="submit" class="btn btn-primary">@_localizer["Open"]</button>
</div>
</form>
</section>

View File

@@ -7,6 +7,6 @@
@using Microsoft.Extensions.Options
@inject IStringLocalizer<Resource> _localizer
@inject Microsoft.AspNetCore.Http.IHttpContextAccessor _accessor
@inject Cultures _cultures
@inject MultiCulture _cultures
@inject IOptions<CustomImages> _cImgOpt
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@@ -87,6 +87,10 @@
{
"Language": "en-US",
"FIClass": "fi-us"
},
{
"Language": "fr-FR",
"FIClass": "fi-fr"
}
],
"DisableMultiLanguage": false,

View File

@@ -0,0 +1,126 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Informations sur la protection des données pour le système de signature à distance signFLOW</title>
<link rel="stylesheet" href="css/privacy-policy.min.css">
</head>
<body>
<header>
<h1>Informations sur la protection des données pour le système de signature à distance : signFLOW</h1>
<p><strong>À jour au :</strong> 18.11.2025</p>
</header>
<section>
<h2>1. Informations générales</h2>
<p>Dans le monde actuel, rapide et de plus en plus numérique, les données personnelles sont une ressource précieuse. Vos données sont importantes et doivent donc être traitées avec le soin requis par les différentes lois et réglementations (RGPD, TDDDG, ...).</p>
<p>En tant que fournisseur de solutions locales (OnPremise), le fabricant de signFLOW, Digital Data GmbH, accorde une attention particulière à la protection et à la sécurité des données. Pour vous, cela signifie que seules les données nécessaires sont collectées et stockées (minimisation des données). De plus, des technologies actuelles et sécurisées sont utilisées lors du traitement.</p>
<p><strong>Coordonnées du fabricant :</strong></p>
<address>
Digital Data GmbH<br>
Ludwig-Rinn-Straße 16<br>
35452 Heuchelheim<br>
<a href="https://digitaldata.works">https://digitaldata.works</a><br>
<a href="mailto:info-flow@digitaldata.works">info-flow@digitaldata.works</a><br>
Téléphone : 0049 641 202360<br>
</address>
<p><strong>Contactez le délégué à la protection des données :</strong> <a href="mailto:privacy-flow@digitaldata.works">privacy-flow@digitaldata.works</a></p>
</section>
<section>
<h2>2. Responsable du traitement des données</h2>
<p>Vos données sont traitées en toute confiance par :</p>
<address>
Digital Data GmbH<br>
Ludwig-Rinn-Straße 16<br>
35452 Heuchelheim<br>
<a href="https://digitaldata.works">https://digitaldata.works</a><br>
<a href="mailto:info-flow@digitaldata.works">info-flow@digitaldata.works</a><br>
Téléphone : 0049 641 202360<br>
</address>
<p><strong>Contactez notre délégué à la protection des données :</strong> <a href="mailto:privacy-flow@digitaldata.works">privacy-flow@digitaldata.works</a></p>
</section>
<section>
<h2>3. Collecte des données</h2>
<h3>3.1 Catégories de données personnelles traitées</h3>
<ul>
<li>Noms : nom dutilisateur, prénom et nom ainsi que votre signature numérique</li>
<li>Coordonnées : numéro de téléphone, numéro de mobile et adresse e-mail</li>
<li>Données techniques : adresse IP, heure daccès ou tentatives daccès</li>
</ul>
<h3>3.2 Source des données personnelles</h3>
<p>Vous avez précédemment fourni les données mentionnées en 3.1 à votre partenaire commercial (le responsable du traitement). Cette transmission a pu se faire verbalement par téléphone, lors dun contact personnel, par e-mail ou via un formulaire de contact.</p>
<p>Vous transmettez votre signature numérique de manière autonome lors de la signature dun document.</p>
<h3>3.3 Durée de conservation / stockage</h3>
<ul>
<li>La correspondance par e-mail automatique est conservée pendant 6 ans.</li>
<li>Les contrats signés sont conservés pendant leur durée + 10 ans.</li>
<li>Le processus technique est stocké dans la solution logicielle signFLOW indéfiniment, selon le type de document ou de contrat.</li>
</ul>
<p>Vos données personnelles seront généralement anonymisées lorsque :</p>
<ul>
<li>Le contrat a expiré et la période légale de conservation est terminée.</li>
<li>Le contrat a été refusé par vous ou jamais signé.</li>
</ul>
<p>La base légale de ces périodes de conservation comprend :</p>
<ul>
<li>Code de commerce (HGB)</li>
<li>Code fiscal (AO)</li>
<li>Principes de tenue correcte et de conservation des livres, registres et documents sous forme électronique et daccès aux données (GoBD)</li>
</ul>
<p>
Selon le type spécifique de document, la période de conservation peut varier. De plus, ces périodes peuvent être prolongées en cas dirrégularités, telles quun litige en cours ou imminent.
</p>
<h3>3.4 Finalité du traitement</h3>
<p>Les données personnelles définies en 3.1 sont traitées pour :</p>
<ul>
<li>Supporter ou fournir le processus techniquement nécessaire.</li>
<li>Permettre à lutilisateur final de signer un document numériquement. Cela nécessite lidentification du demandeur, la vérification et le traitement de la demande, la facturation et le respect des obligations documentaires.</li>
</ul>
<p>Dans certains cas, les données sont traitées séparément par le département informatique, notamment en réponse à des demandes de support, ou éventuellement transmises au fabricant pour un traitement supplémentaire.</p>
<p>Le traitement des données intervient également pour garantir la sécurité de linformation, notamment pour identifier et prévenir les attaques, et pour effectuer des audits internes et externes, le contrôle des exportations et les vérifications des listes de sanctions. Les informations peuvent également être transmises aux autorités compétentes conformément à larticle 8 (2) VDG.</p>
<h3>3.5 Licéité du traitement</h3>
<p>Vos données sont collectées sur la base dune relation commerciale existante ou imminente.</p>
<p>La base légale pour la transmission aux autorités compétentes est larticle 8 (2) VDG. Les demandes des personnes concernées sont traitées conformément aux articles 12 à 23 du RGPD et aux articles 32 à 37 de la loi fédérale sur la protection des données (BDSG).</p>
<h3>3.6 Intérêts légitimes</h3>
<p>Un intérêt légitime du responsable du traitement conformément à larticle 6 (1) (f) RGPD existe dans les cas suivants :</p>
<p>Des mesures sont prises pour la sécurité de linformation, incluant à la fois des mesures techniques et organisationnelles préventives ainsi que la gestion des incidents. Lobjectif est dévaluer et déviter les dommages potentiels pour lentreprise, les personnes concernées par le traitement des données et les utilisateurs des services de confiance.</p>
<h3>3.7 Nécessité des données</h3>
<p>Les données collectées représentent le minimum nécessaire pour la signature numérique. Sans les données mentionnées en 3.1, le service ne peut pas être opéré.</p>
<p>Il est particulièrement important de fournir un numéro de mobile ou un numéro fixe allemand, car cela est utilisé pour lauthentification et le déclenchement de la signature comme second facteur. Sans ce mécanisme de sécurité, le service ne peut être fourni.</p>
<h3>3.8 Transfert de données</h3>
<p>Aucun transfert systématique de données na lieu.</p>
<p>Les données ne sont transmises au fabricant pour le support que dans des cas exceptionnels. Un accord de traitement des données (DPA) valide existe avec le fabricant, garantissant la sécurité et lintégrité de la gestion de vos données.</p>
</section>
<section>
<h2>4. Utilisation des cookies</h2>
<p>
Lors de la visite de certaines pages, des cookies temporaires sont utilisés, nécessaires à la fourniture technique des services. Ces cookies de session ne contiennent aucune donnée personnelle et sont automatiquement supprimés à la fin de la session. Aucune méthode telle que les applets Java ou les contrôles Active-X, pouvant suivre le comportement de lutilisateur, nest utilisée.
</p>
</section>
<section>
<h2>5. Droits des personnes concernées</h2>
<p>
Si vous avez des questions concernant vos données ou souhaitez demander une correction, suppression ou limitation du traitement, veuillez envoyer votre demande par courrier ou e-mail à ladresse indiquée ci-dessus. Cela sapplique également si vous souhaitez vous opposer au traitement conformément à larticle 21 RGPD ou demander la portabilité des données.
</p>
<p>
Si vous avez des questions ou des plaintes concernant une procédure, vous pouvez également nous contacter via les coordonnées fournies. Si vous avez dautres motifs de plainte, vous pouvez contacter notre autorité de contrôle. Vous pouvez vérifier quelle autorité de contrôle est compétente pour vous ici :
<a href="https://www.bfdi.bund.de/DE/Service/Anschriften/Laender/Laender-node.html">Laender-node.html</a>
</p>
</section>
</body>
</html>