You are here:
Render Seamless Multi-Language Fonts in Generated PDFs
By enabling advanced text shaping for specific document processes, you can correct rendering issues for complex scripts in generated PDFs. Use the text shaper flag when you have documents containing non-English text that requires advanced text shaping settings. Doing so prevents unnecessary performance degradation for documents that contain standard English text.
Required Editions
Note Text shaping is a performance-intensive operation, so use it sparingly. Limit text shaping
to the document templates that you need, as it increases document generation time during both
automatic and manual setup.
| Available in: Lightning Experience |
| Available in: Professional, Enterprise, Unlimited, and Developer Editions |
| User Permissions Needed | |
|---|---|
| To generate a document: | DocGen User Permission Set |
- Turn On Text Shaping Manually
Add the text shaper flag directly to the document generation process record to resolve font sequencing issues. - Automate Text Shaping with a Trigger
Use an Apex trigger to programmatically add the text shaper flag into document requests based on your specific template requirements.
Turn On Text Shaping Manually
Add the text shaper flag directly to the document generation process record to resolve font sequencing issues.
- Prepare your JSON payload for a new Document Generation Process record.
- In the Request Text field, add the "useTextShaper": true parameter into the JSON payload.
Automate Text Shaping with a Trigger
Use an Apex trigger to programmatically add the text shaper flag into document requests based on your specific template requirements.
- From Setup, in the Quick Find box, enter Object Manager, and then select Object Manager.
- Select Document Generation Process, and then click Triggers.
- Click New and enter your trigger logic.
Example Use this sample trigger logic after adding your specific template IDs. We recommend
customizing the logic to target only the specific templates that require advanced text
shaping to avoid unnecessary performance
overhead.
trigger DocumentGenerationProcessTrigger on DocumentGenerationProcess (before insert) {
// Define the list of applicable template IDs (Content Version IDs or Document Template IDs)
// Update this list with their specific template IDs where useTextShaper should be enabled
Set<String> applicableTemplates = new Set<String>();
applicableTemplates.add('068VW000000FsGDYA1'); // Example ContentVersion ID - replace with actual IDs
applicableTemplates.add('2dtVW000000EcgXYAS'); // Example DocumentTemplate ID - replace with actual IDs
// Add more Content Version IDs or Document Template IDs here as needed
for (DocumentGenerationProcess dgp : Trigger.new) {
Boolean shouldApplyTextShaper = false;
String templateContentVersionId = null;
// Check requestText for templateContentVersionId
if (String.isNotBlank(dgp.requestText)) {
try {
// 1. Deserialize the existing JSON string into a Map
Map<String, Object> requestMap = (Map<String, Object>) JSON.deserializeUntyped(dgp.requestText);
// 2. Extract templateContentVersionId from requestText JSON
if (requestMap.containsKey('templateContentVersionId')) {
templateContentVersionId = (String) requestMap.get('templateContentVersionId');
}
// 3. Check if templateContentVersionId is in the applicable list
if (String.isNotBlank(templateContentVersionId) && applicableTemplates.contains(templateContentVersionId)) {
shouldApplyTextShaper = true;
}
// 4. If not found via templateContentVersionId, check DocumentTemplate field
if (!shouldApplyTextShaper && String.isNotBlank(dgp.DocumentTemplateId)) {
if (applicableTemplates.contains(dgp.DocumentTemplateId)) {
shouldApplyTextShaper = true;
}
}
// 5. Apply useTextShaper only if template is in the applicable list
if (shouldApplyTextShaper) {
requestMap.put('useTextShaper', true);
dgp.requestText = JSON.serialize(requestMap);
}
} catch (Exception e) {
System.debug('Error parsing requestText JSON: ' + e.getMessage());
// Optional: Handle malformed JSON here (e.g., dgp.addError('Invalid JSON format'));
}
} else {
// If requestText is empty, check DocumentTemplate field
if (String.isNotBlank(dgp.DocumentTemplateId) && applicableTemplates.contains(dgp.DocumentTemplateId)) {
dgp.requestText = '{"useTextShaper": true}';
}
}
}
}
Did this article solve your issue?
Let us know so we can improve!

