Multi-Language & Branded Documents
Build enterprise-ready document templates with multi-language support, consistent branding, reusable components, and centralized management.
Learning Objectives
By the end of this article, you’ll be able to:
- Implement multi-language document templates
- Apply consistent branding across documents
- Create reusable document components
- Manage document templates centrally
- Handle localization and internationalization
- Build scalable template systems
Multi-Language Template Architecture
Base Template with Language Support
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' lang="{{lang}}">
<head>
<title>{{strings.documentTitle}}</title>
<style>
/* Brand Colors */
:root {
--brand-primary: {{brand.colors.primary}};
--brand-secondary: {{brand.colors.secondary}};
--brand-accent: {{brand.colors.accent}};
--brand-text: {{brand.colors.text}};
--brand-light: {{brand.colors.light}};
}
@page {
size: letter;
margin: {{brand.margins.top}}pt {{brand.margins.right}}pt
{{brand.margins.bottom}}pt {{brand.margins.left}}pt;
}
body {
font-family: {{brand.fonts.primary}}, sans-serif;
font-size: {{brand.fonts.baseSize}}pt;
line-height: {{brand.fonts.lineHeight}};
color: var(--brand-text);
}
/* Brand header */
.brand-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2pt solid var(--brand-primary);
padding-bottom: 15pt;
margin-bottom: 30pt;
}
.brand-logo {
height: {{brand.logo.height}}pt;
}
.brand-tagline {
font-size: 10pt;
color: var(--brand-secondary);
font-style: italic;
}
/* Headings */
h1 {
font-size: {{brand.fonts.h1Size}}pt;
color: var(--brand-primary);
font-weight: bold;
margin: 0 0 15pt 0;
font-family: {{brand.fonts.heading}}, sans-serif;
}
h2 {
font-size: {{brand.fonts.h2Size}}pt;
color: var(--brand-secondary);
font-weight: 600;
margin: 20pt 0 10pt 0;
}
h3 {
font-size: {{brand.fonts.h3Size}}pt;
color: var(--brand-text);
font-weight: 600;
margin: 15pt 0 8pt 0;
}
/* Brand footer */
.brand-footer {
position: absolute;
bottom: {{brand.margins.bottom}}pt;
left: {{brand.margins.left}}pt;
right: {{brand.margins.right}}pt;
text-align: center;
font-size: 8pt;
color: #666;
border-top: 1pt solid var(--brand-light);
padding-top: 10pt;
}
/* Language-specific adjustments */
{{#if lang.isRTL}}
body {
direction: rtl;
text-align: right;
}
{{/if}}
/* Content sections */
.content-section {
margin-bottom: 25pt;
}
.section-title {
background-color: var(--brand-light);
color: var(--brand-primary);
padding: 10pt 15pt;
margin-bottom: 15pt;
font-weight: bold;
border-left: 4pt solid var(--brand-primary);
}
/* Data tables */
.data-table {
width: 100%;
border-collapse: collapse;
margin: 15pt 0;
}
.data-table thead {
background-color: var(--brand-primary);
color: white;
}
.data-table th {
padding: 10pt;
text-align: left;
font-weight: bold;
}
.data-table td {
padding: 8pt 10pt;
border-bottom: 1pt solid var(--brand-light);
}
.data-table tbody tr:nth-child(even) {
background-color: #f9fafb;
}
/* Call-to-action */
.cta {
background: linear-gradient(135deg,
var(--brand-primary) 0%,
var(--brand-secondary) 100%);
color: white;
padding: 20pt;
border-radius: 8pt;
text-align: center;
margin: 30pt 0;
}
.cta h2 {
color: white;
margin-top: 0;
}
</style>
</head>
<body>
<!-- Branded Header -->
<div class="brand-header">
<div>
<img src="{{brand.logo.path}}" class="brand-logo" alt="{{brand.name}}" />
{{#if brand.tagline}}
<p class="brand-tagline">{{brand.tagline}}</p>
{{/if}}
</div>
<div style="text-align: right;">
<h1>{{strings.documentTitle}}</h1>
<p style="margin: 5pt 0 0 0; font-size: 10pt; color: #666;">
{{strings.documentSubtitle}}
</p>
</div>
</div>
<!-- Document Content -->
<div class="content-section">
<div class="section-title">{{strings.section1Title}}</div>
<p>{{strings.section1Content}}</p>
<!-- Example table with localized headers -->
<table class="data-table">
<thead>
<tr>
<th>{{strings.table.columnName}}</th>
<th>{{strings.table.columnDescription}}</th>
<th>{{strings.table.columnValue}}</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{this.name}}</td>
<td>{{this.description}}</td>
<td>{{this.value}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<!-- Additional sections -->
{{#each sections}}
<div class="content-section">
<div class="section-title">{{this.title}}</div>
{{#each this.paragraphs}}
<p>{{this}}</p>
{{/each}}
</div>
{{/each}}
<!-- Call to Action -->
{{#if strings.cta}}
<div class="cta">
<h2>{{strings.cta.title}}</h2>
<p>{{strings.cta.message}}</p>
</div>
{{/if}}
<!-- Branded Footer -->
<div class="brand-footer">
<p>{{brand.name}} | {{brand.contact.phone}} | {{brand.contact.email}} | {{brand.contact.website}}</p>
<p>{{strings.footer.copyright}} {{brand.copyrightYear}} {{brand.name}}. {{strings.footer.allRightsReserved}}</p>
</div>
</body>
</html>
C# Multi-Language Document System
using Scryber.Components;
using Scryber.PDF;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
public class MultiLanguageDocumentGenerator
{
private readonly string _templatePath;
private readonly Dictionary<string, LocalizationStrings> _localization;
private readonly BrandConfiguration _brandConfig;
public MultiLanguageDocumentGenerator(
string templatePath,
BrandConfiguration brandConfig)
{
_templatePath = templatePath;
_brandConfig = brandConfig;
_localization = new Dictionary<string, LocalizationStrings>();
// Load localization resources
LoadLocalizationResources();
}
public void GenerateDocument(
DocumentData documentData,
string languageCode,
Stream output)
{
// Get localized strings
var strings = GetLocalizedStrings(languageCode);
// Load template
var doc = Document.ParseDocument(_templatePath);
// Set metadata
doc.Info.Title = strings.DocumentTitle;
doc.Info.Author = _brandConfig.Name;
doc.Info.CreationDate = DateTime.Now;
// Bind data
doc.Params["brand"] = _brandConfig;
doc.Params["strings"] = strings;
doc.Params["lang"] = new LanguageInfo
{
Code = languageCode,
IsRTL = IsRightToLeft(languageCode)
};
doc.Params["items"] = documentData.Items;
doc.Params["sections"] = documentData.Sections;
// Configure
doc.RenderOptions.Compression = PDFCompressionType.FlateDecode;
doc.RenderOptions.FontSubsetting = true;
// Generate
doc.SaveAsPDF(output);
}
private void LoadLocalizationResources()
{
// English
_localization["en"] = new LocalizationStrings
{
DocumentTitle = "Product Catalog",
DocumentSubtitle = "Premium Solutions for Your Business",
Section1Title = "Our Products",
Section1Content = "Discover our comprehensive range of innovative products designed to meet your needs.",
Table = new TableStrings
{
ColumnName = "Product Name",
ColumnDescription = "Description",
ColumnValue = "Price"
},
Cta = new CtaStrings
{
Title = "Ready to Get Started?",
Message = "Contact us today to learn more about our products and services."
},
Footer = new FooterStrings
{
Copyright = "Copyright ©",
AllRightsReserved = "All rights reserved."
}
};
// Spanish
_localization["es"] = new LocalizationStrings
{
DocumentTitle = "Catálogo de Productos",
DocumentSubtitle = "Soluciones Premium para su Negocio",
Section1Title = "Nuestros Productos",
Section1Content = "Descubra nuestra gama completa de productos innovadores diseñados para satisfacer sus necesidades.",
Table = new TableStrings
{
ColumnName = "Nombre del Producto",
ColumnDescription = "Descripción",
ColumnValue = "Precio"
},
Cta = new CtaStrings
{
Title = "¿Listo para Comenzar?",
Message = "Contáctenos hoy para conocer más sobre nuestros productos y servicios."
},
Footer = new FooterStrings
{
Copyright = "Derechos de Autor ©",
AllRightsReserved = "Todos los derechos reservados."
}
};
// French
_localization["fr"] = new LocalizationStrings
{
DocumentTitle = "Catalogue de Produits",
DocumentSubtitle = "Solutions Premium pour Votre Entreprise",
Section1Title = "Nos Produits",
Section1Content = "Découvrez notre gamme complète de produits innovants conçus pour répondre à vos besoins.",
Table = new TableStrings
{
ColumnName = "Nom du Produit",
ColumnDescription = "Description",
ColumnValue = "Prix"
},
Cta = new CtaStrings
{
Title = "Prêt à Commencer?",
Message = "Contactez-nous aujourd'hui pour en savoir plus sur nos produits et services."
},
Footer = new FooterStrings
{
Copyright = "Droits d'auteur ©",
AllRightsReserved = "Tous droits réservés."
}
};
// German
_localization["de"] = new LocalizationStrings
{
DocumentTitle = "Produktkatalog",
DocumentSubtitle = "Premium-Lösungen für Ihr Unternehmen",
Section1Title = "Unsere Produkte",
Section1Content = "Entdecken Sie unser umfassendes Sortiment an innovativen Produkten, die Ihren Anforderungen gerecht werden.",
Table = new TableStrings
{
ColumnName = "Produktname",
ColumnDescription = "Beschreibung",
ColumnValue = "Preis"
},
Cta = new CtaStrings
{
Title = "Bereit anzufangen?",
Message = "Kontaktieren Sie uns noch heute, um mehr über unsere Produkte und Dienstleistungen zu erfahren."
},
Footer = new FooterStrings
{
Copyright = "Urheberrecht ©",
AllRightsReserved = "Alle Rechte vorbehalten."
}
};
}
private LocalizationStrings GetLocalizedStrings(string languageCode)
{
if (_localization.ContainsKey(languageCode))
{
return _localization[languageCode];
}
// Default to English
return _localization["en"];
}
private bool IsRightToLeft(string languageCode)
{
var rtlLanguages = new[] { "ar", "he", "fa", "ur" };
return rtlLanguages.Contains(languageCode);
}
}
// Brand Configuration
public class BrandConfiguration
{
public string Name { get; set; }
public string Tagline { get; set; }
public int CopyrightYear { get; set; }
public LogoConfig Logo { get; set; }
public ColorScheme Colors { get; set; }
public FontConfig Fonts { get; set; }
public MarginConfig Margins { get; set; }
public ContactInfo Contact { get; set; }
}
public class LogoConfig
{
public string Path { get; set; }
public int Height { get; set; }
}
public class ColorScheme
{
public string Primary { get; set; }
public string Secondary { get; set; }
public string Accent { get; set; }
public string Text { get; set; }
public string Light { get; set; }
}
public class FontConfig
{
public string Primary { get; set; }
public string Heading { get; set; }
public int BaseSize { get; set; }
public decimal LineHeight { get; set; }
public int H1Size { get; set; }
public int H2Size { get; set; }
public int H3Size { get; set; }
}
public class MarginConfig
{
public int Top { get; set; }
public int Right { get; set; }
public int Bottom { get; set; }
public int Left { get; set; }
}
public class ContactInfo
{
public string Phone { get; set; }
public string Email { get; set; }
public string Website { get; set; }
}
// Localization models
public class LocalizationStrings
{
public string DocumentTitle { get; set; }
public string DocumentSubtitle { get; set; }
public string Section1Title { get; set; }
public string Section1Content { get; set; }
public TableStrings Table { get; set; }
public CtaStrings Cta { get; set; }
public FooterStrings Footer { get; set; }
}
public class TableStrings
{
public string ColumnName { get; set; }
public string ColumnDescription { get; set; }
public string ColumnValue { get; set; }
}
public class CtaStrings
{
public string Title { get; set; }
public string Message { get; set; }
}
public class FooterStrings
{
public string Copyright { get; set; }
public string AllRightsReserved { get; set; }
}
public class LanguageInfo
{
public string Code { get; set; }
public bool IsRTL { get; set; }
}
// Document data
public class DocumentData
{
public List<DocumentItem> Items { get; set; } = new List<DocumentItem>();
public List<DocumentSection> Sections { get; set; } = new List<DocumentSection>();
}
public class DocumentItem
{
public string Name { get; set; }
public string Description { get; set; }
public string Value { get; set; }
}
public class DocumentSection
{
public string Title { get; set; }
public List<string> Paragraphs { get; set; }
}
Usage Example
// Configure brand
var brandConfig = new BrandConfiguration
{
Name = "Acme Corporation",
Tagline = "Innovation for Tomorrow",
CopyrightYear = 2025,
Logo = new LogoConfig
{
Path = "./images/acme-logo.png",
Height = 50
},
Colors = new ColorScheme
{
Primary = "#2563eb",
Secondary = "#1e40af",
Accent = "#3b82f6",
Text = "#1f2937",
Light = "#eff6ff"
},
Fonts = new FontConfig
{
Primary = "Helvetica",
Heading = "Arial",
BaseSize = 11,
LineHeight = 1.6m,
H1Size = 20,
H2Size = 16,
H3Size = 13
},
Margins = new MarginConfig
{
Top = 72,
Right = 72,
Bottom = 100,
Left = 72
},
Contact = new ContactInfo
{
Phone = "(555) 123-4567",
Email = "info@acme.com",
Website = "www.acme.com"
}
};
// Create document data
var documentData = new DocumentData
{
Items = new List<DocumentItem>
{
new DocumentItem
{
Name = "Product A",
Description = "Premium solution",
Value = "$999"
},
new DocumentItem
{
Name = "Product B",
Description = "Standard solution",
Value = "$499"
}
},
Sections = new List<DocumentSection>
{
new DocumentSection
{
Title = "Why Choose Us",
Paragraphs = new List<string>
{
"We provide the best quality products.",
"Customer satisfaction is our priority."
}
}
}
};
// Generate documents in multiple languages
var generator = new MultiLanguageDocumentGenerator(
"multilanguage-template.html",
brandConfig
);
var languages = new[] { "en", "es", "fr", "de" };
foreach (var lang in languages)
{
using (var output = new FileStream($"catalog-{lang}.pdf", FileMode.Create))
{
generator.GenerateDocument(documentData, lang, output);
Console.WriteLine($"Generated {lang} version");
}
}
Template Management System
public class TemplateManager
{
private readonly string _templatesDirectory;
private readonly Dictionary<string, BrandConfiguration> _brands;
public TemplateManager(string templatesDirectory)
{
_templatesDirectory = templatesDirectory;
_brands = new Dictionary<string, BrandConfiguration>();
LoadBrandConfigurations();
}
private void LoadBrandConfigurations()
{
// Load brand configurations from JSON files
// This is a simplified example
}
public Stream GenerateDocument(
string templateName,
string brandId,
string languageCode,
object data)
{
var templatePath = Path.Combine(_templatesDirectory, $"{templateName}.html");
var brand = _brands[brandId];
var generator = new MultiLanguageDocumentGenerator(templatePath, brand);
var output = new MemoryStream();
// Convert data to DocumentData
var documentData = ConvertToDocumentData(data);
generator.GenerateDocument(documentData, languageCode, output);
output.Position = 0;
return output;
}
private DocumentData ConvertToDocumentData(object data)
{
// Convert generic data to DocumentData
// Implementation depends on your data structure
return new DocumentData();
}
}
Try It Yourself
Exercise 1: Add Languages
Extend the system with additional languages:
- Add Chinese (simplified/traditional)
- Add Japanese
- Add Arabic (RTL support)
- Test with Unicode characters
Exercise 2: Brand Themes
Create multiple brand themes:
- Corporate theme
- Modern theme
- Classic theme
- Implement theme switching
Exercise 3: Resource Management
Build a resource management system:
- Store strings in JSON files
- Load from database
- Cache localization resources
- Support fallback languages
Best Practices
- Externalize Strings - Never hardcode text in templates
- Unicode Support - Use UTF-8 encoding throughout
- RTL Support - Handle right-to-left languages properly
- Brand Consistency - Use centralized brand configuration
- Template Versioning - Track template versions
- Testing - Test all language variations
- Performance - Cache compiled templates
- Documentation - Document string keys and usage
Localization Checklist
- All strings externalized
- Language files created for each locale
- RTL support implemented (if needed)
- Date/number formatting localized
- Currency symbols localized
- Unicode characters tested
- Fallback language configured
- Brand colors consistent across languages
- Tested with native speakers
Brand Consistency Checklist
- Logo usage consistent
- Colors match brand guidelines
- Typography follows standards
- Spacing and margins consistent
- Headers and footers branded
- Contact information accurate
- Legal notices included
- Version control implemented
Congratulations!
You’ve completed the Practical Applications series and mastered real-world PDF generation with Scryber!
What You’ve Learned
Through this series, you’ve built complete, production-ready examples:
- Invoice Template - Professional invoicing
- Business Letter - Formal correspondence
- Report Template - Multi-section reports
- Certificate Template - Awards and certificates
- Data-Driven Report - Database integration
- Catalog & Brochure - Product catalogs
- Form Template - Print-and-fill forms
- Multi-Language & Branded Documents - Enterprise systems
Next Steps
Continue Your Journey:
- Review Previous Series - Reinforce your learning
- Build Your Own Projects - Apply these patterns to your needs
- Explore API Documentation - Deep dive into Scryber features
- Join the Community - Share your experiences and learn from others
Additional Resources
- Complete Reference - API documentation
- Code Examples - More sample code
- GitHub Repository - Source code and issues
- Community Forum - Ask questions
Explore more → Learning Guide Home