Multi-linguagem no Angular – exemplos

Pode-se utilizar a biblioteca angular angular-translate para trabalhar com traduções de páginas feitas utilizando angular.

Bower: “angular-translate”: “2.13.0”

Dentro de uma arquitetura de sistema, sabemos que a responsabilidade de exibir as mensagens aos usuários é da tela, e nada mais justo que utilizar uma ferramenta do angular para resolver questões de multi-linguagem.

O principal argumento para responsabilizar a tela pela exibição das mensagens é porque na tela é que se estuda a melhor maneira de se apresentar uma informação, e a mesma informação pode ser exibida de maneiras diferentes em telas diferentes, por exemplo uma informação sendo exibida para celular e para computador.

No código abaixo adicionamos a referência do serviço (pascalprecht.translate) no módulo app e utilizamos a implementação config do angular para que essa configuração seja a primeira executada ao iniciar o sistema. O config do Angular não aceita a injeção de serviços, então para resolver isso usamos um provider ($translateProvider). No config utilizações 2 funções, sendo a primeira translations para informar as traduções e a  preferredLanguage para informar a linguagem padrão.

Segue a implementação em Javascript do código escrito com Angular 1, abaixo:


    var app = angular.module('app', ['pascalprecht.translate']);

    app.config(function ($translateProvider) {

        $translateProvider.translations('pt-br', {
            MENU_TITULO: 'Site',
            MENU_CAPA: 'Página inicial',
            MENU_SOBRE: 'Sobre',
            MENU_CONTATO: 'Contato'
        });

        $translateProvider.translations('en', {
            MENU_TITULO: 'Site',
            MENU_CAPA: 'Home',
            MENU_SOBRE: 'About',
            MENU_CONTATO: 'Contact'
        });

        $translateProvider.preferredLanguage('pt-br');

Segue a implementação em HTML de como usar as traduções, abaixo:

<ul class="nav navbar-nav">
	<li><a href="#">{{ 'MENU_TITULO' | translate }}</a></li>
	<li><a href="#">{{ 'MENU_CAPA' | translate }}</a></li>
	<li><a href="#">{{ 'MENU_SOBRE' | translate }}</a></li>
	<li><a href="#">{{ 'MENU_CONTATO' | translate }}</a></li>
</ul>

Para não complexificar a explicação, vou colocar meu projeto de teste em anexo.

Segue o linque do exemplo para download (zip): http://www.4shared.com/zip/YH5kRblLce/AngularTranslatePlayground.html?

Nesse projeto tenho 2 implementações.
Sendo a primeira e mais simples a que segue o exemplo acima.

E a mais complexa é utilizando cookies para salvar a linguagem selecionada e utilizando API para consultar as traduções por linguagem.
Optei por transitar na API somente 1 linguagem de cada vez por uma questão de desempenho e por salvar a linguagem em cookie pois acredito ser uma boa solução neste caso.

Javascript: Exemplo de como adicionar (push) e remover (splice) itens de um Array.

Ao trabalhar com Arrays em Javascript é muito comum ter a necessidade de Adicionar e Remover itens do Array.
Para Adicionar um item deve-se utilizar a função PUSH, onde deve-se utilizar a seguinte sintaxe: arr_nomes.push(valor) onde o arr_nomes é o array e o valor é o item a ser adicionado.
Para Remover um item deve-se utilizar a função SPLICE, onde deve-se utilizar a seguinte sintaxe: arr_nomes.splice(posicao, 1) onde arr_nomes é o array, a posição é o índice a ser removido e o numero 1 é a quantidade de itens a serem excluídos.

Veja o exemplo completo abaixo:

    <div class="container">

        <h2>Adicionar:</h2>
        <p><input type="text" id="addNome" class="form-control" placeholder="Preencher o Nome" /></p>
        <p><button type="button" class="btn btn-default" onclick="Add($('#addNome').val()); $('#addNome').val('');">Adicionar</button></p>

        <h2>Remover:</h2>
        <p><input id="removeNome" type="number" class="form-control" placeholder="Preencher o Índice" /></p>
        <p><button type="button" class="btn btn-default" onclick="Remove($('#removeNome').val()); $('#removeNome').val('');">Remover</button></p>

        <h2>Resultado:</h2>
        <div id="RETORNO" class="row" style="padding: 10px 12px;"></div>
    </div>
        var arr_nomes = ["José", "Roberto", "Maria", "Silva"];
        document.getElementById("RETORNO").innerHTML = arr_nomes;

        function Add(valor) {
            arr_nomes.push(valor);
            document.getElementById("RETORNO").innerHTML = arr_nomes;
        }

        function Remove(posicao) {
            arr_nomes.splice(posicao, 1);
            document.getElementById("RETORNO").innerHTML = arr_nomes;
        }

Angular JS – Documentação para Estudo

  • Como iniciar uma aplicação Angular
    • ng-app
    • script do AngularJS
  • Diretivas nativas do Angular
    • ng-app
    • ng-show
    • ng-hide
    • ng-if
    • ng-repeat
    • ng-controller
    • ng-model
    • ng-bind
  • Como escrever variáveis nos templates
    • {{ message }}
  • Controllers
    • app.controller(‘MainCtrl’, function($scope) {
             $scope.message = ‘Message’;
      });
  • $scope e $rootScope
  • $scope.watch

Material de Estudo AngularJS – 01

  • ANGULARJS EVENTS SYSTEM
    • $scope.
    • $on.
    • $emit.
    • $broadcast
  • BUILT-IN SERVICES
    •  $http,
    • $filter,
    • $log, …
  • FILTROS
    • “AngularJS” | uppercase
  •  ANGULAR.CONSTANT E ANGULAR.VALUE
  • DEPENDENCY INJECTION & PROMISES

Material de Estudo AngularJS – 02

  • Como criar serviços
  • HTTP Interceptors
  • angular.run & angular.config
  • Como criar diretivas
  • data-ng-app
  • $q
  • Como criar filtros
  • services vs factories

Material de Estudo AngularJS – 03

.Net Mvc C# – Cadastro de Pedido com Itens de Produto ( múltiplos registros )

Para conseguir postar um cadastro com múltiplos registros segui este tutorial:
http://dotnetawesome.blogspot.com.br/2013/09/how-to-update-multiple-row-at-once.html

Conversei com o Cleyton Ferrari e ele sugeriu utilizar AngularJs ou knockoutJS. Eles tornam o serviço mais simples nas interações com os elementos/componentes HTML, principalmente pra ir adicionando itens em uma lista. O Cleyton me indicou este código fonte dele: https://github.com/cleytonferrari/SPAAngularJS?files=1

no meu primeiro teste utilizei a model:

namespace MultiplosIntes.Models
{
    public class Pedido
    {
        [Required(ErrorMessage = "Favor preecher o Número do Pedido!", AllowEmptyStrings = false)]
        public int NumeroPedido { get; set; }
        public IList Itens { get; set; }
    }

    public class ItensPedido
    {
        public ItensPedido()
        {
            this.Produto = "";
            this.Quantidade = 0;
            this.Valor = 0;
        }

        [Required(ErrorMessage = "Favor preecher o Produto!", AllowEmptyStrings = false)]
        public string Produto { get; set; }
        [Required(ErrorMessage = "Favor preecher a Quantidade!", AllowEmptyStrings = false)]
        public int Quantidade { get; set; }
        [Required(ErrorMessage = "Favor preecher o Valor!", AllowEmptyStrings = false)]
        public decimal Valor { get; set; }
    }

}

Controller:

namespace MultiplosIntes.Controllers
{
    public class PedidoController : Controller
    {        
        public ActionResult Cadastrar()
        {
            Pedido pedido = new Pedido(); 
            pedido.Itens = new List();
            pedido.Itens.Add(new ItensPedido { Produto = "", Quantidade = 0, Valor = 0 });

            return View(pedido);
        }

        [HttpPost]
        public ActionResult Cadastrar(Pedido model)
        {
            var teste = model;

            return View(model);
        }
    }
}

View:

@model MultiplosIntes.Models.Pedido
@{
    ViewBag.Title = "Cadastrar";
}

<h2>Cadastrar</h2>

@using (Html.BeginForm())
{
    <table id="dataTable">
        <tr>
            <td>Número</td>
            <td>@Html.TextBoxFor(a=&gt;a.NumeroPedido)</td>
            <td></td>
        </tr>        
        <tr>
            <td>Produto</td>
            <td>Quantidade</td>
            <td>Valor</td>
        </tr>
        @if (Model.Itens != null &amp;&amp; Model.Itens.Count &gt; 0)
        {
            int j = 0;
            foreach (var i in Model.Itens)
            {
                <tr style="border:1px solid black;">
                    <td>@Html.TextBoxFor(a=&gt;a.Itens[j].Produto) @Html.ValidationMessageFor(a=&gt;a.Itens[j].Produto)</td>
                    <td>@Html.TextBoxFor(a=&gt;a.Itens[j].Quantidade) @Html.ValidationMessageFor(a=&gt;a.Itens[j].Quantidade)</td>
                    <td>@Html.TextBoxFor(a=&gt;a.Itens[j].Valor) @Html.ValidationMessageFor(a=&gt;a.Itens[j].Valor)</td>
                    <td>
                        @if (j &gt; 0)
                        {
                            <a href="#" class="remove">Remove</a>
                        }
                    </td>
                </tr>
                j++;
            }
        }
        
        <tr>
            <td colspan="4"></td>
        </tr>
        <tr>
            <td colspan="4"></td>
        </tr>
        <tr>
            <td colspan="4"></td>
        </tr>
    </table>
}

.Net Mvc C# – Trabalhando com Json com chamadas Ajax ($.getJSON e $.ajax)

Para trabalhar com Chamadas em Ajax e Json se faz necessário ter adicionado uma biblioteca Jquery.

Usando o Jquery você pode usar tanto a chamada $.getJSON quanto $.ajax, sendo que a primeira é um “resumo” da segunda.

Veja o Exemplo com $.getJSON :

function ConsultarStatusWs() {     
            $.getJSON("../ConsumoWS/JsonStatusWs", null, function (data) {   
                $("#Resultado").html("");
                $("#Resultado").append("<p>Transacoes=" + data.Result.Transacoes + "<br>Consumidas=" + data.Result.Consumidas + "<br>Saldo=" + data.Result.Saldo + "<br></p>");
            });
        }

Para que este exemplo funcione inicializar a função “ConsultarStatusWs()” e ter uma div “div id=”Resultado”/div”, alem é claro do de um include do jquery: “script src=”~/Scripts/jquery-2.0.3.js””

Um exemplo que possui um resultado exatamente igual ao anterior é com o uso do $.ajax:

function ConsultarStatusWsAjax() {
            $.ajax({
                dataType: "json",
                url: "../ConsumoWS/JsonStatusWs",
                success: function (data) {
                    $("#Resultado").html("");
                    $("#Resultado").append("<p>Transacoes=" + data.Result.Transacoes + "<br>Consumidas=" + data.Result.Consumidas + "<br>Saldo=" + data.Result.Saldo + "<br></p>");
                }
            });

Agora veja o Código do Controller ConsumoWS:

namespace STI.Associados.PortalWeb.Controllers
{
    public class ConsumoWSController : STIControllerBase
    {
        private IConsumoWsApp _consumoWsApp;

        public ConsumoWSController()
        {
            this._consumoWsApp = StructureMap.ObjectFactory.GetInstance<IConsumoWsApp>();
        }
        
        public ActionResult Index()
        {

            return PartialView("Index");
        }

        public JsonResult JsonListaConsumoPorMes()
        {
            IList<ConsumoWsDTO> consumo = this._consumoWsApp.GetWSTransacoesTotalisadasPorMes();
            return this.Json(new { Result = consumo }, JsonRequestBehavior.AllowGet);
        }

        public JsonResult JsonStatusWs()
        {
            StatusDTO status = this._consumoWsApp.GetWSStatus();
            return this.Json(new { Result = status }, JsonRequestBehavior.AllowGet);
        }
    }
}

A Action JsonStatusWs retorna o seguinte json:

{"Result":{"Transacoes":1000000,"Consumidas":862,"Saldo":999138}}

E a Action JsonListaConsumoPorMes retorna o seguinte json:

{"Result":[{"Mes":"2","Ano":"2015","Total":190},{"Mes":"3","Ano":"2015","Total":467},{"Mes":"4","Ano":"2015","Total":209}]}

Algumas observações importantes:
1º É interessante sempre utilizar o tipo de result da action “JsonResult”, para que você tenha certeza que essa action retornará somente um código JSON.
2º No return tem o código JsonRequestBehavior.AllowGet que é necessário para que a action receba requisições de qualquer lugar. Sem esse comando é comum encontrar o erro: ” This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet. “.

Veja no Exemplo abaixo como tratar o caso da lista de resultados.
Exemplo:

function ConsultarConsumoWs() {
            $("#Resultado").fadeOut();
            $.getJSON("../ConsumoWS/JsonListaConsumoPorMes", null, function (data) {
                $("#Resultado").fadeIn(); $("#Resultado").html("");
                $.each(data.Result, function (index, valor) {                   
                    $("#Resultado").append("<p>Consumo em " + valor.Mes + "/" + valor.Ano + ": " + valor.Total + " </p>");
                });
            });
        }

Ferramentas para Equipes de Desenvolvimento

  • IDE de desenvolvimento
    • VS2013, VS2012 e VS2010
  • Produtividade
    • ReSharper
    • Code Compare
    • ReShaper (R#)
  • Arquitetura
    • Enterprise Architect
    • Visio
  • IDE de Banco de Dados
    • Sql Server Management Studio
    • DatabaseNet4
  • Banco de Dados
    • NHibernate
    • Entity Framework
    • NHibernate Profile
    • PL/SQL
    • Glimpse
    • ErWin – Modelagem
    • RedGate ToolBelt – Intellisense para o SQL Management Studio
  • Editor de Texto
    • PSPad e Notepad++
  • Editor de Imagens
    • Paint.NET
  • Projetos
    • Microsoft Project
    • Gantter
    • Bug track – FogBuz
  • Cobertura de testes
    • dotCover
    • MSTest (integrado com R#)
    • NCRUNCH
  • Continuous Integration Server
    • TFS e Team City
    • AppVeyor e WebDeploy
    • Octopus Deploy
  • Subversion SVM
    • Tortoise
    • AnkhSVN
    • Kiln + Mercurial + TortoiseHG
  • Sniffing e simulador de requests
    • Fiddler

E você, quais ferramentas usa?

C# – Sobrecarga de Métodos (override)

O Override diferente do Overload, necessita o uso de herança. O método é declarado na classe base como Abstract ou Virtual. O Método então é sobre-escrito na classe descendente definindo um comportamento diferente nas classes descendentes (no overload é sobre a classe base). Nessa estrutura não se pode variar os tipos e números de parâmetros. A declaração do método sobre-escrito deve ser idêntica ao que for escrito na classe base.

Veja o Exemplo:


    public abstract class Arquivo
    {
        public string Nome;
        public int Tamanho;
        public abstract void Abrir();

    }

    public class Musica : Arquivo
    {
        // os atributos são herdados da classe base.
        public override void Abrir ()
        {
            Console.WriteLine("Tocando música: "+Nome);
        }
    }

    public class DocumentoWord : Arquivo
    {
        public override void Abrir()
        {
            Console.WriteLine("Mostrando documento word: " + Nome);
        }
    }

    public class Imagem : Arquivo
    {
        public override void Abrir()
        {
            Console.WriteLine("Mostrando imagem: " + Nome);
        }
    }

    public class Txt : Arquivo
    {
        public override void Abrir()
        {
            Console.WriteLine("Mostrando texto: " + Nome);
        }
    }

Na trecho public abstract class Arquivo é criado a Classe Base. E as outras classes herdam dela, como no exemplo o trecho public class Musica : Arquivo onde a na classe Música não se faz necessário colocar os atributos (eles herdam da classe base Arquivo) e apenas se sobre-escreve o comportamento do método Abrir usando o public override void Abrir().

public class Windows
    {
        private List<Arquivo> _arquivos;

        public Windows()
        {
            this._arquivos = new List<Arquivo>();
        }

        public void Add(Arquivo arquivo)
        {
            this._arquivos.Add(arquivo);
        }

        public void Abrir(Arquivo arquivo)
        {
            arquivo.Abrir();
        }

        public void AbrirTodos()
        {
            foreach (Arquivo arquivo in _arquivos)
            {
                arquivo.Abrir();
            }
        }

    }

Note no trecho arquivo.Abrir(); que em nenhum momento é informado ao método Abrir o tipo de dado que ele deve abrir. Em tempo de execução é que o Abstract vai tomar a forma da classe sobrescrita e vai executar o arquivo da forma correta. Por isso motivo é que o Método deve ser idêntico a classe Base.

class Program
    {
        static void Main(string[] args)
        {
            Arquivo mp3 = new Musica() { Nome = "Ramones - Rock n Roll High School" };
            Arquivo doc = new DocumentoWord() { Nome = "Magazine" };
            Arquivo img = new Imagem() { Nome = "Monalisa" };
            Arquivo txt = new Txt() { Nome = "Cópia do E-mail" };
            Windows win = new Windows();
            win.Abrir(mp3);
            win.Abrir(doc);
            win.Abrir(img);
            win.Abrir(txt);
            Console.ReadKey();

        }
    }

 

Uma classe Abstract é impossível de ser Estanciada. Ela serve mesmo como um contrato para as demais implementações e é por isso que quando executada necessita ter um tipo.

Quando se declara o Método como abstract na classe descendente o comportamento sempre é sobrescrito. Veja Abaixo o Diagrama de Classes.

Class Diagram

Class Diagram

Para que você possa dividir o comportamento entre a classe base e as descendentes, você precisa usar o tipo virtual, ex: public virtual class Arquivo

Ainda assim na classe do descendente que deseja abrir o comportamento da classe Base se chama desta forma: base.Abrir();