יצירת פתרונות שתומכים בשפות מרובות
Microsoft Dataverse תומך בשפות מרובות. אם ברצונך שהפתרון שלך יותקן עבור ארגונים הכוללים שפות בסיס שונות או הקצאה של שפות מרובות, קח זאת בחשבון בעת תכנון הפתרון שלך. הטבלה שלהלן מפרטת טקטיקות לשימוש יחד עם רכיבי פתרונות שיש לכלול בפתרון התומך בשפות מרובות.
| טקטיקה | סוג רכיב פתרון |
|---|---|
| משאבי אינטרנט של מחרוזת (RESX) | משאבי אינטרנט |
| תוויות משובצות | ניווט ביישומים (מפת אתר) רצועות כלים |
| ייצוא וייבוא של תרגומים | תכונות תרשימים לוחות מחוונים Entity קשרי גומלין בין ישויות טפסים הודעות קבוצות אפשרויות צפיות |
| התאמה לשפות אחרות במחרוזות של שפת בסיס | תבניות חוזה תפקידי חיבור תהליכים (זרימת עבודה) תפקידי אבטחה פרופילי אבטחת שדות |
| התאמה לשפות אחרות לא נדרשת | שלבי עיבוד של הודעות SDK נקודות קצה של שירות |
| רכיב נפרד לכל שפה | תבניות מאמרים תבניות דואר אלקטרוני תבניות מיזוג דואר דוחות תיבות דו-שיח |
| שימוש במשאבי אינטרנט של XML כמשאבי שפה | הרכבות תוספים |
הסעיפים הבאים מספקים פרטים נוספים עבור כל טקטיקה.
משאבי אינטרנט של מחרוזת (RESX)
הודות למשאבי אינטרנט של מחרוזת (RESX) שנוספו ל- Dataverse, למפתחים יש אפשרות יציבה יותר ליצירת משאבי אינטרנט התומכים בשפות מרובות. מידע נוסף משאבי אינטרנט מסוג מחרוזת (RESX)
תוויות משובצות
כל אחד מרכיבי הפתרון המשתמשים בטקטיקה זו מחייב לכלול כל טקסט המותאם לשפה אחרת ברכיב הפתרון.
רצועות כלים
כאשר מותקנת ערכת שפה, רצועת הכלים של היישום מציגה אוטומטית טקסט המותאם לשפה אחרת עבור כל טקסט ברית המחדל ברצועת הכלים. תוויות מערכת מוגדרות בערך תכונת ResourceId המיועד לשימוש פנימי בלבד. כשאתה מוסיף טקסט משלך עליך להשתמש ברכיב <LocLabels> כדי לספק טקסט המותאם לשפה אחרת לשפות בהן אתה תומך. מידע נוסף: שימוש בתוויות מותאמות לשפות אחרות עם רצועות כלים
SiteMap
כאשר מותקנת ערכת שפה, טקסט ברירת המחדל בסרגל הניווט של היישום מציג אוטומטית טקסט המותאם לשפה אחרת. כדי לעקוף את טקסט ברירת המחדל או כדי לספק טקסט משלך, השתמש ברכיב <Titles>. הרכיב Titles אמור להכיל רכיב <Title> שמכיל טקסט המותאם לשפה אחרת עבור כל שפה שהפתרון שלך תומך בה. אם רכיב Title אינו זמין בשפה המועדפת של המשתמש, הכותרת המתאימה לשפת הבסיס של הארגון מוצגת.
הרכיב <SubArea> מאפשר העברה של העדפת שפת המשתמש באמצעות הפרמטר userlcid כך שתוכן שהוא היעד של התכונה SubArea.Url יוכל להיות מודע להעדפת השפה של המשתמש ולהתאים את עצמו בהתאם. מידע נוסף: העברת פרמטרים אל כתובת URL באמצעות מפת אתר
ייצוא וייבוא של תרגומים
ניתן לייצא תוויות שניתן להתאים לשפות אחרות עבור רכיבי הפתרון בטבלה הבאה לצורך התאמה לשפות אחרות.
| ישויות | תכונות | קשרים |
| קבוצות אפשרויות כלליות | הודעות ישות | טפסי ישות |
| תצוגות ישות (SavedQuery) | תרשימים | לוחות מחוונים |
תרגום תוויות ומחרוזות תצוגה
באפשרותך לבצע התאמות אישיות ביישום אך ורק באמצעות שפת הבסיס. לכן, כאשר ברצונך לספק תוויות המותאמות לשפות אחרות ומחרוזות תצוגה עבור התאמות אישיות אלה, עליך לייצא את טקסט התוויות כך שיהיה ניתן להתאים אותו לשפות אחרות עבור כל שפה אחרת המופעלת עבור הארגון. השתמש בשלבים הבאים:
ודא כי בארגון שאתה עובד בו מותקנות כל חבילות ה- MUI והשפות המוקצות עבור השפות שברצונך לספק תרגומים עבורן.
צור את הפתרון שלך ושנה את הרכיבים.
לאחר שסיימת לפתח את הפתרון שלך השתמש בפונקציונליות "ייצוא תרגומים". פעולה זו יוצרת גליון אלקטרוני של Office Excel (CrmTranslations.xml) המכיל את כל התוויות הזקוקות לתרגום.
בגליון האלקטרוני, ספק את התרגומים המתאימים.
יבא תרגומים בחזרה לאותו ארגון Dataverse באמצעות הפונקציונליות "ייבוא תרגומים" ופרסם את השינויים שלך.
בפעם הבאה שהפתרון מיוצא, הוא מכיל את כל התרגומים שסיפקת.
כאשר פתרון מיובא, תוויות עבור שפות שאינן זמינות במערכת היעד מתבטלות ונרשמת אזהרה.
אם תוויות עבור שפת הבסיס של מערכת היעד אינן כלולות בחבילת הפתרונות, משתמשים במקום זאת בתוויות של שפת הבסיס של המקור. לדוגמה, אם אתה מייבא פתרון המכיל תוויות עבור אנגלית וצרפתית עם אנגלית כשפת הבסיס, אבל מערכת היעד כוללת יפנית וצרפתית עם יפנית כשפת הבסיס, התוויות באנגלית ישמשו במקום התוויות ביפנית. התוויות של שפות הבסיס לא יכולות להיות Null או ריקות.
ייצוא תרגומים
לפני שאתה מייצא תרגומים, עליך להתקין תחילה את ערכות השפה ולהקצות את כל השפות שברצונך להתאים לשפות אחרות. באפשרותך לייצא את התרגומים ביישום האינטרנט או באמצעות הודעת ExportTranslationRequest. לקבלת מידע נוסף, ראה ייצוא של ישות מותאמת אישית וטקסט לתרגום.
תרגום טקסט
כשתפתח את הקובץ CrmTranslations.xml ב- Office Excel תראה את שלושת גליונות העבודה מופיעים בטבלה הבאה.
| גליון עבודה | תיאור |
|---|---|
| מידע | מציג מידע על הארגון והפתרון שממנו יוצאו התוויות והמחרוזות. |
| מחרוזות תצוגה | הצגת מחרוזות המייצגות את הטקסט של כל ההודעות המשויכות לרכיב מטה-נתונים. טבלה זו כוללת הודעות שגיאה ומחרוזות המשמשות עבור רכיבי רצועת הכלים של המערכת. |
| תוויות המותאמות לשפות אחרות | הצגת כל הטקסט עבור כל תווית של רכיב מטה-נתונים. |
באפשרותך לשלוח קובץ זה למומחה לשוני, לסוכנות תרגום או לחברת לוקליזציה. הם יצטרכו לספק מחרוזות המותאמות לשפות אחרות עבור כל אחד מהתאים הריקים.
הערה
עבור ישויות מותאמות אישית, יש מספר תוויות נפוצות המשותפות עם ישויות מערכת, כגון נוצר ב: או נוצר על-ידי. מכיוון שכבר התקנת והקצית את השפות, אם אתה מייצא שפות עבור פתרון ברירת המחדל, ייתכן שתוכל להתאים תוויות מסוימות בישויות המותאמות אישית שלך לטקסט המותאם לשפות אחרות עבור תוויות זהות המשמשות ישויות אחרות. זה יכול להפחית את עלויות ההתאמה לשפות אחרות ולשפר את העקביות.
לאחר שהטקסט בגליונות העבודה הותאם לשפות אחרות, הוסף הן את הקובץ CrmTranslations.xml והן את הקובץ [Content_Types].xml לקובץ .zip דחוס יחיד. באפשרותך לייבא כעת את הקובץ.
אם אתה מעדיף לעבוד עם הקבצים המיוצאים באופן תכנותי כמסמך XML, ראה תמיכה בתקנים של Word, Excel ו- PowerPoint לקבלת מידע אודות הסכימות שקבצים אלה משתמשים בהן.
ייבוא טקסט מתורגם
חשוב
באפשרותך רק לייבא טקסט מתורגם בחזרה לאותו ארגון שממנו הוא יוצא.
לאחר הייצוא והתרגום של הטקסט המותאם אישית של ישות או של תכונה, באפשרותך לייבא את מחרוזות הטקסט המתורגמות ביישום האינטרנט באמצעות הודעת ImportTranslationRequest. הקובץ שאתה מייבא צריך להיות קובץ דחוס המכיל את CrmTranslations.xml ואת קובץ ה [Content_Types].xml בבסיס. לקבלת מידע נוסף, ראה ייבוא של טקסט מתורגם של ישות ושדה.
לאחר ייבוא התרגומים שהושלמו, יופיע טקסט מותאם אישית עבור משתמשים העובדים בשפות שאליהן תרגמת את הטקסט.
הערה
ל- Dataverse אין אפשרות לייבא טקסט מתורגם שאורכו עולה על 500 תווים. אם אורכו של אחד הפריטים בקובץ התרגום ארוך מ- 500 תווים, תהליך הייבוא נכשל. אם תהליך הייבוא נכשל, סקור את השורה בקובץ שגרמה לכשל, הקטן את מספר התווים ונסה שוב לייבא.
מכיוון שהתאמה אישית נתמכת בשפת הבסיס בלבד, ייתכן שאתה עובד ב- Dataverse כאשר שפת הבסיס מוגדרת כהעדפת השפה שלך. כדי לוודא שהטקסט המתורגם מופיע, עליך לשנות את העדפת השפה שלך עבור ממשק המשתמש של Dataverse. כדי לבצע עבודה נוספת של התאמה אישית, עליך לעבור בחזרה לשפת הבסיס.
התאמה לשפות אחרות במחרוזות של שפת בסיס
חלק מרכיבי הפתרונות אינם תומכים במספר שפות. רכיבים אלה כוללים שמות או טקסט שיכולים להיות בעלי משמעות רק בשפה ספציפית. אם אתה יוצר פתרון עבור שפה ספציפית, הגדר רכיבי פתרון אלה עבור שפת הבסיס של הארגון המיועדת.
אם עליך לתמוך במספר שפות, טקטיקה אחת היא לכלול התאמה לשפות אחרות במחרוזות שפת הבסיס. לדוגמה, אם יש לך תפקיד חיבור בשם "Friend" ועליך לתמוך באנגלית, ספרדית וגרמנית, אתה יכול להשתמש בטקסט "Friend (Amigo / Freund)” כשם תפקיד החיבור. בשל בעיות באורך הטקסט, קיימות מגבלות לגבי מספר השפות שניתן לתמוך בהן באמצעות טקטיקה זו.
רכיבי פתרונות מסוימים בקבוצה זו גלויים רק למנהלי מערכת. משום שניתן לבצע התאמה אישית של המערכת רק בשפת הבסיס של הארגון, אין צורך לספק גירסאות מרובות של שפות. רכיבי תפקידי אבטחה ו פרופיל אבטחת שדה שייכים לקבוצה זו.
תבניות חוזה מספקות תיאור של סוג חוזה שירות. הן דורשות טקסט עבור השדות שם ו קיצור. כדאי לשקול שימוש בשמות ובקיצורים ייחודיים ומתאימים עבור כל משתמשי הארגון.
תפקידי חיבור מסתמכים על אדם שבוחר קטגוריות ושמות של תפקיד חיבור תיאורי. מכיוון שהם עשויים להיות קצרים יחסית, מומלץ לכלול התאמה לשפות אחרות במחרוזות של שפת בסיס.
תהליכים (זרימות עבודה) שמופעלים עבור אירועים יכולים לפעול היטב כל עוד אינם צריכים לעדכן רשומות בטקסט המיועד להתאמה לשפות אחרות. ניתן להשתמש בהרכבת זרימת עבודה כך שהלוגיקה שעשויה לחול על טקסט המותאם לשפות אחרות עשויה להשתמש באותה אסטרטגיה כהרכבות יישום plug-in (שימוש במשאבי אינטרנט של XML כמשאבי שפה).
זרימות עבודה לפי דרישה דורשות שם כדי שאנשים יוכלו לבחור בהן. בנוסף להכללת התאמה לשפות אחרות בתוך שם זרימת העבודה לפי דרישה, טקטיקה נוספת היא יצירת זרימות עבודה מרובות עם שמות המותאמים לשפות אחרות שכל אחת מהן קוראת לאותו תהליך צאצא. עם זאת, כל המשתמשים יראו את הרשימה המלאה של זרימות עבודה לפי דרישה, ולא רק את אלה בשפת ממשק המשתמש המועדף עליהם.
התאמה לשפות אחרות לא נדרשת
רכיבי הפתרון שלב עיבוד של הודעת SDK ו נקודת קצה של שירות אינם חושפים טקסט הניתן להתאמה לשפות אחרות למשתמשים. אם חשוב שלמרכיבים אלה יהיו שמות ותיאורים התואמים את שפת הבסיס של הארגון, באפשרותך ליצור ולייצא פתרון מנוהל עם שמות ותיאורים בשפה זו.
רכיב נפרד לכל שפה
רכיבי הפתרון הבאים עשויים לכלול כמות ניכרת של טקסט שיש להתאים לשפות אחרות:
תבניות מאמרים
תבניות דואר אלקטרוני
תבניות מיזוג דואר
דוחות
תיבות דו-שיח
עבור סוגים אלה של רכיבי פתרון, הטקטיקה המומלצת היא יצירת רכיבים נפרדים עבור כל שפה. פירוש הדבר שאתה בדרך כלל יוצר פתרון מנוהל בסיסי המכיל את רכיבי הבסיס של הליבה שלך ולאחר מכן פתרון מנוהל נפרד המכיל רכיבי פתרון אלה עבור כל שפה. לאחר שהלקוחות יתקינו את פתרון הבסיס, הם יוכלו להתקין את הפתרונות המנוהלים עבור השפות שהם הקצו לארגון.
בניגוד ל תהליכים (זרימות עבודה), באפשרותך ליצור תיבות דו-שיח שישקפו את הגדרות העדפת השפה הנוכחיות של המשתמש ויציגו את תיבות הדו-שיח רק למשתמשים בשפה זו.
יצירת תיבת דו-שיח המותאמת לשפות אחרות
התקן את ערכת השפה המתאימה והקצה את השפה.
לקבלת מידע נוסף, ראה הוראות להתקנת ערכת שפה.
שנה את האפשרויות האישיות שלך כדי לציין את שפת ממשק המשתמש עבור השפה הרצויה לתיבת הדו-שיח.
נווט אל הגדרות ובקבוצה מרכז תהליכים, בחר תהליכים.
לחץ על חדש וצור את תיבת הדו-שיח בשפה שציינת.
לאחר שיצרת את תיבת הדו-שיח, שנה את האפשרויות האישיות שלך כדי לציין את שפת הבסיס של הארגון.
בעת השימוש בשפת הבסיס של הארגון תוכל לנווט אל האזור פתרונות ב הגדרות ולהוסיף את תיבת הדו-שיח המותאמת לשפות אחרות כחלק מפתרון.
תיבת הדו-שיח שנוצרה בשפה השנייה תוצג רק למשתמשים המציגים את Dataverse באמצעות שפה זו.
שימוש במשאבי אינטרנט של XML כמשאבי שפה
רכיבי פתרון הרכבה של יישום plug-in יכולים לשלוח הודעות אל משתמש קצה על-ידי הפקת InvalidPluginExecutionException וכן יצירה ועדכון של רשומות. בניגוד למשאבי האינטרנט של Silverlight, יישומי plug-in לא יכולים להשתמש בקבצי משאבים.
כאשר יישום plug-in דורש טקסט המותאם לשפות אחרות, באפשרותך להשתמש במשאב אינטרנט של XML כדי לאחסן את המחרוזות המותאמות לשפות אחרות כך שיישום ה- plug-in יוכל לגשת אליהם בעת הצורך. מבנה ה- XML הוא האפשרות שלך, אך ייתכן שתרצה לנהוג לפי המבנה המשמש את קבצי משאב ASP.NET (.resx) כדי ליצור משאבי אינטרנט של XML נפרדים עבור כל שפה. לדוגמה, להלן משאב אינטרנט של XML בשם localizedString.en_US שנוהג לפי התבנית שהוא משתמש בה. קבצי resx.
<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>
הקוד הבא מראה כיצד ניתן להעביר הודעה המותאמת לשפות אחרות בחזרה ליישום plug-in כדי להציג הודעה למשתמש. הדבר מיועד לשלב הקדם-אימות של אירוע Delete עבור הישות 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));
}
}