Me base en un ejemplo de vb6 que encontre con google:
http://www.recursosvisualbasic.com.ar/htm/trucos-codigofuente-visual-basic/227-aplicacion-multilenguaje-con-ado.htm
Adapte el codigo a vb.net con el framework 2.0 y SQLite
Herramientas:
- Sharpdevelop 2.2 para el .NET Framework 2.0
- SQLite-1.0.66.0 (driver Ado.net 2.0)
Links:
http://www.icsharpcode.net/OpenSource/SD/Download/
SQLite-1.0.66.0-setup (descarguen el Setup)
http://sourceforge.net/projects/sqlite-dotnet2/files/SQLite%20for%20ADO.NET%202.0/1.0.66.0/
Una vez instalado sólo hay que Referenciar la DLL "System.Data.SQLite.dll" al proyecto.
(http://i1093.photobucket.com/albums/i439/maurice_lupin/img3.png)
(http://i1093.photobucket.com/albums/i439/maurice_lupin/img2.png)
Al final dejo el link del proyecto.
' Metodo para cambiar la propiedad "Text"
' a todos los controles del Form
Public Sub changeCaptions( Lista As Object)
Dim myControl As Object
If (TypeOf(Lista) Is Form) Then
setCaption( CType(lista, Form) )
End If
If Not( (TypeOf(Lista) Is ToolStripButton) Or _
(TypeOf(Lista) Is ToolStripMenuItem) ) Then
' Labels, Buttons, Textboxs
For Each myControl In Lista.Controls
setCaption( myControl )
changeCaptions( myControl)
Next
End If
If (TypeOf(Lista) Is ToolStrip) Or _
(TypeOf(Lista) Is MenuStrip) Then
For Each myControl In Lista.Items
If (TypeOf(myControl) Is ToolStripButton) Or _
(TypeOf(myControl) Is ToolStripMenuItem) Then
setCaption( myControl )
changeCaptions(myControl)
End If
Next
End If
If (TypeOf(Lista) Is ToolStripMenuItem)
For Each myControl In Lista.DropDownItems
If (TypeOf(myControl) Is ToolStripMenuItem) Then
setCaption( CType(myControl, ToolStripMenuItem) )
changeCaptions(myControl)
End If
Next
End If
End Sub
Private Sub setCaption(ob As Object)
Dim texto As String = selectCaption(dt, ob.Name)
If texto <> "" Then
ob.Text = selectCaption(dt, ob.Name)
'msgbox( ob.Text )
End If
End Sub
Private Function selectCaption(dt As DataTable, nomC As String) As String
Dim s As String = ""
Dim foundRows() As DataRow
foundRows = dt.Select("NombreControl Like '" & nomC & "%'")
If foundRows.Length = 1 Then s = BlobToString(foundRows(0).Item(2))
Return s
End Function
proyecto en google Docs (https://docs.google.com/open?id=0B_IPc-jU-prBdXdlTmczbFY5d3c)
Saludos ;D
Muy bueno, esto es necesario, nuestros programas tienen más oportunidad de progresar mientras más público tengan y eso es igual a tener la aplicación disponible en más lenguajes.
Hace tiempo necesite que una aplicación cubriera varios lenguajes, era por archivos locales, pero sigue el mismo principio; se basaba en un Diccionario String, String que como Key guardaba el nombre del control, como llegar a el y la propiedad a asignarle el Value del Diccionario, quiero decir, como que Key podría ser por ejemplo:
Form1\Contenedor\Button1*Text y Value Texto en Español
De modo que cuando se cargaba el Diccionario que estaba serializado en un archivo, se usaba Split para separar la ruta que lleva al control, usando Find desde la raíz hasta encontrar el Control deseado Form1.Find para obtener el control Contenedor y Contenedor.Find para obtener Button1 luego se asignaba con Reflection la propiedad Text.
Para los textos que no guardaban relación con un Control los guardaba con un Key #0001 por ejemplo y seguía #0002, #0003 de modo que al cargar el Diccionario y aplicar las propiedades se ignorara todo lo que comienza con #.
Tenía muchos Form e infinidad de Controles por lo qué me ayude con este código que generá el Diccionario:
Una que lista todos los controles de un Form y otra que le da el nombre al control en la forma que te mencione antes.
Public Function GenerateTreeName(ByVal x As Control) As String
GenerateTreeName = x.Name
Do While x.Parent IsNot Nothing
x = x.Parent
GenerateTreeName = x.Name & "\" & GenerateTreeName
Loop
End Function
Public Function ListControls(ByVal x As Control) As List(Of Control)
ListControls = New List(Of Control)
Dim Parents As New List(Of Control)
For Each y As Control In x.Controls
If y.HasChildren Then
Parents.Add(y)
End If
ListControls.Add(y)
Next
For Each y As Control In Parents
ListControls.AddRange(ListControls(y))
Next
End Function
Realmente me pareció la mejor forma y que resume código de manera increíble.
Keyen Night, mi problema fue que al intentar acceder a los elementos de un ToolStrip o MenuStrip utilizando el tipo Control me daba error.
La colección MenuStrip1.Controls no contiene los ToolStripMenuItem sino la colección MenuStrip1.Items, el error que me daba es que los ToolStripMenuItem no son del tipo Control.
Al menos que si hayas logrado acceder a los elementos de un MenuStrip o de un ToolStrip usando el tipo Control, me encantaria ver tu codigo ;D
Saludos y gracias por el comentario.
Eso me paso también con TabPageControl, eso ya está resuelto en código, es una Clase llamada LanguageFile, estructura y serializa las propiedades que tengas que almacenar en un archivos que contiene información del lenguaje, el autor, y la parte de los datos con contiene el diccionario serializado. Cuando se quiere cambiar de idioma se crea un objeto LanguageFile que apunta hacia un archivo '*.lng', se llama al Sub Apply, el diccionario se deserializa, y se recorre siguiendo el cada control con Find a través de todos los Parent, una vez que lo encuentra, lee la parte que dice *PROPIEDAD y dependiendo el tipo, lee y asigna el Value del diccionario, de manera distinta, ya que en tiempo de ejecución Reflection te brinda todas las herramientas para jugar con las propiedades de forma no administrada.
Aquí está el código, coloco en la siguiente lista cosas que le faltarían hacerle que me han dado flojera :xD
Desventajas:
- Obtener objetos Form por su nombre, por ahora se le debe decir a Apply cuales son los Form disponibles y su nombre.
- Brindar soporte para todos los tipos de array, por ahora solo tiene para Columns y TabPages.
En Value '#D#' queda comprendido como un salto de línea.
Se podría hacer algo con Flags para saber cuando la propiedad a asignar es del tipo Array y tomar las precauciones al colocar Value como valor de la propiedad. Pero como por ahora no me ha servido para lo que quiero me ha dado flojera actualizarla :silbar:
Para el Caso del Tool/MenuStrip se podría crear un Flag especial de modo que en Apply se le trate de una forma particular, probablemente me pondré a hacer eso :laugh: de los Flags resultaría muy útil.
Imports System.Runtime.Serialization, System.IO
Imports System.Globalization, System.Reflection
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Text
<Serializable()> _
Public Class LanguageFile
Implements ISerializable
Public Event Applied()
#Region " Delegados "
Public Delegate Sub SetProperty_Delegate( _
ByVal ObjectControl As Control, _
ByVal ObjectName As String, _
ByVal ObjectValue As Object)
Public Sub SetProperty( _
ByVal ObjectControl As Control, _
ByVal ObjectName As String, _
ByVal ObjectValue As Object)
If ObjectControl.InvokeRequired Then
ObjectControl.Invoke(New SetProperty_Delegate(AddressOf SetProperty), _
New Object() {ObjectControl, ObjectName, ObjectValue})
Else
ObjectControl.GetType.GetProperty(ObjectName).SetValue( _
ObjectControl, _
ObjectValue, _
Nothing)
End If
End Sub
Public Delegate Function GetProperty_Delegate( _
ByVal ObjectControl As Control, _
ByVal ObjectName As String) As Object
Public Function GetProperty(ByVal ObjectControl As Control, _
ByVal ObjectName As String) As Object
If ObjectControl.InvokeRequired Then
Return ObjectControl.Invoke(New GetProperty_Delegate(AddressOf GetProperty), _
New Object() {ObjectControl, ObjectName})
Else
Return ObjectControl.GetType.GetProperty(ObjectName).GetValue( _
ObjectControl, _
Nothing)
End If
End Function
#End Region
#Region " Private Fields "
Private _
_ShortName As String, _
_Dic As Dictionary(Of String, String), _
_Author As String
#End Region
#Region " Serializable "
Protected Sub GetObjectData(ByVal info As System.Runtime.Serialization.SerializationInfo, ByVal context As System.Runtime.Serialization.StreamingContext) Implements System.Runtime.Serialization.ISerializable.GetObjectData
For Each x As FieldInfo In Me.GetType.GetFields(BindingFlags.NonPublic Or _
BindingFlags.Instance)
If x.Name.StartsWith("_") Then
info.AddValue(x.Name, x.GetValue(Me))
End If
Next
'info.AddValue("_ShortName", _ShortName)
'info.AddValue("_Author", _Author)
'info.AddValue("_Dic", _Dic)
End Sub
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
For Each x As FieldInfo In Me.GetType.GetFields(BindingFlags.NonPublic Or _
BindingFlags.Instance)
If x.Name.StartsWith("_") Then
x.SetValue(Me, info.GetValue(x.Name, x.FieldType))
End If
Next
'_ShortName = info.GetValue("_ShortName", GetType(String))
'_Author = info.GetValue("_Author", GetType(String))
'_Dic = info.GetValue("_Dic", GetType(Dictionary(Of String, String)))
End Sub
#End Region
#Region " Public Constructors "
Public Sub New(ByVal Buffer As Byte())
If Buffer.Length > (1024 ^ 2) Then
Throw New OverflowException()
Else
Dim MStream As New MemoryStream
MStream.Write(Buffer, 0, Buffer.Length)
MStream.Seek(0, SeekOrigin.Begin)
Dim BFormatter As New BinaryFormatter
Dim [Me] As LanguageFile = BFormatter.Deserialize(MStream)
MStream.Close()
MStream.Dispose()
MStream = Nothing
_Dic = [Me]._Dic
_ShortName = [Me]._ShortName
_Author = [Me].Author
Erase Buffer
End If
End Sub
Public Sub New(ByVal LanguageFile As String)
If File.Exists(LanguageFile) Then
Dim LF As New FileInfo(LanguageFile)
If LF.Length > (1024 ^ 2) Then
Throw New OverflowException(LanguageFile)
Else
Dim MStream As New MemoryStream
Dim FStream As New FileStream(LanguageFile, FileMode.Open, FileAccess.Read)
Dim FBuffer As Byte() = New Byte(LF.Length - 1) {}
FStream.Read(FBuffer, 0, LF.Length)
FStream.Close()
FStream.Dispose()
FStream = Nothing
MStream.Write(FBuffer, 0, FBuffer.Length)
MStream.Seek(0, SeekOrigin.Begin)
Dim BFormatter As New BinaryFormatter
Dim [Me] As LanguageFile = BFormatter.Deserialize(MStream)
MStream.Close()
MStream.Dispose()
MStream = Nothing
_Dic = [Me]._Dic
_ShortName = [Me]._ShortName
_Author = [Me].Author
Erase FBuffer
End If
Else
Throw New FileNotFoundException(LanguageFile)
End If
End Sub
Public Sub New(ByVal LanguageFile As String, _
ByVal Dic As Dictionary(Of String, String), _
ByVal ShortName As String, _
ByVal Author As String)
_Dic = Dic
_ShortName = ShortName
_Author = Author
Dim FStream As New FileStream(LanguageFile, FileMode.Create, FileAccess.Write)
Dim MStream As New MemoryStream
Dim BFormatter As New BinaryFormatter
Dim FBuffer As Byte()
BFormatter.Serialize(MStream, Me)
FBuffer = New Byte(MStream.Length - 1) {}
MStream.Seek(0, SeekOrigin.Begin)
MStream.Read(FBuffer, 0, MStream.Length)
MStream.Close()
MStream.Dispose()
MStream = Nothing
FStream.Write(FBuffer, 0, FBuffer.Length)
FStream.Close()
FStream.Dispose()
FStream = Nothing
Erase FBuffer
End Sub
#End Region
#Region " ReadOnly Properties "
Public ReadOnly Property GetString() As Dictionary(Of String, String)
Get
Return _Dic
End Get
End Property
Public ReadOnly Property Author() As String
Get
Return _Author
End Get
End Property
Public ReadOnly Property Culture() As CultureInfo
Get
Return New CultureInfo(_ShortName)
End Get
End Property
#End Region
#Region " Public Sub "
Public Sub Apply()
For Each x As KeyValuePair(Of String, String) In _Dic
If Not x.Key.StartsWith("#") Then
Dim Tree As String = x.Key.Split("*")(0)
Dim PropertyName As String = x.Key.Split("*")(1)
Dim Controls As String() = Tree.Split("\")
Dim CurrentControl As Control = Nothing
If Controls.Length = 1 Then
Select Case Controls(0)
Case "Form1"
'SetProperty(Form1, PropertyName, x.Value)
Case "Form2"
'SetProperty(Form2, PropertyName, x.Value)
End Select
Else
Select Case Controls(0)
Case "Form1"
'CurrentControl = Form1
Case "Form2"
'CurrentControl = Form2
End Select
For y As Integer = 1 To Controls.Length - 1
CurrentControl = CurrentControl.Controls.Find(Controls(y), False)(0)
Next
If PropertyName.StartsWith("Columns") Then
Dim Index As Integer = PropertyName.Replace("Columns(", "").Replace(")", "")
CType(GetProperty(CurrentControl, "Columns")(Index), ColumnHeader).Text = x.Value
ElseIf PropertyName.StartsWith("TabPages") Then
Dim Index As Integer = PropertyName.Replace("TabPages(", "").Replace(")", "")
CType(GetProperty(CurrentControl, "TabPages")(Index), TabPage).Text = x.Value
Else
SetProperty(CurrentControl, PropertyName, x.Value.Replace("#D#", Environment.NewLine))
End If
End If
End If
Next
RaiseEvent Applied()
End Sub
#End Region
End Class