Using too much resources

Good day

I've got a VB6 application for English users, now I want to translate it to a different language.
I want to create a variable for each English word or sentence used in my application eg:

Public Const Lang_Search As String = "Search"
Public Const Lang_Open As String = "Open"

All this variable I put in a module called mod_English.bas
And for any other language I just create a new module and change the variable's string values.

But I have a couple of thousand words / sentences in my software that must be translated.

I assume this method will take up a lot of resources, because all the variables will be stored in memory.

Is there a better way of doing this that is more resource friendly?

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Neil RussellTechnical Development LeadCommented:
Stop what your doing and go here and read.....
koossaAuthor Commented:
Thank you Neilsr

Don't know if I'm understanding it correctly, but this link is for translation with the Unicode / ANSI character problem.  

But in my case the 2 languages that I want to use is using only standard alpha numeric characters, I just want to find a way to do the translation without using public constants, because public constants will use way too much memory if you have a couple of thousand of them?

Please let me know if I'm missing something?
Brook BraswellApplication Development ManagerCommented:
Here is a different idea....

Are you using a database for your application ?
Create a Table - call it LangTag or whatever you prefer....
pKey   bigint
BaseLang  long varchar   - Holds the values you want to look up, the words or phrases in your app
Eng - add any number of additional language columns for what you want to translate into...

BaseLang might hold the value "Username"
Eng would be where you hold a different way to say it such as "USER" or "End User"
Spn would hold the Spanish equivalent
Frn would hold the French equivalent

Give the logged in user a default language to interpret - based on your field name:

Global var MyLang as string
'  User Pierre might have
MyLang = "Frn"
' User Jose might have
MyLang = "Spn"
' Default users would have
MyLang = "Eng"

Dim SQL as string

SQL = "Select " & myLang & " from LangTag where BaseLang = " & InterPretValue

Index your table with BaseLang

Build a routine that you pass the Form Object to
Cycle through each of the objects you wish to interpret

To Speed things up:
Create a Public ( or Global depending on your needs ) recordset
gather all the LangTag table when you app opens with the values of the users language...
Make one read to your database then just get data from the "ClientSide" Recordset...

I have an example of this written in VB6 if you need.

Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

koossaAuthor Commented:
Thank you Brook.

I'm gone compile a different applications for each language, so it don't need to dynamically change the language.

If I "make one read" and get all the data from the database, it will still be stored in memory, so am I correct that this would use the same amount of memory than public constants in a module, because it is still stored in memory?

The other thing is, if I want to insert for example 10 language dependent values in the database, it must do 10 look-ups in the recordset, would this not slowdown my application dramatically?
Brook BraswellApplication Development ManagerCommented:
Are you going to be only looking up one language at a time or will your application show values of more than one language.
If you only get the two fields in your recordset  BaseLang and users language "Select baselang, Eng from"
I do believe that the recordset will actually take up less memory than variables ( PLUS ) you only have to update your database should a value change or more interpretations are required.

If that still does not free up enough resources then you could just make a procedure to interpret the values and read from your table one row at a time when you need the row...
' your label here would be your base lang at form design - unless you interpret more than once this would work fine - otherwise use the TAG property of your label to hold what you want interpreted

' this process is slower than loading the table but frees up more memory
lblME.Caption = InterpretME(lblME.Caption)

Public Function InterpretME(byval sPhrase as string) as string
   SQL = "SELECT " & gsUserLang & " FROM LANGTAG WHERE BASELANG = '" & sPhrase & "' "
   ' open your recordset and return your data...
   InterpretME = RS.fields(0).value

End Function
koossaAuthor Commented:
Thank you very much!!

Yes, only 1 language at a time

Can't I do something like this or anything similar:
Private Const m_LookupLang As String = "|Lang_Search|Lang_Test|Lang_go|Lang_exit|Lang_Monday|Lang_Tuesday|"
Private Const m_ActiveLang As String = "|Search|Test|go|exit|Monday|Tuesday|"

Public Function InterpretME(ByVal sPhrase As String) As String
  Dim lPos As Long
  Dim lIndex As Long
  Dim sItems() As String
  lIndex = InStr(1, m_LookupLang, "|" & sPhrase & "|")
  If lIndex > 0 Then
    sItems = Split(Mid(m_LookupLang, 1, lIndex), "|")
    lPos = UBound(sItems)
    sItems = Split(m_ActiveLang, "|")
    InterpretME = sItems(lPos)
  End If
End Function

Open in new window

I have been doing this for seventeen years, using a method my boss suggested. Being that old, the method may not be "modern", but it works FAST and doesn't take up any resources. First, I have a master lexicon file that contains al text the program displays, in three different languages. Here is a snippet of the file:

   1 #### Master Lexicon File 03-18-94 Copyright (c) 1994 My Company, Inc. #####
   2 ########### 1-English, 2-Spanish, 3-French  (* in col 5 = not used) #########
   3 &Setup
   3 &Configuracion
   3 &Configuration
   4 Configure Plant &Location
   4 Configuracion de la Planta &Localidad
   4 Configurer Endroit de &Usine
   5 Configure &Groups
   5 Configuracion de &Grupos
   5 Configurer &Groupes
   6 Configure Supply I&nventory Data
   6 Configuracion de Datos de &Inventario de Suministros
   6 Configurer Donnees de Inventaire de &Fourniture
   7 Configure Plant &Utility Data
   7 Configuracion de &Datos de Servicios de Planta
   7 Configurer Donnees de Utilite de U&sine
   8 Configure &Classification
   8 Configuracion de &Clasificacion
   8 Configurer &Classification
   9 E&xit
   9 S&alir
   9 S&ortir
  10 &Group
  10 &Grupo
  10 &Groupe

I edit this file to add new entries when needed. Right now it has 2110 entries (actually three times that, 2110 times three languages). Anyway, I have a utility I wrote that, after editing, creates three specialized lexicon files, such as Pnet_ENG.lex, Pnet_ESP.lex, and Pnet_FRA.lex. These individual lexicon files contain only the strings for that language. There is a user-selectable variable that sets the language, so I know which file to pull from. Then everywhere I use text, instead of saying:

lblWarning.Text = "Warning"

I use:

lblWarning.Text = Lang$(540)   'XL "Warning"

The XL comment stands for "translation", and reminds me in the program what text I'm using.

Here is the Lang$ routine:

Function Lang$(offset&)
   Rem *** lex$ is a global that holds either "ENG", "ESP", or "FRA" ***
   a$ = String$(80, 32)
   Call CRFO(AppPath$() & "\Lexicon\Pnet_" & lex$ & ".lex", "b", h%, 0)
   Get h%, 80 * offset& - 79, a$
   Close h%
   Lang$ = RTrim$(a$)
End Function

As you can see, the utility I use outputs the individual lexicon files with 80 characters per line. This enables me to use binary mode to access the file for speed.

The CRFO routine is just a fancy file open routine, and can easily be replaced with:

Open AppPath$() & "\Lexicon\Pnet_" & lex$ & ".lex" For Binary As h%

The whole thing looks like it would be slow, but is very, very fast and holds nothing in memory. Of course I don't have all th ecode listed here, like the utility to output the master lexicon into the three individual ones, but all this may give you some ideas.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Brook BraswellApplication Development ManagerCommented:
Just to keep you from having to rebuild each time you change or modify your lang you could read it at once, build your string and close the recordset...

Public m_LookupLang As String ' = "|Lang_Search|Lang_Test|Lang_go|Lang_exit|Lang_Monday|Lang_Tuesday|"
Public m_ActiveLang As String ' = "|Search|Test|go|exit|Monday|Tuesday|"

Public Sub InitLang()
           dim RS as new adodb.RecordSet
           dim SQL as string
           RS.OPEN SQL, YOURCONN, adOpenStatic, adLockReadOnly
           m_LookUpLang = "|"
           m_ActiveLang = "|"
           DO WHILE NOT RS.EOF
              m_LookUpLang = m_LookUpLang & RS!BASELANG & "|"
              m_ActiveLang = m_ActiveLang & RS!ALT_LANG & "|"
           SET RS = NOTHING
End Sub

Public Function InterpretME(ByVal sPhrase As String) As String
  Dim lPos As Long
  Dim lIndex As Long
  Dim sItems() As String
  lIndex = InStr(1, m_LookupLang, "|" & sPhrase & "|")
  If lIndex > 0 Then
    sItems = Split(Mid(m_LookupLang, 1, lIndex), "|")
    lPos = UBound(sItems)
    sItems = Split(m_ActiveLang, "|")
    InterpretME = sItems(lPos)
  End If
End Function

Open in new window

koossaAuthor Commented:
I've done it with an INI file api

Option Explicit
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function GetINIString(ByVal sApp As String, ByVal sKey As String) As String
  Dim sFile As String
  Dim sBuf As String * 256
  Dim lBuf As Long
  sFile = App.Path & "\MyData.ini"
  lBuf = GetPrivateProfileString(sApp, sKey, "", sBuf, Len(sBuf), sFile)
  GetINIString = Left$(sBuf, lBuf)
End Function

Private Sub Command1_Click()
  MsgBox GetINIString("Words", "Lang_Search")
End Sub

Open in new window

Then the ini file's content looks like this:
Lang_Search=Search test

Open in new window

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.