Anwar Minarso

See also: Other Geeks@INDC
Multilingual ResourceManager dgn Auto Translate (Part II)

Sebelumnya saya telah membuat contoh Custom ResourceManger dengan implementasi API Bing Translator pada post Multilingual ResourceManager dgn Auto Translate (Part I).  

Kali ini, saya akan tune up agar performance lebih baik dan juga lebih mudah dimaintain. Adapun yg di Tune Up adalah sbb :

  1. Menggunakan database
    ResourceManager akan menarik resource data cache terlebih dahulu, jika tidak ada menarik ke database, jika resource tidak ditemukan, maka secara automatis mentranslate dgn service Translator dan menyimpannya kedalam database dan di cache
  2. Memudahkan Maintain
    Dengan menggunakan database akan memudahkan kita memaintain data output translatenya, jika translatornya salah.

source code dapat didownload di sini

Ok, kita lanjut ...

Pertama2 membuat class untuk store database (dengan LinqToSql)

Code Snippet
  1. [Table(Name = "ResourceData")]
  2.     public class ResourceData
  3.     {
  4.         [Column(Name = "ResourceID", CanBeNull = false, IsDbGenerated = true, IsPrimaryKey = true, AutoSync = AutoSync.OnInsert)]
  5.         public long ResourceID { get; set; }
  6.         [Column(Name = "ResourceType", DbType = "NVARCHAR(1000) NOT NULL", CanBeNull = false)]
  7.         public string ResourceType { get; set; }
  8.         [Column(Name = "ResourceKey", DbType = "NVARCHAR(MAX) NOT NULL", CanBeNull = false)]
  9.         public string ResourceKey { get; set; }
  10.         [Column(Name = "FromLanguageCode", DbType = "VARCHAR(20) NOT NULL", CanBeNull = false)]
  11.         public string FromLanguageCode { get; set; }
  12.         [Column(Name = "ToLanguageCode", DbType = "VARCHAR(20) NOT NULL", CanBeNull = false)]
  13.         public string ToLanguageCode { get; set; }
  14.         [Column(Name = "ResourceValue", DbType = "NVARCHAR(MAX) NOT NULL", CanBeNull = false)]
  15.         public string ResourceValue { get; set; }
  16.     }

Kemudian membuat DataContextnya (dengan default connectionStringName nya adalah "MyResourceManager")

Code Snippet
  1. public class ResourceDataContext : DataContext
  2.     {
  3.         private static string ConnectionString = ConfigurationManager.ConnectionStrings["MyResourceManager"].ConnectionString;
  4.         private static AttributeMappingSource mappingSource = new AttributeMappingSource();
  5.         public Table<ResourceData> Resources
  6.         {
  7.             get
  8.             {
  9.                 return GetTable<ResourceData>();
  10.             }
  11.         }
  12.         public ResourceDataContext()
  13.             : base(ConnectionString, mappingSource)
  14.         {
  15.         }
  16.         /// <summary>
  17.         /// attribute [MethodImpl(MethodImplOptions.Synchronized)] memaksa agar fungsi ini menjadi thread-safe
  18.         /// </summary>
  19.         [MethodImpl(MethodImplOptions.Synchronized)]
  20.         public ResourceData GetByResourceKey(string ResourceType, string ResourceKey, string FromLanguageCode, string ToLanguageCode)
  21.         {
  22.             var query = from r in Resources
  23.                         where r.ResourceType.Equals(ResourceType) && r.ResourceKey.Equals(ResourceKey) && r.FromLanguageCode.Equals(FromLanguageCode) && r.ToLanguageCode.Equals(ToLanguageCode)
  24.                        select r;
  25.             var data = query.ToArray(); // pada sql 2005 query equal operator tidak case sensitive
  26.             return data.FirstOrDefault(t => t.ResourceKey.Equals(ResourceKey)); // memaksa agar case sensitive
  27.         }
  28.         [MethodImpl(MethodImplOptions.Synchronized)]
  29.         public ListDictionary GetByFromLanguageCodeToLanguageCode(string ResourceType, string FromLanguageCode, string ToLanguageCode)
  30.         {
  31.             var query = from r in Resources
  32.                         where r.ResourceType.Equals(ResourceType) && r.FromLanguageCode.Equals(FromLanguageCode) && r.ToLanguageCode.Equals(ToLanguageCode)
  33.                         select new { r.ResourceKey, r.ResourceValue };
  34.             ListDictionary dic = new ListDictionary();
  35.             foreach (var result in query)
  36.                 dic.Add(result.ResourceKey, result.ResourceValue);
  37.             return dic;
  38.         }
  39.     }


 Kemudian update coding dibawah ini pada class MyResourceProvider method GetObject

Code Snippet
  1. public object GetObject(string resourceKey, CultureInfo culture)
  2.         {
  3.             if (Disposed)
  4.                 throw new ObjectDisposedException("MyResourceProvider object is already disposed.");
  5.             if (string.IsNullOrEmpty(resourceKey))
  6.                 throw new ArgumentNullException("resourceKey");
  7.             if (culture == null)
  8.                 culture = CultureInfo.CurrentUICulture;
  9.             if (string.IsNullOrEmpty(culture.Name))
  10.                 culture = System.Globalization.CultureInfo.CurrentUICulture;
  11.             string resourceValue = null;
  12.             Dictionary<string, string> resCacheByCulture = null;
  13.             if (resourceCache.ContainsKey(culture.Name))
  14.             {
  15.                 resCacheByCulture = resourceCache[culture.Name];
  16.                 if (resCacheByCulture.ContainsKey(resourceKey))
  17.                     resourceValue = resCacheByCulture[resourceKey];
  18.             }
  19.             if (resourceValue == null)
  20.             {
  21.                 using (ResourceDataContext ctxt = new ResourceDataContext())
  22.                 {
  23.                     // Create Database jika tidak ada
  24.                     if (!ctxt.DatabaseExists())
  25.                         ctxt.CreateDatabase();
  26.                     string fromLanguageCode = resourceKeyLanguage.GetLanguageType().GetLanguageCode();
  27.                     string toLanguageCode = culture.GetLanguageType().GetLanguageCode();
  28.                     // Tarik data Resource
  29.                     ResourceData data = ctxt.GetByResourceKey(classKey, resourceKey, fromLanguageCode, toLanguageCode);
  30.                     if (data == null)
  31.                     {
  32.                         // jika data tidak ada, menarik service API
  33.                         resourceValue = Utils.Translate(resourceKey, resourceKeyLanguage.GetLanguageType(), culture.GetLanguageType());
  34.                         data = new ResourceData();
  35.                         data.ResourceType = classKey;
  36.                         data.ResourceKey = resourceKey;
  37.                         data.FromLanguageCode = fromLanguageCode;
  38.                         data.ToLanguageCode = toLanguageCode;
  39.                         data.ResourceValue = resourceValue;
  40.                         // Insert data
  41.                         ctxt.Resources.InsertOnSubmit(data);
  42.                         ctxt.SubmitChanges();
  43.                     }
  44.                     else
  45.                         resourceValue = data.ResourceValue;
  46.                 }
  47.                 // add this result to the cache
  48.                 // find the dictionary for this culture
  49.                 // add this key/value pair to the inner dictionary
  50.                 lock (this)
  51.                 {
  52.                     if (resCacheByCulture == null)
  53.                     {
  54.                         resCacheByCulture = new Dictionary<string, string>();
  55.                         resourceCache.Add(culture.Name, resCacheByCulture);
  56.                     }
  57.                     resCacheByCulture.Add(resourceKey, resourceValue);
  58.                 }
  59.             }
  60.             return resourceValue;
  61.         }

 Dan yang terakhir tambahakn ConnectionString pada web.config

Code Snippet
  1. <connectionStrings>
  2.     <add name="MyResourceManager" connectionString="Data Source=.\SQL2005;Initial Catalog=MyResourceManagerDB;User ID=sa;Password=12345" providerName="System.Data.SqlCLient"/>
  3.   </connectionStrings>

Rename DataSource, User dan password, sesuai environment kalian...

Semoga bermanfaat Big Smile 

Share this post: | | | |
Posted: Aug 22 2011, 09:22 PM by Anwar Minarso | with no comments
Filed under: ,
Multilingual ResourceManager dgn Auto Translate (Part I)

Dalam pengembangan aplikasi, multi language merupakan point plus dalam aplikasi. Dalam .NET sendiri fitur tersebut sudah ada yaitu menggunakan ResourceManager, namun dalam prakteknya setiap bahasa kita membutuhkan tenaga kerja yg menguasai bahasa terkait, dan juga harus mencompile dan mendeploy kembali. Tentunya ujung2nya adalah waktu dan cost.

Source code dapat didownload di sini

Dalam postingan kali ini saya akan memberikan contoh membuat Custom ResourceManager dgn implementasi service Translator Microsoft. Contoh screennya adalah sbb :

English

Indonesian

Japanese

Korean

Cukup menarik bukan ?

Sebelum menyentuh lebih dalam, sebaiknya lihat dahulu link dibawah ini :

  1. ResourceManager, detail penggunanaannya dapat dilihat pada http://msdn.microsoft.com/en-us/library/aa905797.aspx.
  2. Contoh Implementasi Translator telah posting oleh teman kita Yugie, linknya adalah http://students.netindonesia.net/blogs/yugie/archive/2011/03/02/mudah-translator-dengan-bing-web-service.aspx
  3. Dan juga untuk detail API Translator dapat dilihat pada http://api.microsofttranslator.com/

Jika sudah membaca link diatas, oke kita lanjut....

Saya membuat enum LanguageType dan Extensionnya, tujuannya untuk mapping dengan API Translator dan juga mapping CultureInfonya

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Globalization;
  6. namespace MyResourceManager
  7. {
  8.     public enum LanguageType
  9.     {
  10.         AutoDetect,
  11.         Arabic,
  12.         Bulgarian,
  13.         Catalan,
  14.         Chinese_Simplified,
  15.         Chinese_Traditional,
  16.         Czech,
  17.         Danish,
  18.         Dutch,
  19.         English,
  20.         Estonian,
  21.         Finnish,
  22.         French,
  23.         German,
  24.         Greek,
  25.         Haitian_Creole,
  26.         Hebrew,
  27.         Hungarian,
  28.         Indonesian,
  29.         Italian,
  30.         Japanese,
  31.         Korean,
  32.         Latvian,
  33.         Lithuanian,
  34.         Norwegian,
  35.         Polish,
  36.         Portuguese,
  37.         Romanian,
  38.         Russian,
  39.         Slovak,
  40.         Slovenian,
  41.         Spanish,
  42.         Swedish,
  43.         Thai,
  44.         Turkish,
  45.         Ukrainian,
  46.         Vietnamese
  47.     }
  48.     public static class LanguageTypeExtension
  49.     {
  50.         public static string GetLanguageCode(this LanguageType value)
  51.         {
  52.             switch (value)
  53.             {
  54.                 case LanguageType.AutoDetect:
  55.                     return "";
  56.                 case LanguageType.Arabic:
  57.                     return "ar";
  58.                 case LanguageType.Bulgarian:
  59.                     return "bg";
  60.                 case LanguageType.Catalan:
  61.                     return "ca";
  62.                 case LanguageType.Chinese_Simplified:
  63.                     return "zh-CHS";
  64.                 case LanguageType.Chinese_Traditional:
  65.                     return "zh-CHT";
  66.                 case LanguageType.Czech:
  67.                     return "cs";
  68.                 case LanguageType.Danish:
  69.                     return "da";
  70.                 case LanguageType.Dutch:
  71.                     return "nl";
  72.                 case LanguageType.English:
  73.                     return "en";
  74.                 case LanguageType.Estonian:
  75.                     return "et";
  76.                 case LanguageType.Finnish:
  77.                     return "fi";
  78.                 case LanguageType.French:
  79.                     return "fr";
  80.                 case LanguageType.German:
  81.                     return "de";
  82.                 case LanguageType.Greek:
  83.                     return "el";
  84.                 case LanguageType.Haitian_Creole:
  85.                     return "ht";
  86.                 case LanguageType.Hebrew:
  87.                     return "he";
  88.                 case LanguageType.Hungarian:
  89.                     return "hu";
  90.                 case LanguageType.Indonesian:
  91.                     return "id";
  92.                 case LanguageType.Italian:
  93.                     return "it";
  94.                 case LanguageType.Japanese:
  95.                     return "ja";
  96.                 case LanguageType.Korean:
  97.                     return "ko";
  98.                 case LanguageType.Latvian:
  99.                     return "lv";
  100.                 case LanguageType.Lithuanian:
  101.                     return "lt";
  102.                 case LanguageType.Norwegian:
  103.                     return "no";
  104.                 case LanguageType.Polish:
  105.                     return "pl";
  106.                 case LanguageType.Portuguese:
  107.                     return "pt";
  108.                 case LanguageType.Romanian:
  109.                     return "ro";
  110.                 case LanguageType.Russian:
  111.                     return "ru";
  112.                 case LanguageType.Slovak:
  113.                     return "sk";
  114.                 case LanguageType.Slovenian:
  115.                     return "sl";
  116.                 case LanguageType.Spanish:
  117.                     return "es";
  118.                 case LanguageType.Swedish:
  119.                     return "sv";
  120.                 case LanguageType.Thai:
  121.                     return "th";
  122.                 case LanguageType.Turkish:
  123.                     return "tr";
  124.                 case LanguageType.Ukrainian:
  125.                     return "uk";
  126.                 case LanguageType.Vietnamese:
  127.                     return "vi";
  128.                 default:
  129.                     return "";
  130.             }
  131.         }
  132.     }
  133.     public static class CultureInfoExtension
  134.     {
  135.         public static LanguageType GetLanguageType(this CultureInfo value)
  136.         {
  137.             string name = value.Name.ToLower();
  138.             LanguageType result = LanguageType.English;
  139.             switch (name)
  140.             {
  141.                 case "af":
  142.                 case "af-za":
  143.                     result = LanguageType.English;
  144.                     break;
  145.                 case "sq":
  146.                 case "sq-al":
  147.                     break;
  148.                 case "ar":
  149.                 case "ar-dz":
  150.                 case "ar-bh":
  151.                 case "ar-eg":
  152.                 case "ar-iq":
  153.                 case "ar-jo":
  154.                 case "ar-kw":
  155.                 case "ar-lb":
  156.                 case "ar-ly":
  157.                 case "ar-ma":
  158.                 case "ar-om":
  159.                 case "ar-qa":
  160.                 case "ar-sa":
  161.                 case "ar-sy":
  162.                 case "ar-tn":
  163.                 case "ar-ae":
  164.                 case "ar-ye":
  165.                     result = LanguageType.Arabic;
  166.                     break;
  167.                 case "hy":
  168.                 case "hy-am":
  169.                     break;
  170.                 case "az":
  171.                 case "az-az-cyrl":
  172.                 case "az-az-latn":
  173.                     break;
  174.                 case "eu":
  175.                 case "eu-es":
  176.                     break;
  177.                 case "be":
  178.                 case "be-by":
  179.                     break;
  180.                 case "bg":
  181.                 case "bg-bg":
  182.                     result = LanguageType.Bulgarian;
  183.                     break;
  184.                 case "ca":
  185.                 case "ca-es":
  186.                     result = LanguageType.Catalan;
  187.                     break;
  188.                 case "zh-hk":
  189.                 case "zh-mo":
  190.                 case "zh-cn":
  191.                 case "zh-sg":
  192.                 case "zh-tw":
  193.                 case "zh-chs":
  194.                     result = LanguageType.Chinese_Simplified;
  195.                     break;
  196.                 case "zh-cht":
  197.                     result = LanguageType.Chinese_Traditional;
  198.                     break;
  199.                 case "hr":
  200.                 case "hr-hr":
  201.                     break;
  202.                 case "cs":
  203.                 case "cs-cz":
  204.                     result = LanguageType.Czech;
  205.                     break;
  206.                 case "da":
  207.                 case "da-dk":
  208.                     result = LanguageType.Danish;
  209.                     break;
  210.                 case "div":
  211.                 case "div-mv":
  212.                     break;
  213.                 case "nl":
  214.                 case "nl-be":
  215.                 case "nl-nl":
  216.                     result = LanguageType.Dutch;
  217.                     break;
  218.                 case "en":
  219.                 case "en-au":
  220.                 case "en-bz":
  221.                 case "en-ca":
  222.                 case "en-cb":
  223.                 case "en-ie":
  224.                 case "en-jm":
  225.                 case "en-nz":
  226.                 case "en-ph":
  227.                 case "en-za":
  228.                 case "en-tt":
  229.                 case "en-gb":
  230.                 case "en-us":
  231.                 case "en-zw":
  232.                     result = LanguageType.English;
  233.                     break;
  234.                 case "et":
  235.                 case "et-ee":
  236.                     result = LanguageType.Estonian;
  237.                     break;
  238.                 case "fo":
  239.                 case "fo-fo":
  240.                     break;
  241.                 case "fa":
  242.                 case "fa-ir":
  243.                     break;
  244.                 case "fi":
  245.                 case "fi-fi":
  246.                     result = LanguageType.Finnish;
  247.                     break;
  248.                 case "fr":
  249.                 case "fr-be":
  250.                 case "fr-ca":
  251.                 case "fr-fr":
  252.                 case "fr-lu":
  253.                 case "fr-mc":
  254.                 case "fr-ch":
  255.                     result = LanguageType.French;
  256.                     break;
  257.                 case "gl":
  258.                 case "gl-es":
  259.                     break;
  260.                 case "ka":
  261.                 case "ka-ge":
  262.                     break;
  263.                 case "de":
  264.                 case "de-at":
  265.                 case "de-de":
  266.                 case "de-li":
  267.                 case "de-lu":
  268.                 case "de-ch":
  269.                     result = LanguageType.German;
  270.                     break;
  271.                 case "el":
  272.                 case "el-gr":
  273.                     result = LanguageType.Greek;
  274.                     break;
  275.                 case "gu":
  276.                 case "gu-in":
  277.                     break;
  278.                 case "he":
  279.                 case "he-il":
  280.                     result = LanguageType.Hebrew;
  281.                     break;
  282.                 case "hi":
  283.                 case "hi-in":
  284.                     break;
  285.                 case "hu":
  286.                 case "hu-hu":
  287.                     result = LanguageType.Hungarian;
  288.                     break;
  289.                 case "is":
  290.                 case "is-is":
  291.                     break;
  292.                 case "id":
  293.                 case "id-id":
  294.                     result = LanguageType.Indonesian;
  295.                     break;
  296.                 case "it":
  297.                 case "it-it":
  298.                 case "it-ch":
  299.                     result = LanguageType.Italian;
  300.                     break;
  301.                 case "ja":
  302.                 case "ja-jp":
  303.                     result = LanguageType.Japanese;
  304.                     break;
  305.                 case "kn":
  306.                 case "kn-in":
  307.                     break;
  308.                 case "kk":
  309.                 case "kk-kz":
  310.                     break;
  311.                 case "kok":
  312.                 case "kok-in":
  313.                     break;
  314.                 case "ko":
  315.                 case "ko-kr":
  316.                     result = LanguageType.Korean;
  317.                     break;
  318.                 case "ky":
  319.                 case "ky-kz":
  320.                     break;
  321.                 case "lv":
  322.                 case "lv-lv":
  323.                     result = LanguageType.Latvian;
  324.                     break;
  325.                 case "lt":
  326.                 case "lt-lt":
  327.                     result = LanguageType.Lithuanian;
  328.                     break;
  329.                 case "mk":
  330.                 case "mk-mk":
  331.                     break;
  332.                 case "ms":
  333.                 case "ms-bn":
  334.                 case "ms-my":
  335.                     break;
  336.                 case "mr":
  337.                 case "mr-in":
  338.                     break;
  339.                 case "mn":
  340.                 case "mn-mn":
  341.                     break;
  342.                 case "no":
  343.                     result = LanguageType.Norwegian;
  344.                     break;
  345.                     
  346.                 case "nb-no":
  347.                     break;
  348.                 case "nn-no":
  349.                     break;
  350.                 case "pl": break;
  351.                 case "pl-pl":
  352.                     result = LanguageType.Polish;
  353.                     break;
  354.                 case "pt":
  355.                 case "pt-br":
  356.                 case "pt-pt":
  357.                     result = LanguageType.Portuguese;
  358.                     break;
  359.                 case "pa":
  360.                 case "pa-in":
  361.                     break;
  362.                 case "ro":
  363.                 case "ro-ro":
  364.                     result = LanguageType.Romanian;
  365.                     break;
  366.                 case "ru":
  367.                 case "ru-ru":
  368.                     result = LanguageType.Russian;
  369.                     break;
  370.                 case "sa":
  371.                 case "sa-in":
  372.                     break;
  373.                 case "sr-sp-cyrl":
  374.                 case "sr-sp-latn":
  375.                     break;
  376.                 case "sk":
  377.                 case "sk-sk":
  378.                     result = LanguageType.Slovak;
  379.                     break;
  380.                 case "sl":
  381.                 case "sl-si":
  382.                     result = LanguageType.Slovenian;
  383.                     break;
  384.                 case "es":
  385.                 case "es-ar":
  386.                 case "es-bo":
  387.                 case "es-cl":
  388.                 case "es-co":
  389.                 case "es-cr":
  390.                 case "es-do":
  391.                 case "es-ec":
  392.                 case "es-sv":
  393.                 case "es-gt":
  394.                 case "es-hn":
  395.                 case "es-mx":
  396.                 case "es-ni":
  397.                 case "es-pa":
  398.                 case "es-py":
  399.                 case "es-pe":
  400.                 case "es-pr":
  401.                 case "es-es":
  402.                 case "es-uy":
  403.                 case "es-ve":
  404.                     result = LanguageType.Spanish;
  405.                     break;
  406.                 case "sw":
  407.                 case "sw-ke":
  408.                     break;
  409.                 case "sv":
  410.                 case "sv-fi":
  411.                 case "sv-se":
  412.                     result = LanguageType.Swedish;
  413.                     break;
  414.                 case "syr":
  415.                 case "syr-sy":
  416.                     break;
  417.                 case "ta":
  418.                 case "ta-in":
  419.                     break;
  420.                 case "tt":
  421.                 case "tt-ru":
  422.                     break;
  423.                 case "te":
  424.                 case "te-in":
  425.                     break;
  426.                 case "th":
  427.                 case "th-th":
  428.                     result = LanguageType.Thai;
  429.                     break;
  430.                 case "tr":
  431.                 case "tr-tr":
  432.                     result = LanguageType.Turkish;
  433.                     break;
  434.                 case "uk":
  435.                 case "uk-ua":
  436.                     result = LanguageType.Ukrainian;
  437.                     break;
  438.                 case "ur":
  439.                 case "ur-pk":
  440.                     break;
  441.                 case "uz":
  442.                 case "uz-uz-cyrl":
  443.                 case "uz-uz-latn":
  444.                     break;
  445.                 case "vi":
  446.                 case "vi-vn":
  447.                     result = LanguageType.Vietnamese;
  448.                     break;
  449.                 default:
  450.                     result = LanguageType.AutoDetect;
  451.                     break;
  452.             }
  453.             return result;
  454.         }
  455.     }
  456.     
  457. }

 Kemudian saya membuat class Utility untuk memudahkan memanggil fungsi API Translatornya

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Configuration;
  6. using System.Globalization;
  7. namespace MyResourceManager
  8. {
  9.     public static class Utils
  10.     {
  11.         /// <summary>
  12.         /// Application ID untuk kebutuhan Service API Translator, APP ID dapat dibuat dari link http://www.bing.com/developers/appids.aspx
  13.         /// </summary>
  14.         private static string _AppId = ConfigurationManager.AppSettings["MSTranslatorAppId"].ToString();
  15.         /// <summary>
  16.         /// default kode bahasa ResourceKey valuenya dapat didapat dari LanguageTypeExtension.GetLanguageCode()
  17.         /// </summary>
  18.         private static string _ResourceKeyLanguage = ConfigurationManager.AppSettings["ResourceKeyLanguage"].ToString();
  19.         public static string ResourceKeyLanguage
  20.         {
  21.             get
  22.             {
  23.                 return _ResourceKeyLanguage;
  24.             }
  25.         }
  26.         public static string AppId
  27.         {
  28.             get
  29.             {
  30.                 return _AppId;
  31.             }
  32.         }
  33.         public static string Translate(string resourceKey, LanguageType from, LanguageType to)
  34.         {
  35.             if (from.Equals(to)) // Skip jika translate ke bahasa yg sama;
  36.                 return resourceKey;
  37.             string result = string.Empty;
  38.             using (MSTranslator.LanguageServiceClient client = new MSTranslator.LanguageServiceClient())
  39.             {
  40.                 result = client.Translate(_AppId, resourceKey, from.GetLanguageCode(), to.GetLanguageCode(), "text/plain", "general");
  41.             }
  42.             return result;
  43.         }
  44.         public static string Translate(string resourceKey, CultureInfo from, CultureInfo to)
  45.         {
  46.             LanguageType fromLang = from.GetLanguageType();
  47.             LanguageType toLang = to.GetLanguageType();
  48.             return Translate(resourceKey, fromLang, toLang);
  49.         }
  50.     }
  51. }

Kemudian implementasi ResourceManagernya (disini saya tidak menjelaskan lebih detail, beberapa code saya ambil dari contoh http://msdn.microsoft.com/en-us/library/aa905797.aspx.  

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Resources;
  6. using System.Globalization;
  7. using System.Web.Compilation;
  8. using System.Collections.Specialized;
  9. namespace MyResourceManager
  10. {
  11.     public class DisposableBaseType : IDisposable
  12.     {
  13.         private bool m_Disposed;
  14.         protected bool Disposed
  15.         {
  16.             get
  17.             {
  18.                 lock (this)
  19.                 {
  20.                     return m_Disposed;
  21.                 }
  22.             }
  23.         }
  24.         #region IDisposable Members
  25.         public void Dispose()
  26.         {
  27.             lock (this)
  28.             {
  29.                 if (m_Disposed == false)
  30.                 {
  31.                     Cleanup();
  32.                     m_Disposed = true;
  33.                     GC.SuppressFinalize(this);
  34.                 }
  35.             }
  36.         }
  37.         #endregion
  38.         protected virtual void Cleanup()
  39.         {
  40.             // override to provide cleanup
  41.         }
  42.         ~DisposableBaseType()
  43.         {
  44.             Cleanup();
  45.         }
  46.     }
  47.     public class MyResourceReader : DisposableBaseType, IResourceReader, IEnumerable<KeyValuePair<string, object>>
  48.     {
  49.         private ListDictionary _listDic;
  50.         public MyResourceReader(ListDictionary dic)
  51.         {
  52.             this._listDic = dic;
  53.         }
  54.         #region IResourceReader Members
  55.         public void Close()
  56.         {
  57.             this.Dispose();
  58.         }
  59.         public System.Collections.IDictionaryEnumerator GetEnumerator()
  60.         {
  61.             if (Disposed)
  62.                 throw new ObjectDisposedException("MyResourceReader object is already disposed.");
  63.             return this._listDic.GetEnumerator();
  64.         }
  65.         #endregion
  66.         #region IEnumerable Members
  67.         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  68.         {
  69.             if (Disposed)
  70.                 throw new ObjectDisposedException("MyResourceReader object is already disposed.");
  71.             return this._listDic.GetEnumerator();
  72.         }
  73.         #endregion
  74.         protected override void Cleanup()
  75.         {
  76.             try
  77.             {
  78.                 this._listDic = null;
  79.             }
  80.             finally
  81.             {
  82.                 base.Cleanup();
  83.             }
  84.         }
  85.         #region IEnumerable<KeyValuePair<string,object>> Members
  86.         IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator()
  87.         {
  88.             if (Disposed)
  89.                 throw new ObjectDisposedException("MyResourceReader object is already disposed.");
  90.            return this._listDic.GetEnumerator() as IEnumerator<KeyValuePair<string, object>>;
  91.         }
  92.         #endregion
  93.     }
  94.     public class MyResourceProvider : DisposableBaseType, IResourceProvider
  95.     {
  96.         private string classKey;
  97.         private Dictionary<string, Dictionary<string, string>> resourceCache = new Dictionary<string, Dictionary<string, string>>();
  98.         private CultureInfo resourceKeyLanguage = new CultureInfo(Utils.ResourceKeyLanguage);
  99.         public MyResourceProvider(string classKey)
  100.         {
  101.             this.classKey = classKey;
  102.         }
  103.         #region IResourceProvider Members
  104.         public object GetObject(string resourceKey, CultureInfo culture)
  105.         {
  106.             if (Disposed)
  107.                 throw new ObjectDisposedException("MyResourceProvider object is already disposed.");
  108.             if (string.IsNullOrEmpty(resourceKey))
  109.                 throw new ArgumentNullException("resourceKey");
  110.             if (culture == null)
  111.                 culture = CultureInfo.CurrentUICulture;
  112.             if (string.IsNullOrEmpty(culture.Name))
  113.                 culture = System.Globalization.CultureInfo.CurrentUICulture;
  114.             string resourceValue = null;
  115.             Dictionary<string, string> resCacheByCulture = null;
  116.             if (resourceCache.ContainsKey(culture.Name))
  117.             {
  118.                 resCacheByCulture = resourceCache[culture.Name];
  119.                 if (resCacheByCulture.ContainsKey(resourceKey))
  120.                     resourceValue = resCacheByCulture[resourceKey];
  121.             }
  122.             if (resourceValue == null)
  123.             {
  124.                 resourceValue = Utils.Translate(resourceKey, resourceKeyLanguage, culture);
  125.                 // add this result to the cache
  126.                 // find the dictionary for this culture
  127.                 // add this key/value pair to the inner dictionary
  128.                 lock (this)
  129.                 {
  130.                     if (resCacheByCulture == null)
  131.                     {
  132.                         resCacheByCulture = new Dictionary<string, string>();
  133.                         resourceCache.Add(culture.Name, resCacheByCulture);
  134.                     }
  135.                     resCacheByCulture.Add(resourceKey, resourceValue);
  136.                 }
  137.             }
  138.             return resourceValue;
  139.         }
  140.         public IResourceReader ResourceReader
  141.         {
  142.             get
  143.             {
  144.                 if (Disposed)
  145.                     throw new ObjectDisposedException("MyResourceProvider object is already disposed.");
  146.                 // this is required for implicit resources
  147.                 // this is also used for the expression editor sheet
  148.                 ListDictionary resourceDictionary = new ListDictionary();
  149.                 return new MyResourceReader(resourceDictionary);
  150.             }
  151.         }
  152.         #endregion
  153.         protected override void Cleanup()
  154.         {
  155.             try
  156.             {
  157.                 this.resourceCache.Clear();
  158.             }
  159.             finally
  160.             {
  161.                 base.Cleanup();
  162.             }
  163.         }
  164.     }
  165.     public class MyResourceProviderFactory : ResourceProviderFactory
  166.     {
  167.         public override IResourceProvider CreateGlobalResourceProvider(string classKey)
  168.         {
  169.             return new MyResourceProvider(classKey);
  170.         }
  171.         public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
  172.         {
  173.             string classKey = virtualPath;
  174.             if (!string.IsNullOrEmpty(virtualPath))
  175.             {
  176.                 virtualPath = virtualPath.Remove(0, 1);
  177.                 classKey = virtualPath.Remove(0, virtualPath.IndexOf('/') + 1);
  178.             }
  179.             return new MyResourceProvider(classKey);
  180.         }
  181.     }
  182. }


Kemudian tambahan web.config nya

Code Snippet
  1. .
  2. .
  3. .
  4. <appSettings>
  5.     <!-- default kode bahasa ResourceKey valuenya dapat didapat dari LanguageTypeExtension.GetLanguageCode() -->
  6.     <add key="ResourceKeyLanguage" value="en" />
  7.     <!-- Application ID untuk kebutuhan Service API Translator, APP ID dapat dibuat dari link http://www.bing.com/developers/appids.aspx -->
  8.     <add key="MSTranslatorAppId" value="2FF28BD209C6653904A8307F0BA50E1D97E862B0"/>
  9.   </appSettings>
  10.   <system.web>
  11.     <!-- uiCulture untuk default tampilan bahsa di UInya -->
  12.     <globalization culture="en-US" uiCulture="en-US" resourceProviderFactoryType="MyResourceManager.MyResourceProviderFactory, MyResourceManager" />
  13.    .
  14.    .
  15.    .
  16.    .

Pada contoh ini ada beberapa configurasi yg perlu kita ketahui

  1. Pada AppSetting ResourceKeyLanguage ini digunakan untuk default bahasa ResourceKey nya. Setiap kita membuat resourceKey, musti dalam bahasa yg diset pada ResourceKeyLanguage.
  2. Pada AppSetting MSTranslatorAppId, Application ID harus diset untuk mendapatkannya harus register terlebih dahulu pada link http://www.bing.com/developers/appids.aspx

Berhubung waktu terbatas, sepertinya cukup untuk sekian dulu... Big Smile


 

Share this post: | | | |
Posted: Aug 22 2011, 08:44 AM by Anwar Minarso | with 1 comment(s)
Filed under: ,
Recursive Calculation

Dengar nama Recursive, sering menjadi bottle neck dalam aplikasi. Banyak cara untuk meningkatkan performance agar metode recursive tidak menjadi berat.

Source code dapat di download di sini

Contoh Struktur Table Part

Contoh Isi Data Part

Result

Class Part

Code Snippet
  1. [Table(Name = "Part")]
  2. public partial class Part
  3. {
  4.     [Column(DbType = "INT NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert, Name = "PartID")]
  5.     public int PartID { get; set; }
  6.     [Column(DbType="INT NULL",  CanBeNull=true, Name="ParentPartID")]
  7.     public int? ParentPartID { get; set; }
  8.     [Column(DbType = "VARCHAR(255) NOT NULL", CanBeNull = false, Name = "PartName")]
  9.     public string PartName { get; set; }
  10.     [Column(DbType = "DECIMAL NOT NULL", CanBeNull = false, Name = "Price")]
  11.     public Decimal Price { get; set; }
  12.     [Column(DbType = "INT NOT NULL", CanBeNull = false, Name = "Qty")]
  13.     public int Qty { get; set; }
  14. }

Addional Property class Part (untuk memudahkan perhitungan Recursive)

Code Snippet
  1. public partial class Part
  2. {
  3.     public Part Parent { get; set; }
  4.     private List<Part> _childs = new List<Part>();
  5.     public List<Part> Childs
  6.     {
  7.         get { return _childs; }
  8.         set { _childs = value; }
  9.     }
  10.     public Decimal Total
  11.     {
  12.         get
  13.         {
  14.             return (Price * Qty);
  15.         }
  16.     }
  17.     public Decimal SubTotal
  18.     {
  19.         get
  20.         {
  21.             return _childs.Sum(t => t.SubTotal) + Total;
  22.         }
  23.     }
  24.     public int TotalPart
  25.     {
  26.         get
  27.         {
  28.             return _childs.Sum(t => t.TotalPart) + Qty;
  29.         }
  30.     }
  31.     public override string ToString()
  32.     {
  33.         string LabelPrice = string.Empty;
  34.         if (Parent == null)
  35.             LabelPrice = "Grand Total";
  36.         else if (_childs.Count > 0)
  37.             LabelPrice = "Sub Total";
  38.         else
  39.             LabelPrice = "Total";
  40.         return string.Format("Part Name : {0}, Price: Rp {1}, Qty: {2}, Total Part: {3}, {4}: Rp {5}", PartName, Price.ToString("n0"), Qty, TotalPart, LabelPrice, SubTotal.ToString("n0"));
  41.     }
  42. }

Part Context (untuk caching data, dan membuat struktur Tree)

Code Snippet
  1. public class PartContext
  2. {
  3.     private static string ConnectionString = ConfigurationManager.ConnectionStrings["MyPartDB"].ConnectionString;
  4.     private static Dictionary<int, Part> dicParts = new Dictionary<int, Part>();
  5.     public static Part[] GetAllParts()
  6.     {
  7.         if (dicParts.Count == 0)
  8.             PopulatePart();
  9.         return dicParts.Values.ToArray();
  10.     }
  11.     public static Part[] GetAllParent()
  12.     {
  13.         if (dicParts.Count == 0)
  14.             PopulatePart();
  15.         return dicParts.Values.Where(t => !t.ParentPartID.HasValue).ToArray();
  16.     }
  17.     public static Part GetByPartID(int PartID)
  18.     {
  19.         if (dicParts.Count == 0)
  20.             PopulatePart();
  21.         if (dicParts.ContainsKey(PartID))
  22.             return dicParts[PartID];
  23.         else
  24.             return null;
  25.     }
  26.     public static void ClearCache()
  27.     {
  28.         dicParts.Clear();
  29.     }
  30.     private static void PopulatePart()
  31.     {
  32.         using (DBContext ctxt = new DBContext(ConnectionString))
  33.         {
  34.             #region Create Database
  35.             if (!ctxt.DatabaseExists())
  36.             {
  37.                 // Create Database
  38.                 ctxt.CreateDatabase();
  39.                 // Create Dummy Record;
  40.                 Part PC = new Part()
  41.                 {
  42.                     ParentPartID = null,
  43.                     PartName = "PC",
  44.                     Price = 0,
  45.                     Qty = 1
  46.                 };
  47.                 ctxt.Parts.InsertOnSubmit(PC);
  48.                 ctxt.SubmitChanges();
  49.                 Part Casing = new Part()
  50.                 {
  51.                     ParentPartID = PC.PartID,
  52.                     PartName = "Casing",
  53.                     Price = 500000,
  54.                     Qty = 1
  55.                 };
  56.                 ctxt.Parts.InsertOnSubmit(Casing);
  57.                 ctxt.SubmitChanges();
  58.                 Part PowerSupply = new Part()
  59.                 {
  60.                     ParentPartID = Casing.PartID,
  61.                     PartName = "Power Supply",
  62.                     Price = 400000,
  63.                     Qty = 1
  64.                 };
  65.                 ctxt.Parts.InsertOnSubmit(PowerSupply);
  66.                 ctxt.SubmitChanges();
  67.                 Part ExtraFan = new Part()
  68.                 {
  69.                     ParentPartID = Casing.PartID,
  70.                     PartName = "Extra Fan",
  71.                     Price = 120000,
  72.                     Qty = 1
  73.                 };
  74.                 ctxt.Parts.InsertOnSubmit(ExtraFan);
  75.                 ctxt.SubmitChanges();
  76.                 Part DVD = new Part()
  77.                 {
  78.                     ParentPartID = Casing.PartID,
  79.                     PartName = "DVD ROM RW",
  80.                     Price = 400000,
  81.                     Qty = 1
  82.                 };
  83.                 ctxt.Parts.InsertOnSubmit(DVD);
  84.                 ctxt.SubmitChanges();
  85.                 Part Motherboard = new Part()
  86.                 {
  87.                     ParentPartID = Casing.PartID,
  88.                     PartName = "Motherboard",
  89.                     Price = 1200000,
  90.                     Qty = 1
  91.                 };
  92.                 ctxt.Parts.InsertOnSubmit(Motherboard);
  93.                 ctxt.SubmitChanges();
  94.                 Part Processor = new Part()
  95.                 {
  96.                     ParentPartID = Motherboard.PartID,
  97.                     PartName = "Processor",
  98.                     Price = 2500000,
  99.                     Qty = 1
  100.                 };
  101.                 ctxt.Parts.InsertOnSubmit(Processor);
  102.                 ctxt.SubmitChanges();
  103.                 Part Memory = new Part()
  104.                 {
  105.                     ParentPartID = Motherboard.PartID,
  106.                     PartName = "Memory 4GB",
  107.                     Price = 600000,
  108.                     Qty = 4
  109.                 };
  110.                 ctxt.Parts.InsertOnSubmit(Memory);
  111.                 ctxt.SubmitChanges();
  112.                 Part VGACARD = new Part()
  113.                 {
  114.                     ParentPartID = Motherboard.PartID,
  115.                     PartName = "VGA CARD",
  116.                     Price = 1200000,
  117.                     Qty = 1
  118.                 };
  119.                 ctxt.Parts.InsertOnSubmit(VGACARD);
  120.                 ctxt.SubmitChanges();
  121.                 Part SOUNDCARD = new Part()
  122.                 {
  123.                     ParentPartID = Motherboard.PartID,
  124.                     PartName = "SOUND CARD",
  125.                     Price = 600000,
  126.                     Qty = 1
  127.                 };
  128.                 ctxt.Parts.InsertOnSubmit(SOUNDCARD);
  129.                 ctxt.SubmitChanges();
  130.                 Part HardDisk = new Part()
  131.                 {
  132.                     ParentPartID = Motherboard.PartID,
  133.                     PartName = "Hard Disk 1 TB",
  134.                     Price = 1300000,
  135.                     Qty = 2
  136.                 };
  137.                 ctxt.Parts.InsertOnSubmit(HardDisk);
  138.                 ctxt.SubmitChanges();
  139.                 Part CoolingFan = new Part()
  140.                 {
  141.                     ParentPartID = Processor.PartID,
  142.                     PartName = "Super Cooler",
  143.                     Price = 350000,
  144.                     Qty = 1
  145.                 };
  146.                 ctxt.Parts.InsertOnSubmit(CoolingFan);
  147.                 ctxt.SubmitChanges();
  148.             }
  149.             #endregion
  150.             #region Populate Dic
  151.             Part[] parts = ctxt.Parts.ToArray();
  152.             // Populate Dic
  153.             foreach (Part part in parts)
  154.                 dicParts.Add(part.PartID, part);
  155.             // Populate Parent & Child
  156.             foreach (Part part in parts)
  157.             {
  158.                 if (part.ParentPartID.HasValue)
  159.                 {
  160.                     Part parentPart = dicParts[part.ParentPartID.GetValueOrDefault()];
  161.                     part.Parent = parentPart;
  162.                     parentPart.Childs.Add(part);
  163.                 }
  164.             }
  165.             #endregion
  166.         }
  167.     }
  168. }

Kesimpulan :

Metode ini sangat berguna untuk menaikan kinerja aplikasi. Akan tetapi jgn lupa Clear Cache atau Partial Update pada PartContextnya jika terjadi perubahan data..

Apakah ada cara yg lebih cepat dari ini ?

Share this post: | | | |
Posted: Aug 20 2011, 12:58 AM by Anwar Minarso | with no comments |
Filed under:
Bermain dengan Extension (fitur .NET 3.0)

Salah satu fitur yg saya suka pada .NET adalah fitur Extension. Fitur ini digunakan untuk membuat tambahan method/function pada class tanpa harus mencompile ulang..

Source Code dapat didownload di sini


Syntax :

Code Snippet
  1. public static <ReturnType> MyFunction(this <ObjectExtension> value)
  2. {
  3.     //Do Something
  4.     return <ReturnType>;
  5. }

Contoh Extension

Berikut ini contoh Extension untuk class IEnumerable<T> agar menambah method konversi ke DataTable

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Data;
  6. using System.Reflection;
  7. namespace MyNamespace
  8. {
  9.     /// <summary>
  10.     /// Untuk membuat Extension harus dibuatkan static Member
  11.     /// </summary>
  12.     public static class MyExtension
  13.     {
  14.         /// <summary>
  15.         /// untuk membuat Extension method harus dibuatkan method/function static Member
  16.         /// </summary>
  17.         /// <typeparam name="T"></typeparam>
  18.         /// <param name="values"></param>
  19.         /// <returns></returns>
  20.         public static DataTable ToDataTable<T>(this IEnumerable<T> values)
  21.             where T: class
  22.         {
  23.             if (values == null)
  24.                 throw new ArgumentNullException("values", "value tidak boleh null");
  25.             Type _type = typeof(T);
  26.             DataTable dt = new DataTable(_type.Name);
  27.             // ambil informasi property pada class
  28.             PropertyInfo[] _propertyInfoArr = _type.GetProperties();
  29.             // membuat column
  30.             foreach (PropertyInfo pi in _propertyInfoArr)
  31.             {
  32.                 DataColumn col = new DataColumn(pi.Name, pi.PropertyType);
  33.                 dt.Columns.Add(col);
  34.             }
  35.             
  36.             // mengisi data
  37.             foreach (T value in values)
  38.             {
  39.                 DataRow row = dt.NewRow();
  40.                 foreach (PropertyInfo pi in _propertyInfoArr)
  41.                 {
  42.                     object propertyValue = pi.GetValue(value, null);
  43.                     row[pi.Name] = propertyValue;
  44.                 }
  45.                 dt.Rows.Add(row);
  46.             }
  47.             return dt;
  48.         }
  49.     }
  50. }

Contoh penggunaannya :

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using MyNamespace;
  6. using System.Data;
  7. namespace TestExtension
  8. {
  9.     class Program
  10.     {
  11.         static void Main(string[] args)
  12.         {
  13.             List<MyClass> myClassCol = new List<MyClass>();
  14.             for (int i = 1; i <= 100; i++)
  15.             {
  16.                 myClassCol.Add(new MyClass()
  17.                 {
  18.                     ID = i,
  19.                     Name = string.Format("Name {0}", i)
  20.                 });
  21.             }
  22.             DataTable dt = myClassCol.ToDataTable(); // Ini adalah Extension
  23.             int totalColumn = dt.Columns.Count;
  24.             foreach (DataRow row in dt.Rows)
  25.             {
  26.                 for (int i = 0; i < totalColumn; i++)
  27.                 {
  28.                     Console.WriteLine("{0} : {1}", dt.ColumnsIdea.ColumnName, rowIdea.ToString());
  29.                 }
  30.                 Console.WriteLine("---------------------------");
  31.             }
  32.             Console.ReadLine();
  33.         }
  34.     }
  35.     public class MyClass
  36.     {
  37.         public int ID { get; set; }
  38.         public string Name { get; set; }
  39.     }
  40. }

Semoga bermanfaat.....

Share this post: | | | |
Posted: Aug 19 2011, 07:30 PM by Anwar Minarso | with 1 comment(s)
Filed under:
Blog Test

Hari ini adalah hari account geeks.netindonesia saya dibuat.

Share this post: | | | |