Repository navigation
Language Ranges
Language ranges are defined by RFC 4647 and are used to select or filter language tags.
A language range is not a LanguageTag. In particular, extended ranges can contain the wildcard * in individual subtag positions. Enbrea.Bcp47 therefore models ranges separately using LanguageRange and LanguageRangeParser.
A basic range contains a primary language-range subtag followed by zero or more ordinary subtags, or consists entirely of *.
Examples include:
de
de-DE
zh-Hant
*
Parse a basic range explicitly with ParseBasic():
var range = LanguageRangeParser.ParseBasic("de-DE");For input that may be invalid:
if (LanguageRangeParser.TryParseBasic(value, out var range))
{
Console.WriteLine(range);
}Check syntax without creating a range:
LanguageRangeParser.IsBasic("de-DE"); // trueBasic ranges are required by RFC 4647 Basic Filtering and Lookup.
Extended ranges additionally permit wildcard subtags:
de-*-DE
*-Latn
zh-*-CN
Use Parse() for the extended grammar:
var range = LanguageRangeParser.Parse("de-*-DE");The extended grammar includes all valid basic ranges, so this is also valid:
var range = LanguageRangeParser.Parse("de-DE");Use TryParse() when invalid input is expected:
if (LanguageRangeParser.TryParse(value, out var range))
{
Console.WriteLine(range);
}Or test the grammar directly:
LanguageRangeParser.IsExtended("de-*-DE"); // trueUse Parse() when an extended range is acceptable:
var range = LanguageRangeParser.Parse("de-*-DE");Use ParseBasic() when the range is intended for an operation that requires basic syntax:
var range = LanguageRangeParser.ParseBasic("de-DE");This makes invalid combinations fail early rather than later when a matching operation is called.
Like LanguageTag, LanguageRange preserves the original input:
var range = LanguageRangeParser.Parse("DE-*-Ch");
Console.WriteLine(range.Value); // DE-*-ChToString() returns the normalized representation. Language ranges are case-insensitive and normalized to lowercase:
Console.WriteLine(range); // de-*-chThe normalized subtags are available through Subtags:
foreach (var subtag in range.Subtags)
{
Console.WriteLine(subtag);
}Every parsed range exposes IsBasic:
var basic = LanguageRangeParser.Parse("de-DE");
var extended = LanguageRangeParser.Parse("de-*-DE");
Console.WriteLine(basic.IsBasic); // true
Console.WriteLine(extended.IsBasic); // falseThis is useful when a range was parsed using the general Parse() method but later passed to an operation that only accepts basic ranges.
The standalone wildcard is valid in both basic and extended syntax:
var range = LanguageRangeParser.ParseBasic("*");
Console.WriteLine(range.IsWildcard); // trueIn filtering operations it matches all language tags. Lookup treats * differently because a wildcard does not identify one best language tag. See Language Tag Matching.
Language-range parsing is registry-independent. The parser validates the RFC 4647 range syntax but does not resolve subtags through the IANA Language Subtag Registry.
This is by design: matching language ranges is based on their subtag sequence rather than registry semantics.
See Language Tag Matching for Basic Filtering, Extended Filtering, and Lookup.