Multi-Language/Traductions dans ABAP Cloud

Catégorie
ABAP Cloud
Publié
Auteur
Johannes

Les applications SAP internationales doivent afficher des textes dans differentes langues. ABAP Cloud offre plusieurs mecanismes pour le multilinguisme : Message Classes pour les messages, Text Elements pour les textes UI et CDS Text Associations pour les textes de base de donnees. Cet article montre comment developper des applications multilingues dans ABAP Cloud.

Apercu des mecanismes de traduction

Dans ABAP Cloud, il existe differentes approches pour le multilinguisme :

MecanismeUtilisationEmplacement de stockage
Message ClassesMessages (erreurs, avertissements, succes)Classe de messages
Text ElementsTextes UI dans le code ABAPElements de texte de la classe
CDS Text AssociationsTextes de base de donnees (ex. descriptions d’articles)Tables de texte
Data ElementsLabels de champsDDIC Data Element
CDS AnnotationsTextes de metadonnees pour Fiori@EndUserText, @UI.*

Message Classes - Traduire les messages

Les Message Classes sont le standard pour les messages d’erreur, avertissements et informations. Dans ABAP Cloud, vous les creez dans ADT sous Other ABAP Repository Objects > Message Class.

Creer une Message Class

" Definition d'une Message Class (dans ADT)
" Message Class : ZTRAVEL_MSG
" Messages :
" 001 - Voyage & cree avec succes
" 002 - Voyage & deja reserve
" 003 - Dates de voyage invalides : & a &
" 004 - Duree maximale de voyage de & jours depassee

Les placeholders & sont remplaces a l’execution par des parametres :

CLASS zcl_travel_validation DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_abap_behavior_handler.
ENDCLASS.
CLASS zcl_travel_validation IMPLEMENTATION.
METHOD if_abap_behavior_handler~validate.
" Afficher un message avec parametres
DATA(ls_travel) = <fs_travel>.
IF ls_travel-begin_date > ls_travel-end_date.
" Message 003 : Dates de voyage invalides : & a &
APPEND VALUE #(
%tky = ls_travel-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Dates de voyage invalides : { ls_travel-begin_date } a { ls_travel-end_date }|
)
) TO reported-travel.
ENDIF.
" Alternative : Utiliser Message Class
APPEND VALUE #(
%tky = ls_travel-%tky
%msg = new_message(
id = 'ZTRAVEL_MSG"
number = '003"
severity = if_abap_behv_message=>severity-error
v1 = |{ ls_travel-begin_date }|
v2 = |{ ls_travel-end_date }|
)
) TO reported-travel.
ENDMETHOD.
ENDCLASS.

Traduire les messages

Les traductions sont gerees dans ADT via Properties > Translations. La langue originale est typiquement l’anglais (EN), les traductions sont faites dans les langues cibles.

" ZTRAVEL_MSG - Message 003
" EN : Invalid travel dates: & to &
" DE : Ungueltige Reisedaten: & bis &
" FR : Dates de voyage invalides : & a &
" ES : Fechas de viaje no validas: & a &

Text Elements - Textes de programme

Les Text Elements sont des textes utilises directement dans le code ABAP. Dans ABAP Cloud, ils sont definis comme partie de la classe ABAP.

Text Elements dans les classes

CLASS zcl_travel_report DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
" Les Text Symbols sont definis dans la classe
" TEXT-001 : Apercu des voyages
" TEXT-002 : Aucun voyage trouve
" TEXT-003 : Voyage cree le
METHODS generate_report
RETURNING VALUE(rv_html) TYPE string.
ENDCLASS.
CLASS zcl_travel_report IMPLEMENTATION.
METHOD generate_report.
" Utiliser les Text Symbols
DATA(lv_title) = TEXT-001. " Apercu des voyages
" Alternativement : Texte inline avec traduction
DATA(lv_no_data) = 'No travels found'(002).
" Texte avec variables
rv_html = |<h1>{ lv_title }</h1>|.
IF lt_travels IS INITIAL.
rv_html = rv_html && |<p>{ lv_no_data }</p>|.
ENDIF.
ENDMETHOD.
ENDCLASS.

Gerer le Text Pool

Dans ADT, ouvrez la classe et naviguez vers Text Elements dans la vue Outline. Les textes y sont geres :

SymbolTexte (EN)Texte (FR)
001Travel OverviewApercu des voyages
002No travels foundAucun voyage trouve
003Travel created onVoyage cree le

CDS Text Associations - Textes de base de donnees

Pour les donnees de base dependantes de la langue (ex. descriptions d’articles, noms de pays), ABAP Cloud utilise les CDS Text Associations. Celles-ci lient une table principale a une table de textes.

Creer une table de textes

D’abord, vous creez une table de textes avec cle de langue :

@EndUserText.label : 'Textes produits"
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
define table zproduct_text {
key client : abap.clnt not null;
key product_id: zproduct_id not null;
key language : abap.lang not null;
name : abap.char(60);
description : abap.char(255);
}

CDS View avec Text Association

Le CDS View connecte les donnees de base avec les textes :

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Produit avec textes"
define view entity ZI_Product
as select from zproduct as Product
association [0..*] to zproduct_text as _Text
on _Text.product_id = Product.product_id
{
key Product.product_id as ProductId,
Product.product_type as ProductType,
Product.price as Price,
Product.currency as Currency,
" Exposer la Text Association
_Text
}

Text Association dans la Projection View

Dans la Projection View, vous utilisez @ObjectModel.text.association :

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Produit (Projection)"
@Metadata.allowExtensions: true
define view entity ZC_Product
as projection on ZI_Product
{
key ProductId,
ProductType,
Price,
Currency,
" Text Association avec filtrage automatique de la langue
@ObjectModel.text.association: '_Text"
_Text
}

Filtrage automatique de la langue

Avec @Semantics.language: true, vous marquez le champ de langue :

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Vue texte produit"
define view entity ZI_ProductText
as select from zproduct_text
{
key product_id as ProductId,
@Semantics.language: true
key language as Language,
name as Name,
description as Description
}

Fiori Elements filtre automatiquement sur la langue de connexion de l’utilisateur.

Text Element pour champ d’affichage

Pour un seul champ d’affichage avec traduction automatique :

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Produit avec description"
define view entity ZI_ProductWithText
as select from zproduct as Product
left outer join zproduct_text as Text
on Text.product_id = Product.product_id
and Text.language = $session.system_language
{
key Product.product_id as ProductId,
Product.price as Price,
" Texte dans la langue utilisateur
Text.name as ProductName,
Text.description as ProductDescription
}

La variable systeme $session.system_language fournit la langue de connexion.

Data Elements - Labels de champs

Les Data Elements definissent les labels de champs qui sont automatiquement affiches dans Fiori et ALV.

Data Element avec traductions

@EndUserText.label : 'ID Produit"
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
define type zproduct_id : abap.char(10);

Les labels sont geres dans ADT sous Properties > Translations :

LangueTexte courtTexte moyenTexte long
ENProduct IDProduct IdentifierProduct Identification Number
DEProdukt-IDProduktkennungProduktidentifikationsnummer
FRID produitIdentifiant produitNumero d’identification du produit

Domain avec valeurs fixes

Pour les plages de valeurs fixes (ex. statut), les domains avec valeurs fixes traduites conviennent :

@EndUserText.label : 'Statut voyage"
define domain ztravel_status : abap.char(1) {
value 'N' : 'New'; " Nouveau
value 'O' : 'Open'; " Ouvert
value 'A' : 'Approved'; " Approuve
value 'X' : 'Rejected'; " Rejete
}

CDS Annotations pour les textes UI

Fiori Elements utilise les CDS Annotations pour les textes UI. Celles-ci peuvent aussi etre traduites.

Annotation @EndUserText

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Travel Management"
@EndUserText.quickInfo: 'Manage business travels and expenses"
define view entity ZI_Travel
as select from ztravel
{
@EndUserText.label: 'Travel ID"
@EndUserText.quickInfo: 'Unique travel identifier"
key travel_id as TravelId,
@EndUserText.label: 'Agency"
agency_id as AgencyId,
@EndUserText.label: 'Customer"
customer_id as CustomerId,
@EndUserText.label: 'Begin Date"
begin_date as BeginDate,
@EndUserText.label: 'End Date"
end_date as EndDate,
@EndUserText.label: 'Total Price"
total_price as TotalPrice
}

Annotations @UI avec textes

@UI.headerInfo: {
typeName: 'Travel',
typeNamePlural: 'Travels',
title: { value: 'TravelId' },
description: { value: 'Description' }
}
define view entity ZC_Travel
as projection on ZI_Travel
{
@UI.facet: [
{
id: 'GeneralInfo',
label: 'General Information',
type: #IDENTIFICATION_REFERENCE
},
{
id: 'Dates',
label: 'Travel Dates',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Dates"
}
]
@UI.identification: [{ position: 10 }]
@UI.lineItem: [{ position: 10, label: 'Travel' }]
key TravelId,
@UI.fieldGroup: [{ qualifier: 'Dates', position: 10, label: 'From' }]
BeginDate,
@UI.fieldGroup: [{ qualifier: 'Dates', position: 20, label: 'To' }]
EndDate
}

Workflow de traduction

Le processus de traduction dans ABAP Cloud differe de l’ABAP classique (Transaction SE63).

Exporter les objets traduisibles

Dans ADT, vous pouvez exporter les objets traduisibles :

  1. Selectionner Package > Export Translations
  2. Choisir les langues cibles
  3. Un fichier XLIFF est genere
<!-- Exemple export XLIFF -->
<xliff version="1.2">
<file source-language="en" target-language="fr">
<body>
<trans-unit id="ZTRAVEL_MSG.001">
<source>Travel & successfully created</source>
<target>Voyage & cree avec succes</target>
</trans-unit>
<trans-unit id="ZTRAVEL_MSG.002">
<source>Travel & already booked</source>
<target>Voyage & deja reserve</target>
</trans-unit>
</body>
</file>
</xliff>

Importer les traductions

Apres la traduction (par des traducteurs ou un bureau de traduction) :

  1. Selectionner Package > Import Translations
  2. Choisir le fichier XLIFF traduit
  3. Les traductions sont importees dans le systeme

Fiori App : Maintain Translations

Pour les environnements BTP, l’application Fiori Maintain Translations est disponible :

  1. Demarrer l’app dans le Launchpad
  2. Choisir le Software Component et la langue
  3. Traduire les textes directement dans l’interface
  4. Sauvegarder et activer les modifications

Conventions de nommage pour les traductions

Type d’objetConvention de nommageExemple
Message ClassZ{PROJET}_MSGZTRAVEL_MSG
Data Elementz{domaine}_{champ}ztravel_status
Domainz{domaine}_{domain}ztravel_status
Table de textez{master}_textzproduct_text

Bonnes pratiques

1. Definir la langue originale

Definissez une langue originale uniforme (typiquement EN) :

" Toujours utiliser des textes originaux en anglais
" ZTRAVEL_MSG
" 001 - EN: Travel & successfully created
" 001 - FR: Voyage & cree avec succes

2. Terminologie coherente

Utilisez un glossaire pour des traductions coherentes :

Terme (EN)Terme (FR)
TravelVoyage
BookingReservation
CustomerClient
AgencyAgence
StatusStatut

3. Utiliser les placeholders judicieusement

" Bien : Texte flexible avec placeholders
" & records were processed successfully.
" & enregistrements traites avec succes.
" Mauvais : La grammaire ne fonctionne pas dans toutes les langues
" & record(s) processed.

4. Interroger les tables de textes efficacement

" Performant : Join avec fallback
define view entity ZI_ProductWithText
as select from zproduct as Product
left outer join zproduct_text as UserText
on UserText.product_id = Product.product_id
and UserText.language = $session.system_language
left outer join zproduct_text as FallbackText
on FallbackText.product_id = Product.product_id
and FallbackText.language = 'E' " Anglais comme fallback
{
key Product.product_id,
" Preferer la langue utilisateur, sinon fallback
coalesce( UserText.name, FallbackText.name ) as Name
}

5. Verifier le statut de traduction

Avant une release, tous les textes doivent etre traduits :

" CDS View pour les traductions manquantes
define view entity ZI_MissingTranslations
as select from zproduct as Product
left outer join zproduct_text as Text
on Text.product_id = Product.product_id
and Text.language = 'F' " Traduction francaise
{
key Product.product_id,
case when Text.product_id is null then 'X' else '' end as MissingFR
}
where Text.product_id is null

Problemes frequents et solutions

Probleme : Les textes ne s’affichent pas

Cause : La table de textes n’a pas d’entree pour la langue utilisateur.

Solution : Implementer une logique de fallback :

coalesce(
UserText.name,
FallbackText.name,
cast( Product.product_id as abap.char(60) )
) as DisplayName

Probleme : Textes d’annotation non traduits

Cause : Les annotations @EndUserText ne sont pas automatiquement traduites.

Solution : Utiliser les textes des Data Elements ou gerer la traduction manuelle.

Probleme : Textes dynamiques

Cause : Les textes sont assembles a l’execution.

Solution : Utiliser Message Class avec placeholders :

" Message Class au lieu de concatenation de strings
MESSAGE e001(ztravel_msg) WITH lv_travel_id INTO DATA(lv_msg).

Resume

Les applications ABAP Cloud multilingues necessitent la bonne combinaison des mecanismes disponibles :

  • Message Classes pour tous les messages (erreurs, avertissements, informations)
  • Text Elements pour les textes de programme statiques
  • CDS Text Associations pour les donnees de base dependantes de la langue
  • Data Elements pour les labels de champs
  • CDS Annotations pour les metadonnees UI dans Fiori

Le workflow de traduction dans ABAP Cloud utilise l’export/import XLIFF ou l’application Fiori “Maintain Translations”. Une langue originale coherente et un glossaire facilitent considerablement la traduction.

Articles complementaires