DCSIMG
Resource and Culture and UICulture (והשמה אוטומטית של מידע) - שלמה גולדברג (הרב דוטנט)

שלמה גולדברג (הרב דוטנט)

מרצה בסלע ויועץ בעולם ה - net.

Resource and Culture and UICulture (והשמה אוטומטית של מידע)

 

קבצי resource הם דרך נהדרת לשמור את ההודעות והטקסט של האפליקצייה לפי ה culture,
 
הדבר שמעצבן אותי כמפתח, שאני צריך בכל פעם לכתוב את הקוד של ההשמה מתוך קובץ ה resource על ה label המתאים.
 
אז לפני שאני אראה את הפיתרון שאני משתמש, נעשה מעבר מהיר על הנושא. לטובת אלו שלא יודעים מה זה resource ומה זה culture.
 
 
נניח שיש לי אפליקצייה שאני רוצה שתהיה גם באנגלית וגם בעברית, נתעלם לרגע מהעובדה שכיון הכתיבה הוא הפוך, ונתמקד בזה שהטקסט צריך להיות בשתי השפות.
 
איך נעשה את זה ?
 
קליק ימין עם העכבר על הפרויקט שלנו, נבחר ב add new item, ונבחר ב  Resource
 
 
Resource 1
 
 
אני נוהג לייצר קובץ עבור כל דף, והשם של ה resource הוא בדרך כלל השם של הדף.
 
כעת נוסיף עוד קובץ resource שהשם שלו יהיה זהה לשם של הקובץ הקודם, אבל עם סיומת של ה culture, לדוגמא: Default.he-IL.resx,
 
אחרי שנוסיף את הקבצים, ונתחיל לערוך אותם, נוכל להוסיף ערכים, שהם למעשה key-value, כשה key, יהיה זהה בשני הקבצים, אבל ה value, יהיה שונה, לדוגמא:
 
(העליון הוא הקובץ עם הסיומת של he-IL)
 
Resource2
 
 
וכעת בקוד מה שאנחנו צריכים לעשות, זה לתת לכל label, את הkey המתאים,
 
לדוגמא:
 

    protected void Page_Load(object sender, EventArgs e)

    {

        lblHello.Text = Default.lblHello;

        lblWelcome.Text = Default.lblWelcome;

    }

 
כעת נשאר לנו רק לקבוע, מאיזה קובץ לקחת את הערכים,
 
אז למעשה יש כמה דרכים, אפשר מקונפיג, אפשר על ידי הגדרות הדף, כאן אפשר לקרוא מאמר שמסביר את הנושא.
 
אני בדרך כלל עושה את זה מקוד, צריך לעשות override ל InitializeCulture, ושם להחליט מה ה resource המתאים,
 
יש לדף שני properties שמחליטים על הסביבה, הראשון, הוא ה Culture, זה אינו קשור אלינו, הוא מחליט באיזה פורמט יוצגו המספרים ותאריכים,
 
לדוגמא הקוד הבא,
 

    protected void Page_Load(object sender, EventArgs e)

    {

        lblTime.Text = DateTime.Now.ToLongDateString();

    }

 

    protected override void InitializeCulture()

    {

        Culture = "he-IL";

    }

 
יחזיר את התוצאה: שבת 09 מאי 2009
 
לעומת זאת הקוד הבא:
 

    protected void Page_Load(object sender, EventArgs e)

    {

        lblTime.Text = DateTime.Now.ToLongDateString();

    }

 

    protected override void InitializeCulture()

    {

        Culture = "en-US";

    }

 
יחזיר את התוצאה: Saturday, May 09, 2009
 
אבל כמו שאמרתי, זה לא המאפיין שכרגע אנחנו מדברים עליו, אנחנו מדברים על המאפיין UICulture,
הוא מחליט מאיזה קובץ resource לקחת את הערכים, ולכן הקוד הבא:
 

    protected void Page_Load(object sender, EventArgs e)

    {

        lblHello.Text = Default.lblHello;

        lblWelcome.Text = Default.lblWelcome;

    }

 

    protected override void InitializeCulture()

    {

        UICulture = "he-IL";

    }

 
יחזיר את הערכים מתוך קובץ ה resource עם סיומת ה he-IL,
 
לעומת זאת הקוד הבא:
 

    protected void Page_Load(object sender, EventArgs e)

    {

        lblHello.Text = Default.lblHello;

        lblWelcome.Text = Default.lblWelcome;

    }

 

    protected override void InitializeCulture()

    {

        UICulture = "en-US";

    }

 
יחזיר את הערכים, מתוך הקובץ הרגיל (ללא סיומת של תרבות כלשהו).
 
בעייה אחת, יש לזה, שבמידה ואנחנו צריכים גישה לערכים מתוך ה javascript, אין לנו, הפיתרון לזה, נמצא כאן.
 
והבעייה האחרונה (שלכבודה נכתב כל הפוסט הזה),
 
אני לא רוצה כמפתח לדאוג להשמה של כל הערכים על ה labels השונים, אז כדי לפתור את זה כתבתי את הפיתרון הבא:
 
בקבצי ה resource, השמות שאני נותן ל keys הם שם האובייקט_שם המאפיין לדוגמא:
 
resource3
 
 
שני הראשונים, הם שמות של label ומאפיין הטקסט שלהם, האחרון הינו RequiredFieldValidator ומאפיין ErrorMessage.
 
כעת בקוד אני מפעיל את המתודה הבאה:
 

private void SetDataFromResource()

{

    Type type = typeof(Default);

    PropertyInfo[] properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static);

 

    var stringProperties = from property in properties

                           where property.PropertyType == typeof(string)

                           select new Pair(property.Name, property.GetValue(null, null));

 

    foreach (var item in stringProperties)

    {

        string[] arr = item.First.ToString().Split('_');

        if (arr.Length == 2)

        {

            Control ctr = FindControl(arr[0]);

            if (ctr != null)

            {

                PropertyInfo pi = ctr.GetType().GetProperty(arr[1]);

                if (pi != null)

                {

                    pi.SetValue(ctr, item.Second.ToString(), null);

                }

            }

        }

    }

}

 
אני מוציא את כל הערכים מתוך קובץ ה resource.
 
מחפש control עם השם של האובייקט, במידה ואני מוצא, אני משים את הערך למאפיין.
 
 
הפיתרון הזה הוא לא כל כך טוב מבחינת ביצועים, אבל במידה והנקודה הזאת לא מפריעה, אז זה פותר לי את הבעייה שאני צריך לדאוג להשים את הערכים למקומות המתאימים

תוכן התגובה

Rotem Bloom כתב/ה:

תראה שלמה בגדול אתה צודק זה לא ממש נוח לנהל את כל קיבצי ה-RESOURCES אבל אם יש לך אפליקציה פשוטה יחסית ולא מעניין אותך ביצועים .NET יכול לאפשר לך לעשות את הכל בצורה אוטומטית.

אז אתה רוצה לדעת איך עושים את זה עם VS 2008 בבקשה:

1) תפתח את קובץ ה-ASPX שלך במצב של DESIGN

2) ב-VS תלחץ כל TOOLS ואז תבחר GENERATE LOCAL RESOURCE

מה שזה בעצם יעשה לך זה יצור לך קובץ RESOURCE שיכיל לך כבר את כל המפתחות כולל טקסט לכל ה-CONTROLS שלך. מה שישאר לך זה רק להעתיק את הקובץ לפי שפה ולתרגם את הטקסט בהתאם.

כמובן שעדיף לעשות את זה ממש בסוף שכל הדף שלך כבר מוכן אחרת בכל עידכון תצטרך לייצר את הקובץ מחדש.

מקווה שזה יעזור לך לדעתי זה קצת מקל על העבודה ועל ההתעסקות בכל נושא ה-RESOURCES.

שוב הפיתרון הזה הוא לא הכי מושלם בעיקר כי הוא משכפל לך ערכי תירגום ולא עובד עם GLOBAL RESORCES אבל בהחלט מקל על יצירת ה- LOCAL RESOURCE.

ביי רתם

# May 10, 2009 9:13 AM

Shlomo כתב/ה:

לא הכרתי, תודה

# May 10, 2009 9:25 AM

Baruch Frei כתב/ה:

פוסט זה נכתב בעברית מכיון שהוא המשך לפוסט שנכתב בעברית. שלמה כתב על הנושא שמעצבן אותו לכתוב את כל קוד

# May 14, 2009 11:14 PM

שלמה גולדברג כתב/ה:

דרך נפוצה מאוד לשמור הודעות/תמונות וכד' היא ב - Resource file. הסבר על הנושא. הבעייה הגדולה שלהם

# July 14, 2009 11:58 AM

עמירם כתב/ה:

תודה רבה , הפוסט הזה עזר לי המון , שברתי את הראש ימים עד שראיתי את השורות האלו

    protected override void InitializeCulture()

   {

       Culture = "he-IL";

   }

משום מה כשאני נמצא בסביבת הפיתוח , התאריך מוצג לי בפורמט המתאים dd/MM/yyyy

אבל בסביבת הפרוד , משום מה התאריך מוצג כUS , בפורמט MM/dd/yyyy

אני מקווה שזה יפתור לי את הבעיה ,

אתה ממליץ לשים את הקוד הזה ב Master Page ? או בכל דף בנפרד ?

שוב,

תודה

# July 16, 2009 1:52 PM

Shlomo כתב/ה:

ה - MasterPage יכול להיות אפשרות.

אני הייתי ממליץ לך לעשות class בשם PgaeBase שיורש מ - Page וכל הדפים יורשים ממנו ושם לעשות את זה (וכן את כל הקוד המשותף) כי Page לר יורש מ - masterPage אלא מכיל אותו (כי הוא UserControl).

אופצייה נוספת היא: ב - Config

אתה יכול להוסיף כניסה בשם globalization שבו אתה יכול לקנפג את ה - uiCulture ואת ה - culture

# July 16, 2009 2:16 PM

עמירם כתב/ה:

היי,

תודה רבה , זה באמת עזר!

הוספתיבWEBCONFIOG  , הגדרה של globaliztaion , וזה תר לי את הבעיה.

תודה רבה !

# July 17, 2009 11:14 AM
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 4 and 2 and type the answer here:


Enter the numbers above: