Makale Özeti

Uygulamamlarımızda nadir de olsa müşteri tarafından uygulamanın arabiriminin çoklu dil desteği olması istenir.Bu istek sadece arabirimde ise çok fazla bir problem yoktur ve resx dosyaları ile çözülür. Bu makalemde bu sorunu çözmenin resx dışındaki bir yolundan bahsedeceğim. Bence çok daha yönetilebilir ve hızlı çalışır bir yöntem olan bu yöntem de her kontrolün karşılığı veritabanında tutulmaktadır. Bu değerler cache'lendiği için oldukça hızlı çalışmaktadır. Zaten kullanıcının her dilde combobox'a verilerin o dilde gelmesi gibi bir istek istemesi durumunda bazı işlemleri veritabanından halletmeniz gerekmektedir. Bahsedeceğim yöntem ufak değişikliklerle web ve windows uygulamalarına uygulanabilir.

Makale

         Merhabalar,

         Uygulamamlarımızda nadir de olsa müşteri tarafından uygulamanın arabiriminin çoklu dil desteği olması istenir.Bu istek sadece arabirimde ise çok fazla bir problem yoktur ve resx dosyaları ile çözülür. Bu makalemde bu sorunu çözmenin resx dışındaki bir yolundan bahsedeceğim. Bence çok daha yönetilebilir ve hızlı çalışır bir yöntem olan bu yöntem de her kontrolün karşılığı veritabanında tutulmaktadır. Bu değerler cache'lendiği için oldukça hızlı çalışmaktadır. Zaten kullanıcının her dilde combobox'a verilerin o dilde gelmesi gibi bir istek istemesi durumunda bazı işlemleri veritabanından halletmeniz gerekmektedir. Bahsedeceğim yöntem ufak değişikliklerle web ve windows uygulamalarına uygulanabilir. Şimdi isterseniz bu sistemi geliştirmeye başlayalım.

         Öncelikle veritabanımızı tasarlayalım.

        

         Veritabanımızda bulunan tabloları ve alanları açıklayalım.

         Languages : Bu tabloda dil ayarlarını tutuyoruz. Uygulamamızda bulunan tüm diller bu tabloda tanımlanmalıdır.
        

LanguageId Dil bilgisinin Id'sidir.
LanguageNameDil'in kullanıcı arabiriminde gösterilecek adı. Örn. English,Türkçe
LanguageCultureUygulama dilinin kullanıcının culture bilgilerine göre otomatik belirlenebilmesi için culture bilgisi.

         Pages : Bu tabloda web uygulamamızda bulunacak sayfaların isimlerini yazıyoruz. Windows uygulamalarımızda ise formlarımızı benzer bir tabloda tutabiliriz.
 

PageIdSayfa bilgisinin Id'sidir.
PageClassNameSayfamızın tanımlanması için ClassName'dir. Uygulamamızda kullanıcının hangi sayfada olduğu yani hangi sayfanın dil bilgilerini istediği bu class adı ile alınabilir.
PageDescriptionSayfamızın açıklamasıdır. Bulunması zorunlu bir alan değildir.

         MultilanguageSettings : Bu tabloda bir sayfada bulunan bir kontrolün bir dilde karşılığının ne olduğu bilgisi tutulacaktır.

MultiLanguageSettingIdDil ayarları tablosunun Id'sidir.
PageIdSayfa'nın bilgisinin tutulduğu alandır.
ControlIdSayfa üzerinde bulunan kontrolün Id sinin tutulduğu alandır.
LanguageIdDil bilgisinin tutulduğu alandır.
ControlTextKontrolün belirlenen dildeki karşılığıdır. Örneğin label'ın Text property'sine atanacak olan değerdir

         Şimdi bu tabloların içlerini veri dolu olarak görelim:

 

         Tablolardaki veriler tüm anlattıklarımı tamamlayıcı nitelik taşıyor. Ancak önemli bir nokta grid için gözktüğü gibi kolon başlıklarının | ile ayrılarak yazılmasıdır. Bunun gibi kendi kontrolleriniz için kendi syntax'ınızı yazabilirsiniz. Unutmayın bu syntax'ı kod tarafında çalışabilir durumda kılmalısınız.

         Şimdi bu verilerin nasıl cache'lendiğini inceleyelim.

 

        public void LoadMultilanguage()
        {
            if (Application["Multilanguage"] == null)
            {
                BusinessLayer.busLanguages insBusLanguages = new BusinessLayer.busLanguages();
                System.Data.DataTable insDataTableLanguages = insBusLanguages.SelectLanguages();
 
                Hashtable insHashTableMultiLanguage = new Hashtable();
                foreach (System.Data.DataRow dr in insDataTableLanguages.Rows)
                {
                    foreach (DataRow drPages in ((DataTable)Application["Pages"]).Rows)
                    {
                        entMultilanguageSettings insEntMultilanguageSettings = new entMultilanguageSettings();
                        insEntMultilanguageSettings.LanguageId = Convert.ToInt32(dr["LanguageId"]);
                        insEntMultilanguageSettings.PageId = Convert.ToInt32(drPages["PageId"]);
                        busMultilanguageSettings insBusMultilanguageSettings = new busMultilanguageSettings();
                        System.Data.DataTable insDataTableMultilanguageSettings = insBusMultilanguageSettings.SelectMultilanguageSettingsByLanguageIdAndPageId(insEntMultilanguageSettings);
                        insHashTableMultiLanguage.Add(insEntMultilanguageSettings.ToString(), insDataTableMultilanguageSettings);
                    }
                }
                Application["Multilanguage"] = insHashTableMultiLanguage;
            }
        }


         Yaptığımız örnek bir web uygulamasına ait olduğu için ilk önce application nesnesinde dil ayarlarının bulunup bulunmadığı bilgileri kontrol ediliyor. Sonrasında ise sistemde tanımlı diller ve sayfalar veritabanında bulunan Languages ve Pages tablolarından çekiliyor. Sırada ise dil bilgilerini tutabilmek için bir HashTable oluşturuyoruz. Daha sonra Languages ve Pages tablosundan gelen verilerin içerisinde bir döngüde dönerken döngünün bulunduğu dil ve sayfa değerlerine göre MultiLanguages tablosunu sorguluyoruz ve burdan dönen değeri hashtable'ın valuesi olarak ayıyoruz. hashtable'ın key'i olarak bize PageId-LanguageId şeklinde değer döndüren bir ToString fonksiyonunu atıyoruz ve döngüden çıktığımızda mevcut hashtable'ı application nesnesine atıyoruz.

         Şimdi bu bilgilere nasıl ulaşacağımızı inceleyelim.

         Bilgilere ulaşmak oldukça basit esasında. Sayfamız açılırken ClassName'ine göre öncelikle PageId'sini buluyoruz. Kullanıcının hangi dil seçimini yaptığıda bilinmektedir. Artık hashtable'dan istediğimiz veriyi almak için key'i oluşturabiliriz. Bundan sonraki adım Hashtable içinden key'i almak ve bir datatable'a atamaktır.Örneği aşağıda anlatmaya çalıştım.
 

                    entMultilanguageSettings insEntMultilanguage = new entMultilanguageSettings();
                    insEntMultilanguage.PageId = this.PageId;
                    insEntMultilanguage.LanguageId = CurrentContext.LanguageId.Value;
                    this._Multilanguage = (DataTable)CurrentContext.Multilanguage[insEntMultilanguage.ToString()];


         Şimdi ise çekilen bu verilerin kontrollere uygulanmasında. Burada iki farklı yöntem izlenebilir. İkisinden de bahsedeceğim.

         1. Yöntem : Sayfanın load event'ında kontrollerin ilgili property'leri atamak.
         Bu yöntem çok basit bir yöntemdir kullanışı öncelikle bir dil ayarlarımızın bulunduğu datatable içerisinde dönerek this.FindControl ile kontrolün bulunması daha sonrasında ise kontrolünün tipine göre bir sınama yaparak kontrole değerleri atıyoruz. Örnek kodu aşağıda veriyorum.Örnek kodda sadece Label ve DataGrid için kod yazılmıştır diğer kontroller için kendiniz yazmanız gerekmektedir.
 

                foreach (DataRow dr in (DataTable)CurrentContext.Multilanguage[insEntMultilanguage.ToString()])
                {
                    Control c = this.Page.FindControl(dr["ControlId"].ToString());
                    if (c is Label)
                    {
                        ((Label)c).Text = dr["ControlText"].ToString();
                    }
                    else if (c is DataGrid)
                    {
                        string[] s = dr["ControlText"].ToString().Split("|".ToCharArray());
                        int i = 0;
                        foreach (string str in s)
                        {
                            ((DataGrid)c).Columns[i].HeaderText = str;
                            i++;
                        }
                    }
                }

        
         2.Yöntem : Bir interface kullanarak kullandığınız kontrollere bu yeteneği kazandırmak.
         Geliştirdiğimiz interface'in içinde SetControlLanguage() isminde bir metod olacaktır ve bu metod kontrollerin belirli property'lerine seçili dile göre değerleri atayacaktır. Şimdi sayfa'nın load'ında bu interface'i implement etmiş kontrolleri bulacağız ve daha sonrasında ise bu kontrolün SetControlLanguage metodunu çağıracağız.
 

        public void SetLanguage()
        {
            SetLanguage(this);
        }
        public void SetLanguage(Control parControl)
        {
            for (int i = 0; i < parControl.Controls.Count; i++)
            {
                if (parControl.Controls[i] is IMultiLanguage)
                {
                    ((IMultiLanguage)parControl.Controls[i]).SetControlLanguage();
                }
                SetLanguage(parControl.Controls[i]);
            }
        }


         Şimdi ise birkaç kontrolümüze örnek olarak interface'imizi implement edelim.

         Label kontrlü için SetControlLanguage metodunu yazalım.
 

        public void SetControlLanguage()
        {
            string txt = "";
            DataRow[] drArr = ((SFPage)parControl.Page).Multilanguage.Select("ControlId='" + parControl.ID + "'");
            if (drArr.Length == 1)
            {
                txt= drArr[0]["ControlText"].ToString();
            }
            if(txt!="")
            {
                this.Text = txt;
            }
        }


         Görüldüğü gibi daha önceden sayfaya özel oluşturduğumuz datatable içerisinden bir select sorgusuyla mevcut kontrolün text'ini buluyoruz.         

         Şimdi ise Grid için bu interface'in nasıl implement edildiğini inceleyelim.
 

        public void SetControlLanguage()
        {
            string txt = "";
            DataRow[] drArr = ((SFPage)parControl.Page).Multilanguage.Select("ControlId='" + parControl.ID + "'");
            if (drArr.Length == 1)
            {
                txt = drArr[0]["ControlText"].ToString();
            }
            if (txt != "")
            {
                string[] columnNames = txt.Split("|".ToCharArray());
                foreach (DataControlField dgc in this.Columns)
                {
                    dgc.HeaderText = columnNames[this.Columns.IndexOf(dgc)];
                }
            }
        }


         Grid için bu interface'i implement ederken biraz öncekinden farklı bir işlem yapmıyoruz. Sadece gelen stringi | karakterlerine göre bölerek gridin kolon başlıklarına atıyoruz.

         Bu iki yöntemden istediğinizi kullanabilirsiniz. Eğer kendi yazdığınız kontrol kütüphanelerini kullanıyorsanız Interface kullanmanızı kesinlikle tavsiye ederim. Bu örneğin uygulamasını canlı olarak www.tameroz.com adresinde deneyebilirsiniz. Umarım faydalı bir makale olmuştur.

 
         oztamer@hotmail.com
         tamer.oz@yazgelistir.com
         oztamer@hotmail.com