El sistema que utilizamos para el multi-idioma en Access es el siguiente:
- Primero se realiza la aplicación Access en castellano (por ejemplo)
- Le pasamos una rutina que documenta en una tabla Access los siguientes elementos:
- Etiquetas de Formularios
- Etiquetas de Informes
- Caption’s de Botones
- Caption’s de Páginas en el control ficha
- Los nombres de las etiquetas quedan asociados al idioma ‘es’
- Ahorra mucho tiempo en documentar, es automático
- Si queremos que la aplicación se presente también en Inglés copiamos la tabla de etiquetas del idioma ‘es’ al ‘en’ y ponemos la descripción de la etiqueta en inglés
- Definimos los usuarios que tienen acceso a la aplicación y con que idioma quieren trabajar
- Cada vez que se carga un formulario en el evento Form_load añadimos una línea que llama a una función donde se asigna a cada Caption de Etiquetas, botones, etc. su descripción en el idioma del usuario, cuando se presenta el formulario o informe éste ya esta traducido y no se nota ningún tiempo de espera significativo.
Ventaja
Si una etiqueta como ‘Codigo Cliente’ se repite 50 veces en una aplicación de gestión sólo es necesario traducirla una vez. Traducir una aplicación completa lleva 20 minutos.
Consultar más Ejemplos de VBA Access.
A continuación he puesto algunos ejemplos de las principales clases y módulos de VBA que se usan en el sistema multi-idioma que programé para ser utilizado en Microsoft Access. La utilidad multi-idioma completa está en este archivo ZIP: INTEX Translator
Idioma.cls
Clase Idioma que genera el objeto del mismo nombre para encapsular todas las funciones y propiedades relacionadas con un idioma-
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "Idioma"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit
Dim rstIdiomas As Recordset
Dim rstTextos As Recordset
Dim rstTextos1 As Recordset
Dim rstDiccionario As Recordset
Dim strSQL As String
Dim lngPalabrasNuevas As Long
Public Codigo As String
Public Descripcion As String
Public Existe As Boolean
Public Event PalabraTraducida()
Public Event PalabrasTraducidas()
Public Event PalabraGenerada()
Public Event PalabrasGeneradas(NumeroPalabrasNuevas As Long)
Public Property Get NumeroRegistros(Optional CodigoIdioma As String = "es") As Long
' El idioma predeterminado es "es" por la barra de progreso para saber las palabras en castellano
strSQL = "SELECT * FROM Textos WHERE " & _
"Aplicacion='" & strAplicacion & "' AND Idioma='" & CodigoIdioma & "'"
Set rstTextos = New ADODB.Recordset
rstTextos.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
rstTextos.MoveLast
NumeroRegistros = rstTextos.RecordCount
rstTextos.Close
End Property
Public Sub Inicializar(CodigoIdioma As String)
strSQL = "SELECT * FROM Idiomas WHERE Idioma='" & CodigoIdioma & "'"
Set rstIdiomas = New ADODB.Recordset
rstIdiomas.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
Existe = Not rstIdiomas.EOF
If Existe Then
Codigo = rstIdiomas!Idioma
Descripcion = rstIdiomas!Descripcion
End If
rstIdiomas.Close
End Sub
Public Sub TraducirPalabra(TextoCastellano As String, TextoTraducido As String)
Set rstTextos = New ADODB.Recordset
rstTextos.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
Do While Not rstTextos.EOF
rstTextos!Texto = Replace(rstTextos!Texto, TextoCastellano, TextoTraducido)
Debug.Print rstTextos!Texto
rstTextos.Update
RaiseEvent PalabraTraducida
rstTextos.MoveNext
Loop
rstTextos.Close
RaiseEvent PalabrasTraducidas
End Sub
Public Sub Generar()
lngPalabrasNuevas = 0
strSQL = "SELECT * FROM Textos WHERE " & _
"Aplicacion='" & strAplicacion & "' AND Idioma='es'"
Set rstTextos = New ADODB.Recordset
Set rstTextos1 = New ADODB.Recordset
Set rstDiccionario = New ADODB.Recordset
rstTextos.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
Do While Not rstTextos.EOF
On Error Resume Next ' Por los Duplicados
strSQL = "SELECT * FROM Textos WHERE " & _
"Aplicacion='" & rstTextos!Aplicacion & "' AND TextoES='" & rstTextos!TextoES & "' AND " & _
"Idioma='" & Codigo & "'"
rstTextos1.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
If rstTextos1.EOF Then
rstTextos1.AddNew
rstTextos1!Aplicacion = rstTextos!Aplicacion
rstTextos1!TextoES = rstTextos!TextoES
rstTextos1!Idioma = Codigo
strSQL = "SELECT * FROM Diccionario WHERE TextoES='" & rstTextos!TextoES & "' AND Idioma='" & Codigo & "'"
rstDiccionario.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
If Not rstDiccionario.EOF Then
rstTextos1!Texto = rstDiccionario!Texto
Else
rstTextos1!Texto = rstTextos!Texto
End If
rstDiccionario.Close
rstTextos1.Update
lngPalabrasNuevas = lngPalabrasNuevas + 1
End If
rstTextos1.Close
RaiseEvent PalabraGenerada
rstTextos.MoveNext
Loop
rstTextos.Close
RaiseEvent PalabrasGeneradas(lngPalabrasNuevas)
End Sub
Funciones.cls
Un módulo de clase que contiene la función principal de traducción
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "Funciones"
Attribute VB_GlobalNameSpace = True
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = True
Option Explicit
Dim ctl As Object
Dim ctl1 As Object
Dim ctl2 As Object
Dim colh As Object
Dim strSQL As String
Dim strSQLApl As String
Dim strCaption As String
Dim clsObjeto As Objeto
Attribute clsObjeto.VB_VarHelpID = -1
Dim strPaso As String
Dim rstTextos As ADODB.Recordset
Dim strFormularioNombre As String
Dim strAplicacionCodigo As String
Dim itxFormularioTipo As itxTipoObjeto
Dim strKey As String
Dim strParametro As String
Dim intParametro As Integer
Dim varParametro As Variant
Dim varBackColor As Variant
Dim varForeColor As Variant
Dim intCadena As Integer
Public Sub TituloAplicacion(app As Object, Optional Titulo As String = "Microsoft Access")
On Error Resume Next
app.CurrentDb.Properties("AppTitle").Value = Titulo
app.RefreshTitleBar
End Sub
' Formulario: Puede ser un Formulario Access o Visual Basic por eso se pasa como Object
' Evento : Para distinguir si son acciones de "LOAD" o de "UNLOAD"
' ConfigurarPosicion : Para ajustar el tamaño en formularios VisualBasic
' ConfigurarParametros: Para configurar parametros por defecto
Public Function ConfigurarForm(Formulario As Object, Optional Evento As String = "LOAD", Optional ConfigurarPosicion As Boolean = False, Optional ConfigurarParametros As Boolean = False, Optional ParametroDeCarpeta As Boolean = False)
On Error GoTo ErrorSub
' Determinar Variables Generales
strAplicacionCodigo = GetSetting("INTEXIT", "INTEX Tools", "APLide", "Aplicacion Desconocida")
strFormularioNombre = Formulario.Name
itxFormularioTipo = TipoObjeto(Formulario)
' Procesar según evento
Select Case UCase(Evento)
Case "LOAD"
If ConfigurarPosicion Then
Formulario.Left = GetSetting("INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainLeft", 1000)
Formulario.Top = GetSetting("INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainTop", 1000)
Formulario.Width = GetSetting("INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainWidth", 6500)
Formulario.Height = GetSetting("INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainHeight", 6500)
End If
ActualizarFondo Formulario
Traducir Formulario, ConfigurarParametros
Case "UNLOAD"
If ConfigurarPosicion And itxFormularioTipo = itxVisualForm Then
If Formulario.WindowState <> vbMinimized Then
SaveSetting "INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainLeft", Formulario.Left
SaveSetting "INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainTop", Formulario.Top
SaveSetting "INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainWidth", Formulario.Width
SaveSetting "INTEXIT", strAplicacionCodigo, strFormularioNombre & "MainHeight", Formulario.Height
End If
End If
If ConfigurarParametros Then
GrabarParametros Formulario
End If
End Select
Exit Function
ErrorSub:
Debug.Print Err.Description
End Function
Public Sub ActualizarFondo(Formulario As Object)
Dim strFondo As String
On Error GoTo ErrorSub
If ValorParametro("PersonalizarAspectoWinBol") <> True Then Exit Sub
' Se recalculan parametros por si se llama directamente a esta función sin ConfigurarForm
itxFormularioTipo = TipoObjeto(Formulario)
strAplicacionCodigo = GetSetting("INTEXIT", "INTEX Tools", "APLide", "Aplicacion Desconocida")
strFondo = GetSetting("INTEXIT", strAplicacionCodigo, "Fondo", "sinfondo.abc")
If LCase(strFondo) = "sinfondo.abc" Or LCase(strFondo) = "i:\system\easy plantillas\plantilla.jpg" Then
Exit Sub
End If
If Dir(strFondo) <> "" Then
Select Case itxFormularioTipo = itxVisualForm
Case itxAccessForm
Formulario.Picture = strFondo
Case itxVisualForm
Formulario.Picture = LoadPicture(strFondo)
End Select
End If
Exit Sub
ErrorSub:
Debug.Print Err.Description
End Sub
Public Sub Traducir(Formulario As Object, Optional CargarParametros As Boolean = False)
Dim rstTextosF As ADODB.Recordset
On Error GoTo ErrorSub
' Determinar Variables Generales
itxFormularioTipo = TipoObjeto(Formulario)
strAplicacionCodigo = GetSetting("INTEXIT", "INTEX Tools", "APLide", "Aplicacion Desconocida")
strFormularioNombre = Formulario.Name
' Comprobar Formularios
If blnComprobarControles Then
Set clsObjeto = New Objeto
clsObjeto.Inicializar Formulario
Set clsObjeto = Nothing
End If
' Traducir Controles del Informe o Formulario
varBackColor = ValorParametro("ColorFondoControl")
varForeColor = ValorParametro("ColorTextoControl")
For Each ctl In Formulario.Controls
If blnTraduccionActiva Then TraducirControl ctl
If CargarParametros Then ProcesarParametroControl ctl, "Cargar"
If ValorParametro("PersonalizarAspectoWinBol") = True Then
ModificarAspectoControl ctl, itxBackColor
ModificarAspectoControl ctl, itxForeColor
End If
Next ctl
' Caption del Formulario si la traducción está activa
If blnTraduccionActiva Then
strCaption = ValidarString(Formulario.Caption, strAplicacion)
Set rstTextosF = New ADODB.Recordset
strSQL = "SELECT * FROM Textos WHERE " & _
"Aplicacion Like '" & strAplicacion & "' AND " & _
"TextoES='" & strCaption & "' AND " & _
"Idioma='" & strIdioma & "'"
rstTextosF.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
If Not rstTextosF.EOF Then
Formulario.Caption = ValidarString(rstTextosF!Texto, strCaption)
End If
rstTextosF.Close
End If
Exit Sub
ErrorSub:
MsgErr "Funciones.Traducir"
End Sub
Private Sub TraducirControl(ByRef ControlOrigen As Object)
'ProcesarControl ctl, "pz" ESTA PENDIENTE
On Error GoTo TraducirEspecial
' Select Case TypeName(ControlOrigen)
' Case ""
' End Select
' Controles que tienen la propiedad Caption
strCaption = ""
strCaption = ValidarString(ControlOrigen.Caption)
If strCaption <> "" Then
ControlOrigen.Caption = TraducirTexto(ControlOrigen.Caption)
End If
Exit Sub
TraducirEspecial:
On Error GoTo TraducirFin
TraducirColumnas ControlOrigen ' Controles de Lista
Exit Sub
TraducirFin:
MsgErr "Funciones.Traducir"
End Sub
Private Sub TraducirColumnas(ByRef ControlOrigen As Object)
On Error GoTo TraducirFin
For Each colh In ctl.ColumnHeaders
colh.Text = TraducirTexto(colh.Text)
Next
Exit Sub
TraducirFin:
' No se pone mensaje para evitar error reiterativos
End Sub
Public Function TraducirTexto(Texto As String) As String
Dim strTexto As String
On Error GoTo ErrorSub
Debug.Print Texto
TraducirTexto = ValidarString(Texto)
If Not blnTraduccionActiva Then Exit Function
If ValidarString(Texto) = "" Then Exit Function
Select Case Right(Texto, 1)
Case ":"
strTexto = Mid(Texto, 1, Len(Texto) - 1)
Case " "
strTexto = Mid(Texto, 1, Len(Texto) - 1)
Case Else
strTexto = Texto
End Select
strSQL = "SELECT * FROM Textos WHERE " & _
"TextoES=" & """" & strTexto & """" & " AND Idioma='" & strIdioma & "'"
If ValidarString(strAplicacion) <> "" Then
If strAplicacion <> "*" Then
strSQL = strSQL & " AND Aplicacion='" & strAplicacion & "'"
End If
End If
If rstTextos Is Nothing Then
Set rstTextos = New ADODB.Recordset
End If
rstTextos.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
If Not rstTextos.EOF Then
TraducirTexto = ValidarString(rstTextos!Texto)
If TraducirTexto <> "" Then
Select Case Right(Texto, 1)
Case ":"
TraducirTexto = TraducirTexto & ":"
Case " "
TraducirTexto = TraducirTexto & " "
End Select
Else
If blnComprobarControles Then ' Se actualiza el texto
rstTextos!Texto = strTexto
rstTextos.Update
End If
End If
Else
If blnComprobarControles Then
AltaControl Texto
End If
End If
rstTextos.Close
Exit Function
ErrorSub:
MsgErr "Funciones.TraducirTexto"
Debug.Print Err.Description
'Resume
End Function
Private Sub AltaControl(Texto As String)
Dim rstTextosA As ADODB.Recordset
On Error GoTo ErrorSub
If Len(Texto) >= 256 Then Exit Sub
Set rstTextosA = New ADODB.Recordset
rstTextosA.Open "Textos", Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdTable
rstTextosA.AddNew
rstTextosA("Aplicacion") = strAplicacion
rstTextosA("TextoES") = Texto
rstTextosA("Idioma") = strIdioma
rstTextosA("Texto") = Texto
rstTextosA.Update
rstTextosA.Close
Exit Sub
ErrorSub:
' No se pone error por los duplicados
End Sub
Public Sub OpcionesINTEXTranslator()
frmOpciones.Show 1
End Sub
Public Sub CambioIdiomaINTEXTranslator(NuevoIdioma As String)
strIdioma = NuevoIdioma
SaveSetting app.Title, "Settings", "Idioma", NuevoIdioma
End Sub
Public Sub TraducirMenusAccess(BarraMenu As Object, CodigoIdioma As String)
If Not blnTraduccionActiva Then Exit Sub
For Each ctl In BarraMenu.Controls
If CodigoIdioma = "es" Then
ctl.Caption = TextoES(ctl.Caption)
Else
ctl.Caption = TraducirTexto(ctl.Caption)
End If
If ctl.Type = 10 Then
For Each ctl1 In ctl.Controls
If CodigoIdioma = "es" Then
ctl1.Caption = TextoES(ctl1.Caption)
Else
ctl1.Caption = TraducirTexto(ctl1.Caption)
End If
If ctl1.Type = 10 Then
For Each ctl2 In ctl1.Controls
If CodigoIdioma = "es" Then
ctl2.Caption = TextoES(ctl2.Caption)
Else
ctl2.Caption = TraducirTexto(ctl2.Caption)
End If
Next
End If
Next
End If
Next
End Sub
Private Function TextoES(Texto As String) As String
On Error GoTo ErrorSub
TextoES = Texto
strSQL = "SELECT * FROM Textos WHERE Texto=" & """" & Texto & """"
If rstTextos Is Nothing Then
Set rstTextos = New ADODB.Recordset
End If
rstTextos.Open strSQL, Parametros.ADO.ITR, adOpenKeyset, adLockOptimistic, adCmdText
If Not rstTextos.EOF Then
TextoES = rstTextos!TextoES
End If
rstTextos.Close
Exit Function
ErrorSub:
'MsgErr TextoES
End Function
Public Sub Mensaje(Texto As String, Optional Titulo As String = "")
On Error Resume Next
If Titulo = "" Then
Titulo = GetSetting("INTEXIT", "INTEX Tools", "APLide", "Mensaje")
If Titulo = "INTEX WinBol2000" Then Titulo = "WinBol"
End If
If blnTraduccionActiva Then
MsgBox TraducirTexto(Texto), vbInformation, Titulo
Else
MsgBox ValidarString(Texto), vbInformation, Titulo
End If
End Sub
Private Sub GrabarParametros(Formulario As Object)
' Determinar Variables Generales
On Error GoTo ErrorSub
For Each ctl In Formulario.Controls
ProcesarParametroControl ctl, "Grabar"
Next
Exit Sub
ErrorSub:
End Sub
Private Sub ProcesarParametroControl(ByRef ControlOrigen As Object, Accion As String)
On Error GoTo ErrorSub
' Control de que exista el literal PARAM
intParametro = InStr((UCase(ControlOrigen.Tag)), "PARAM") ' Por parametro
If intParametro = 0 Then Exit Sub
' Control de que sea un parametro de carpeta
intParametro = InStr((UCase(ControlOrigen.Tag)), "CARP") ' Por parametro de Carpeta
If intParametro = 0 Then ' No es un parametro de Carpeta
strKey = "Parametro." & strFormularioNombre & "." & ControlOrigen.Name
Else ' Es un parametro que depende de la carpeta activa
strKey = "Parametro." & strFormularioNombre & "." & ControlOrigen.Name & "." & GetSetting("INTEXIT", strAplicacionCodigo, "CarpetaActiva", "Shared")
End If
' Pendiente probar para campos de fechas de momento solo funciona para textos
Select Case itxFormularioTipo
Case itxVisualForm ' Para formularios de Visual Basic
If Accion = "Grabar" Then
Select Case TypeName(ControlOrigen)
Case "DTPicker"
SaveSetting "INTEXIT", strAplicacionCodigo, strKey, ControlOrigen.Value
Case Else
SaveSetting "INTEXIT", strAplicacionCodigo, strKey, ControlOrigen.Text
End Select
Else ' Accion=Cargar
strParametro = GetSetting("INTEXIT", strAplicacionCodigo, strKey, "")
Select Case TypeName(ControlOrigen)
Case "DTPicker"
If strParametro <> "" Then ControlOrigen.Value = strParametro
Case Else
If strParametro <> "" Then ControlOrigen.Text = strParametro
End Select
End If
Case itxAccessForm ' Para formularios de Access
If Accion = "Grabar" Then
'MsgBox TypeName(ControlOrigen) Checkbox
Select Case TypeName(ControlOrigen)
Case "DTPicker"
SaveSetting "INTEXIT", strAplicacionCodigo, strKey, ControlOrigen.Value
Case Else
SaveSetting "INTEXIT", strAplicacionCodigo, strKey, ControlOrigen.Value
End Select
Else ' Accion=Cargar
strParametro = GetSetting("INTEXIT", strAplicacionCodigo, strKey, "")
Select Case TypeName(ControlOrigen)
Case "DTPicker"
If strParametro <> "" Then ControlOrigen.Value = strParametro
Case Else
If strParametro <> "" Then ControlOrigen.Value = strParametro
End Select
End If
SaveSetting "INTEXIT", strAplicacionCodigo, strKey, ControlOrigen.Value
End Select
Exit Sub
ErrorSub:
End Sub
Public Function ValorParametro(NombreParametro As String, Optional ValorPorDefecto As Variant) As Variant
ValorParametro = ""
strAplicacionCodigo = GetSetting("INTEXIT", "INTEX Tools", "APLide", "Aplicacion Desconocida")
varParametro = GetAllSettings("INTEXIT", strAplicacionCodigo)
' Primero intenta encontrar los parametros Generales y despues comprobar la carpeta activa
For intParametro = LBound(varParametro, 1) To UBound(varParametro, 1)
intCadena = InStr(1, UCase(varParametro(intParametro, 0)), UCase(NombreParametro))
If intCadena > 0 Then ' Comprobar si hay un parametro con este nombre y tomar el primero que se encuentre
ValorParametro = varParametro(intParametro, 1)
intCadena = InStr(1, UCase(varParametro(intParametro, 0)), GetSetting("INTEXIT", strAplicacionCodigo, "CarpetaActiva", "Shared"))
If intCadena > 0 Then ' Comprobar si puede depender de la carpeta
ValorParametro = varParametro(intParametro, 1)
Exit For ' Se sale no puede haber 2 parametros iguales para la misma carpeta
End If
'Debug.Print varParametro(intParametro, 0), varParametro(intParametro, 1)
End If
Next intParametro
' Comprobar Valores
If ValorParametro = "" Then
If Not IsMissing(ValorPorDefecto) Then
ValorParametro = ValorPorDefecto
End If
End If
End Function
' Modificar Propiedades del Control:
' 1. BackColor
Private Sub ModificarAspectoControl(ByRef ControlOrigen As Object, PropiedadControl As itxPropiedadControl)
On Error GoTo ModificarAspectoControlErr
If ValorParametro("PersonalizarAspectoWinBol") <> True Then Exit Sub
' Select Case TypeName(ControlOrigen)
' Case ""
' End Select
Select Case PropiedadControl
Case itxBackColor
ControlOrigen.BackColor = varBackColor
Case itxForeColor
ControlOrigen.ForeColor = varForeColor
End Select
Exit Sub
ModificarAspectoControlErr:
' Por si el control no tiene la propiedad
Exit Sub
End Sub
Private Sub Class_Terminate()
On Error Resume Next
End Sub
Private Sub clsObjeto_Documentar()
'
End Sub

