I need to add support for alternate languages to my VB application. I have started by creating a resource file with strings and values for one form, using GetString. Before I go too far, I want to figure out the best organization. In VB6 I could have a string table with multiple languages in a file which made it easy to add more. It looks like I need files for each langue in .NET.
Should there be a single large file for each language for the entire project, or multiple files, say for groups of forms?
Here is a function I am using to access the strings:
Public Function GetString(ByVal strValue As String)
Select Case m_str_System_Language
Case "EN" 'English
rm = My.Resources.English.ResourceManager
Case "FR" 'French
'rm = My.Resources.French.ResourceManager
Case "ES" 'Spanish
'rm = My.Resources.Spanish.ResourceManager
Case "DE" 'German
'rm = My.Resources.German.ResourceManager
Case Else '"EN" 'English
rm = My.Resources.English.ResourceManager
End Select
'Return language specific string
GetString = rm.GetString(strValue)
End Function
Well, this is a big field. For the beginning, read Walkthrough: Localizing Windows Forms. You will learn a lot from it. Sometimes you find some gems even on the Microsoft website. ;-)
I use three strategies to localize apps. The first is:
Localize Forms
Thats quite easy.
Set the Localizable property to True
Keep in mind that the texts you already have on your form are the default texts which apply when the app is set to a culture which you still didn't create texts for. So this would be normally english.
Now set the Language property of the form to that Language/Culture you want to translate to
Now change all texts on your form (labels, button, menuitems, everything!) with their french, german, spanish or whatever counterpart
Now save the form and switch back to the default language. There you will find your old (english) texts
In the folder where your form locates you will find a new *.resx file which is named YourForm.de-DE.resx or YourForm.fr-FR.resx dependig on what language you just edited
Depending what culture is set for the Thread the appropriate texts will be shown
Localized ComboBox entries
Sometimes you have ComboBoxes in which all texts must be localized. Then I use the old database table approach. This would look like:
ID Group ItemID en_US de_DE
1 Sexes 0 male männlich
2 Sexes 1 female weiblich
3 Sexes 2 diverse divers
4 FamilyStatus 0 single ledig
5 FamilyStatus 1 married verheiratet
6 FamilyStatus 2 divorced geschieden
7 FamilyStatus 3 widowed verwitwet
And then get the right SELECT Statement depending on the language you want and the group you want.
The other stuff
The other stuff means e.g. MessageBox messages. That's stuff which is just shown temporaily or changes from time to time.
Here the resources table in project properties is your default language store. To add new languages do:
Create a folder named "Resources" in your project
In this folder add a new element. Choose Resourcefile. Name it Resources.de-DE.resx or Resources.fr-FR.resx for whatever language you want to create.
Add the stuff in here and also in the default resources
Tip: String.Format is your friend. Create texts with placeholders like: "{0} of {1} records". Keep in mind that other languages maybe need some text before the placeholder "{0}", so you should avoid Position & String.Format(" of {0} records", CounterText, DataTable.Rows.Count).
Now, how to use it:
Switching between cultures
To test localization I added a ComboBox to my test form (in the release in your options dialog) and filled it with these Items (in the properties window):
(machine default)
English
German
French
Gaelic
Then the according event handler looks like:
Imports System.Threading
Private Sub CboLanguage_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CboLanguage.SelectedIndexChanged
If CboLanguage.SelectedItem Is Nothing Then Return
Dim Infos = {"", "en-US", "de-DE", "fr-FR", "gd-GB"}
If CboLanguage.SelectedIndex = 0 Then
Thread.CurrentThread.CurrentUICulture = CultureInfo.CurrentCulture
Else
Thread.CurrentThread.CurrentUICulture = New CultureInfo(Infos(CboLanguage.SelectedIndex))
End If
End Sub
The list contains Gaelic only to test a language I really dont have in my resources, which means to test the switch to the default resource. In production you would delete the languages you don't have resources for from the list and of course the (machine default) entry.
The two default cultures
Note that there are two default cultures when you start an application.
We have the default culture which is defined in your project properties about which I told before. But there is another one which is the computers language the app is running on. There are two scenarios how an app will find the culture it will use.
You start the app, the app determines the computers culture and searches in your resources for the according ressources (this will happen every time a resource is needed). If the according resource is found, it will be used, otherwise the resource from the default resources will be used.
The user sets another language in the options, this is saved in whatever settings strategy (My.Settings, app.config, INI-File, Registry, Isolated Storage, Database), you load it at Initialization/Start of your app and set the proper Threads UICulture, then this Culture will take place where the computers was. From now on resources will be searched in the according Resource file and analog, if not found, in the Default resources.
Getting the texts
Regarding the forms you have to do nothing. Depending on your Thread.CurrentThread.CurrentUICulture the according texts will be shown.
As soon as you add a resource text to the default resources or one of your other language resource files VS will create a new property with the name of your resource text in then Resources.Designer.vb which is located in the "My Project" folder.
This means, if you create a resource text named "New" and with value "&New" in the default resources or the Resources.en-US.resx file, the same with value "&Nouveau" in the Resources.fr-FR.resx file and "&Neu" in the Resources.de-DE.resx file, you can access the text with:
My.Resources.New
That's it. Depending on your Thread.CurrentThread.CurrentUICulture you will get the text in the according language.
Transfer between Assemblies
Note that the My.Resources namespace is declared with the Friend modifier which means it applies only to the local assembly. And every assembly has its own My.Resources namespace.
If you do not Multithreading and every DLL has its own localized texts in the same cultures, you have no problem. But if you want to manage texts in a DLL from your main assembly then you need to have a reference of the main ResourceManager in your DLL. This looks like in your DLL class:
Public Class MyPublicDLLClass
' Members
Public Property ResourceManager As Resources.ResourceManager = Nothing
' Other members
End Class
And in the calling assembly:
Dim DLLObject = New MyPublicDLLClass With {
.ResourceManager = My.Resources.ResourceManager
}
Then you could do this to have access to the resources of the calling assembly:
Function GetText(Item As String) As String
Return GetText(Item, Nothing)
End Function
Function GetText(Item As String, [Default] As String) As String
Dim Def As String = If([Default], Item)
If ResourceManager IsNot Nothing Then
Dim Text = ResourceManager.GetString(Item)
Return If(String.IsNullOrEmpty(Text), Def, Text)
Else
Return Def
End If
End Function
Related
,
I read lots of answer here and learn something about this topic but I need more help.Some pages in my project are getting the html(page body) from database.For my controls I use resx files and it works great, but now I need save the html values with multi-lang in my database.
I have a admin panel for my project and I edit sometimes the html or text or pictures in my editor and save it back to DB.I cache the html values in my website and get better performance for my project.But the html text parts is yet in my default lang I will create multi-lang.
I thought of a few possible solutions,
First solution was copying all of the same HTML data and create for all lang one by one
First solution problem : But later this doesnt make sense If I copy the values and create for other lang, then I had be repeating unnecessarily in my database the html values.
My second solution was like this :
this I hid it in the normal way in my DB (only a part of html in one column)
<li>Hello World</li>
<li>Hello Me</li>
Solution :
<li>[HelloWorld]</li>
<li>[HelloMe]</li>
string newHtmlValue = oldValue.ReplaceByLang("[HelloWorld]", GetCulture();,"Hallo Welt");
***// GetCulture(); return for this example german !
I create a new table for the replace text like the key is [HelloWorld]
1(ROW)- [HelloWorld] eng Hello World
2(ROW)- [HelloWorld] german Hallo Welt
3(ROW)- [HelloWorld] fr bonjour tout le monde
and in my project I select the right html value by culture lang.
Now my question is have you any better idea ?
I hope I've been clear and not messy, but if you need more informations I'll be glad to tell you more.Sorry for english.
I would prefer to store all your localized string in single repository like - DB or Satellite assembly.
For Example if you choose DB as repository - Define 3 tables (minimal structure)
1.Locale - Define your locale
2.Resourcemaster - Define your source string and reference Key and this key should be unique in you application and define a standard format like Module_Control_Section ..
3.LocalizedResource - Define your localized sting of Resourcemaster with Locale Key. Foreign key with ResourceMaster and Locale
In front End you can resole any string like control , Html string with localized string and Unique reference key.
Also Implement UI Caching / API caching for better performance.
Regards
Abdul
I'm writing a program that can upload files to multiple FTP servers.
There is a table, at the top row there are the sites, and at the far left column there are the files. through this table I define what should be uploaded to where.
the program is already working, but what i want to do now is to upload the files parallely on each site. so when i hit start each column will go through the rows on its own and upload the files to that site if the content of the specific cell says so. sites can be any number between 1 and 50. and all uploads should be in parallel. (one file at the time for each site)
what i am asking is what is the best way to handle such thing? i know i have to set up multiple uploaders, but what is confusing me is how to keep track what each site is doing. the only thing i can come up with is an array of arrays. where each position is for a site, and the array at that position defines what file is beeing uploaded and all the informations it needs for that. would that be a good solution?
thanks!
You can put your data into array then use for loop
use this code
$web = ['www.firstSite.com','www.secondSite.com']
$user = ['firstUser','secondUser']
$pass = ['firstPass','secondPass']
for($i=0;$i<sizeof($web);$i++)
{
$conn_id = ftp_connect($web[$i]);
$login_result = ftp_login($conn_id,$user[$i],$pass[$i]);
if (ftp_put($conn_id, $server_file, $local_file, FTP_BINARY))
{echo "Success";}
else {echo "Failed";}
}
You can make a custom class and use a List(Of SiteFiles) for a collection of them. You iterate the sites data and create a new SiteFiles object for each site and add the files names to the Files property that need to be uploaded to that site. Then when your done making this List(Of SiteFiles) then you can iterate each file in SiteFiles.Files for each SiteFiles object and use threading/async methods if needed and upload the files. This gives you a neat and tidy way to organize what your doing.
Public Class SiteFiles
Public Property Site As String
Public Property Files As New List(Of String)
End Class
i want my program to ask user "Do u want to set .mp3 file type always default open by this program?" (for first time only) any example to do this?
First, you will need to familiarize yourself with the Windows Registry.
Associations between programs and extensions are handled inside the HKEY_CLASSES_ROOT key.
Each extension appears as a sub-key.
As each key's default value you will find the associated key that handles most of the operations, currently supported, for that particular file type.
For example, you might find the .mp3's default value is set to "WMP11.AssocFile.MP3" or perhaps it set to "VLC.mp3", if you have installed VLC and configured it as the default MP3 player.
So, now you need to locate that key, again, inside HKEY_CLASSES_ROOT.
Although this may vary, you should find that "VLC.mp3" (or whatever key was associated with the .mp3 extension) has a sub-key called "shell".
Under "shell" you will find another sub-key called "Open".
And, finally, under "Open" you will another sub-key called "Command".
The "Command" key is the one containing the information used by Windows (and other programs) to open/start whatever application is currently associated with the ".mp3" (or any other) extension.
Once you understand and feel comfortable with the way associations are handled in the Registry, you should then use .NET's Microsoft.Win32's Registry class to navigate and query the required keys and their values.
Here's a very basic illustration of how the code would look like:
Dim mp3 = Registry.ClassesRoot.OpenSubKey(".mp3")
Dim associatedValue = mp3.GetValue("")
Dim associatedKey = Registry.ClassesRoot.OpenSubKey(associatedValue)
Dim defaultProgram = associatedKey.OpenSubKey("Shell\Open\Command").GetValue("")
MsgBox("MP3 Files Are Opened Using: " + vbCrLf + defaultProgram)
Hope this helps...
You need to set file associations. See this article on Code Project on setting File Associations in VB.NET.
An error shows up again after importing and declaring it like
Dim rgText As Registry.ClassesRoot.OpenSubKey(".txt")
and the error looks like this:
Type 'Registry.ClassesRoot.OpenSubKey' is not defined.
I've tried many variations.
Send To Library - That creates a Zipped file in the Drop Off Library, then it doesn't route via the rules in Content Organizer
API - I've tried to do an Export, Import, but always receive the same error. This is per this MSDN documentation: http://msdn.microsoft.com/en-us/library/microsoft.office.documentmanagement.documentsets.documentset.create.aspx
Sample snippet:
byte[] exportedFile = set.Export();
DocumentSet.Import(exportedFile, DocSetNameToCreate, targetFolder, dsCt.Id, properties, web.CurrentUser);
Error Received:
DocID: Site prefix not set.
Finally got it to run. This is related to the Document ID Feature. Make sure it is activated in each site. Let is run over night (timer jobs need to run). Then the content organizer will successfully move and unpackage your document sets.
You don't have to activate the document id feature, just ensure that in the property bag of the root web of the destination site collection (where the document set will be imported again) exists a property named "docid_msft_hier_siteprefix" with an value of "" (empty string).
Use this powershell-script:
$site = Get-SPSite http://host/sites/yoursite
$properties = $site.RootWeb.Properties
if ($properties["docid_msft_hier_siteprefix"] -eq $null)
{
$properties["docid_msft_hier_siteprefix"] = ""
$properties.Update()
}
Note that i use the old property bag RootWeb.Properties instead of the new hashtable RootWeb.AllProperties, thats because the class Microsoft.Office.DocumentManagement.Internal.OobProvider still uses that.
So why is it failing when a document set is imported? The function DocumentSet.ImportProperties() catches an ArgumentException while trying to set the document id of the document set list item (so there's no problem if the document id column doesn't exist yet).
But they missed that the function OobProvider.GetSitePrefix() which is called through the function OobProvider.GenerateDocumentId() throws an InvalidOperationException if the property bag doesn't contain the prefix property.
I need to make a bunch of redirect pages as I've recently updated my web site which previously used .html files and now all the files are .aspx. I have a tab-delimited file containing a list of original filenames and the corresponding new filename.
It seems like there should be a language out there that I should be able to create a file using the first column for the filename and insert the second column as its content with some additional text for the 301 redirect.
Could someone point me in the right direction as to what language(s) would be able to accomplish this? Also, if you could also point out the name of the method/function I would be using so I know where to begin when creating the file.
I've needed to do this type of thing many times and am willing to learn a new language (Perl, Python, or whatever) to accomplish this, but I just need pointed in the right direction. I am using Windows XP to develop on.
Thank you for your time.
This can be done in a few lines of C# if you already are working with aspx you can process this in the codebehind on a dummy page.
System.IO.StreamReader myreader = new System.IO.StreamReader(Server.MapPath("~/Text.txt"));
while (!myreader.EndOfStream)
{
//9 is Ascii value of Tab bad idea to split if the second set of values might contain tabs but can reconstruct the data if inputString.length >2
string[] inputString = myreader.ReadLine().Split(char.ConvertFromUtf32(9).ToCharArray());
//construct the path to where you want to save the file, or if the filename is the full path all the better
System.IO.StreamWriter filemaker = new System.IO.StreamWriter(#"C:\" + inputString[0]);
filemaker.Write(inputString[1]);
filemaker.Close();
}