Localização

Este documento descreve os mecanismos de localização disponíveis para as aplicações Elevation 300.

Localização (traduções)

Definição de traduções

Servidor

O mecanismo nativo de traduções .NET é utilizado na geração de HTML do lado do servidor. As resources .NET podem também ser definidas de igual forma. Estas resources são geradas perante a especificação em modelação e também podem ser definidas pelo implementador. As localizações são definidas nos ficheiros resx.

Cliente

A biblioteca angular-localization é utilizada para obter as traduções de maneira dinâmica e automática.

  • Os ficheiros de localização têm de estar obrigatoriamente disponíveis em um servidor público para poderem ser descarregados pelo browser.
  • Os ficheiros de localização têm o sufixo “.lang.json”
  • Seguindo a nomenclatura existente de resources, o nome deverá começar por “RES_”.
  • O conteúdo do ficheiro está no formato json e contêm um objeto json, em que as chaves são as chaves do resources e os valores são a tradução correspondente.
{
    "RES_NewEntity_Title": "New {1}",
    "RES_InitializationError_DialogTitle": "Try Again",
…
}
  • A estrutura de ficheiros esperada no serviço é a seguinte:
/Resources
    /<locale>
        /<module>
            /<file>.lang.json
  • A pasta de raiz tem o nome Resources. (configurável na inicialização do angular-localization)
  • O 2º nível, “<locale>”, contém a língua da tradução segundo a tag IETF (por exemplo “en-US”)
  • O 3º nível, “<module>”, contém o nome do módulo a que a tradução pertence (por exemplo Core).
  • Dentro da pasta do módulo, encontram-se os ficheiros “<file>.lang.json” que contêm as traduções. Estes ficheiros poderão estar dentro de outras pastas, conforme a estruturação desejada.
  • Poderão existir mais pastas dentro do módulo.
  • O nome das pastas e dos ficheiros não podem conter o “.” (caracter ponto)
  • Todas as pastas e ficheiros, com exceção da tag IETF <locale> e da pasta Resources, são definidos em minúsculas.

Por exemplo, a estrutura de ficheiros do módulo Core é a seguinte:

/Resources
    /en-US
        /core
            /directives.lang.json
            /controllers.lang.json

Utilização de traduções

Traduções no servidor

A utilização de textos localizados no servidor, em geração de HTML e em textos de exceções lançadas para o cliente (via ExpectedException), segue o mecanismo .net nativo de localização, com utilização de ficheiros .resx.

Traduções no cliente

Cada um dos módulos pode conter um ou mais ficheiros (.lang.json) com localizações. Estes ficheiros têm de ser descarregados para o browser. O registo desses ficheiros é efetuado na fase de configuração dos módulos invocando o registo no resourcesServiceProvider. Este resourceServiceProvider está registado no bootstrapping service que por sua vez está definido como dependência do estado “base” angularJS da aplicação. Isto garante que antes do carregamento de estados angular todos os ficheiros de localizações são carregados para serem utilizados.

No cliente, em contexto angularJS, é possível fazer uso das localizações de várias maneiras:

  • directives:
  • i18n ou data-i18n: para substituir o conteúdo do elemento HTML com tradução
data-i18n=“core.controllers.RES_TEST”
  • data-i18n-attr, : para substituir o conteúdo de um atributo HTML com tradução
data-i18n-attr=“{<attributo>:’core.controllers.RES_TEST’}”
  • filter : i18n
  • service: resourcesService

Por exemplo para utilizar a localização da chave RES_TEST que está definida no ficheiro “/Resources/en-US/core/controllers.lang.json”:

resourceService.get(“core.controllers.RES_TEST”);

A especificação (ou nomenclatura) de chaves de localização segue exatamente a estrutura de ficheiros especificada no capitulo Cliente acima, em que:

  • . (caracter ponto) é utilizado para separador de diretorias e ficheiro
  • o último segmento (antes do ponto) é a chave da localização dentro do ficheiro de traduções (lang.json)
  • o penúltimo segmento (antes do ponto) é o nome do ficheiro
  • do antepenúltimo para trás é o caminho até ao ficheiro, a partir da tag IETF (em que a separação de diretórias é feita com o .)

Na aplicação angularJS, o serviço resourceService é concretizado com o resourceServiceProvider que permite a configuração na fase de configuração das aplicações angularJS. O método config tem como argumento um objeto que pode conter as seguintes chaves:

  • localeSupported – array com as localizações suportadas
  • localeFallbacks – objeto com o fallback das localizações
  • basePath – o prefixo de ficheiros de localizações
  • fileExtension – sufixo de ficheiros de localizações

Esta configuração apenas é invocada no início da aplicação angularJS.

O resourceServiceProvider expõe um método de registo de ficheiros de localização no cliente. O método tem como argumento a chave até ao ficheiro. Por exemplo, para registar o ficheiro de localizações /Resources/en-US/core/directives.lang.json:

resourcesService.registerSource(‘core.directives’);

O método registerSource deverá ser chamado na fase de configuração de todos os módulos que necessitem de traduções, com o registo dos ficheiros que contêm as localizações que necessitam.

Método registerSource

A definição da língua (e local) é feita através da função setLocale. Por exemplo, para definir a localização pt-PT:

resourceService.SetLocale(‘pt-PT’)

Se houver uma mudança de localização, os ficheiros registados como fontes de localizações serão obtidos.

O resourceService está configurado para obter todos ficheiros de localizações, no bootstrappingService, que está definido como dependência no estado angularJS “base”. Esta dependência garante que todas as traduções necessárias à aplicação estão disponíveis logo desde o início da aplicação.

resourceService

Alteração da biblioteca angular-localization

Os estados da aplicação do angular js route ui estão dependentes do bootstrapping. O serviço de bootstrapping está depende do serviço ResourcesServices que por sua vez está dependente do angular-localization.

A biblioteca angular-localization tem, por desenho, o comportamento de não retornar qualquer resultado no caso de erro ao obter ficheiro de localização (por exemplo se não existir).

Houve então a necessidade de alterar o angular-localization para devolver a promise como rejected no caso de o ficheiro não existir e permitir o arranque da aplicação, mesmo que haja algum problema na obtenção do ficheiro de localização.

$http.get(url)
.success(function (data) {
…
})
.error(function (data) {
    $log.error("[localizationService] Failed to load: " + url);

    /* FIX start - reject promise when path is not found. */
    var path = getPath(token);
    if (deferrences[path]) {
        deferrences[path].reject(url);
        delete deferrences[path];
    }
    /* FIX end - reject promise when path is not found. */

    // We can try it again later.
      delete root._loading;
});

Exportação/Importação (nuget)

Os pacotes de nuget são utilizados para exportar/importar os binários e todos os outros recursos necessários. As localizações utilizadas de cliente e servidor também são incluídas nos pacotes de nuget.

No ficheiro .nuspec (ficheiro de configuração de pacotes nuget), é necessário especificar regras para incluir os ficheiros de traduções de cliente e servidor.

<?xml version="1.0"?>
<package >
…………
  <files>
    <file src="..\Host\app\modules\sales\**\*.js" target="content\app\modules\sales\" />
    <file src="..\Host\Views\Sales\**\*.cshtml" target="content\Views\Sales" />
    <file src="..\Host\Resources\*\sales\**\*.json" target="content\Resources" />
    <file src="..\bin\NET40\**\$id$.resources.dll" exclude="..\bin\NET40\Test\**\*.*" target="lib\net451" />
  </files>
</package>

No exemplo acima, o nuspec do projecto primavera.sales.web:

  • A regra de inclusão dos ficheiros de cliente (está a amarelo).
  • A regra de inclusão dos ficheiros de servidor da .dll (está a verde)

Na imagem seguinte (estrutura de pacote nuget com inclusão de resource de client), temos o conteúdo do pacote nuget de Primavera.Sales.Web construído com o ficheiro nuspec acima:

Estrutura de pacote nuget com inclusão de resource de client

Dentro da Resources, temos a estrutura de ficheiros esperada para ser publicada.

  • Dentro da pasta “Resources” estão os ficheiros do cliente
  • Dentro da pasta dos binários, neste caso, net451, está a pasta pt com as resources em português da .dll que o pacote nuget transporta.

Globalização

Directives Angular JS - Views

A localização do sistema é feito no serviço authenticationService do módulo query builder.

Ao fazer Login ou refresh da aplicação, é utilizado a script DynamicLocale.js

  • É encontrado a linguagem do browser:
var language = window.navigator.userLanguage || window.navigator.language
  • O $Locale do AngularJS é redefinido com a cultura correspondente do browser.
// Set User Culture
tmhDynamicLocale.set(language);

Todas as directives de data, number, decimal e currency, serão controlados pela diretiva $locale que será definida e de acordo com o idioma do browser. Todas as diretives, terão o formato consistente com o idioma do browser.

Listas

Todas as listas terão também de ter as colunas que formatadas corretamente de acordo com o idioma de preferência do browser.

Todas as colunas e paramentos do tipo Date, DateTime, Time, Number, Decimal e Money, deverão estar no formato de acordo com a linguagem do browser.

  • Na criação da definição das colunas da Query Configuration, é analisado o HttpRequest e extraído a cultura de preferência do browser a partir da lista de userLanguages, Se não houver nenhuma cultura definida, será utilizada a cultura do utilizador na base de dados.
HttpRequest request = HttpContext.Current.Request;

CultureInfo culture = Thread.CurrentThread.CurrentCulture;

if (request.UserLanguages.Any())
{
    var languages = request.UserLanguages
                    .Select(StringWithQualityHeaderValue.Parse)
                    .OrderByDescending(a => a.Quality.GetValueOrDefault(1));

                var selectedLang = languages.FirstOrDefault();
                culture = CultureInfo.CreateSpecificCulture(
            selectedLang.Value.ToString());
  • As colunas serão formatados por tipo de acordo com esta cultura.

Definição do idioma do browser

O idioma do browser deverá ser colocado na ordem correta e definido para ser apresentado no mesmo idioma.