500K characters included every month. Add payment details to start.
C# / .NET Developer Guide

Best Translation API
for C# and .NET

Compare Google Translate, DeepL, and Langbly from a .NET perspective. Real HttpClient code, IHttpClientFactory setup, resource file workflows, and what each one costs.

Payment details required. No charge within 500K characters/month.

Pricing comparison

Real pricing based on monthly character volume. All prices in USD.

VolumeGoogle TranslateDeepLLangblyYou Save
500K chars/mo$0Check live plan$0
Both included/evaluation
1M chars/mo$10Check live plan$2.50
75% vs Google
5M chars/mo$90Check live plan$22.50
75% vs Google
25M chars/mo$490Check live plan$122.50
75% vs Google
100M chars/mo$1,990Above Growth limit$497.50
75% vs Google

Feature comparison

FeatureGoogle TranslateDeepLLangbly
Official .NET SDKGoogle.Cloud.Translation.V2DeepL.netPlain HTTP (no NuGet needed)
Works with HttpClient only
Auth methodService account JSONAPI key headerBearer token header
Extra dependenciesGoogle.Apis stack1 packageNone
System.Text.Json friendlyWrapped in SDK typesWrapped in SDK typesFlat JSON, maps to records
async/await support
IHttpClientFactory typed clientNot applicableNot applicableStandard pattern
Polly / resilience handlerSDK internalSDK internalYour policy, your rules
Retry-After honoured on 429
Google v2 compatible
Languages100+30+100+
Published usage rate$20/1M after 500KCheck live Growth plan$5/1M after 500K
Included/evaluation usage500K/moDeveloper: 1M total500K/mo
Translation qualityNMTNMT + AINext-gen AI
Context-awareLimited

Translating text in C#: three APIs side by side

Most .NET projects do not need a vendor SDK to call a translation API. They need one HTTP call, a couple of records, and System.Text.Json. Here is what each option actually looks like in a modern C# project.

Google Translate (Google.Cloud.Translation.V2):

// dotnet add package Google.Cloud.Translation.V2
using Google.Cloud.Translation.V2;

// Requires a downloaded service account JSON file on disk
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "service-account.json");

TranslationClient client = await TranslationClient.CreateAsync();
TranslationResult result = await client.TranslateTextAsync("Hello world", "nl");

Console.WriteLine(result.TranslatedText);

DeepL (DeepL.net):

// dotnet add package DeepL.net
using DeepL;

var translator = new Translator(Environment.GetEnvironmentVariable("DEEPL_AUTH_KEY")!);
var result = await translator.TranslateTextAsync("Hello world", null, LanguageCode.Dutch);

Console.WriteLine(result.Text);

Langbly (HttpClient, no package):

using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json.Serialization;

public sealed record TranslateRequest(
    [property: JsonPropertyName("q")] string Q,
    [property: JsonPropertyName("target")] string Target,
    [property: JsonPropertyName("source")] string? Source = null,
    [property: JsonPropertyName("format")] string Format = "text");

public sealed record Translation(
    [property: JsonPropertyName("translatedText")] string TranslatedText,
    [property: JsonPropertyName("detectedSourceLanguage")] string? DetectedSourceLanguage);

public sealed record TranslateData(
    [property: JsonPropertyName("translations")] IReadOnlyList<Translation> Translations);

public sealed record TranslateResponse(
    [property: JsonPropertyName("data")] TranslateData Data);

using var http = new HttpClient { BaseAddress = new Uri("https://api.langbly.com/") };
http.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("LANGBLY_API_KEY"));

using var response = await http.PostAsJsonAsync(
    "language/translate/v2",
    new TranslateRequest("Hello world", Target: "nl"));

response.EnsureSuccessStatusCode();

var payload = await response.Content.ReadFromJsonAsync<TranslateResponse>();
Console.WriteLine(payload!.Data.Translations[0].TranslatedText);   // Hallo wereld
Console.WriteLine(payload.Data.Translations[0].DetectedSourceLanguage); // en

The request body is small on purpose: q and target are required, source and format are optional, and format accepts "text" or "html". Send "html" when you are translating Razor fragments or CMS content and you want tags left intact.

Note the response envelope. It is the Google Translate v2 shape, byte for byte, because Langbly is a drop-in replacement for that API. If you already have TranslationResponse DTOs from a Google integration, they deserialize against Langbly without a single edit. Swapping providers is a base address and a header.

There is no official Langbly NuGet package. Official SDKs cover Python, JavaScript/TypeScript, and PHP. In .NET that turns out to be a non-issue: HttpClient plus two records is less code than wiring up a vendor SDK, and you keep full control over serialization, timeouts, logging, and retries.

ASP.NET Core: a typed client with IHttpClientFactory

For anything beyond a console script, register a typed client. You get connection pooling, a single place for the base address and auth header, and a seam you can mock in tests.

The client:

public interface ITranslator
{
    Task<string> TranslateAsync(string text, string target, CancellationToken ct = default);
}

public sealed class LangblyTranslator(HttpClient http, ILogger<LangblyTranslator> logger) : ITranslator
{
    public async Task<string> TranslateAsync(string text, string target, CancellationToken ct = default)
    {
        using var response = await http.PostAsJsonAsync(
            "language/translate/v2",
            new TranslateRequest(text, target),
            ct);

        if (response.StatusCode is System.Net.HttpStatusCode.TooManyRequests)
        {
            var retryAfter = response.Headers.RetryAfter?.Delta;
            logger.LogWarning("Rate limited, retry after {RetryAfter}", retryAfter);
        }

        response.EnsureSuccessStatusCode();

        var payload = await response.Content.ReadFromJsonAsync<TranslateResponse>(ct);

        return payload?.Data.Translations.FirstOrDefault()?.TranslatedText
            ?? throw new InvalidOperationException("Translation response contained no translations.");
    }
}

Registration in Program.cs:

// dotnet user-secrets set "Langbly:ApiKey" "your-api-key"
// dotnet add package Microsoft.Extensions.Http.Resilience

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient<ITranslator, LangblyTranslator>((sp, http) =>
{
    var config = sp.GetRequiredService<IConfiguration>();

    http.BaseAddress = new Uri("https://api.langbly.com/");
    http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
        "Bearer",
        config["Langbly:ApiKey"] ?? throw new InvalidOperationException("Langbly:ApiKey is not configured."));
    http.Timeout = TimeSpan.FromSeconds(30);
})
.AddStandardResilienceHandler();   // Polly-backed retries, timeouts, circuit breaker

var app = builder.Build();

app.MapPost("/translate", async (TranslateBody body, ITranslator translator, CancellationToken ct) =>
    Results.Ok(new { translated = await translator.TranslateAsync(body.Text, body.Target, ct) }));

app.Run();

record TranslateBody(string Text, string Target);

If you are on an older target framework without Microsoft.Extensions.Http.Resilience, a hand-rolled Polly policy does the same job:

.AddPolicyHandler(HttpPolicyExtensions
    .HandleTransientHttpError()
    .OrResult(r => (int)r.StatusCode == 429)
    .WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt))));

Two things worth doing while you are in here. Keep the key in user secrets locally and in your platform's secret store in production, never in appsettings.json. And turn on <Nullable>enable</Nullable> in the csproj so the compiler tells you where a missing translation can slip through as null.

Compare that to the Google SDK, which wants a service account JSON file mounted somewhere your app can read it, plus a GCP project with the Translation API enabled. It works, but it is a lot of ceremony for one POST request.

Practical .NET workflow: translating .resx resource files

Localization in .NET still runs on .resx files, and translating them by hand is nobody's favourite afternoon. Since .resx is just XML, a small utility can generate every satellite file from your neutral resources.

using System.Xml.Linq;

// Reads Strings.resx and writes Strings.nl.resx, Strings.de.resx, and so on.
static async Task TranslateResxAsync(
    ITranslator translator,
    string sourcePath,
    string targetLanguage,
    CancellationToken ct = default)
{
    var doc = XDocument.Load(sourcePath);

    var entries = doc.Root!
        .Elements("data")
        .Where(d => d.Attribute("type") is null && d.Attribute("mimetype") is null) // skip images and blobs
        .ToList();

    foreach (var entry in entries)
    {
        var value = entry.Element("value");
        if (value is null || string.IsNullOrWhiteSpace(value.Value))
            continue;

        value.Value = await translator.TranslateAsync(value.Value, targetLanguage, ct);
    }

    var outputPath = Path.ChangeExtension(sourcePath, $"{targetLanguage}.resx");
    doc.Save(outputPath);

    Console.WriteLine($"{outputPath}: {entries.Count} strings translated");
}

// Usage
foreach (var lang in new[] { "nl", "de", "fr", "es", "ja" })
    await TranslateResxAsync(translator, "Resources/Strings.resx", lang);

Two details that save you a bug report. First, filter out entries with a type or mimetype attribute, because those are icons and serialized objects, not user-facing text. Second, if your strings use composite format placeholders like {0}, add a check that the placeholder count matches before you save. A one-line assertion in the loop is cheaper than a FormatException in production.

For bigger resource sets, batch the calls with Parallel.ForEachAsync and a sensible MaxDegreeOfParallelism, and cache results by source string so repeated labels like "Save" are only paid for once. At $5 per million characters a full resource set for five languages usually lands inside the 500K characters/month free tier anyway.

The same pattern works for JSON localization files, Blazor IStringLocalizer resources, and XLIFF exports. Swap XDocument for whatever parser matches your format and keep the rest.

Frequently asked questions

What is the best translation API for C# and .NET?

It depends on what you optimise for. Google Translate has the widest language coverage but the heaviest setup, since it needs a GCP project and a service account JSON file. DeepL has a clean .NET package and strong European language quality. Langbly is the cheapest of the three at $5 per million characters, is context-aware, and needs no package at all because it works directly with HttpClient.

Is there an official Langbly SDK for .NET?

No. Official Langbly SDKs currently cover Python, JavaScript/TypeScript, and PHP. In C# you call the REST endpoint directly with HttpClient and System.Text.Json, which takes two record types and about ten lines. Register it as a typed client with IHttpClientFactory and you get pooling, resilience, and testability for free.

How do I translate text in C# without a third-party package?

POST to https://api.langbly.com/language/translate/v2 with an Authorization: Bearer header and a JSON body of {"q": "Hello world", "target": "nl"}. Use PostAsJsonAsync and ReadFromJsonAsync from System.Net.Http.Json, and map the response to a small record hierarchy. No NuGet package required beyond what ships with the framework.

Can I switch from the Google Translate API to Langbly in an existing .NET app?

Yes. Langbly is a drop-in replacement for the Google Translate v2 API and returns the identical response shape, so your existing DTOs keep working. If you were using the Google.Cloud.Translation.V2 package, replace it with a typed HttpClient, point the base address at api.langbly.com, and send your key as a Bearer token. There is no service account file to manage afterwards.

How much does a translation API cost for a .NET project?

Google Cloud Translation includes the first 500,000 characters each month, then charges $20 per million for standard NMT. Langbly includes the first 500,000 input characters and charges $5 per million additional input characters. At 5M total characters the current totals are $90 and $22.50. DeepL requires its live Growth subscription and overage for a fair comparison.

Ready to try Langbly?

500K characters included every month. Migrate in minutes.

Same API as Google Translate v2. Just change the URL.