Internationalisation in VB

I need to Internationalise my VB app, I would use a resource file a string tables per LCID but:

Each Customer will need their own string table due to differing names of fields (i.e. some use Branch, others use depot, other location, etc) It seems that you can only have one string table per language per resource file, so this would be impossible. We have lots on English customers so a resource file per customer and recompiling for each is implausible.

We would need to change language on the fly, when dialling in to fix problems or during on site product set up, and as we have found to our cost switch Locales around is not a good idea.

Also some customers have a German LCID but use our product in English, why?, I don't know either.

So what I need is a way to have one string table per customer set from a registry key or database field.
Any tools or ways we can do this?
LVL 1
yerffoegAsked:
Who is Participating?
 
watyConnect With a Mentor Commented:
Thanks to all.

yerffoeg, what is the solution Microsoft gave you?
0
 
watyCommented:
You have several possibilities :
  - Add all language in the same ressource file but with different ID. Ex : for English, begin to ID 0, for French begin to ID 5000
      ID 0 => Print      ID 5000 => Imprimer
      ID 1 => Window     ID 5001 => Fenêtre
Use a global variable to set the actual language. Parse all the windows, text using a function wich make the translation. I use the following function in all my applications (see below)

  - Use a database : Have a table per language, or all language in one table and one field per language.



' *** Here is the code for traduction. The comments are in french.

Option Explicit

' *** Langue
Global gnLangue   As Long

Sub TraductForm(TheForm As Form)
   ' *** Traduction d'une fenêtre ***
   ' *** On utilise l'ID qui est identifié par le @ ***
   
   On Error GoTo ERROR_TraductForm
   
   Dim nI   As Integer
   
   ' *** On commence par traduire le caption de la fenêtre ***
   TheForm.Caption = Traduction(CStr(TheForm.Caption))
   
   For nI = 0 To TheForm.Controls.Count - 1
      ' *** La traduction dépend du type du contrôle ***
   
      If TypeOf TheForm.Controls(nI) Is Label Then
         TheForm.Controls(nI).Caption = Traduction(CStr(TheForm.Controls(nI).Caption))
      ElseIf TypeOf TheForm.Controls(nI) Is Menu Then
         TheForm.Controls(nI).Caption = Traduction(CStr(TheForm.Controls(nI).Caption))
      ElseIf TypeOf TheForm.Controls(nI) Is CommandButton Then
         TheForm.Controls(nI).Caption = Traduction(CStr(TheForm.Controls(nI).Caption))
      ElseIf TypeOf TheForm.Controls(nI) Is Frame Then
         TheForm.Controls(nI).Caption = Traduction(CStr(TheForm.Controls(nI).Caption))
      ElseIf TypeOf TheForm.Controls(nI) Is CheckBox Then
         TheForm.Controls(nI).Caption = Traduction(CStr(TheForm.Controls(nI).Caption))
      ElseIf TypeOf TheForm.Controls(nI) Is OptionButton Then
         TheForm.Controls(nI).Caption = Traduction(CStr(TheForm.Controls(nI).Caption))
      End If
   Next
   
   Exit Sub
   
ERROR_TraductForm:
   Exit Sub
   
End Sub

Function Traduction(szText As String) As String
   ' *** Traduction d'un texte en recherchant l'ID dans le string ***
   
   Dim szTemp     As String
   Dim szID       As String
   Dim nPos       As Integer
   Dim nReturn    As Integer

   On Error GoTo FIND_DLL

   szTemp = ""

   ' *** On recherche le caractère séparateur ***
   nPos = InStr(szText, "@")
   
   If (nPos = 1) Then
      nPos = 1
   End If
   
   ' *** On quitte, pas de traduction ***
   If (nPos = 0) Then
      Traduction = szText
      Exit Function
   End If

   szID = Right(szText, Len(szText) - (nPos))
   
   ' *** On quitte, pas de traduction ***
   If (IsNumeric(szID) = False) Then
      Traduction = szText
      Exit Function
   End If

   If (gbModifyIterfaceText = False) Then
      szTemp = Trim(LoadResString(gnLangue + CLng(szID)))
   Else
      szTemp = Trim(colUserText("ID" & CStr(gnLangue + CLng(szID))))
   End If
   
   ' *** On quitte, pas de traduction ***
   If (szTemp = "") Then
      Traduction = left(szText, nPos - 1)
      Exit Function
   End If

   Traduction = szTemp

   Exit Function

FIND_DLL:
   szTemp = ""
   Resume Next

End Function




Public Sub SetLanguageEnglish()
   ' *** set the english traduction
   
   gnLangue = 0

End Sub

Public Sub SetLanguageFrench()
   ' *** set the french traduction
   
   gnLangue = 1000

End Sub

Public Sub SetLanguageSpanish()
   ' *** set the Spanish traduction
   
   gnLangue = 2000

End Sub

Public Sub SetLanguageGerman()
   ' *** set the german traduction
   
   gnLangue = 3000

End Sub

Public Sub SetLanguageDutch()
   ' *** set the Dutch traduction
   
   gnLangue = 4000

End Sub

Public Sub SetLanguageItalian()
   ' *** set the Italian traduction
   
   gnLangue = 5000

End Sub


0
 
yerffoegAuthor Commented:
It doesn't allow for easy standardisation throughout the code, you end up with large resource files (which will be loaded into memory).
I believe the Microsoft MSDN Document Q188659
Answers our question perfectly keeps the size of the application installation down to a minimum, and the size of resource file loaded into memory.
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
watyCommented:
I use my way, it is very easy to maintain, and it is very quick. So good work.
0
 
yerffoegAuthor Commented:
Does anyone know how I can cancel this question as the MSDN Doc mentioned above suggests the use of satellite DLL's, which seem to fit our needs perfectly.

Or does someone have to answer it?
0
 
yerffoegAuthor Commented:
Does anyone know how I can cancel this question as the MSDN Doc mentioned above suggests the use of satellite DLL's, which seem to fit our needs perfectly.

Or does someone have to answer it?
0
 
watyCommented:
Someone have to answer this.
0
 
MirkwoodCommented:
Answered :-)
0
 
yerffoegAuthor Commented:
What is going on, should I just say Mirkwood has answered it and be done with it, I'd prefer to give Waty the points as he did give me an answer, but it's not like he needs them.
0
 
MirkwoodCommented:
It was just a joke. Nobody answered the question so I did.
I can give you another solution though.
Use the functions below. Put the resources in a seperate library.
With loadlibrary load the correct resource library and close the handle of the library after you don't need it anymore.
With LoadResource you can load the resource of the determined library.

Declare Function LoadResource Lib "kernel32" Alias "LoadResource" (ByVal hInstance As Long, ByVal hResInfo As Long) As Long

Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long

Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Long) As Long



0
 
watyCommented:
If you want, I can accept the answer.
0
 
MirkwoodCommented:
That's ok to. Just reject my answer. Waty answers it and accept his answer.
0
 
yerffoegAuthor Commented:
Rejected for Waty, Sorry I'm a bit confused I'm just getting the used to the way this works.
0
 
yerffoegAuthor Commented:
If you want to know the full idea read the article Q188659 on MSDN, basically it involves creating an Activex DLL which contains the resource file and a couple of functions to read/write the resouce string. Then you can compile a DLL for every customer/language, just be changing the resource file. The id number can obviously stay the same throughout. Then all you need is a simply way to tell the program which DLL to use, in a regkey or the like. I like it better as a solution it just seems neater, a better for our needs than yours, especially if you have alot of customers. I given you a B because I'm sure your method would suit some people more than the method I found. Anyway thanks for your response, hears a ton.

Dave.
0
All Courses

From novice to tech pro — start learning today.