Introducir y seleccionar lengua en modo consola

Iniciado por Meta, 25 Febrero 2019, 05:51 AM

0 Miembros y 1 Visitante están viendo este tema.

Meta

Hola:

Teniendo un menú hecho por defecto en español en este caso. (Cuando todo esté acabado tiene que estar en Inglés por defecto).

Quiero crear menús que sea capaz de elegir el idioma, en al cual hoy en día no hay problema porque está este traductor para escapar.

Mi idea para tener un orden de cada idioma a introducir, por ejemplo, español, inglés, alemán, francés, italiano y portugués.

En este ejemplo hay 6 lenguas. No se si la mejor opción es crear una carpeta de idiomas y ahí meto cada lengua en el cual es llamado.



Código de ejemplo para.
Código (csharp) [Seleccionar]
using System;

namespace Idiomas_consola_01_cs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Título de la ventana.
            Console.Title = "Menú - C# 2017";

            // Tamaño ventana consola.
            // X anchura.
            Console.WindowWidth = 80;

            // Y altura.
            Console.WindowHeight = 40;

            // Oculto el cursor.
            Console.CursorVisible = false;

            // Almacena la tecla pulsada en la variable.
            ConsoleKey teclaInicial;

            // Fondo verde.
            Console.BackgroundColor = ConsoleColor.Green;

            // Letras negras.
            Console.ForegroundColor = ConsoleColor.Black;

            do
            {
                // Limpiar pantalla.
                Console.Clear();

                // Formato numérico dd/MM/yyyy.
                Console.WriteLine(DateTime.Now.ToString("ddd dd MMM"));

                // Almacena en la variable una tecla pulsada.
                teclaInicial = Console.ReadKey(true).Key;

                // ¿Haz pulsado la tecla Enter?
                if (teclaInicial == ConsoleKey.Enter)
                {
                    // Sí. Se ejecuta esta función.
                    menuPrincipal();
                }
            } while (teclaInicial != ConsoleKey.Escape);
        }

        #region Menú Principal.
        public static void menuPrincipal()
        {

            // Contador de teclas y navegador.
            int opcion = 0;
            bool salir = false;
            // Capturar tecla para luego validar.
            ConsoleKey tecla;

            do
            {
                // Limpiar pantalla.
                Console.Clear();

                switch (opcion)
                {
                    case 0:
                        Console.SetCursorPosition(0, 0);
                        Console.Write("Language");
                        break;
                    case 1:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Opción 1.");
                        break;
                    case 2:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Opción 2.");
                        break;
                    case 3:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Opción 3.");
                        break;
                    case 4:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Opción 4.");
                        break;
                    case 5:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Opción 5.");
                        break;
                    case 6:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Opción 6.");
                        break;
                    case 7:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("Salir menú");
                        break;
                    default:
                        break;
                }

                // Fin de pintar el menú.
                //******************************************************************

                // Leer tecla ingresada por el usuario.
                tecla = Console.ReadKey(true).Key;

                // Validar el tipo de tecla.
                if (tecla == ConsoleKey.Enter)
                {
                    switch (opcion)
                    {
                        case 1:
                            // Instrucciones.
                            break;
                        case 2:
                            // Instrucciones.
                            break;
                        case 3:
                            // Instrucciones.
                            break;
                        case 4:
                            // Instrucciones.
                            break;
                        case 6:
                            // Instrucciones.
                            break;
                        case 7:
                            salir = true;
                            break;
                        default:
                            break;
                    }
                }

                if (tecla == ConsoleKey.DownArrow)
                {
                    opcion += 1; // Equivalente ++.
                }

                if (tecla == ConsoleKey.UpArrow)
                {
                    opcion -= 1; // --.
                }

                // Si está en la última opción, salta a la primera.
                if (opcion > 7)
                {
                    opcion = 0;
                }

                // Si está en la primera posición, salta a la última.
                if (opcion < 0)
                {
                    opcion = 7;
                }

                // Uso la tecla escape como salida.
            } while (salir == false);
        }
        #endregion
    }
}


En el menú Languaje, si pulsas Enter, tiene que verse en Inglés, todos los idiomas que vayamos incorporando. El usuario elige el idioma y se queda seleccionado.

¿Alguna idea?

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Serapis

#1
La manera más sencilla y rápida, sobretodos para cosas muy escuetas es usar un array.
Y la forma más sencilla al cargar el programa es leerlo de un ficherito de texto:
Debe quedar claro que podrías separar cada idioma de otro por una etiqueta del tipo:
<idioma>

Así lees el fichero de una tacada y haces un split por la cadena <idioma>, entonces todos los textos de un idioma quedan alojados en el array como una cadena...
Si el inglés ha de ser el idioma por defecto, sugiero que sea el primero de la lista, así se alojaría en el índice 0 del array, este podría ser la forma de componer el menú para inglés y español:
Citar<idioma> English
<menu>
File
....Open ...
....Save
....Save As ...
....Close
....-
....Recent Files:
........1
........2
........3
........4
........5
....Exit
<menu>
Edit
....Copy
....Paste
....Delete
....-
....Select All
....Invert Select
<menu>
Options
....Display ...
....Language
........0 English
........1 Spanish
<menu>
Help
....Manual ...
....About ...
<idioma> Español
<menu>
Fichero
....Abrir ...
....Guardar
....Salvar como ...
....Cerrar
....-
....Ficheros Recientes:
........1
........2
........3
........4
........5
....Salir
<menu>
Editar
....Copiar
....Pegar
....Borrar
....-
....Seleccionar todo
....Invertir Seleccion
<menu>
Optiones
....Display ...
....Idioma
........0 Inglés
........1 Español
<menu>
Ayuda
....Manual ...
....Creditos ...
<idioma> Deutsche

etc...

Como se puede apreciar, el texto se puede guardar fácilmente en un único fichero de texto, (no son menús infinitos), tampoco pasa nada si se guardan en un fichero distinto cada uno... observa como en las opcones al elegir idioma cada uno se asocia a un número, si al final fueran más de diez, será preferible prescindir de números y usar letras A,B,C,D, si fueran más de 26 idiomas, prescindir también de las letras. cada ítem de un menú lleva implícito un índice como ítem de una colección, siempre puede usarse dicho valor para elegir el fichero adecuado, aunque un único fichero conteniéndolos todos puede bastar, se carn todos al cargar el programa y se mantienen en memoria todo el tiempo hasta que el programa se cierra. Así evitas también toda la operatoria de abrir distintos ficheros de idioma cargarlos y tal, con posibilidades de fallos... si los menús fuerna a ser gigantescos (es decir no es un único menú de una ventana si no de todo un programa con sus diferentes ventanas, entonces sí es cuando conviene que cada uno esté en su propio fichero, en tales casos además suelen usarse una clase que aplica los cambios sobre un fichero de idioma. También suele usarse dlls por cada idioma que implementan una interfaz.

...pero vamos para tu caso y experimentar, es suficiente con un ficherito en texto que aloge todos.
Adicionalmente a la función de carga del fichero, debe haber otra función que desglose la cadena que recoge el menú completo de un idioma, y lo deposite en cada ítem del menú. Por lo tanto debe haber una correspondencia, entre ítems del menú y cada ítem del texto en el fichero.
Así a la entrada de la función haces nuevamente un split, que corta por cada <menu>, formando así un array, donde cada indice aloja un ítem del menú principal....
Así si se eligió español:
array string Menus = split(ReadAllFile, "<idioma>")
funcion DesglosarMenuIdioma(string Menu ) = Menus(1) // toma el menú español
   array string MenuTxt = Split(Menu, "<menu>")


...el menú princiapl 1, será pués: 'Editar', y de momento su contenido será éste:
CitarMenuTxt(1) = "Editar
....Copiar
....Pegar
....Borrar
....-
....Seleccionar todo
....Invertir Seleccion"

Nuevamente un split, ahora por cada línea, revela cada subítem de dicho menú...
La jerarquía se compone de "....", es decir con cada aparición de esos 4 puntitos, implica que son hijos del ítem padre. En general una función recursiva resuelve el caso, inclsuo sin los "<menu>", y acabas teniendo un árbol que luego recorres desde la raíz para asignarlo al menú. Nota que si la asignación la vas haciendo sobre la marcha (sin necesidad de guardar nada), no es preciso recrear siquiera un árbol, tan solo (mediante la recursión y splits), vas recorriendo la estructura subyacente del mismo modo que si fuera un árbol pero sin necesidad real de que debas tener, crear ni mantener un árbol...

p.d.: Nota que cosas como 'ficheros recientes' son independientes del idioma, ese contenido deberá rellenarse desde otra parte, seguramente desde algún ficherito que guarde la configuración del programa, eso se hace también al cargar el programa tras meter el idioma elegido.

El menú del idioma podría ubicar también un ítem para reflejar el elegido, tal que así:
Citar....Idioma
........Español
........-
........0 Inglés
........1 Español
Esto es, aparece el seleccionado, luego un separador y detrás la lista elegible.
Finalmente, cuando un usuario elija un idioma, asgúrate que si es el mismo que el ya cargado, debe ignorarse toda acción posterior. El idioma por defecto es el 0, y si el usuario decide "guardar opciones al salir ...", en el fichero de configuración se guardaría 1 (i por ejemplo el actual cargado es el español), y tras una nueva carga tomando el idioma elegido por el usuario, encontrará el 1, y cargará así el español.

Meta

Buen aporte, a leer, interpretar y actuar.

Muchas gracias por la ayuda. ;)
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#3
Visual Studio ya provee herramientas de localización de idioma mediante los archivos de recurso (resources.resx) embedidos en la aplicación, por lo tanto no hay necesidad de reinventar la rueda ni tampoco usar metodologías rudimentarias como pudiera ser un Array de cadenas de texto, aunque, y ya puestos, antes que usar un string con formato Xml y andarse con substrings y splits para obtener un Array de strings, lo cual resulta tedioso o engorroso de hacer, sería mucho más simple y conveniente declarar una variable de tipo XElement y ahí especificar el contenido del documento Xml, y entonces tratarlo como tal mediante las funcionalidades built-in de .NET Framework para el tratamiento de documentos Xml, y con ello aportar mayor estabilidad y simplificación al análisis de datos (o parsing) si lo comparásemos con la manipulación de un string con formato Xml al que hacerle un String.Split().
Dicho de otra forma, la propuesta sería más o menos lo mismo que te ha explicado el compañero @NEBIRE, pero enfocado al uso del tipo XElement en lugar de String, y sin la carga de archivos locales (eso ya sería como prefieras hacerlo).

Un ejemplo muy, muy básico para declarar una cadena de texto Xml con cadenas de texto para distintos idiomas, obtener el idioma por defecto del thread en ejecución (esto se haría al inicío de tu aplicación), establecer un nuevo idioma, y escribir las cadenas de texto del idioma actual establecido:

Código (csharp) [Seleccionar]
using System;
using System.Globalization;
using System.Threading;
using System.Xml.Linq;

namespace ConsoleApp1 {

   class Program {

       private static readonly XElement languages =
           XElement.Parse(@"<languages>
                                <en-US>
                                    <Options>
                                        <Option1>Option 1</Option1>
                                        <Option2>Option 2</Option2>
                                        <Option3>Option 3</Option3>
                                    </Options>
                                    <ExitMessage>Press any key to exit...</ExitMessage>
                                </en-US>
                                <es-ES>
                                    <Options>
                                        <Option1>Opción 1</Option1>
                                        <Option2>Opción 2</Option2>
                                        <Option3>Opción 3</Option3>
                                    </Options>
                                    <ExitMessage>Pulse cualquier tecla para salir...</ExitMessage>
                                </es-ES>
                            </languages>");

       static void Main(string[] args) {      

           // Obtener configuración de idioma actual.
           CultureInfo currentCi = Thread.CurrentThread.CurrentUICulture;
           XElement currenLangXml = languages.Element(currentCi.Name);
           // Si no se encuentra un elemento Xml para el idioma actual, establecer idioma favorito por defecto (Inglés).
           if (currenLangXml == null) {
               currenLangXml = languages.Element("en-US");
           }

           // --------------------------------------------------------------

           // Establecer nueva configuración de idioma.
           CultureInfo newCi = new CultureInfo("es-ES");
           XElement newLangXml = languages.Element(newCi.Name);

           // --------------------------------------------------------------

           // Obtener los campos de opciones del idioma actual establecido.
           string option1 = newLangXml.Element("Options").Element("Option1").Value;
           string option2 = newLangXml.Element("Options").Element("Option2").Value;
           string option3 = newLangXml.Element("Options").Element("Option3").Value;
           string exitMsg = newLangXml.Element("ExitMessage").Value;

           // --------------------------------------------------------------

           // Escribir las opciones en el idioma actual establecido.
           Console.WriteLine(option1);
           Console.WriteLine(option2);
           Console.WriteLine(option3);
           Console.WriteLine();
           Console.WriteLine(exitMsg);

           Console.ReadKey(intercept: true);
       }
   }
}


Logicamente puedes escribir los nodos Xml que desees con cuantos elementos desees y elementos hijos cada uno.

Por cierto, cabría destacar que una de las ventajas o comodidades de VB.NET es simplificar (por no decir perfeccionar) al máximo el tratamiento de Xml en tiempo de diseño gracias a la inclusión directa de código Xml mediante la funcionalidad LINQ to XML incluyendo la declaración de literales Xml, por lo que el equivalente al código de arriba en C# sería más reducido e "interactivo", quedando así:

Código (vbnet) [Seleccionar]
Imports System
Imports System.Globalization
Imports System.Linq
Imports System.Threading
Imports System.Xml.Linq

Public Module Module1

   Private ReadOnly languages As XElement =
       <languages>
           <en-US>
               <Options>
                   <Option1>Option 1</Option1>
                   <Option2>Option 2</Option2>
                   <Option3>Option 3</Option3>
               </Options>
               <ExitMessage>Press any key to exit...</ExitMessage>
           </en-US>
           <es-ES>
               <Options>
                   <Option1>Opción 1</Option1>
                   <Option2>Opción 2</Option2>
                   <Option3>Opción 3</Option3>
               </Options>
               <ExitMessage>Pulse cualquier tecla para salir...</ExitMessage>
           </es-ES>
       </languages>

   Public Sub Main()

       ' Obtener configuración de idioma actual.
       Dim currentCi As CultureInfo = Thread.CurrentThread.CurrentUICulture
       Dim currenLangXml As XElement = languages.Element(currentCi.Name)
       ' Si no se encuentra un elemento Xml para el idioma actual, establecer idioma favorito por defecto (Inglés).
       If currenLangXml Is Nothing Then
           currenLangXml = languages.<en-US>.Single()
       End If

       ' --------------------------------------------------------------

       ' Establecer nueva configuración de idioma.
       Dim newCi As New CultureInfo("es-ES")
       Dim newLangXml As XElement = languages.Element(newCi.Name)

       ' --------------------------------------------------------------

       ' Obtener los campos de opciones del idioma actual establecido.
       Dim option1 As String = newLangXml.<Options>.<Option1>.Value
       Dim option2 As String = newLangXml.<Options>.<Option2>.Value
       Dim option3 As String = newLangXml.<Options>.<Option3>.Value
       Dim exitMsg As String = newLangXml.<ExitMessage>.Value

       ' --------------------------------------------------------------

       ' Escribir las opciones en el idioma actual establecido.
       Console.WriteLine(option1)
       Console.WriteLine(option2)
       Console.WriteLine(option3)
       Console.WriteLine()
       Console.WriteLine(exitMsg)

       Console.ReadKey(intercept:=True)
   End Sub

End Module







Pero esta solución del Xml solo sería si lo quieres hacer de forma muy rudimentaria, por que como ya he mencionado antes Visual Studio ya provee herramientas de localización de idioma, y eso es lo que deberías usar si buscas una solución sofisticada, no rudimentaria como el uso de un Xml / String.

Aquí lo tienes todo explicado de la A a la Z:

Si quieres un resumen o mejor dicho un tutorial en C#, lee esto:

Y por cierto, también puedes utilizar la extensión Jollans Multi-Language for Visual Studio para Visual Studio. Es una joya que ahorra mucho tiempo y ayuda a mantener un seguimiento de los idiomas, eso si, es un producto de pago (para quien no sepa encontrar la respectiva "medicina"). Supongo que habrá extensiones gratuitas igualmente especializadas en la localización de idiomas de aplicaciones .NET, pero tampoco lo voy a buscar yo todo por ti...

Saludos.








Meta

Buenas:

Buen trabajo, esa técnica no lo sabía. Si, se que viene lo del idioma ya preparao, ni siquiera usar XML debo hacerlo, solo desde la edad de pìedra. Hay gente que lo hacen desde un archivo txt también se hace, en mi caso, lo quiero hacer solo a códigos.

Saludos y buen trabajo. ;)
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/