Archivo de la etiqueta: win8

Adding multiple languages to a Windows Store app with Javascript and Angular

Leer este artículo en castellano aqui

Last thursday I could attend a debate organized by MSCoders Madrid user group, related with localization of apps in a web enfironment.

After the event I got interested in frontend localization with Javascript. As Karmacracy for Windows is a Javascript app, I decided to do some experimentation on localizing the user interface in the context of a Windows Store app, to be able to distribute it for other markets.

Detecting the system language

For a Windows Store app the first thing to do is to detect the sustem language. This can be archieved with the following piece of code:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

The culture is the language that is currently being used for the UI, in culture format. For example for Spanish of Spain would be es-ES, for US English would be en-US, and for British English would be en-GB. To be able to change this order and deploy our app, we must go to the control panel:

Captura de pantalla 2014-09-15 00.29.43

In this example we only need the language, not the culture, so we are going to get a substring of the culture getting en, es, de, etc.

Adding angular-translate

Angular-translate is a module that allows us to define key-value pairs for each language and perform the translation according to the configuration. For installing it, if we don’t use a package manager such as bower, we must download the last package from github and add it to our project.

Once installed, we must add it to the configuration of our app, in the section we define external modules (in this case the module is pascalprechtr.translate).

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finally, we configure the different languages by using the code we defined previously for getting the OS display language:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

     $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Also, in case the current language is not available, we set English by default

#Usage

For accessing our keys we don’t need any aditional configuration on our controllers, we just need to modify our views so they can access the localized information

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

If the language is set to English or other language not controlled, the result will be the following:

en

If the language is set to spanish, the result will be the following:

es

As it shows, is an easy way to localize our javascript apps for the Windows Store.

Recap and next steps

Angular-translate provides a simple way of localizing texts in our views and Windows provides the information we need for setting the current language of an app.

As an aditional step, we may try to localize winjs controls such as buttons, which work in a very different way. Angular-translate also supports loading the translations from a json files, an option that may be useful if we want to distribute those files for translation by 3rd parties.

Links

Anuncios

Agregando múltiples idiomas a una aplicación de Windows Store con Javascript y Angular

**Read this article in English here

El pasado jueves tuve la ocasión de asistir a una mesa redonda organizada por el grupo MSCoders relacionada con la localización de aplicaciones en entornos web.

Tras el evento, uno de los temas que más llamó mi atención fue la localización en la parte Javascript, y como tenía una aplicación ya en la Windows Store que usaba ese lenguaje, me pareció interesante intentar localizarla para poder ofrecerla en otros mercados.

Detectando el idioma del sistema

Para una aplicación Windows 8 el primer paso es detectar el idioma del sistema, y eso lo podemos hacer de la siguiente manera:

var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
var language = culture.substr(0, 2);

En este caso tomaremos la lista de lenguajes preferentes, y de esa lista obtendremos el primer elemento. Para poder cambiar el orden de los elementos y probar los diferentes lenguajes, podemos cambiarlo en el panel de control:

Captura de pantalla 2014-09-15 00.29.43

El resultado se muestra en formato cultura, es decir, español de España se mostraría como es-ES, e inglés de EEUU se mostraría como en-US. Para nuestro ejemplo inicial, solamente necesitamos el idioma, con lo cual hacemos un substring y obtenemos en o es respectivamente.

Agregando angular-translate

Angular-translate es un módulo de angular que nos permite definir de manera las claves y los valores para cada lenguaje, y realizar la traducción en función de la configuración. Para instalarlo, si no contamos con gestores de paquetes como bower, es tan sencillo como descargar el último paquete de github y agregarlo a nuestro proyecto.

Una vez instalado, tendremos que agregarlo a la configuración de nuestra app, en el apartado en el que definimos módulos externos en este caso pascalprecht.translate:

var karmacracyApp = angular.module('karmacracyApp', [
    'ngRoute',
    'karmacracyControllers',
    'pascalprecht.translate'
]);

Finalmente, configuramos los diferentes idiomas usando el código que hemos visto anteriormente para seleccionar un idioma acorde con el sistema operativo:

karmacracyApp.config(['$translateProvider', function ($translateProvider) {
    $translateProvider.translations('en', {
        'LOGIN': 'Log in',
        'LOGIN_USERNAME': 'User name',
        'LOGIN_PASSWORD': 'Password'
    });

    $translateProvider.translations('es', {
        'LOGIN': 'Inicia sesión',
        'LOGIN_USERNAME': 'Nombre de usuario',
        'LOGIN_PASSWORD': 'Contraseña'
    });

    var culture = Windows.System.UserProfile.GlobalizationPreferences.languages[0];
    var language = culture.substr(0, 2);

    $translateProvider.preferredLanguage(language).fallbackLanguage('en');
}]);

Además, en caso de que el sistema tenga un idioma no controlado, estableceremos el inglés por defecto.

Uso

Para acceder a nuestras claves no necesitamos realizar ninguna configuración adicional en nuestros controladores, solamente necesitamos modificar nuestras vistas para que accedan a la información localizada:

<span class="loginMessage">{{ 'LOGIN' | translate }}</span>

En caso de que tengamos el idioma establecido a inglés (o a cualquier idioma no controlado), se mostrará el siguiente resultado:

en

En caso de que el idioma esté establecido a español, el resultado será diferente:

es

Como se ve, es una manera sencilla de poder localizar nuestras aplicaciones en javsacript para Windows Store

Conclusiones y pasos adicionales

Angular-translate proporciona una manera sencilla de localizar textos en nuestras vistas, por otra parte, Windows proporciona, a través de su API, la información que necesitamos para saber en qué idioma mostrar una aplicación.

Un paso adicional sería localizar controles winjs como los botones, que funcionan de manera diferente. Por otra parte se podría sacar un fichero de traducciones fuera de la configuración en formato json, útil si queremos distribuir esos ficheros para su procesamiento.

Enlaces adicionales

Preparando el examen 70-484

El pasado 30 de mayo aprobé el examen 70-484 de desarrollo de aplicaciones para Windows 8 con C#, lo que me acerca un paso más al MCPD en desarrollo de apps para la plataforma, y es a su vez una excusa y un reto para aprender más de la misma.

Al comentarlo por Twitter, algunos desarrolladores me preguntaron qué recursos había usado, y aquí va un pequeño resumen.

Sigue leyendo

Viernes 22: Desarrollo para Windows Phone y Windows 8 en la Universidad de Salamanca

El próximo viernes 22 a partir de las 5 PM estaré en la Facultad de Ciencias de la Universidad de Salamanca con los chicos de @DotNetUSAL, hablando de desarrollo para aplicaciones Windows 8 y Windows Phone.

BZXb95zCcAI1UHD

Durante un buen tramo de la tarde estaremos viendo qué ventajas nos da la plataforma Windows Phone y Windows 8, y cómo aprovechar esas ventajas para que nuestras aplicaciones destaquen por encima del resto.

Las herramientas de desarrollo están disponibles en los siguientes enlaces:

Para hacer la charla más dinámica, usaremos VS Anywhere para que todos los asistentes que lo deseen puedan contribuir a la misma, y seguir las demos desde su ordenador. Si quieres aprender de una manera diferente, crea tu cuenta en http://vsanywhere.com y descarga el plugin:

VS Anywhere requiere Visual Studio Professional o superior, que puedes conseguir gratuitamente a través del programa Dreamspark. Si no lo tienes pregunta a los chicos de @DotNetUSAL cómo conseguirlo.

Por otra parte, tienes versiones de prueba de 90 días de cualquiera de las versiones de Visual Studio 2013 en este enlace: http://www.visualstudio.com/downloads/download-visual-studio-vs

Nos vemos en Salamanca!

Microsoft Tech Days 2012

El pasado 22 de Noviembre, un año más, Microsoft España nos presentaba a todos los miembros de las diferentes comunidades (MSP, Technical Rangers, MVP, MAP, Dotnetclubs, grupos de usuarios y todo aquel que quisiera venir) las novedades en cuanto a Visual Studio, Azure, Windows 8 y Windows Phone, todo bajo la dirección de Jose Bonnin y aderezado con un poco de humor y magia para concluir la velada.

El evento con una keynote donde a golpe de datos y estadísticas Jose Bonnin nos contaba cómo la visión de la empresa ha cambiado los últimos tiempos, y que ya es solamente el recuerdo de aquel gigante gris de los noventa, por cambiar han cambiado hasta el logo! (Yo me siento un poco nostálgico por aquél clásico en negrita y cursiva). Esta presentación pasó del clásico powerpoint a un HTML5+CSS3+Javascript+Video…

Tras la keynote nos dividimos en dos grupos. En mi caso me quedé en las charlas de desarrollo, aunque había un track de IT y un par de laboratorios de desarrollo de aplicaciones.

La primera charla que me sorprendió gratamente nos enseñó cómo portar aplicaciones desarrolladas para Windows Phone 7.5 a Windows Phone 8 y finalmente Windows 8, reutilizando la mayor cantidad de código disponible. Para ello tenían una aplicación funcionando, desarrollada mediante el el patrón MVVM (Model-View-ViewModel), y la fueron adaptando a las diferentes plataformas:

  • Convirtieron la aplicación a Windows Phone 8 y adaptaron el live tile a los nuevos formatos.
  • Crearon una Portable Library para evitar repetir código entre estas plataformas. Este tipo proyecto además, garantizaba que el código fuera compatible con todas ellas.
  • Crearon una versión para Windows 8, reutilizando los modelos y los view Models. En Windows 8 había un problema, que todas las API de acceso a disco/red/etc son asíncronas, con lo cual había que cambiar el proyecto de la Portable Library para permitir este tipo de interacción sin perder la compatibilidad con otras plataformas.
  • Finalmente, mediante Azure, crearon un servicio para almacenar los datos generados por las aplicaciones, y poder acceder a ellos desde cualquier plataforma.

Una charla muy dinámica e interesante, que nos fue llevando paso a paso por cada una de las etapas de la migración.

Tras esta, una sesión sobre las novedades que trae Visual Studio 2012 y Team Foundation como plataforma ALM (Application Lifecycle Management o gestión del ciclo de vida del producto). Entre las novedades que comentaron me parecieron destacables:

  • Mejoras en Intellitrace para poder reproducir fallos incluso en producción.
  • Métricas de código y análisis estático del mismo, poder saber qué código está cubierto por tests, medir la complejidad ciclomática…
  • Soporte para tests unitarios con C++, así como para frameworks de terceros como nUnit o xUnit.
  • Coded UI, la manera de generar tests de interfaz, con soporte para aplicaciones Web.

La última charla altamente recomendable estuvo protagonizada por nuestro “Scott Hanselman” vasco, David Salgado. Bajo el nombre de “Orgullo Backend”, nos comentó las novedades de Azure, la facilidad de desplegar máquinas virtuales con linux, así como desplegar sitios web vía git, que si recordamos, no hace demasiado tiempo los despliegues se realizaban a mano generando un paquete con Visual Studio y subiéndolos mediante el portal de Azure, cómo ha cambiado todo… Además hablamos de SignalR que nos permite establecer una comunicación en tiempo real entre clientes y servidor, diseñando un pequeño sistema de chat en tiempo record (y cómo no, colgándolo en su blog horas más tarde).

Este evento lo cerró el Mago More con un poco de Magia 2.0 y algo de humor, que no debería faltar nunca.

Tras el evento, el Community Day, con algunas horas para ver a viejos amigos y conocer a gente que viene, que la familia de las comunidades Microsoft se hace más grande cada año.

Las charlas se grabaron y deberían estar disponibles pronto.

Datos locales en aplicaciones para Windows Store: Serialización de objetos

En un artículo anterior comentaba una de las posibilidades de almacenamiento de datos en aplicaciones Metro, los diccionarios clave-valor. Esto permitía, recordemos almacenar datos simples de una manera fácil y sencilla, aunque en ocasiones, querremos almacenar datos un poco más complejos. En este artículo se verá cómo almacenar objetos complejos sin tener que recurrir a una base de datos.

Pese a que la API de WinRT incluye todos los componentes necesarios para guardar los datos, hay bibliotecas de clases que nos facilitan mucho la vida. Concretamente esta, Generic Object Storage Helper for WinRT nos permite almacenar objetos y obtenerlos con pocas líneas de código.

Clase a guardar

Para este ejemplo, la clase que almacenaremos será una clase Person. Es requisito que las clases que se almacenen sean serializables, aunque no es necesario que incluyan el atributo. Existen limitaciones, claro, ya que por ejemplo, una ObservableCollection no se puede serializar, una imagen o un objeto de tipo URI tampoco. Además, tiene una ventaja muy interesante, y es que se pueden guardar listas con la misma facilidad, como se verá en el ejemplo.

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string PictureURL { get; set; }
        public Person Mother { get; set; }
        public Person Father { get; set; }
    }

Una vez obtenido el componente, se puede agregar el componente WinRtUtility.dll a la solución y ya se puede emplear.

Eligiendo el tipo de guardado y almacenando los datos

Podemos guardar los datos en tres espacios diferentes:

  • Local: Los datos se almacenan en el espacio de la aplicación en el dispositivo. Se borran del dispositivo cuando se elimina la aplicación.
  • Roaming: Los datos se almacenan en el espacio del usuario, de esta manera, si se accedes a la app desde otro ordenador donde esté iniciada la sesión con su cuenta Microsoft, se podrán obtener estos mismos datos.
  • Temp: Almacenamiento temporal y volátil, datos que podamos desechar.

Para almacenar los datos, solamente son necesarias las dos líneas siguientes:

var objectStorageHelper = new ObjectStorageHelper&lt;List&gt;(StorageType.Local);
objectStorageHelper.SaveAsync(personObject);

En la primera línea de código se establece el tipo de objeto a guardar así como el espacio en que se hará el guardado. En la segunda es en la que se realiza en guardado del objeto, de manera asíncrona siguiendo con los patrones de WinRT.

Estas líneas se pueden situar en el método OnSuspending, convenientemente situado para que su ejecución sea asíncrona, y situado en el fichero App.xaml.cs:

        private async void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Save application state and stop any background activity
            var objectStorageHelper = new ObjectStorageHelper&lt;List&gt;(StorageType.Local);
            await objectStorageHelper.SaveAsync(Persons);
            deferral.Complete();
        }

Carga de los datos

La carga de los datos es tan sencilla como el guardado, ya que se emplean dos líneas muy similares a las vistas anteriormente:

var objectStorageHelper = new ObjectStorageHelper&lt;List&gt;(StorageType.Local);
Persons = await objectStorageHelper.LoadAsync();

Estas líneas se pueden situar en el método OnLoad, una vez más, modificado para que se ejecute de manera asíncrona:

        protected async override void OnLaunched(LaunchActivatedEventArgs args)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                if (args.PreviousExecutionState != ApplicationExecutionState.Suspended)
                {
                    var objectStorageHelper = new ObjectStorageHelper&lt;List&gt;(StorageType.Local);
                    Persons = await objectStorageHelper.LoadAsync();
                }
                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            [...]
            // Ensure the current window is active
            Window.Current.Activate();
        }

Conclusiones

En este artículo se ha visto que existe otra opción para el almacenamiento de estructuras de datos más complejas utilizando poco más que de dos líneas de código situadas en los eventos de carga y guardado de la aplicación.

Más información:

BitNami Trac con Windows 8

BitNami es una plataforma que facilita el despliegue de aplicaciones como Trac, Redmine, WordPress, u otros en múltiples plataformas sin que sea necesario instalar o configurar servicios. Se integra perfectamente, aunque al actualizar Windows 8 pueden surgir incidencias, sobre todo relativas a los puertos.

En este caso, tras actualizar, el servicio dejó de funcionar. Tras comprobar que en efecto, el servicio estaba detenido (usando la consola de administración, accesible mediante services.msc) y otras cosas, descubrí que el error estaba relacionado con el puerto, ya que el servidor estaba escuchando en el puerto 80. Para comprobarlo, se puede usar el monitor de recursos (Ctrl+Shift+Esc, pestaña Network, apartado Listening Ports).

Por lo que he podido averiguar, tenía instalado Internet Information Services, o, al menos parte de él. La parte suficiente como para que me devolviera un bonito error 404. En este caso se plantean 2 soluciones.

Cambiar el puerto en IIS

Para ello se accede a la consola de administración de Internet Information Services (IIS desde el menú buscar), y en el apartado Default Web Site, seleccionar Bindings.

Si no se encuentra IIS, es posible que no esté instalado el administrador, para lo que habrá que acudir a Agregar o quitar programas, a la sección Agregar o quitar características de Windows y seleccionar Internet Information Services/Web Management Tools/IIS Management Console

En este menú, tan solo es necesario cambiar el puerto 80 a otro puerto, como 8080. Para que tenga efecto se tendrá que reiniciar el servidor usando la opción Restart situada debajo de Manage Website

Finalmente se podrá reiniciar apache abriendo una consola de comandos y escribiendo

net start tracApache

Cambiar el puerto en Apache

La otra alternativa pasa por editar la configuración de Apache y cambiar el puerto, editando el el fichero httpd.conf, situado en C:\Program Files\BitNami Track Stack\apache2\conf, y editar la siguiente línea, asignando otro puerto (por ejemplo el 8080):

Listen 80

Finalmente se podrá reiniciar apache abriendo una consola de comandos y escribiendo

net start tracApache

Conclusiones

Es importante cuando se trabaja con este tipo de soluciones, tener en cuenta los puertos, ya que nos pueden ahorrar algunos dolores de cabeza.

Más información: