OrchardCMS/OrchardCore · error · InvalidOperationException
Cannot localize an unsupported culture
Error message
Cannot localize an unsupported culture
What it means
DefaultContentLocalizationManager.LocalizeAsync validates the requested target culture against the site's configured supported cultures (ILocalizationService.GetSupportedCulturesAsync) using a case-insensitive comparison. If the culture is not supported it throws InvalidOperationException, because localization cannot proceed without a culture the site can serve.
Solutions
- Add the target culture in admin Settings > Localization before localizing.
- Pass a culture exactly as listed by ILocalizationService.GetSupportedCulturesAsync (case-insensitive).
- Validate the culture with the supported-cultures list in your own code before calling LocalizeAsync.
- Fall back to a supported parent culture (e.g. 'fr' instead of 'fr-CA') if the regional variant is absent.
Example fix
// before
await _contentLocalizationManager.LocalizeAsync(item, "fr-CA"); // throws if not supported
// after
var supported = await _localizationService.GetSupportedCulturesAsync();
var culture = supported.FirstOrDefault(c => c.StartsWith("fr", StringComparison.OrdinalIgnoreCase)) ?? throw new InvalidOperationException("Add a French culture first");
await _contentLocalizationManager.LocalizeAsync(item, culture); Defensive patterns
Strategy: validation
Validate before calling
var supported = await _localizationService.GetSupportedCulturesAsync();
if (!supported.Any(c => string.Equals(c, targetCulture, StringComparison.OrdinalIgnoreCase)))
throw new ArgumentException($"Culture '{targetCulture}' is not enabled for this site.", nameof(targetCulture)); Type guard
static bool IsSupportedCulture(IEnumerable<string> supported, string culture) => supported.Any(c => string.Equals(c, culture, StringComparison.OrdinalIgnoreCase));
Try / catch
try { var localized = await _contentLocalizationManager.LocalizeAsync(item, culture); }
catch (InvalidOperationException ex) when (ex.Message == "Cannot localize an unsupported culture")
{
logger.LogWarning("Culture {Culture} not enabled; falling back to source item", culture);
localized = item;
} Prevention
- Add all needed cultures in Settings > Localization before automating translation
- Fetch the supported list at runtime instead of hard-coding culture strings
- Validate culture codes with CultureInfo.GetCultureInfo before calling
- Fall back to the parent culture when a regional variant is missing
When it happens
Trigger: Calling IContentLocalizationManager.LocalizeAsync(content, targetCulture) with a culture string that is not enabled under Settings > Localization (e.g. 'fr-FR' when only 'en-US' and 'de' are configured), or with a misspelled culture code.
Common situations: Programmatic translation workflows passing cultures that were never added to the site; cultures removed from settings after custom code was written; regional variants ('pt-BR' vs 'pt') not configured.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- The 'Default' tenant can't be removed.
- ,
- Content part name must start with a letter
- Content part name contains invalid characters
- Content field name must start with a letter
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/4ab28683af20afef.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore.Modules/OrchardCore.ContentLocalization/DefaultContentLocalizationManager.cs:71
}
public async Task<IEnumerable<ContentItem>> GetItemsForSetAsync(string localizationSet)
{
return await _session.Query<ContentItem, LocalizedContentItemIndex>(i => (i.Published || i.Latest) && i.LocalizationSet == localizationSet).ListAsync();
}
public async Task<IEnumerable<ContentItem>> GetItemsForSetsAsync(IEnumerable<string> localizationSets, string culture)
{
var invariantCulture = culture.ToLowerInvariant();
return await _session.Query<ContentItem, LocalizedContentItemIndex>(i => (i.Published || i.Latest) && i.LocalizationSet.IsIn(localizationSets) && i.Culture == invariantCulture).ListAsync();
}
public async Task<ContentItem> LocalizeAsync(ContentItem content, string targetCulture)
{
var supportedCultures = await _localizationService.GetSupportedCulturesAsync();
if (!supportedCultures.Any(c => string.Equals(c, targetCulture, StringComparison.OrdinalIgnoreCase)))
{
throw new InvalidOperationException("Cannot localize an unsupported culture");
}
var localizationPart = content.GetOrCreate<LocalizationPart>();
if (string.IsNullOrEmpty(localizationPart.LocalizationSet))
{
// If the source content item is not yet localized, define its defaults.
localizationPart.LocalizationSet = _iidGenerator.GenerateUniqueId();
localizationPart.Culture = await _localizationService.GetDefaultCultureAsync();
await _session.SaveAsync(content);
}
else
{
var existingContent = await GetContentItemAsync(localizationPart.LocalizationSet, targetCulture);
if (existingContent != null)
{
// Already localized.
return existingContent;View on GitHub (pinned to 4306c0717f)