
Compact / Desktop .EXE and Help File |
Internationalizationsrc.zip 350 KB |

With C# this was reduced to main problem is the setting of the size of the Label to fit.
This became obvious when trying to support the local use of "State/Provence/County" (in German it is not much shorter).
Bad enough that you had to support 2 Resources for all strings in external files (also outside the code being written) if you wanted to support the few Dialic differences your getting up to 6-9 Resources for ALLstrings - most of which are the same. What a waste of time and mostly not done.
The next problem is of cource (at least under C++) you had to send an extra .exe for each Language. And if not, mostly the program had to be restarted before the changes took effect.
The Method offered here solves these problems and allthough a bit complicated once done the adding of an extra Language is very simple.
This article will also try to show how usefull Properties can be in C#. In my mind a very usefull extention even if you could claim that the same functionality could be done in extra Functions in C++.
The use of a Flickerfree Panel where the standard override of OnPaintBackground does not work is also used in the Demo for those interested.
The use of an external class to fill the Panel, StatusBar and Menu's defined in the MainForm (Form1 or what ever) is also shown.
The main reason for doing this is to support both Framework (PC) and Framework.Compactwithout out any changes to the code. The resulting file (here Internationalization.cs) is simply copied to the diretory of the other project with no changes.
With Compact Projects I use a precompile directive (called COMPACT) where PC/Compact specific code is used.
The Source Zip has inside it 2 Zip files, one for each Platform.
Beware : I used a different directory for my Projects (Microsoft.Net and Microsoft.Net.Compact) - the directory inside the Zip have the same name !
The Panel designing was not a major goal for this (quick and dirty, copy and paste) project.
The Compact version (SP1) dos not support transparent Lables.
The PC Version supports OnSize logic.
You may not like my Style of writing/Formatting, but most peaple don't like the style of others anyway, so thats no problem for me. I use a lot of #region #endrgion because I like the results shown in Visial Studio - when I use it.
The code is highly documented (taken from a Card playing project I am working on, which I want to sell later) and a ndoc project file and the resulting help file is included.
This effort is a thank you to the peaple of http://www.codeproject.com/ and of course microsoft.public.dotnet.framework.compact and the other microsoft.public.dotnet.framework.* newsgroups, without which I would have been lost in the last six months - please enjoy my Chrismas present.
So I see no real difference to what I am doing since the creation/setting of my String[] Arrays takes place when the program starts.
Just as with the resources, you are using the same Fields Arrays for one Language at a time. We are NOT creating a lot of String[]'s for all the Languages at once. When a language changes the old Arrays will be freed and a new set Created (sa_Menu_Language = new string[]{"Language","English","German","French"};)
The fact that you can define an unknown amount of Strings in an Array (sa_Menu_Language = null;) is very usefull (to say the least) and the fact that with sa_Menu_Language.Length you know automaticly how many you have set is even better.
The use of Properties as a central point where everthing done is appels to me much more that the decentralise way (I at least) did before.
Since Language is not often changed I even (mis)use this for setting constance String[]'s like DataTable Fields and the Coresponding (Language specific) ListView Columns / Labels etc. for these Fields.
As allways there is a bad side effect when using this :
public void OnBuildViewListe(ref TabPage tabPageListen, ref ListView listViewListen,ref DataView dview_Table, ref string[] sa_listViewCols,int i_Hide, int i_Cols)
{
....
listViewListen = new System.Windows.Forms.ListView();
listViewListen.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listView_ColumnClick);
....
for (int i=0;i < dview_Table.Table.Columns.Count;i++)
listViewListen.Columns.Add(sa_listViewCols[i],-2,HorizontalAlignment.Center);
//-----------------------------------------------------------------------------------------------
for (int i=0;i < dview_Table.Count;i++)
{
DataRowView dset_Row = dview_Table[i];
ListViewItem item = null;
for (int j=0;j < dset_Row.DataView.Table.Columns.Count;j++)
{
if (j == 0)
item = new ListViewItem(dset_Row[dset_Row.DataView.Table.Columns[j].ColumnName].ToString());
else
item.SubItems.Add(dset_Row[dset_Row.DataView.Table.Columns[j].ColumnName].ToString());
}
listViewListen.Items.Add(item);
}
}
Don't ask me what sa_listViewCols[17] is ! But also don't ask what it
would look like if you had an extra String for each DataTable Fieldname
and ListView Column.
Setting all the Labels and TextBox's this way is nasty, but the OnBuildViewListe Method above takes care of all (3) ListViews in an another Program.
Here I also use a Property int for each ListView supported. It stores by which Columns the ListView is sorted and does the following :
#region ip_MainFrame00SortCol
///
/// Which Column is to be Sorted
///
protected int ip_MainFrame00SortCol=0;
///
/// Which Column is Sorted
///
public int i_MainFrame00SortCol
{
get
{
return ip_MainFrame00SortCol;
}
set
{
progessBarMainFrame.Value = 1;
// If new Column is selected, Sort Ascending
if (value != ip_MainFrame00SortCol)
ip_MainFrame00SortType = 0;
else
{// Column was selected, Sort the other way around
if (ip_MainFrame00SortType == 0)
ip_MainFrame00SortType = 1;
else
ip_MainFrame00SortType = 0;
}
// Save the SQL Statement to Sort (used with creation of the DataView)
s_MainFrame00SortType = a_SortType[ip_MainFrame00SortType]; // "ASC","DESC"
progessBarMainFrame.Value = 2;
// Check if the chosen Colums is valid, otherwise set to first Column
if ((value < 0) || (value > dtable_MainFrame00.Columns.Count))
ip_MainFrame00SortCol = 0;
else
ip_MainFrame00SortCol = value;
// Save the SQL Fieldname Statement to Sort (Standard one Column) (used with creation of the DataView)
s_MainFrame00SortCol = sa_MainFrame00Rows[ip_MainFrame00SortCol];
progessBarMainFrame.Value = 3;
// Exceptions to the Standard (Sort with two Columns)
if (ip_MainFrame00SortCol == 1) // Name, Firstname
s_MainFrame00SortCol = sa_MainFrame00Rows[1]+","+sa_MainFrame00Rows[2];
progessBarMainFrame.Value = 4;
// Create the sorted DataView
DataView dview_Table = new DataView(dtable_MainFrame00,"",
s_MainFrame00SortCol+a_SortType[ip_MainFrame00SortType],DataViewRowState.CurrentRows);
progessBarMainFrame.Value = 5;
// Create the ListView Build Function
// - on which Control is the ListView placed (positioned)
// - which ListView is to be used
// - which DataView is to be used
// - which Strings are to be used for the ListView Columns
// - Number of first Columns that should be hidden (first=0)
OnBuildViewListe(ref tabPage000, ref listView000, ref dview_Table, ref sa_MainFrame00Cols,0,3);
// Re-Select the last selected entry (Sort)
if (dview_Table.Count > 0)
{
DataRowView dset_Row = null;
for (int i=0;i < dview_Table.Count;i++)
{
dset_Row = dview_Table[i];
if (dset_Row[sa_MainFrame00Rows[0]].ToString() == s_TableMainFrame00_ID)
{
listView000.Items[i].Selected = true;
listView000.Items[i].Focused = true;
listView000.EnsureVisible(i);
// Missing : Scroll to Selected Item
break;
}
}
OnSetTextDialog(ref drow_MainFrame00);
}
else
{
OnSetEmptyDialog(ref drow_MainFrame00);
b_OnMainFrame00Browse = true; // Deactivate the MainFrame00 Text Controls
button0010.Visible = true; // Show
}
progessBarMainFrame.Value = 10;
}
} // public int i_MainFrame00SortCol
#endregion
3 Tables are done this way, with between 10 and 27 Fields.
- Note when the Colums "Name" is sorted, the ListView is sorted by Name, Firstname !
The following Method is all I do to support all three ListViews
#region listView_ColumnClick
///
/// Find out which ListView was clicked
/// Collect the Column Number that was selected and stores it, Build ListView
///
public void listView_ColumnClick(object sender,ColumnClickEventArgs e)
{
System.Windows.Forms.ListView listView = (System.Windows.Forms.ListView) sender;
if (listView == listView000)
i_MainFrame00SortCol = e.Column;
if (listView == listView010)
i_MainFrame01SortCol = e.Column;
if (listView == listView020)
i_MainFrame02SortCol = e.Column;
progessBarMainFrame.Value = 0;
} // private void listView000_ColumnClick(object sender,ColumnClickEventArgs e)
#endregion
I know it looks terrible String[] names, but it is very good and I like it.
BTW: this runs on Compact where ListView Sorting is not supported (not to mention by two Column sorting).
I had not planed the above when planing this Chrismas present, but now you have my best Sample as how to use Properties - it is not included in the Demo !
The following code is from the Documentation and the Demo Code is extended to support the Menu support to change to the listed Languages / Dialic's.
The Panel not only shows the Street/Straße/Gasse/rue that I live in - but to show the local changes that can take effect in a simple Address program.
public string[] sa_Menu_Language = null;
public string[] sa_AdressTitels = null;
protected int ip_Language = 1;
public int i_Language
{
get
{
return ip_Language;
}
set
{
// Check for valid Language, set Default if an unknown value has been set !
if ((value == 1) || (value == 1202) || (value == 1613) || (value == 44) || // English
(value == 33) || (value == 3281) || (value == 4122) || (value == 1418) || // French
(value == 37) || (value == 3287) || (value == 411) || (value == 43) || // German
(value == 49)) // German
ip_Language = value;
else
ip_Language = 1; // English when not supported
// Set Language independent Values (like Table and Columns names)
// Set Language dependent Values (like Buttons, Lables, Messages etc.)
if ((ip_Language == 1) || (ip_Language == 1202) || (ip_Language == 1613) || (ip_Language == 44)) // English
{
sa_Menu_Language = new string[]{"Language","English","German","French"};
sa_AdressTitels = new string[]{"State","City","Street","Zip-Code"}; // US-English
if ((ip_Language == 1613) || (ip_Language == 44)) // Canada and UK
sa_AdressTitels[3] = "Postal-Code";
if (ip_Language == 1613) // Canada - English
sa_AdressTitels[0] = "Provence";
if (ip_Language == 44) // United Kindom
sa_AdressTitels[0] = "County";
} // English
if ((ip_Language == 33) || (ip_Language == 3281) || // France, Belgien,
(ip_Language == 4122) || (ip_Language == 1418)) // Switzerland, Canada - Quebec
{
sa_Menu_Language = new string[]{"Langue","anglais","allemand","française"};
sa_AdressTitels = new string[]{"Departement","ville","rue","code de poste"}; // French
if (ip_Language == 4122) // Switzerland
sa_AdressTitels[0] = "Canton";
if ((ip_Language == 3281) || (ip_Language == 1418)) // Belgien and Canada
sa_AdressTitels[0] = "Province";
} // French
if ((ip_Language == 37) || (ip_Language == 43) || (ip_Language == 49) || // DDR - Austra - Germany
(ip_Language == 3287) || (ip_Language == 411)) // Belgien - Switzerland
{
sa_Menu_Language = new string[]{"Sprache","englisch","deutsch","französisch"};
sa_AdressTitels = new string[]{"Bundesland","Stadt","Straße","Postleitzahl"}; // German
if (ip_Language == 37) // DDR
sa_AdressTitels[0] = "Bezirk";
if (ip_Language == 3287) // Belgien
sa_AdressTitels[0] = "Provinz";
if (ip_Language == 411) // Switzerland
sa_AdressTitels[0] = "Kanton";
if (ip_Language == 43) // Austria
sa_AdressTitels[2] = "Gasse";
} // German
// Set the Controls with the Language dependent Values (Valid Language and setting values must be done by now)
label_State.Text = sa_AdressTitels[0];
if (mainMenuMain != null)
{ // Menu may not exist
menuItemLanguage.Text = sa_Menu_Language[0];
}
} // Set
} // i_Language
For the rest please look at the suppiled Code, it Compiles on Framework
and Framework.Compact with no Warnings by Warning set to 0. (Exception :
my Message's on which Platform it is being compiled on and DEBUG/RELEASE
Infomation).
About me and others I would like to thank (I know, but it is Christmas) I have spent the last 6 Months of my (rather long unemployment) learning C# after being engcouraged by Harald Bähr, Berlin and glad I did - dispite my misgiving's about this "new .NET thing".
Also I would like to thank Stan Persky, Vancouver, Canada for feeding me again this Summer with among other things: Banana Splits.
Also my thanks to Allen Kempe, from the Blue Grass of Kentucky, for the Meals and Italian Wine and for getting my eMbedded Visial Tools version to debug on my PDA.
Otherwise if your looking for someone in Berlin, Germany or an Internet employment, to quote Dickens : I'm Willing !
As to any French readers, it has been a very long time since I was in France and I never wrote it very well. As to Spanish, it's even worse so I din't try. Italian, well I like eating your food and drinking your wine and lisening to your songs, but I speak it worse that I write French.
My Apoligies and Merry Christmas to All.
Mark Johnson, Berlin Germany, mj10777@mj10777.de - 23.12.2003
Mark Johnson - Berlin, Germany
23.12.2003