Exporting SAP Translations to XLIFF via Custom ABAP Class
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_objlist
contains 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.