Skip to content

Modernize to .NET 8 LTS, add fluent API, DI package, and samples#78

Open
DeeJayTC wants to merge 10 commits intomainfrom
deepl-dotnet-2
Open

Modernize to .NET 8 LTS, add fluent API, DI package, and samples#78
DeeJayTC wants to merge 10 commits intomainfrom
deepl-dotnet-2

Conversation

@DeeJayTC
Copy link
Copy Markdown
Member

@DeeJayTC DeeJayTC commented Apr 24, 2026

Why

A bundled modernization of the library that fixes a pile of latent issues and pays the "eventually we should do this" tax in one coordinated change.

Runtime and dependency support has rotted

  • net5.0 reached end of support on 2022-05-10. netcoreapp3.1 ended on 2022-12-13. Both have been unsupported for multiple years. The library's test project still targeted both.
  • The 5.x-line dependencies we were pinning (Microsoft.Extensions.Http.Polly 5.0.1, System.Text.Json 5.0.2) have known security advisories that only ship fixes on 6.x+ / 8.x lines. We were shipping consumers onto a patched-CVE surface by default.
  • Polly v7 (the version referenced by Microsoft.Extensions.Http.Polly 5.x) is effectively frozen — active development moved to Polly v8's ResiliencePipeline API and Microsoft's replacement package Microsoft.Extensions.Http.Resilience. Sitting on the 5.x-of-the-wrapper permanently blocks us from that ecosystem.
  • Test harness: xunit 2.4.1 / NSubstitute 4.3.0 / Microsoft.NET.Test.Sdk 16.9.4 are all 2021-era and miss several analyzer fixes, async-safety guards, and bug fixes that ship in 2.9 / 5.3 / 17.11.
  • The custom workaround code we'd carried around (LargeFormUrlEncodedContent for a size-limit bug, LowerSnakeCaseNamingPolicy for missing BCL API) was no longer necessary: the first was fixed in .NET 5 (Remove unnecessary length restriction on Uri.Escape{Data/Uri}String dotnet/corefx#41686, as our own source comment noted), the second is built into .NET 8 as JsonNamingPolicy.SnakeCaseLower.

Consumer ergonomics gaps

  • No fluent builder API — every option had to be set by constructing a TextTranslateOptions / DocumentTranslateOptions etc. and passing it through positional arguments. Verbose for the common case of "translate this with formality=more".
  • No DI integration — every ASP.NET Core / Worker service consumer that wanted DeepL had to hand-roll a singleton registration, wire up IHttpClientFactory themselves, handle options validation themselves. Every major .NET client library ships a companion *.Extensions.DependencyInjection package; we didn't.
  • No runnable samples.

What this PR delivers

Logically separated commits. Each can be reviewed independently.

1. feat: Add fluent API layer (220a5d8)

LINQ-style extensions on top of ITranslator / IWriter / IGlossaryManager / IStyleRuleManager. Builders are directly awaitable (GetAwaiter) and have implicit Task<T> conversion so they drop into Task.WhenAll etc. Non-breaking: every fluent method is an extension over an existing interface, so the new API works with any ITranslator/IWriter implementation (including mocks) and doesn't alter existing call sites.

await translator.Translate("Hello").From("en").To("de")
      .WithFormality(Formality.More)
      .WithGlossary(glossary)
      .WithCustomInstructions("Keep it concise");

await client.CreateGlossary("My glossary")
      .WithDictionary("en", "de", enDeEntries)
      .WithDictionary("de", "en", deEnEntries);

await translator.TranslateDocument(input)
      .From("en").To("de")
      .WithFormality(Formality.More)
      .SaveTo(output);

Includes 73 unit tests (NSubstitute-based, no network) covering argument forwarding, every option helper, validation, single + batch shapes, cancellation propagation, and the implicit Task<T> conversion.

2. build: Modernize target frameworks to net8.0 + netstandard2.0 (53b10b1)

Project Before After
Library TFMs net5.0;netstandard2.0 netstandard2.0;net8.0
Library LangVersion 8 12
Test TFMs net5.0;netcoreapp3.1;net462 net8.0;net462

Dependency bumps:

Package Before After
Microsoft.Extensions.Http.Polly 5.0.1 8.0.26
System.Text.Json 5.0.2 8.0.6
System.Net.Http.Json (new) 8.0.1
Microsoft.NET.Test.Sdk 16.9.4 17.11.1
xunit 2.4.1 2.9.2
xunit.runner.visualstudio 2.4.3 2.8.2
NSubstitute 4.3.0 5.3.0
coverlet.collector 3.0.2 6.0.2
JunitXml.TestLogger 3.0.98 5.0.0

netstandard2.0 retained as the floor — the package stays usable from .NET Framework 4.7.2+, Mono, Unity, etc. net462 retained in the test project to validate that consumer story.

3. refactor: Adopt .NET 8 BCL APIs in HTTP/JSON internals (4a0465f)

Modern BCL on net8.0, existing code preserved as netstandard2.0 fallback behind #if NET8_0_OR_GREATER / NET5_0_OR_GREATER:

  • JsonNamingPolicy.SnakeCaseLower + HttpContent.ReadFromJsonAsync replace the custom snake-case policy and stream reader.
  • HttpMethod.Patch replaces the new HttpMethod("PATCH") allocation (factored to a static field in both cases).
  • JsonContent.Create replaces new StringContent(JsonSerializer.Serialize(...)) — streams instead of an intermediate string allocation.
  • SocketsHttpHandler with PooledConnectionLifetime = 5min and PooledConnectionIdleTimeout = 2min replaces HttpClientHandler. Long-lived HttpClient instances now pick up DNS changes correctly.
  • HttpVersion.Version20 + RequestVersionOrHigher policy: DeepL's API supports HTTP/2, enabling proper multiplexing for batch translation.
  • FormUrlEncodedContent (built-in) replaces LargeFormUrlEncodedContent on net5+. The underlying size-limit bug was fixed in .NET 5 — our custom workaround is now compiled out of the modern asset and only survives for ns2.0.

No public API change; ns2.0 consumers see identical behavior, net8 consumers get the modern paths.

4. feat: Add DeepL.Extensions.DependencyInjection companion package (d9bba3a)

New NuGet package (TFMs: netstandard2.0 + net8.0) providing Microsoft.Extensions.DependencyInjection integration:

services.AddDeepLClient(o => o.AuthKey = "...");
services.AddDeepLClient(builder.Configuration);                           // binds "DeepL" section
services.AddDeepLClient(builder.Configuration.GetSection("Translation"));
  • Registers DeepLClient as a singleton (documented thread-safe) and forwards every surface interface (ITranslator, IWriter, IGlossaryManager, IStyleRuleManager) to the same instance.
  • Routes the underlying HttpClient through IHttpClientFactory with the named client "DeepL", so consumers can layer their own handlers / resilience policies on top:
services.AddDeepLClient(o => o.AuthKey = key);
services.AddHttpClient(DeepLOptions.HttpClientName).AddStandardResilienceHandler();
  • Validates AuthKey via IValidateOptions<> — missing key surfaces on first resolve, not on first API call.
  • Idempotent (TryAdd semantics).

Why a separate package rather than adding DI to DeepL.net itself:

  1. DeepL.net stays dependency-free for consumers using Autofac / DryIoc / SimpleInjector or constructing DeepLClient manually.
  2. Matches the established .NET ecosystem pattern (MediatR.Extensions.Microsoft.DependencyInjection, Polly.Extensions.Http, Serilog.Extensions.Hosting, OpenTelemetry.Extensions.Hosting).
  3. DI-integration shape can evolve independently without forcing main-library version bumps.

Versioning: lockstep with DeepL.net for simplicity. Strong-named with the shared sgKey.snk. Includes 15 DI-container tests covering registration, singleton lifetime, interface forwarding, auth-key validation, HttpClientFactory integration, ServerUrl propagation (verified end-to-end via a capturing HttpMessageHandler), idempotency, and both the configure-delegate + IConfiguration overloads.

5. docs: Add /samples with FluentApi and DependencyInjection examples (4b88dc8)

Two runnable sample console apps:

  • samples/FluentApi — exhaustive demo of every fluent entry point (text translation, rephrase, document translation one-shot + split, glossary CRUD, style rule CRUD).
  • samples/DependencyInjection — generic host + AddDeepLClient + an IHostedService consumer pulling ITranslator / IWriter / IGlossaryManager from DI.

Samples live in their own solution (samples/DeepL.Samples.slnx) deliberately — out of the main CI scope so they don't affect the library's build or NuGet pack. They use ProjectReference against the sibling library so local changes are picked up on each build.

6. chore: Drop in-progress Voice API draft from this branch (d772750)

The branch had picked up an unrelated WIP commit for the Voice API. That work is separately tracked on tc/add-voice and will land in its own PR; it was stripped from this branch to keep scope clean. When Voice lands, the DI package just needs one line re-added to forward IVoiceManager to the same singleton.

Verification

All projects build clean on all TFMs. Tests pass:

Main solution (DeepL.net.sln):
  DeepL                                        net8.0 + netstandard2.0   0 warn / 0 err
  DeepLTests                                   net8.0 + net462           0 warn / 0 err
  DeepL.Extensions.DependencyInjection         net8.0 + netstandard2.0   0 warn / 0 err
  DeepL.Extensions.DependencyInjection.Tests   net8.0                    0 warn / 0 err

Samples (DeepL.Samples.slnx):
  FluentApi                                    net8.0                    0 warn / 0 err
  DependencyInjection                          net8.0                    0 warn / 0 err

Tests (net8.0, no network required):
  Fluent API                     73/73 pass
  DI integration                 15/15 pass

The existing integration test suite (DeepLTests/*Test.cs, requires DEEPL_AUTH_KEY or a mock server) is unchanged and untouched by this PR — needs a run against staging / mock server before merge to confirm no behavioral regression from the HTTP/JSON refactor.

Notes for reviewers

  • The modernization sequence (commits 2–3) was structured to be behavior-preserving on netstandard2.0. Consumer apps on .NET Framework 4.7.2+ see identical behavior; only the net8.0 asset swaps to the new BCL paths.
  • What's not in this PR (deferred):
    • Language-cleanup sweep (file-scoped namespaces, ArgumentNullException.ThrowIfNull conversion). ~40-file mechanical diff; belongs in its own PR.
    • STJ source generators for AOT / trim readiness. High value but reshapes every DTO.
    • Polly v8 / Microsoft.Extensions.Http.Resilience migration. Rewrites the retry stack; separate PR.

Test plan

  • dotnet build DeepL.net.sln — clean on all TFMs
  • dotnet test DeepLTests/DeepLTests.csproj -f net8.0 --filter FullyQualifiedName~Fluent — 73/73
  • dotnet test DeepL.Extensions.DependencyInjection.Tests — 15/15
  • dotnet test DeepLTests/DeepLTests.csproj -f net8.0 with DEEPL_AUTH_KEY or mock-server — existing suite passes (verifies HTTP/JSON refactor is behavior-preserving)
  • dotnet test DeepLTests/DeepLTests.csproj -f net462 with auth key — verifies ns2.0 consumer story still works
  • dotnet build samples/DeepL.Samples.slnx — samples build clean
  • (optional) dotnet run --project samples/FluentApi with a real DEEPL_AUTH_KEY — end-to-end smoke
  • (optional) dotnet run --project samples/DependencyInjection — DI end-to-end smoke

🤖 Generated with Claude Code

DeeJayTC and others added 8 commits March 31, 2026 11:22
…saries, and style rules

Adds a LINQ-style fluent layer on top of the existing ITranslator / IWriter /
IGlossaryManager / IStyleRuleManager surfaces. Builders are directly awaitable;
every fluent method is an extension over the existing interfaces, so the new
API is non-breaking and works with any ITranslator/IWriter implementation
(including mocks).

Examples:
  await translator.Translate("Hello").From("en").To("de")
        .WithFormality(Formality.More)
        .WithGlossary(glossary);

  await client.CreateGlossary("My glossary")
        .WithDictionary("en", "de", entries);

  await translator.TranslateDocument(input)
        .To("de")
        .WithFormality(Formality.More)
        .SaveTo(output);

Includes 73 unit tests (via NSubstitute) covering argument forwarding,
option-configuration helpers, validation, and both single/batch shapes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops dead runtimes and brings dependencies onto the .NET 8 LTS line.

Library:
  TFMs:  net5.0;netstandard2.0 -> netstandard2.0;net8.0
  LangVersion:  8 -> 12
  Microsoft.Extensions.Http.Polly:  5.0.1  -> 8.0.26
  System.Text.Json:                 5.0.2  -> 8.0.6
  System.Net.Http.Json:             (new)  -> 8.0.1

Tests:
  TFMs:  net5.0;netcoreapp3.1;net462 -> net8.0;net462
  LangVersion:  8 -> 12
  Microsoft.NET.Test.Sdk:      16.9.4 -> 17.11.1
  xunit:                       2.4.1  -> 2.9.2
  xunit.runner.visualstudio:   2.4.3  -> 2.8.2
  NSubstitute:                 4.3.0  -> 5.3.0
  coverlet.collector:          3.0.2  -> 6.0.2
  JunitXml.TestLogger:         3.0.98 -> 5.0.0

Motivation:
- net5.0 reached end of support in May 2022; netcoreapp3.1 in Dec 2022.
  The 5.x dependencies have since-patched CVEs that only ship in 8.0+.
- netstandard2.0 is retained as the floor so the package stays usable from
  .NET Framework 4.7.2+, Mono, Unity, etc.
- LangVersion 12 is purely additive on ns2.0 (no new BCL surface required).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Uses modern BCL surface on net8.0 while keeping the existing code as the
netstandard2.0 fallback, guarded by #if NET8_0_OR_GREATER / NET5_0_OR_GREATER.

Changes:
- JsonUtils: use JsonNamingPolicy.SnakeCaseLower (net8 built-in) and
  HttpContent.ReadFromJsonAsync; fall back to the custom snake-case policy
  + stream reader on ns2.0.
- DeepLHttpClient:
  * HttpMethod.Patch factored to a static field (net5+ uses the built-in
    HttpMethod.Patch, ns2.0 uses the string constructor once at init).
  * Extracted CreateJsonContent/CreateFormContent helpers; on net8 JSON
    bodies flow through JsonContent.Create (streams instead of string).
  * Inner handler on net8 is SocketsHttpHandler with PooledConnectionLifetime
    and PooledConnectionIdleTimeout set, so long-lived HttpClient instances
    pick up DNS changes correctly.
  * HTTP/2 preferred (RequestVersionOrHigher) on net8 for proper multiplexing
    on batch translation.
- LargeFormUrlEncodedContent: the .NET 5 fix for the pre-.NET 5 size limit
  (dotnet/corefx#41686) means the built-in FormUrlEncodedContent now works
  correctly. The custom type is gated behind !NET5_0_OR_GREATER so it only
  compiles into the ns2.0 asset.

No public API change. netstandard2.0 consumers see identical behavior;
net8.0 consumers get the modern BCL paths and per-call allocation wins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New NuGet package (TFMs: netstandard2.0 + net8.0) providing
Microsoft.Extensions.DependencyInjection integration for DeepL.net.

Surface:
  services.AddDeepLClient(o => o.AuthKey = "...");
  services.AddDeepLClient(builder.Configuration);
  services.AddDeepLClient(builder.Configuration.GetSection("..."));

Behavior:
- Registers DeepLClient as a singleton (documented thread-safe).
- Forwards every surface interface (ITranslator, IWriter, IGlossaryManager,
  IStyleRuleManager, IVoiceManager) to the same singleton.
- Routes the underlying HttpClient through IHttpClientFactory with the named
  client "DeepL", so consumers can layer their own handlers / resilience /
  logging on top without re-implementing the DeepL client.
- Validates AuthKey via IValidateOptions — missing key surfaces on first
  resolve, not on first API call.
- AddDeepLClient is idempotent (TryAdd semantics).

Why a separate package (rather than adding DI to DeepL.net itself):
- The main DeepL.net package stays dependency-free for consumers who use
  Autofac/DryIoc/SimpleInjector or construct DeepLClient manually.
- Matches the established .NET ecosystem pattern
  (MediatR.Extensions.Microsoft.DependencyInjection, Polly.Extensions.Http,
  Serilog.Extensions.Hosting, OpenTelemetry.Extensions.Hosting).
- DI-integration shape can evolve independently without forcing main-library
  version bumps.

Versioning: lockstep with DeepL.net for simplicity until integration surface
diverges. Strong-named with the shared sgKey.snk.

Includes 15 DI-container tests covering registration, singleton lifetime,
interface forwarding, auth-key validation, HttpClientFactory integration,
ServerUrl propagation (verified with a capturing HttpMessageHandler),
idempotency, and both configure-delegate + IConfiguration overloads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two runnable sample console apps demonstrating idiomatic use of the new
fluent API and the DeepL.Extensions.DependencyInjection package.

Layout:
  samples/
    DeepL.Samples.slnx         (standalone solution, not in main CI scope)
    Directory.Build.props      (shared net8.0 / LangVersion 12)
    README.md                  (usage + ASP.NET Core adaptation)
    FluentApi/                 (every fluent entry point)
    DependencyInjection/       (generic host + AddDeepLClient + IHostedService consumer)

The samples solution is deliberately separate from DeepL.net.sln so the
library's CI build scope, NuGet pack, and signing behavior are unaffected.
They reference the library via ProjectReference, so local changes to the
library are picked up on each build.

Both samples require DEEPL_AUTH_KEY to run, but compile without it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverts the changes introduced by 5330a21 ("Draft for a DeepL Voice
implementation") so this branch no longer carries an unrelated WIP. Voice
remains tracked on branch tc/add-voice and can be landed independently.

Removed:
- DeepL/IVoiceManager.cs, IVoiceSession.cs, VoiceSession.cs,
  VoiceSessionOptions.cs, VoiceMessageFormat.cs, TargetMediaVoice.cs,
  SourceMediaContentType.cs, SourceLanguageMode.cs
- DeepL/Model/TargetMediaChunk.cs, TranscriptSegment.cs, TranscriptUpdate.cs,
  VoiceSessionInfo.cs, VoiceStreamError.cs
- DeepLTests/VoiceSessionTest.cs
- DeepL/DeepLClient.cs: using System.Net.WebSockets; IVoiceManager interface
  on DeepLClient; CreateVoiceSessionAsync method
- DeepL/DeepL.csproj: System.Net.WebSockets.Client package reference

Follow-up edits to keep this branch internally consistent:
- DeepL.Extensions.DependencyInjection: drop the IVoiceManager forwarder;
  the DI package now forwards only ITranslator / IWriter / IGlossaryManager /
  IStyleRuleManager to the singleton. When Voice lands, re-adding the line
  is a one-line change.
- DI package README + samples README: remove IVoiceManager from the interface
  list.
- DI tests: drop the IVoiceManager assertions from the two "register-all" /
  "all-resolve-to-singleton" tests.

Verified green: main solution builds on net8.0 + netstandard2.0 + net462,
samples solution builds, Fluent tests 73/73 pass, DI tests 15/15 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nslation

Two ergonomic additions to the fluent document-translation layer that address
the async-poll nature of DeepL's document API.

IProgress<DocumentStatus>:
- New DocumentTranslationBuilder.WithProgress(IProgress<DocumentStatus>) method.
  Reports each status tick during the wait phase (between upload and download),
  useful for UI progress indicators, structured logging, or webhook emissions.
- New DocumentRef.WaitUntilDoneAsync(IProgress<DocumentStatus>, CancellationToken)
  overload so the split upload/poll/download flow can also use progress.
- When progress is configured the builder runs upload → poll-with-callbacks →
  download in the fluent layer rather than delegating to the library's one-shot
  TranslateDocumentAsync (which has no progress hook). Without progress the
  existing delegation path is preserved, so DocumentTranslationException
  wrapping and minification semantics stay identical to the non-fluent API.

DocumentTranslationJob:
- SaveTo(FileInfo) and SaveTo(Stream) now return DocumentTranslationJob, a
  lightweight wrapper around Task that also exposes Cancel(). The job is
  directly awaitable (GetAwaiter) and implicitly converts to Task, so every
  existing call site (await builder.SaveTo(...)) compiles and behaves
  unchanged.
- Internally each SaveTo call creates a CancellationTokenSource linked to any
  token provided via WithCancellation, so job.Cancel() propagates cancellation
  into the library even when the caller supplied their own token. The linked
  CTS is disposed in a continuation once the job completes.
- Lets callers keep the fluent style end-to-end without pre-building a
  CancellationTokenSource just to have a cancel handle:

    var job = translator.TranslateDocument(file).To("de").SaveTo(out);
    // ...later...
    job.Cancel();
    await job;  // throws OperationCanceledException

Tests (7 new, 80 total Fluent tests passing on net8.0 + net462):
- SaveTo_ReturnsAwaitableJob — job is awaitable + implicitly convertible to Task
- Job_Cancel_PropagatesThroughLinkedToken — cancel propagates into library call
- Job_Cancel_AfterCompletion_IsNoOp — safe post-completion
- WithCancellation_ExternalCancelPropagatesThroughLinkedToken — external cts
  cancellation also propagates via the linked token
- WithProgress_ReportsStatusDuringPolling — each poll tick surfaces to progress
- WithProgress_ErrorStatus_ThrowsDeepLException — error-status path
- WithProgress_NullProgress_Throws — null guard
- DocumentRef_WaitUntilDoneAsync_WithProgress_ReportsTicks — split-flow progress

Samples:
- samples/FluentApi/Program.cs demonstrates both new features end-to-end:
  WithProgress callback printing each status tick, and SaveTo-returns-Job with
  a mid-flight job.Cancel() triggered from a background task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Modernizes the DeepL .NET SDK to current TFMs/dependencies while adding a fluent API layer, a companion Microsoft DI integration package, and runnable sample apps to demonstrate both.

Changes:

  • Add fluent, awaitable builder extensions for translation/rephrase/document/glossary/style-rule flows plus unit tests.
  • Upgrade library/tests to net8.0 (keeping netstandard2.0 for the library) and adopt newer BCL HTTP/JSON APIs with conditional fallbacks.
  • Introduce DeepL.Extensions.DependencyInjection + tests and add /samples solution demonstrating fluent + DI usage.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
samples/README.md Documents how to build/run the sample apps.
samples/FluentApi/Program.cs End-to-end console sample showcasing the fluent API surface.
samples/FluentApi/FluentApi.csproj Sample project referencing the library via ProjectReference.
samples/Directory.Build.props Shared build settings for sample projects (net8, nullable, no pack/sign).
samples/DependencyInjection/TranslationService.cs Hosted service sample consuming DeepL interfaces from DI.
samples/DependencyInjection/Program.cs Generic-host sample wiring up AddDeepLClient.
samples/DependencyInjection/DependencyInjection.csproj Sample project referencing DI package + Hosting.
samples/DeepL.Samples.slnx Standalone samples solution file.
DeepLTests/FluentTranslationTest.cs Unit tests for fluent text translation + rephrase builders.
DeepLTests/FluentStyleRuleTest.cs Unit tests for fluent style-rule management builders/refs.
DeepLTests/FluentGlossaryTest.cs Unit tests for fluent glossary builders/refs.
DeepLTests/FluentDocumentTranslationTest.cs Unit tests for fluent document translation builders/refs including progress + cancellation.
DeepLTests/DeepLTests.csproj Update test TFMs/packages to net8/net462 and newer test deps.
DeepL/Internal/LargeFormUrlEncodedContent.cs Compile out workaround on modern TFMs (keep for pre-.NET5).
DeepL/Internal/JsonUtils.cs Use JsonNamingPolicy.SnakeCaseLower + ReadFromJsonAsync on net8 with fallback.
DeepL/Internal/DeepLHttpClient.cs Modernize HTTP internals (PATCH static, JSON/form helpers, SocketsHttpHandler, HTTP/2 defaults).
DeepL/FluentTranslation.cs New fluent translation/rephrase API with awaitable builders and option helpers.
DeepL/FluentStyleRule.cs New fluent API for style-rule management (refs + create builder).
DeepL/FluentGlossary.cs New fluent API for multilingual glossary management (refs + create builder).
DeepL/FluentDocumentTranslation.cs New fluent API for document translation (one-shot, split flow, progress + cancelable job).
DeepL/DeepL.csproj Update TFMs/lang version and bump core dependencies.
DeepL.net.sln Add DI projects to the main solution and expand configs.
DeepL.Extensions.DependencyInjection/README.md Usage docs for the DI companion package.
DeepL.Extensions.DependencyInjection/DeepLServiceCollectionExtensions.cs Implements AddDeepLClient registration and interface forwarding.
DeepL.Extensions.DependencyInjection/DeepLOptions.cs Options contract for DI registration (AuthKey, ServerUrl, client name).
DeepL.Extensions.DependencyInjection/DeepL.Extensions.DependencyInjection.csproj New package project targeting netstandard2.0/net8.0 with signing/pack settings.
DeepL.Extensions.DependencyInjection.Tests/DeepLServiceCollectionExtensionsTest.cs Container-level tests for registration/validation/httpclient usage.
DeepL.Extensions.DependencyInjection.Tests/DeepL.Extensions.DependencyInjection.Tests.csproj New test project for DI package (net8, updated test deps).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread DeepL/FluentDocumentTranslation.cs
Comment thread DeepL.Extensions.DependencyInjection/README.md
Comment thread DeepL/FluentTranslation.cs Outdated
Comment thread DeepL/FluentGlossary.cs
Comment thread DeepL/FluentDocumentTranslation.cs
…; guard unsupported minification paths in FluentDocumentTranslation

Agent-Logs-Url: https://github.com/DeepLcom/deepl-dotnet/sessions/7bbc1d60-4844-45bd-9a53-7bcbcbe8e1de

Co-authored-by: DeeJayTC <4077759+DeeJayTC@users.noreply.github.com>
@DeeJayTC DeeJayTC requested a review from sjsyrek April 26, 2026 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants