Exam Area: Area 1 – Product Knowledge (15%) Reference: https://docs.developers.optimizely.com/content-management-system/docs/globalization
Globalization in CMS 12 means supporting multiple languages for content. Each content item can exist in multiple language branches — one per enabled language.
Content item: "About Us" page
├── en (English) [Published]
├── sv (Swedish) [Draft]
└── de (German) [Not created]
Admin UI → Websites → [Site] → Languages
→ Add: Swedish (sv) [enabled: ✅]
→ Add: German (de) [enabled: ✅]
→ Master Language: English (en)
// In code — check available languages
var languages = _languageBranchRepository.ListEnabled();
foreach (var lang in languages)
{
Console.WriteLine($"{lang.Name}: {lang.LanguageID}");
}
If content is not yet translated, CMS can fall back to another language:
Page "About Us" has:
en: Published
sv: Not created
Visitor arrives at /sv/about-us/
→ No Swedish version → fall back to en (if fallback is configured)
→ OR show 404 (if no fallback)
// Configure language fallback in appsettings.json
{
"EPiServer": {
"CMS": {
"Languages": [
{ "Language": "sv", "FallbackLanguages": ["en"] }
]
}
}
}
The Master Language is the language in which content is first created.
Properties that have [LanguageSpecific] attribute can differ per language branch.
Properties without this attribute are shared across all language branches.
public class ArticlePage : PageData
{
// Language-specific — each language has its own value
[Display(Name = "Heading")]
public virtual string Heading { get; set; } // ← Auto language-specific for string
// Shared across all languages — only one value
[CultureSpecific(false)]
[Display(Name = "Article Date")]
public virtual DateTime ArticleDate { get; set; }
// Explicitly language-specific
[CultureSpecific]
[Display(Name = "Hero Image")]
public virtual ContentReference HeroImage { get; set; }
}
Default rule: Most property types are language-specific by default in CMS 12. Use
[CultureSpecific(false)]to make a property shared.
// Access enabled languages
public class LanguageService
{
private readonly ILanguageBranchRepository _languageRepo;
public LanguageService(ILanguageBranchRepository languageRepo)
{
_languageRepo = languageRepo;
}
public IEnumerable<LanguageBranch> GetEnabledLanguages()
=> _languageRepo.ListEnabled();
public LanguageBranch GetLanguage(string languageId)
=> _languageRepo.Load(languageId);
}
// Load a specific language version
var swedishPage = _contentLoader.Get<ArticlePage>(
contentRef,
new LanguageSelector("sv"));
// Load all language versions
var allVersions = _contentLoader.GetAllLanguageVersions(contentRef);
URL structure per language depends on site configuration:
| Pattern | Example |
|---|---|
| Hostname per language | www.mysite.se (Swedish), www.mysite.com (English) |
| Path segment | /sv/about-us/, /en/about-us/ |
| Querystring | /about-us/?lang=sv |
English page published
→ Add Swedish translation:
Edit View → Language selector → "Add translation" (sv)
→ Edit Swedish content
→ Publish Swedish version
→ Swedish and English versions are independent
→ Can have different publish states per language
_contentLoader.Get<T>(ref, new LanguageSelector("sv")))[CultureSpecific(false)])