Detecting document language
Routing a document often starts with one question: what language is it in? An incoming invoice in German goes to one queue, the same form in Japanese to another — and the OCR step downstream needs the right language before it can read a single word. Language detection answers that question up front, per page, without sending anything to a server.
This sample shows how to detect the language and text direction of a document using Nutrient .NET SDK. Detection runs fully offline — no network, no API keys.
Download sampleHow Nutrient helps
Nutrient .NET SDK runs the full offline detection pipeline behind a single method call. The SDK handles:
- Rendering each page to a bitmap
- Identifying the writing script(s) present on the page (Latin, Cyrillic, Arabic, Han, and so on)
- Reading the page’s text in the full repertoire of those scripts, preserving diacritics and tone marks
- Identifying the specific language(s) in that text — distinguishing, for example, French from Spanish within the Latin script
- Serializing the per-page result to JSON
The result is a predicted language plus a per-page breakdown, each with its detected language(s) and text direction.
How detection works
For each page, the SDK first determines which writing scripts are present, then reads the page’s text and identifies the language. Languages are reported as ISO 639-2 three-letter codes (eng, fra, rus, vie). Right-to-left scripts (Arabic, Hebrew) report a rltb text direction; everything else reports lrtb.
Detection runs fully offline; resources for non-Latin scripts are fetched once on first use. Language detection requires the OCR feature in your license.
Detecting multiple languages and scripts
By default, detection reports the single dominant script and language of each page — the fastest path and the right choice for single-language documents. Documents that mix scripts (Cyrillic and Han on the same page) or mix languages within one script (English and French) need detection to consider more than one, so the sample raises two OCR settings before detecting:
MaxScriptsbounds how many distinct writing scripts a page is read in.MaxLanguagesbounds how many languages are reported.
Both default to 1. With them raised, each page’s detected languages list contains every language found, ordered most-prominent first.
Multi-page documents
Every page is detected independently and reported in its own entry, so a document whose pages are in different languages surfaces each page’s language rather than collapsing to one. The top-level predictedLanguage is the first page’s language, a convenient default for single-language documents.
Complete implementation
Import the Nutrient namespace:
using Nutrient;Detecting a document’s language
Open the document inside a using statement(opens in a new tab) so resources are cleaned up after processing, raise the script and language caps, create a vision instance bound to it with Vision.Set(document), then call DetectLanguages():
try{ using Document document = Document.Open("input_ocr_multiple_languages.png"); // Read each page in up to two scripts and report up to two languages. document.Settings.OcrSettings.MaxScripts = 2; document.Settings.OcrSettings.MaxLanguages = 2;
Vision vision = Vision.Set(document); string resultJson = vision.DetectLanguages();
File.WriteAllText("output.json", resultJson);}catch (NutrientException e){ Console.Error.WriteLine($"Error: {e.Message}"); Environment.Exit(1);}Understanding the output
DetectLanguages() returns JSON with a top-level languageDetection object:
predictedLanguage— The primary detected language as an ISO 639-2 code. For a document, this is the first page’s language.textDirection— The primary text direction (lrtbleft-to-right,rltbright-to-left).pages— One entry per page, each with itspageNumber, detectedlanguages, andtextDirection.
{ "languageDetection": { "predictedLanguage": "fra", "textDirection": "lrtb", "pages": [ { "pageNumber": 1, "languages": ["fra"], "textDirection": "lrtb" } ] }}Detecting the language of text you already have
When you already have the text — an email body, a database field, your own extraction pipeline — and no file to open, skip the document entirely and call the static Vision.DetectLanguages("…"). Nothing is opened or rendered; the text is scored directly, and the result has the same shape with an empty pages array:
{ "languageDetection": { "predictedLanguage": "rus", "textDirection": "lrtb", "pages": [] }}Error handling
The SDK throws a NutrientException when detection fails. Common failure scenarios include:
- The document can’t be read due to path or permission issues
- A script model is missing or inaccessible, or the OCR feature isn’t licensed
- No document and no text were supplied (detection has nothing to work on)
In production code:
- Catch
NutrientException. - Return a clear error message.
- Log failure details for debugging.
Conclusion
The workflow for offline language detection is:
- Open the source document using a using statement(opens in a new tab) for automatic resource cleanup.
- Raise
MaxScripts/MaxLanguageswhen a page mixes scripts or languages. - Create a vision instance with
Vision.Set()and callDetectLanguages()to detect every page and export the result as JSON (or call the staticVision.DetectLanguages()for text you already have). - Write the JSON to a file for routing or downstream processing.
- Handle
NutrientExceptionfor robust error recovery.
For related extraction workflows, refer to the .NET SDK guides.
Download this ready-to-use sample package to explore language detection.