1

I want to show the translations / localized strings of an object record type in a radio button element in a flow, however configured translation is not shown.

Any idea on how to get RecordType translations in a flow?

Details:

I have a similar case to Get the translations of Record Types in Flows or Use of Schema Class in Flows but the solution is not very helpful.

I am using a standard salesforce object with different RecordTypes. By default each record type has an Id, a label and a description. The label and description properties - by default configured in english - have been translated to another language (setup > translate > (language) > RecordType > Label / Description)

In a flow with a screen I am using a radio button element, which is not defining individual choices, but references a record choice set.

The record choice set gets all RecordTypes of a standard salesforce object, using the Name as label and Id as choice value.

The radio button element is working perfectly in the screen flow, showing me all available RecordTypes of my desired object. However if I switch the users language to the other language - for which translations are defined - the radio button labels are still in english (same if using Name or Description as label for the record choice set)

Any idea - or further input to the referenced question - on how to get RecordType translations in a flow?

2 Answers 2

1

Unfortunately, that linked answer is the way to do this strictly only using Flow. And, since you're interested in Description - you'll see that Description is not part of RecordTypeLocalization so you don't have any option to do what you want only using Flow. I'll point out that, even if you were just interested in name - it would still be cumbersome to do as RecordTypeLocalization has some big limitations that would add complexity just to get a list of record type names:

  • This object only returns translated record types for that specific language. If you don't have a translation for the record type in that language - it won't be returned at all. For example, English wouldn't have any "translations" so this type of logic would only be for the non-default language.
  • big pain with the Get Record element for RecordTypeLocalization
    • you can't query by SObject
    • can't query with the IN operation on ParentId (can upvote this idea and for reference, there is another unofficialsf package for this)
    • "best" filter you can do is by language (which still goes against all SObjects) and could retrieve a lot of rows (and require a for loop and decision element to filter what you're interested in)

So you're left with calling an apex action to get this information.

There's an example from unofficialsf called Get Record Type Info By Object. This action would return the list of record type names which would be its UI labels (translated). You don't have to use that unlocked package as you can take a look at their source

The key is that RecordTypeInfo has a method, getName() which handles giving you the UI label of the record type in Apex.

Returns the UI label of this record type. The label can be translated into any language that Salesforce supports.

However, there is no method to get the translated value of Description (or any method to get the value of Description). As such, you'll want to go at this a different way.

SOQL provides toLabel() which will make this Apex method pretty straightforward.

Use toLabel(fields) to translate SOQL query results into the user’s language. A client application can have results from a query returned that are translated into the user’s language, using toLabel():

Some notes

  • Returning a List<List<RecordType>> to facilitate using the output easily as a record collection variable.
  • I did a query in a for loop because even though Flow passes a List - that list will be 1 if you're not passing a list of inputs. Depending on how you'd re-use this, you'd want to consider the scenario of more inputs (multiple objects, etc). This is just an example of how to do this
  • You could take a look at the unofficialsf example for more inputs you may want to put (get default record type, ignore master, only get active) to add more functionality
@InvocableMethod
global static List<List<RecordType>> get(List<Requests> requestList){
    List<List<RecordType>> recordTypeResponse = new List<List<RecordType>>();
    for(Requests curRequest : requestList) {
        List<RecordType> recordTypes = [SELECT Id, toLabel(Name), toLabel(Description) FROM RecordType WHERE SobjectType =: curRequest.objectName];
        recordTypeResponse.add(recordTypes);
    }
    return recordTypeResponse;

    global class Requests {
        @InvocableVariable(label='Object Name' required=true)
        global String objectName;
    }
}

Then, in your Flow you could define the Name or Description as the value and that will display as translated when applicable.

enter image description here

enter image description here

8
  • Thanks @KrisGoncalves for your very valuable input. I was really hoping for a simpler way, since Salesforce has great language support (apart from adding the actual translation ;-) ). This indeed sounds like a pain and the apex approach is defnitely favorable instead of blowing up the whole flow just for this collection... I will try the apex approach asap.
    – HeXor
    Apr 5 at 15:06
  • Is my understanding correct, that I can only get the translation of the RecordType label using this looped flow, i.e. not the translated description?
    – HeXor
    Apr 6 at 8:19
  • Just realized that GetRecordTypeTranslations returns all translations, i.e. I now have doubled options for my radio buttons caused by the translations for label and description ...
    – HeXor
    Apr 6 at 8:49
  • So the returned translation objects for the label and description do not have any property to differentiate them and they both have the same parent. Hence I do not see any chance to differentiate between them, which renders the loop-flow approach unusable for me...
    – HeXor
    Apr 6 at 9:02
  • 1
    Completely missed your ask about Description. Did a big edit on my answer to leverage SOQL on RecordType in the apex action as opposed to doing the unofficialsf way. Apr 6 at 13:30
0

For reference here is my complete setup (in my case for a WorkOrder object (Salesforce FieldService module).

With this setup I was able to provide a screen with a radio button selection for all active, non-master, available for current user RecordTypes, displaying description (or name) of the record type with the proper translation in the user's language, translated in the translation work bench.

Big thanks an cheers goes to @KrisGoncalves


Flow setup

enter image description here


Flow elements

Get_proper_record_type_translation Apex action

enter image description here

WorkOrder_RecordType_Choices Collection Choice Set

enter image description here

Screen with radio buttons

enter image description here


Apex code GetRecordTypeInfobyObject

global with sharing class GetRecordTypeInfobyObject {

    @InvocableMethod
    global static List<List<RecordType>> get(List<Requests> l_requests){
          
        // Build list of record types
        List<List<RecordType>> l_record_types = new List<List<RecordType>>();
        
        // Loop object requests
        for (Requests current_request : l_requests) {  
            List<RecordType> l_record_types_selected = new List<RecordType>();
        
            try {
                // Retrieve actual list of record type candidates, toLabel(...) does actual work for translation to user language
                List<RecordType> l_record_type_candidates = [SELECT Id, toLabel(Name), toLabel(Description) FROM RecordType WHERE SobjectType =: current_request.object_name];
                
                // Additional information on record type schemas
                Map<String, Schema.RecordTypeInfo> m_record_type_info = Schema.getGlobalDescribe().get(current_request.object_name).getDescribe().getRecordTypeInfosByName();
                List<Schema.RecordTypeInfo> l_record_type_info = m_record_type_info.values();
                
                // Loop record type candidates
                for(RecordType record_type_candidate : l_record_type_candidates) {
                    Boolean b_skip_candidate = false;
                  
                    // Check record type info for current candidate
                    for(Schema.RecordTypeInfo record_type_info : l_record_type_info) {
                        // check current record type matches candidate Id
                        if(record_type_info.getRecordTypeId() != record_type_candidate.Id) {
                            continue;
                        }                        
                        // skip inactive record types (if filtering enabled)
                        if (current_request.b_only_return_active_record_types == true && ! record_type_info.IsActive()) {
                            b_skip_candidate = true;                                                         
                        }                    
                        // skip record types not accessible by current user (if filtering enabled)
                        if (current_request.b_only_return_record_types_available_to_current_user == true && ! record_type_info.isAvailable()) {
                            b_skip_candidate = true; 
                        }                    
                        // skip master record types (if filtering enabled)
                        if (current_request.b_ignore_master_record_type == true && record_type_info.isMaster()) {
                            b_skip_candidate = true; 
                        } 
                        break; // candidate id found, omit other entries
                    }
                    // skip record if any skip condition met
                    if(b_skip_candidate == true) {
                        continue;
                    }
                    // add record type to selected
                    l_record_types_selected.add(record_type_candidate); 
                }
                // add selected record types to output
                l_record_types.add(l_record_types_selected);
                
            } catch (InvocableActionException e){
                System.debug ('exception occured: ' + e.getMessage());                
            } 
        }
        return l_record_types; 
    }
    
    // Definition of request input variables
    global class Requests {
        @InvocableVariable(label='Object Name' required=true)
        global String object_name;

        @InvocableVariable(label='Only return active RecordTypes')
        global Boolean b_only_return_active_record_types;

        @InvocableVariable(label='Only return RecordTypes available to current user')
        global Boolean b_only_return_record_types_available_to_current_user;

        @InvocableVariable(label='Ignore master RecordTypes')
        global Boolean b_ignore_master_record_type;
    }

    // Definition of output variables
    global class Results {
        @InvocableVariable
        global List<String> l_record_types;
    }

    global class InvocableActionException extends Exception {}
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.