Exporting SAP Translations to XLIFF via Custom ABAP Class
Learn how to export SAP translations to XLIFF using a custom ABAP class. This guide covers automation, integration with localization tools, and best practices for managing SAP translation data.
Working with localization in SAP systems can be quite the task especially when your team needs to extract translations for use in external tools like Weblate or other XLIFF-compatible editors. While SAP provides tooling (such as the transaction LXE_MASTER and report RS_LXE_TEXTEXT_EXPORT), the manual handling can be tedious and lacks flexibility.
In this post, I’ll walk you through how we tackled this issue by creating a custom ABAP class that reads predefined object lists and exports the data into XLIFF in a way that’s reusable across other ABAP logic.
Along the way, we’ll explore some important SAP translation infrastructure concepts and walk through the main building blocks of the solution.
Understanding XLIFF and SAP’s Translation Layer
Before diving into code, a quick overview:
- XLIFF (XML Localization Interchange File Format) is an industry-standard XML format for storing translatable data and their translations.
- In SAP, translations are managed via the Translation Hub, and objects to be translated are grouped in Object Lists within
LXE_MASTER. - These object lists can include reports, data elements, domains, etc.
Exporting translations in XLIFF format enables integration with modern localization pipelines, including services like Weblate or Crowdin.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
DATA lt_objtypes TYPE TABLE OF lxeobjtype.
" check if there is at least one object list
IF gr_objlist IS INITIAL.
RAISE EXCEPTION TYPE cx_lxe_textext
EXPORTING
textid = cx_lxe_textext=>object_selection.
ENDIF.
" Read allowed object types
SELECT obj_type
FROM lxe_attob
INTO TABLE lt_objtypes
WHERE typeatt EQ cl_lxe_constants=>c_typeatt_short.
IF sy-subrc NE 0.
RAISE EXCEPTION TYPE cx_lxe_textext
EXPORTING
textid = cx_lxe_textext=>object_selection.
ENDIF.
" allow export of virtual objects
APPEND cl_lxe_constants=>c_objtype_dems
TO lt_objtypes.
" Get translation objects
SELECT custmnr objtype objname orig_lang collnam domanam
FROM lxe_colob
INTO CORRESPONDING FIELDS OF TABLE gt_colob_st
FOR ALL ENTRIES IN lt_objtypes
WHERE objlist IN gr_objlist
AND objtype EQ lt_objtypes-table_line.
gr_objlistcontains the object lists you want to export.
Extracting and Formatting Localization Data
After retrieving the objects, the next step is converting them into XLIFF. This includes reading existing translations, formatting the XML structure, and transforming it into a human-readable and standards-compliant format.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
METHOD create_xliff_for_lang.
DATA: lv_source_lang TYPE lxestring,
lv_destination_lang TYPE lxestring,
lv_reference_lang TYPE lxestring,
lv_tstamp_str TYPE lxestring.
DATA: lt_objects TYPE cl_lxe_textext_aux=>tt_lxe_object_full.
" prepare the texts
lt_objects = prepare_short_texts( iv_lang ).
" convert langs to xml
lv_source_lang = cl_lxe_textext_aux=>convert_lang_sap_to_xml( gv_source_lang ).
lv_destination_lang = cl_lxe_textext_aux=>convert_lang_sap_to_xml( iv_lang ).
lv_tstamp_str = create_xliff_date( ).
CALL TRANSFORMATION lxe_shorttext_to_xliff
SOURCE objects = lt_objects
src_lang = lv_source_lang
tgt_lang = lv_destination_lang
ref_lang = lv_reference_lang
timestamp = lv_tstamp_str
RESULT XML rv_result.
" Transform it to a nicely intended XML
TRY.
" read the XML file
DATA(lo_reader) = cl_sxml_string_reader=>create( rv_result ).
" set up the writer
DATA(lo_writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10
encoding = 'UTF-8' ) ).
lo_writer->set_option( if_sxml_writer=>co_opt_linebreaks ).
lo_writer->set_option( if_sxml_writer=>co_opt_indent ).
lo_reader->next_node( ).
lo_reader->skip_node( lo_writer ).
" and write it back to the xstring
rv_result = CAST cl_sxml_string_writer( lo_writer )->get_output( ).
CATCH cx_root INTO DATA(e_txt).
ENDTRY.
" validate the created xliff
cl_lxe_textext_aux=>validate_xliff(
EXPORTING
xliff = rv_result
EXCEPTIONS
invalid = 1 ).
IF sy-subrc NE 0.
RAISE EXCEPTION TYPE cx_lxe_textext
EXPORTING
textid = cx_lxe_textext=>xml_transform.
ENDIF.
ENDMETHOD.
*Pretty-printing XML: The code includes logic to reformat the generated XLIFF to make it readable using cl_sxml_string_reader and cl_sxml_string_writer.
Building the Text Export Logic
Prepare Translation Objects
The prepare_short_texts method reads the translation data using SAP’s standard function modules like LXE_OBJ_TEXT_PAIR_READ.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
METHOD prepare_short_texts.
DATA: ls_object TYPE lxe_object_full,
ls_texts TYPE lxe_texts_export.
DATA: lt_pcx_s1 TYPE TABLE OF lxe_pcx_s1.
FIELD-SYMBOLS: <colob> TYPE t_colob,
<pcx> TYPE lxe_pcx_s1.
" get the objects
LOOP AT gt_colob_st ASSIGNING <colob>.
CLEAR: ls_object, lt_pcx_s1.
MOVE-CORRESPONDING <colob> TO ls_object.
IF ls_object-objname(3) = '---'.
ls_object-objname(3) = sy-mandt.
ENDIF.
CALL FUNCTION 'LXE_OBJ_TEXT_PAIR_READ'
EXPORTING
t_lang = iv_lang
s_lang = gv_source_lang
custmnr = ls_object-custmnr
objtype = ls_object-objtype
objname = ls_object-objname
TABLES
lt_pcx_s1 = lt_pcx_s1.
CHECK lt_pcx_s1 IS NOT INITIAL.
CALL FUNCTION 'LXE_OBJ_TRANSLATION_STATUS2'
EXPORTING
t_lang = iv_lang
s_lang = gv_source_lang
custmnr = ls_object-custmnr
objtype = ls_object-objtype
objname = ls_object-objname
IMPORTING
stattrn = ls_object-stattrn.
" cumulate
" (target text must by ignored as it would cause redundant translations)
SORT lt_pcx_s1 BY s_text unitmlt.
DELETE ADJACENT DUPLICATES FROM lt_pcx_s1 COMPARING s_text unitmlt.
LOOP AT lt_pcx_s1 ASSIGNING <pcx>.
MOVE-CORRESPONDING <pcx> TO ls_texts.
APPEND ls_texts TO ls_object-texts.
ENDLOOP.
prepare_short_texts_lines( EXPORTING iv_lang = iv_lang
CHANGING cs_object = ls_object ).
ls_object-path = |//{ sy-sysid }//{ sy-mandt }//{ ls_object-custmnr }//{ ls_object-objtype }//{ ls_object-objname }|.
APPEND ls_object
TO rt_objects.
ENDLOOP.
ENDMETHOD.
Redundant entries are cleaned, and a reference path is constructed for each object.
Prepare Short Text Lines
This step evaluates the translation state (e.g., translated/untranslated) and marks the approved status accordingly.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
METHOD prepare_short_texts_lines.
CONSTANTS: lc_approved_yes TYPE string VALUE 'yes',
lc_approved_no TYPE string VALUE 'no'.
DATA: lv_stattrn TYPE lxestattrn,
lt_ref_texts TYPE STANDARD TABLE OF lxe_pcx_s1,
wa_text TYPE lxe_pcx_s1.
FIELD-SYMBOLS <text> TYPE lxe_texts_export.
LOOP AT cs_object-texts ASSIGNING <text>.
CLEAR lv_stattrn. " lv_pstatus.
TRY.
cl_lxe_pp=>factory->getlib_eval( )->evaluate_get(
EXPORTING
i_src_lang = gv_source_lang
i_tgt_lang = iv_lang
i_domain = cs_object-domanam
i_src_text = <text>-s_text
i_tgt_text = <text>-t_text
i_max_length = <text>-unitmlt
IMPORTING
e_trl_status = lv_stattrn
e_best_p_text = <text>-best_pp
e_best_p_status = <text>-best_pp_status ).
CATCH cx_lxe_pp.
DELETE TABLE cs_object-texts FROM <text>.
CONTINUE.
ENDTRY.
IF lv_stattrn = cl_lxe_constants=>c_trl_status_translated.
<text>-state = lv_stattrn.
<text>-approved = lc_approved_yes.
ELSE.
<text>-state = lv_stattrn.
<text>-approved = lc_approved_no.
ENDIF.
ENDLOOP.
ENDMETHOD.
Depending on e_trl_status, the translation line is either marked approved (yes) or not (no).
Use Cases and Integration
Once the class is complete, it can be reused from other ABAP reports or batch jobs, for example:
- Scheduled background jobs to export translations nightly.
- Integration with CI/CD pipelines to push localization content.
- Syncing translations with external translators using Git + Weblate.
Final Thoughts
Adding automation around SAP’s translation tools can save a ton of time, especially for internationalized systems that change frequently. By wrapping RS_LXE_TEXTEXT_EXPORT logic into a callable class, we made our translation export process scriptable and reliable.
XLIFF as a format opens the door to powerful external tooling and allows us to keep translations versioned alongside our codebase.