Opret løsninger, som understøtter flere sprog
Udgivet: januar 2017
Gælder for: Dynamics 365 (online), Dynamics 365 (on-premises), Dynamics CRM 2016, Dynamics CRM Online
Microsoft Dynamics 365 (online og i det lokale miljø) understøtter flere sprog. Hvis løsningen skal installeres for organisationer, der omfatter forskellige udgangssprog, eller som har flere sprog, der er klargjort, skal du tage dette i betragtning, når du planlægger din løsning. I følgende tabel vises taktik til brug sammen med løsningskomponenter, som skal inkluderes i en løsning, der understøtter flere sprog.
Taktik |
Løsningskomponenttype |
---|---|
Udviklerindstilling |
Webressourcer |
Integrerede etiketter |
Programnavigation (SiteMap) |
Eksportér og importér oversættelser |
Attributter |
Oversættelse i strenge i udgangssproget |
Kontraktskabeloner |
Oversættelse ikke påkrævet |
Behandlingstrin for SDK-meddelelser |
Separat komponent for hvert sprog |
Artikelskabeloner |
Brug XML-webressourcer som sprogressourcer |
Plug-in-assemblies |
Følgende afsnit indeholder flere detaljer for hver taktik.
Udviklerindstilling
Webressourcer har en LanguageCode-attribut, der kan angives i brugergrænsefladen, men denne værdi bruges ikke af programmet. Da webressourcer er URL-adresserbare, får du normalt adgang til en webressource efter navn i stedet for ved at forespørge på tilgængelige webressourcer med LanguageCode som et kriterium. Derfor er LanguageCode af begrænset værdi. Det mest almindelige scenario er, at du skal registrere det pågældende sprog baseret på den kontekst, webressourcen vises i. For webressourcer, giver kontekstobjektet adgang til funktionerne getOrgLcid og getUserLcid. Begge disse funktioner returnerer en heltalsværdi, der svarer til værdierne for landestandard-id'et (LCID).Du kan finde gyldige landestandard-id'er på Oversigt over landestandard-id'er.
Du kan bruge enhver metode, som du vil administrere, til at angive, hvordan tekst og layout støtter brugerens sprogindstillinger, for webressourcer, der viser tekst i brugergrænsefladen. Implementeringen afhænger af typen af webressource.
HTML-webressourcer
Én mulighed er at oprette separate oversatte webressourcer, der varierer afhængigt af det navn, der er anvendt. For eksempel kan du have en webressource, der hedder new_/my_solution/1033/content.htm, til understøttelse af engelsk og en, der hedder new_/my_solution/1041/content.htm, til understøttelse af japansk. Du kan finde oplysninger om sprog med retning fra højre mod venstre under Sådan vises højre mod venstre-tekst ved hjælp af HTML-koder for globalisering.
Hvis du vil være i stand til at angive UI-tekst, der er baseret på en brugers sprog, dynamisk, kan du gemme alle oversatte strengværdier i et objekt, der er defineret i en scriptfil til webressourcen. Baseret på brugerens foretrukne sprog, kan du angive UI-tekstelementer ved hjælp af strenge, der er gemt i objektet, når siden indlæses. Følgende JavaScript-kodeeksempel viser en metode til at angive oversatte strenge.
var userLcid = 1033;
var localizedStrings = {
ErrorMessage: {
_1033: "There was an error completing this action. Please try again.",
_1041: "このアクションを完了、エラーが発生しました。もう一度実行してください。",
_1031: "Es ist ein Fehler aufgetreten, der Abschluss dieser Aktion. Bitte versuchen Sie es erneut.",
_1036: "Il y avait une erreur complétant cette action. Veuillez essayer à nouveau.",
_1034: "Hubo un error al completar esta acción. Vuelva a intentarlo.",
_1049: "Произошла ошибка, выполнение этого действия. Пожалуйста, попробуйте снова."
},
Welcome: {
_1033: "Welcome",
_1041: "ようこそ",
_1031: "Willkommen",
_1036: "Bienvenue",
_1034: "Bienvenido",
_1049: "Добро пожаловать"
}
};
var LocalizedErrorMessage = localizedStrings.ErrorMessage["_" + userLcid];
var LocalizedWelcomeMessage = localizedStrings.Welcome["_" + userLcid];
Silverlight-webressourcer
Silverlight-programmer kan skrives for at understøtte sprogressourcer.Flere oplysninger:Oversættelse af Silverlight-baserede programmer.
Den følgende klasse giver adgang til brugerens foretrukne sprog baseret på konteksten, som Silverlight-webressourcen præsenteres i. Denne klasse understøtter engelsk, arabisk, tysk, hebræisk og japansk. Det skal ændres til de sprog, der understøttes af Silverlight-webressourcen.
public static class Localization
{
// The locale ID.
public static int LCID { get; set; }
// Create a dictionary of right-to-left language codes (Hebrew and Arabic).
private static Dictionary<int, bool> _rightToLeftLanguages =
new Dictionary<int, bool>
{
{ 1025, true },
{ 1037, true },
};
private static Dictionary<int, String> _lcidToCultureNameMap =
new Dictionary<int, String>
{
{ 1025, "ar-SA" },
{ 1031, "de-DE" },
{ 1033, "en-US" },
{ 1037, "he-IL" },
{ 1041, "ja-JP" }
};
public static void InitializeCulture()
{
// Get the user's LCID from the page's context to determine what language to
// display.
dynamic window = HtmlPage.Window;
//Get the user's language code from the context.
try
{
//If the containing window is a CRM form
LCID = Convert.ToInt32(window.Xrm.Page.context.getUserLcid());
// For testing, comment the line above and uncomment one of the lines below
//representing a user language.
//LCID = 1033; //English
//LCID = 1041; //Japanese
//LCID = 1031; //German
//LCID = 1037; //Hebrew - a right-to-left language.
//LCID = 1025; //Arabic - a right-to-left language.
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
{
try
{
//If the containing window is a CRM web resource with
//the WebResources/ClientGlobalContext.js.aspx page linked
LCID = Convert.ToInt32(window.GetGlobalContext().getUserLcid());
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
{
LCID = 1033; //Setting a default for design time when the context
//object is not present and one of the sample languages are not set.
}
}
// Sets the culture of the thread to the appropriate culture, based on what
// LCID was retrieved.
if (_lcidToCultureNameMap.ContainsKey(LCID))
{
var culture = new CultureInfo(_lcidToCultureNameMap[LCID]);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
}
public static FlowDirection GetFlowDirection()
{
if (_rightToLeftLanguages.ContainsKey(LCID))
{
return FlowDirection.RightToLeft;
}
return FlowDirection.LeftToRight;
}
}
Du kan finde oplysninger om sprog med retning fra højre mod venstre under FrameworkElement.FlowDirection egenskab.
XML-webressourcer
Mens XML-webressourcer normalt ikke vises til brugere, kan de være nyttige til lagring af oversatte strenge som ressourcer for andre løsningskomponenter, som beskrevet i Brug XML-webressourcer som sprogressourcer.
Integrerede etiketter
Hver af de løsningskomponenter, der bruger denne taktik, kræver, at al oversat tekst indgår i løsningskomponenten.
Bånd
Når en sprogpakke er installeret, vises båndet i programmet automatisk oversat tekst for al standardtekst på båndet. Systemetiketter defineres i en ResourceId-attributværdi, som kun er til intern brug. Når du tilføjer din egen tekst, skal du bruge det <LocLabels> (RibbonDiffXml)-element, der leverer oversat tekst til de sprog, du understøtter.Flere oplysninger:Bruge oversatte etiketter med bånd
SiteMap
Når en sprogpakke er installeret, viser standardteksten i programmets navigationsrude automatisk oversat tekst. For at tilsidesætte standardteksten eller levere din egen tekst skal du bruge elementet <Titles> (SiteMap).Titles-elementet skal indeholde et <Title> (SiteMap)-element, der indeholder oversat tekst til de sprog, din løsning understøtter. Hvis et Title-element ikke er tilgængeligt for brugerens foretrukne sprog, vises den titel, der svarer til udgangssproget for organisationen.
<SubArea> (SiteMap)-elementet giver mulighed for at overføre brugerens foretrukne sprog ved hjælp af parameteren userlcid, så indhold, der er mål for attributten SubArea.Url, kan være opmærksom på brugerens foretrukne sprog og justere i overensstemmelse hermed.Flere oplysninger:Overføre parametre til en URL ved hjælp af SiteMap
Eksportér og importér oversættelser
Etiketter, som kan oversættes, til løsningskomponenterne i følgende tabel kan eksporteres til oversættelse.
Objekter |
Attributter |
Relationer |
Globale grupperede indstillinger |
Objektmeddelelser |
Objektformularer |
Objektvisninger (SavedQuery) |
Diagrammer |
Dashboards |
Oversættelse af etiketter og visningsstrenge
Du kan kun foretage tilpasninger i programmet på udgangssproget. Derfor, når du vil levere oversatte etiketter og visningsstrenge til disse tilpasninger, skal du eksportere teksten til etiketterne, så de kan blive oversat til andre sprog, der er aktiveret for organisationen. Brug følgende trin:
Sørg for, at den organisation, du arbejder i, har alle MUI-pakker installeret og sprog, der er klargjort, for sprog, du vil angive oversættelser for.
Opret din løsning, og rediger komponenterne.
Når du er færdig med at udvikle din løsning, skal du bruge funktionen "Eksportér oversættelser". Dette opretter et Microsoft Office Excel-regneark (CrmTranslations.xml), der indeholder alle de etiketter, der skal oversættes.
I regnearket skal du angive de tilsvarende oversættelser.
Importér oversættelser tilbage til den samme Microsoft Dynamics 365-organisation ved hjælp af funktionen "Importér oversættelser", og publicer ændringerne.
Næste gang løsningen eksporteres, indeholder den alle de oversættelser, du har angivet.
Når en løsning importeres, kasseres etiketter til sprog, der ikke findes i destinationssystemet, og der logføres en advarsel.
Hvis etiketterne for udgangssproget i målsystemet ikke indgår i løsningspakken, bruges etiketterne for udgangssproget for kilden i stedet. For eksempel, hvis du importerer en løsning, der indeholder etiketter til engelsk og fransk med engelsk som udgangssprog, men destinationssystemet har japansk og fransk med japansk som udgangssprog, bruges engelske etiketter i stedet for japanske. Udgangssprogenes etiketter må ikke være null eller tomme.
Eksport af oversættelser
Inden du eksporterer oversættelser skal du først installere sprogpakker og klargøre alle de sprog, du vil have oversat. Du kan eksportere oversættelser i webprogrammet eller ved hjælp af meddelelsen ExportTranslationRequest. Du kan finde flere oplysninger i Hjælp og undervisning: Eksport af tilpasset objekt- og felttekst til oversættelse.
Oversættelse af tekst
Når du åbner filen CrmTranslations.xml i Excel, vil du se de tre regneark, der er angivet i følgende tabel.
Regneark |
Beskrivelse |
---|---|
Oplysninger |
Viser oplysninger om organisationen og den løsning, som etiketterne og strengene blev eksporteret fra. |
Vis strenge |
Visningsstrenge, der repræsenterer teksten i alle de meddelelser, der er tilknyttet en metadatakomponent. Denne tabel indeholder fejlmeddelelser og strenge, der anvendes til elementer på båndet i systemet. |
Oversatte navne |
Viser hele teksten for etiketter til metadatakomponenter. |
Du kan sende denne fil til en sprogekspert, et oversættelsesbureau eller en lokaliseringsvirksomhed. De skal levere lokaliserede strenge til alle de tomme celler.
Bemærk
For brugerdefinerede objekter er der nogle almindelige etiketter, som deles med systemobjekter, f.eks Oprettet den eller Oprettet af. Da du allerede har installeret og klargjort sprogene, kan du muligvis matche nogle etiketter i dine brugerdefinerede objekter med oversat tekst til identiske etiketter, der bruges af andre enheder, hvis du eksporterer sprog for standardløsningen. Dette kan reducere omkostningerne til lokalisering og forbedre ensartetheden.
Når teksten i regnearkene er oversat, kan du føje både CrmTranslations.xml- og [Content_Types].xml-filer til en enkelt komprimeret .zip-fil. Du kan nu importere denne fil.
Hvis du foretrækker at arbejde med de eksporterede filer via programmering, som XML-dokumenter, kan du finde oplysninger om skemaerne, som disse filer bruger, under Office 2003 XML-referenceskemaer.
Import af oversat tekst
Vigtigt
Du kan kun importere oversat tekst tilbage til den samme organisation, som den blev eksporteret fra.
Når du har eksporteret den tilpassede objekt- eller attributtekst og har fået den oversat, kan du importere de oversatte tekststrenge i webprogrammet ved hjælp af meddelelsen ImportTranslationRequest. Filen, du importerer, skal være en komprimeret fil, der indeholder filen CrmTranslations.xml og filen [Content_Types].xml i roden. Du kan finde flere oplysninger i Hjælp og undervisning: Importere tilpasset objekt- og felttekst.
Når du har importeret de færdige oversættelser, kan de brugere, der arbejder på de sprog, teksten er oversat til, se den tilpassede tekst.
Bemærk
I Microsoft Dynamics 365 kan der ikke importeres oversat tekst, der indeholder mere end 500 tegn. Hvis der findes elementer i oversættelsesfilen, som indeholder mere end 500 tegn, mislykkes importen. Hvis importen mislykkes, skal du gennemse linjen i den fil, der medførte fejlen, reducere antallet af tegn og prøve at udføre importen igen.
Da tilpasning kun understøttes på udgangssproget, arbejder du muligvis i Microsoft Dynamics 365 med udgangssproget angivet som dit foretrukne sprog. Du skal ændre det foretrukne sprog for Microsoft Dynamics 365-brugergrænsefladen for at kontrollere, om den oversatte tekst vises. Hvis du vil foretage yderligere tilpasning, skal du skifte tilbage til basissproget.
Oversættelse i strenge i udgangssproget
Visse løsningskomponenter understøtter ikke flere sprog. Disse komponenter omfatter navne eller tekst, der kun giver mening på et bestemt sprog. Hvis du opretter en løsning for et bestemt sprog, kan du definere disse løsningskomponenter for den tilsigtede organisation på udgangssproget.
Hvis du har brug at understøtte flere sprog, er en taktik at medtage oversættelse i strengene på udgangssproget. For eksempel, hvis du har en forbindelsesrolle, der hedder "Ven", og du har brug for at understøtte engelsk, spansk og tysk, kan du bruge teksten "Ven (Amigo/Freund)" som navn til forbindelsesrollen. På grund af problemer med længden af teksten, er der begrænsninger på, hvor mange sprog kan understøttes ved hjælp af denne taktik.
Visse løsningskomponenter i denne gruppe er kun synlige for administratorer. Det er ikke nødvendigt at levere flere sprogversioner, da tilpasning af systemet kun kan ske på udgangssproget for organisationen.Sikkerhedsroller- og Feltsikkerhedsprofil-komponenter hører til denne gruppe.
Kontraktskabeloner giver en beskrivelse af en servicekontrakttype. Disse kræver tekst til felterne Navn og Forkortelse. Du bør overveje at bruge navne og forkortelser, der er entydige og relevante for alle brugere i organisationen.
Forbindelsesroller er afhængige af, at en person vælger beskrivende forbindelsesrollekategorier og -navne. Da disse kan være forholdsvis korte, anbefales det, at du sørger for oversættelse i udgangssprogets strenge.
Processer (arbejdsprocesser), der startes for hændelser, kan fungere godt, så længe de ikke behøver at opdatere poster med tekst, der skal oversættes. Det er muligt at bruge en arbejdsprocesassembly, så logik, der kan gælde for oversat tekst, kunne bruge den samme strategi, som plug-in-assemblyer (Brug XML-webressourcer som sprogressourcer).
Anmodede arbejdsprocesser kræver et navn, så personer kan vælge dem. Ud over at medtage oversættelse i navnet på den anmodede arbejdsproces er en anden taktik at oprette flere arbejdsgange med oversatte navne, der hver kalder de samme underordnede processer. Men alle brugere vil kunne se den komplette liste over anmodede arbejdsprocesser, ikke kun dem med deres foretrukne brugergrænsefladesprog.
Oversættelse ikke påkrævet
Løsningskomponenterne Behandlingstrin for SDK-meddelelse og Slutpunkt for tjeneste viser ikke oversættelig tekst for brugere. Hvis det er vigtigt, at disse komponenter har navne og beskrivelser, der svarer til organisationens udgangssprog, kan du oprette og eksportere en administreret løsning med navne og beskrivelser på det pågældende sprog.
Separat komponent for hvert sprog
De følgende løsningskomponenter kan hver især indeholde en stor mængde tekst, der skal oversættes:
Artikelskabeloner
Mailskabeloner
Skabeloner til brevfletning
Rapporter
Dialogbokse
For disse typer af løsningskomponenter er den anbefalede fremgangsmåde at oprette separate komponenter for hvert sprog. Det betyder, at du typisk opretter en grundlæggende administreret løsning, der indeholder de centrale løsningskomponenter, og derefter en separat administreret løsning, der indeholder disse løsningskomponenter for hvert sprog. Når kunder installerer basisløsningen, kan de installere de administrerede løsninger for de sprog, de har klargjort til organisationen.
I modsætning til processer (arbejdsprocesser) kan du oprette dialoger, der afspejler brugerens foretrukne sprogindstillinger og kun viser dialogerne for brugere af dette sprog.
Opret en oversat dialogboks
Installer den korrekte sprogpakke, og klargør sproget.
Du kan finde flere oplysninger under TechNet: Installationsvejledning til sprogpakke.
Rediger dine personlige indstillinger for at angive brugergrænsefladesprog for det sprog, du vil bruge til dialogboksen.
Gå til Indstillinger, og vælg Processer i gruppen Procescenter.
Klik på Ny, og opret dialogen på det sprog, du angav.
Når du har oprettet dialogen, kan du ændre dine personlige indstillinger for at angive udgangssproget for organisationen.
Når du benytter udgangssproget for organisationen, kan du navigere til området Løsninger i Indstillinger og tilføje den oversatte dialog som en del af en løsning.
Den dialog, der oprettes på det andet sprog, vises kun for brugere, der ser Microsoft Dynamics 365 ved hjælp af dette sprog.
Brug XML-webressourcer som sprogressourcer
Plug-in-assemblyers løsningskomponenter kan sende meddelelser til en slutbruger ved at udløse en InvalidPluginExecutionException og oprette og opdatere poster. Plug-ins kan ikke bruge ressourcefiler, i modsætning til Silverlight-webressourcer.
Når en plug-in kræver oversat tekst, kan du bruge en XML-webressource til at gemme de oversatte strenge, så plug-in-programmet kan få adgang til dem efter behov. Strukturen i XML-koden er din indstilling, men du kan evt. følge den struktur, der bruges af ASP.NET-ressourcefiler (.resx), til at oprette separate XML-webressourcer for hvert sprog. For eksempel er følgende en XML-webressource med navnet localizedString.en_US, der følger det mønster, som bruges afresx-filer.
<root>
<data name="ErrorMessage">
<value>There was an error completing this action. Please try again.</value>
</data>
<data name="Welcome">
<value>Welcome</value>
</data>
</root>
Følgende kode viser, hvordan en oversat meddelelse kan sendes tilbage i en plug-in for at vise en meddelelse til en bruger. Den er til fasen før validering af en Delete-hændelse for objektet Account:
protected void ExecutePreValidateAccountDelete(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
int OrgLanguage = RetrieveOrganizationBaseLanguageCode(localContext.OrganizationService);
int UserLanguage = RetrieveUserUILanguageCode(localContext.OrganizationService,
localContext.PluginExecutionContext.InitiatingUserId);
String fallBackResourceFile = "";
switch (OrgLanguage)
{
case 1033:
fallBackResourceFile = "new_localizedStrings.en_US";
break;
case 1041:
fallBackResourceFile = "new_localizedStrings.ja_JP";
break;
case 1031:
fallBackResourceFile = "new_localizedStrings.de_DE";
break;
case 1036:
fallBackResourceFile = "new_localizedStrings.fr_FR";
break;
case 1034:
fallBackResourceFile = "new_localizedStrings.es_ES";
break;
case 1049:
fallBackResourceFile = "new_localizedStrings.ru_RU";
break;
default:
fallBackResourceFile = "new_localizedStrings.en_US";
break;
}
String ResourceFile = "";
switch (UserLanguage)
{
case 1033:
ResourceFile = "new_localizedStrings.en_US";
break;
case 1041:
ResourceFile = "new_localizedStrings.ja_JP";
break;
case 1031:
ResourceFile = "new_localizedStrings.de_DE";
break;
case 1036:
ResourceFile = "new_localizedStrings.fr_FR";
break;
case 1034:
ResourceFile = "new_localizedStrings.es_ES";
break;
case 1049:
ResourceFile = "new_localizedStrings.ru_RU";
break;
default:
ResourceFile = fallBackResourceFile;
break;
}
XmlDocument messages = RetrieveXmlWebResourceByName(localContext, ResourceFile);
String message = RetrieveLocalizedStringFromWebResource(localContext, messages, "ErrorMessage");
throw new InvalidPluginExecutionException(message);
}
protected static int RetrieveOrganizationBaseLanguageCode(IOrganizationService service)
{
QueryExpression organizationEntityQuery = new QueryExpression("organization");
organizationEntityQuery.ColumnSet.AddColumn("languagecode");
EntityCollection organizationEntities = service.RetrieveMultiple(organizationEntityQuery);
return (int)organizationEntities[0].Attributes["languagecode"];
}
protected static int RetrieveUserUILanguageCode(IOrganizationService service, Guid userId)
{
QueryExpression userSettingsQuery = new QueryExpression("usersettings");
userSettingsQuery.ColumnSet.AddColumns("uilanguageid", "systemuserid");
userSettingsQuery.Criteria.AddCondition("systemuserid", ConditionOperator.Equal, userId);
EntityCollection userSettings = service.RetrieveMultiple(userSettingsQuery);
if (userSettings.Entities.Count > 0)
{
return (int)userSettings.Entities[0]["uilanguageid"];
}
return 0;
}
protected static XmlDocument RetrieveXmlWebResourceByName(LocalPluginContext context, string webresourceSchemaName)
{
context.TracingService.Trace("Begin:RetrieveXmlWebResourceByName, webresourceSchemaName={0}", webresourceSchemaName);
QueryExpression webresourceQuery = new QueryExpression("webresource");
webresourceQuery.ColumnSet.AddColumn("content");
webresourceQuery.Criteria.AddCondition("name", ConditionOperator.Equal, webresourceSchemaName);
EntityCollection webresources = context.OrganizationService.RetrieveMultiple(webresourceQuery);
context.TracingService.Trace("Webresources Returned from server. Count={0}", webresources.Entities.Count);
if (webresources.Entities.Count > 0)
{
byte[] bytes = Convert.FromBase64String((string)webresources.Entities[0]["content"]);
// The bytes would contain the ByteOrderMask. Encoding.UTF8.GetString() does not remove the BOM.
// Stream Reader auto detects the BOM and removes it on the text
XmlDocument document = new XmlDocument();
document.XmlResolver = null;
using (MemoryStream ms = new MemoryStream(bytes))
{
using (StreamReader sr = new StreamReader(ms))
{
document.Load(sr);
}
}
context.TracingService.Trace("End:RetrieveXmlWebResourceByName , webresourceSchemaName={0}", webresourceSchemaName);
return document;
}
else
{
context.TracingService.Trace("{0} Webresource missing. Reinstall the solution", webresourceSchemaName);
throw new InvalidPluginExecutionException(String.Format("Unable to locate the web resource {0}.", webresourceSchemaName));
return null;
// This line never reached
}
}
protected static string RetrieveLocalizedStringFromWebResource(LocalPluginContext context, XmlDocument resource, string resourceId)
{
XmlNode valueNode = resource.SelectSingleNode(string.Format(CultureInfo.InvariantCulture, "./root/data[@name='{0}']/value", resourceId));
if (valueNode != null)
{
return valueNode.InnerText;
}
else
{
context.TracingService.Trace("No Node Found for {0} ", resourceId);
throw new InvalidPluginExecutionException(String.Format("ResourceID {0} was not found.", resourceId));
}
}
Se også
Pakke- og distributionsudvidelser ved hjælp af løsninger
Introduktion til løsninger
Plan for løsningsudvikling
Afhængighedssporing for for løsningskomponenter
Oprette, eksportere eller importere en ikke-administreret løsning
Opret, installer, og opdater en administreret løsning
Fjern eller slet en løsning
Løsningsobjekter
Lokaliser produktegenskabernes værdier
Microsoft Dynamics 365
© 2017 Microsoft. Alle rettigheder forbeholdes. Ophavsret