Programa multilenguaje con diccionarios (tablas hash)

y programas personales para otros como tu, puede que te corrijan ;)
Responder
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Programa multilenguaje con diccionarios (tablas hash)

Mensaje por Ximorro »

Últimamente se habla mucho de la internacionalización de programas, os presento mi versión usando diccionarios, en concreto el objeto de Windows Scripting.Dictionary, que implementa una tabla hash.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Necesita Windows Script 5.6 o superior pero será raro que no lo tengáis ya en el sistema.

Funcionalidad:
.- Acceso directo a las cadenas por nombre identificativo
.- Uso de StringFormat para insertar variables en su posición correcta y hacer textos de varias líneas.

CapturaEsp.PNG
CapturaEsp.PNG (20.37 KiB) Visto 2163 veces
CapturaEng.PNG
CapturaEng.PNG (20.85 KiB) Visto 2163 veces
En principio estaba haciendo un archivo para cada lenguaje, creo que eso facilitaría que otros usuarios proporcionaran otros archivos de idiomas, pero como en el foro otros compañeros están usando un único archivo he seguido la tendencia.
Uso tres idiomas muy utilizados: español, inglés y haxor ;-)

El selector de idioma es muy simple (aunque sí mira qué lenguajes hay disponibles), no mira codificaciones estándar ni cosas de esas, lo importante es el uso del diccionario para usar las cadenas.
Con el diccionario accedemos a las cadenas por un nombre identificativo que les asignamos, de esta manera no importa el orden en que están en al archivo, o si sobran o faltan cadenas (si falta saldrá en blanco en este ejemplo simple, luego comento cómo mejorar ese comportamiento).
Si con un diccionario quiero acceder a la cadena "tituloGUI" simplemente se hace dict.item("tituloGUI"). Lo bueno del asunto es que los objetos COM pueden tener métodos por defecto, y el de Scripting.Dictionary es item(), así que se puede hacer dict("tituloGUI"), lo que simplifica el código y aunmenta la legibilidad, pero recordar que dict no es una función, en realidad estamos llamando a su método item()

He usado StringFormat sólo cuando es necesario (para insertar variables o para cadenas multilínea). Se podría usar para todas las cadenas para hacerlo siempre igual, pero creo que es una sobrecarga innecesaria.

Este es el código, luego comento alguna mejora:

Código: Seleccionar todo

#AutoIt3Wrapper_AU3Check_Parameters=-d -w 3 -w 4
#AutoIt3Wrapper_Run_Obfuscator=y
#Obfuscator_Parameters=/striponly

#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>

;Variables para manejo de idioma
Global $IdiomaPath = @ScriptDir & "\Lenguajes.config"
Global $IdiomaLista = "", $Idioma, $idiDict, $idiIni, $idiIniSecciones

$idiIniSecciones = IniReadSectionNames($IdiomaPath)
For $i = 1 To $idiIniSecciones[0]
	$IdiomaLista &= $idiIniSecciones[$i] & "|"
Next

;Hago un simple GUI para seleccionar idioma, en este uso... ningún idioma ;-)
Global $lista, $listIdioma, $btnSeguir, $nMsg
Global $guiSelIdioma = GuiCreate("", 180, 150)
$listIdioma = GuiCtrlCreateList("", 40,30, 100,50)
GuiCtrlSetData(-1, $IdiomaLista, "ESPAÑOL")
$btnSeguir = GUICtrlCreateButton("", 40,90, 100,40, $BS_ICON)
GUICtrlSetImage(-1, @WindowsDir & "\System32\shell32.dll", -138, 1) ; 138,145,177
GUISetState()

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit ;Ha cancelado desde la selección de idioma
		Case $btnSeguir
			$Idioma = GuiCtrlRead($listIdioma)
			ExitLoop
	EndSwitch
WEnd
GUIDelete($guiSelIdioma)


;Preparamos el diccionario de idioma
$IdiDict = ObjCreate("Scripting.Dictionary")
$idiIni = IniReadSection($IdiomaPath, $Idioma)
For $i = 1 To $idiIni[0][0]
	$IdiDict.Add($idiIni[$i][0], $idiIni[$i][1])
Next
$idiIni = 0 ;Eliminamos la matriz para ahorrar memoria, importante en programas muy grandes con muchos textos

;;;; Este GUI es multilenguaje
Global $guiMultiLengu, $btnMensaje, $btnSalir
$guiMultiLengu = GuiCreate($idiDict("tituloGUI"), 400,140)
GuiCtrlCreateLabel(StringFormat($idiDict("lblOrdeChulo"), @UserName), 20,20, 300, 20)
GUICtrlSetFont(-1, 12, 800)
$btnMensaje = GuiCtrlCreateButton($idiDict("btnMEnsaje"), 140,60, 120,30)
$btnSalir = GuiCtrlCreateButton($idiDict("btnSalir"), 320,100, 60,30)
GUICtrlSetFont(-1, -1, 800)
GUISetState()

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE, $btnSalir
			$IdiDict.RemoveAll()
			$IdiDict = 0
			Exit
		Case $btnMensaje
			MsgBox(64, $idiDict("tituMsgBox"), StringFormat($idiDict("textoMsgBox")))
	EndSwitch
WEnd
Este es el archivo de idiomas que he usado, hay que ponerlo, descomprimido, en la misma carpeta que el programa:
Lenguajes.zip
(512 Bytes) Descargado 198 veces
Es un .config que podría tener cualquier formato, pero siguiendo también la tendencia del foro he acabado usando un formato INI, pero sólo lo uso para crear el diccionario, no me importan en qué posición del INI están las cadenas y no me afecta (no es un error fatal al menos) que haya cadenas de más o de menos.

Este código de ejemplo aunque es totalmente funcional no mira muchos errores, por ejemplo que no exista el archivo de idiomas o que nos hayan pasado uno donde falte alguna cadena.
Una buena solución para esto es tener un idioma por defecto, que no se lea del archivo externo de idiomas externo, sino que esté en el mismo exe (instalado con un FileInstall, pero este archivo SOLO tendría un idioma) o se asigna a mano cada cadena en código, por ejemplo:
$IdiDict.Add("tituloGUI", "Estás viendo el GUI en español")

Después se reactualiza el diccionario con el idioma que elija el usuario. De esta manera si falta alguna cadena al menos saldrá la del idioma por defecto, y si no hay archivo de idioma podemos ignorar la selección de idioma y mostramos el lenguaje por defecto.
Para actualizar un valor ya asignado del diccionario no se hace con Add(), pues eso es para crear pares clave-valor nuevos. Si ya hemos asignado un idioma por defecto el bucle para reasignar valores se haría así:

Código: Seleccionar todo

$idiIni = IniReadSection($IdiomaPath, $Idioma)
For $i = 1 To $idiIni[0][0]
	$IdiDict.item($idiIni[$i][0]) = $idiIni[$i][1]
Next
Con este mecanismo si nos pasan un archivo de idiomas con cadenas de más o de menos no es problema, aunque en el INI variarán las posiciones las cadenas extra serán ignoradas, y las que usemos se encontrarán sin problema pues no las buscamos por posición, sino por nombre.
Las cadenas que falten saldrán en el idioma por defecto.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Avatar de Usuario
BasicOs
Site Admin
Mensajes: 2085
Registrado: 21 Nov 2006, 19:24
Ubicación: El Internet - (Canarias, España)
Contactar:

Re: Programa multilenguaje con diccionarios (tablas hash)

Mensaje por BasicOs »

Hola,
Felicidades por la propuesta.
Además aquí van otros enlaces con multiples lenguas: http://www.emesn.com/autoitforum/search ... d&sr=posts

Y las solución de Jscript OSLANG:
http://www.emesn.com/autoitforum/viewto ... les#p11934

Salu22:)
jamaro
Hacker del Foro
Mensajes: 253
Registrado: 03 Nov 2010, 23:04

Re: Programa multilenguaje con diccionarios (tablas hash)

Mensaje por jamaro »

Interesante propuesta. ¿Debemos entender que Windows Script esté instalado en prácticamente todos los ordenadores?

EDITO: Perdón, ya veo la respuesta en este hilo que precisamente inicié yo :-)

http://www.emesn.com/autoitforum/viewto ... 352#p10364

Saludos
Avatar de Usuario
Ximorro
Profesional del Autoit
Mensajes: 1500
Registrado: 10 Jul 2009, 12:35
Ubicación: Castellón, España

Re: Programa multilenguaje con diccionarios (tablas hash)

Mensaje por Ximorro »

Creo que será prácticamente imposible que no esté disponible. Me parece que los últimos SO lo llevan ya directamente.
En XP por ejemplo yo lo uso sin problemas, por ejemplo leí que el MSOffice lo instala, pero es que nosotros por ejemplo ni siquiera usamos MSOffice y aún así también está disponible el diccionario. No sé si lo ha instalado otro programa y algún Service Pack o ya venía con XP...

Creo que lo difícil es no encontrarlo.

Lo que sí ha hecho es cambiar de versión, no sé qué habrá cambiado pero este objeto se usa exactamente igual, y por lo que veo en la documentación no le han añadido nada nuevo.
"¿Y no será que en este mundo hay cada vez más gente y menos personas?". Mafalda (Quino)
Responder