Angular: i18n: Capaz de usar cadenas de traducción fuera de una plantilla

Creado en 7 sept. 2016  ·  204Comentarios  ·  Fuente: angular/angular

Estoy enviando un... (marque uno con "x")

[x] feature request

Comportamiento actual
https://github.com/angular/angular/issues/9104#issuecomment-244909246

No creo que sea posible, como dije antes, solo funciona con texto estático, no analizará texto en el código js, ​​solo plantillas

Comportamiento esperado/deseado
Ser capaz de traducir cadenas utilizadas en cualquier parte del código, utilizando una API.

Reproducción del problema

¿Cuál es el comportamiento esperado?
Estoy haciendo referencia al uso de $translate.instant para exponer casos de uso reales:

  • Texto renderizado personalizado:
if (data._current_results === data._total) {
                content = this.$translate.instant('CLIPPINGS__LIST__SUMMARY_ALL', {'num': data._current_results});
            } else {
                if (undefined === data._total) {
                    data._total = '...';
                }

                content = this.$translate.instant('CLIPPINGS__LIST__SUMMARY', {
                    'num': data._current_results,
                    'total': data._total
                });
            }

            // Put 'mentions' first
            data = angular.merge({}, {
                mentions: mentions
            }, data);

            _.each(data, (value:number, key:string):void => {
                if (value) {
                    details += value + ' ' + this.$translate.instant('CLIPPINGS__LIST__SUMMARY_TYPE_' + key) + ', ';
                }
            });

            if (details) {
                details = '(' + _.trim(details, ', ') + ')';
            }

            content = content.replace(':details', details);

Más ejemplos:

  • Obtener el nombre de archivo de la imagen de la imagen exportada de un informe renderizado en HTML:
getExportImageName(hideExtension:boolean):string {
        let fileName:string;

        fileName = this.$translate.instant('D_CHART_FACET_authors__EXPORT_FILENAME', {
            'profileName': this.ExportService.GetProfileName(),
            'period': this.ExportService.GetPeriodString(this.SearchFilter.GetPeriodFromInterval())
        });

        if (!Boolean(hideExtension)) {
            fileName += '.png';
        }

        return fileName;
    }
  • A veces está traduciendo, a veces usa datos del modelo (podría ser muy detallado en una plantilla):
private _getTitle():string {
        if (this.inShareColumn) {
            return this.$translate.instant('COMPARISONS__SHARE_COLUMN_share_of_voice_TITLE');
        } else if (this.inTotalsColumn) {
            return this.$translate.instant('COMPARISONS__TOTAL_COLUMN_share_of_voice_TITLE');
        } else {
            return _.get<string>(this.group, 'profileName', '');
        }
    }
  • Uso de un complemento de gráficos de terceros (Highcharts)
this.chart = new Highcharts.Chart(<any>{
            title: {
                text: this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_TITLE_tone').toUpperCase(),
            },
            xAxis: {
                title: {
                    text: this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_TITLE_tone_xaxis')
                }
            },
            yAxis: {
                min: 0,
                title: {
                    text: this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_TITLE_tone_yaxis')
                }
            },
            plotOptions: {
                scatter: {
                    tooltip: {
                        headerFormat: '<b>{point.key}</b><br>',
                        pointFormat: '{point.y} ' + this.$translate.instant('REPORTS_BLOG_MAPPING_CHART_mentions')
                    }
                }
            }
        });
  • Para configurar variables de configuración y representar el texto sin canalizaciones, ya que no siempre es una cadena traducida
this.config = {
            requiredList: true,
            bannedList: false,
            allowSpaces: false,
            allowComma: false,
            colorsType: false,
            defaultEnterAction: 'required',
            requiredTooltip: this.$translate.instant('D_CLIPPING_TAGS__REQUIRED_TOOLTIP'),
            bannedTooltip: this.$translate.instant('D_CLIPPING_TAGS__BANNED_TOOLTIP')
        };
  • Para configurar window.title :):
SetWindowTitle(title:string) {
        if (!!title) {
            this.$window.document.title = this.$translate.instant(title);
        }
    }
  • Formato de fecha personalizado:
dateHuman(date:Date):string {
        return date.getDate() + ' ' + this.$translate.instant('GLOBAL_CALENDAR_MONTH_' + date.getMonth())
            + ' ' + date.getFullYear();
    }
  • Ordenar las cosas según los valores traducidos:
// Sort types
            tmpTypes = _.sortBy(tmpTypes, (type:string):string => {
                // 'MISC' at the end
                if ('MISC' === type) {
                    return 'zzzzz';
                }

                return this.$translate.instant('FACET_phrases2__TYPE_' + type);
            });
GetSortedLanguages():IFacetLangDetectedCommonServiceLanguageObject[] {
        // We have to sort by translated languages!
        return _.sortBy(_.map(this.facetOptions, (item:string):any => {
            return {
                key: item,
                label: this.$translate.instant('FACET_langDetected_' + item),
                cssStyle: (_.includes(['english', 'catalan', 'spanish', 'french', 'italian'], item))
                    ? {'font-weight': 'bold'} : null,
                flag: _.get(this.lutFlags, item, null)
            };
        }), (item):string => {
            return item.label.toLowerCase();
        });
    }
  • Exporte datos sin procesar a CSV o Excel con valores traducidos:
getDataExportStacked(inputData:any):any {
        let exportData = angular.copy(inputData);

        if (angular.isArray(exportData) && exportData.length) {
            exportData[0].name = this.$translate.instant('CLIPPINGS__CHARTS_volume_TITLE');

            exportData[0].data = _.map(exportData[0].data, (inputDataItem:any):any => {
                return {
                    'label': inputDataItem.association.profileName,
                    'value': inputDataItem.value
                };
            });
        }

        return exportData;
    }
  • Establezca cadenas de configuración para complementos de terceros:
UpdateCalendarStrings():void {
        Highcharts.setOptions({
            lang: {
                months: [
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_January'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_February'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_March'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_April'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_May'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_June'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_July'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_August'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_September'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_October'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_November'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_December')
                ],
                shortMonths: [
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Jan'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Feb'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Mar'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Apr'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_May'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Jun'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Jul'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Aug'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Sep'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Oct'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Nov'),
                    this.$translate.instant('GLOBAL_CALENDAR_MONTH_SHORT_Dec')
                ],
                weekdays: [
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Sunday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Monday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Tuesday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Wednesday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Thursday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Friday'),
                    this.$translate.instant('GLOBAL_CALENDAR_DAY_Saturday')
                ]
            }
        });
    }


¿Cuál es la motivación/caso de uso para cambiar el comportamiento?
Ser capaz de traducir cadenas fuera de las plantillas.

Cuéntanos sobre tu entorno:

  • Versión angular: 2.0.0-rc.6
  • Navegador: [todos]
  • Idioma: [Mecanografiado 2.0.2 | ES5 | sistemaJS]

@vicb

i18n feature high

Comentario más útil

Creo que esto es realmente sorprendente, i18n no está listo para usar hasta que se implemente.
Por ejemplo, no puedo establecer mensajes de validación traducidos en código

Todos 204 comentarios

Creo que esto es realmente sorprendente, i18n no está listo para usar hasta que se implemente.
Por ejemplo, no puedo establecer mensajes de validación traducidos en código

@ Mattes83 ¿Lo intentaste de esta manera?

<p [hidden]="!alertManagerRowForm.controls.sendTo.hasError('validateEmail')" class="help-error">
    {{ 'ALERTMANAGER__FORM__FIELD__sendTo__ERROR__validateEmail' | translate }}
</p>

:confused: La documentación te dice lo bueno que es tener mensajes de error en el código y el soporte de traducción requiere cualquier cosa en la plantilla. Parece que hay más necesidad de comunicación.

@marcalj Lo sé de esta manera... pero necesito tener cadenas localizadas en mis archivos ts.
@manklu estoy totalmente de acuerdo

Creo que esto es realmente sorprendente, i18n no está listo para usar hasta que se implemente.
Por ejemplo, no puedo establecer mensajes de validación traducidos en código

Sí, lo mismo aquí, acabo de cambiar de ng2-translate a Angular2 i18n porque prefiero usar módulos OOTB, y es mucho más fácil extraer traducciones (ng2-translate requiere más tiempo en mi opinión)
En este momento no puedo traducir los mensajes de error generados por mis servicios. No hay solución tampoco.

Si alguien quiere comenzar una especificación de diseño, sería útil (es decir, en Google Docs).

Tendría que enumerar todos los casos. Pensando rápidamente en ello, veo la necesidad de

_.('static text');
_.('with {{ parameter }}', {parameter: "parameter" });
_.plural(count, {'few': '...'});
_.select(on, {'value': '...'});

Hola chicos, gran solicitud de función :+1:

¿Hay alguna solución sugerida para traducir textos *.ts?

@fbobbio Lo que he estado haciendo es crear elementos ocultos en la plantilla, ej.
<span class="translation" #trans-foo i18n>foo</span> .

Enlázalos usando:
@ViewChild('trans-foo) transFoo : ElementRef; .

Luego recupera el valor traducido
transFoo.nativeElement.textContent .

Parece retrasado, pero funciona para mis necesidades.

Como ng-xi18n ya procesa todo el código TS, ¿por qué no implementar un decorador como @i18n() para las propiedades (de cadena)? Luego, estos podrían completarse con el valor traducido, como @Input() se usa con el enlace de datos unidireccional.
Si el valor sin traducir no se puede extraer fácilmente del código, simplemente colóquelo en el argumento de la siguiente manera:

@i18n( {
  source : 'Untranslated value',
  description: 'Some details for the translator'
} )
public set translatedProperty( value : string ) {
   this._translatedProperty = value;
}

e introduzca la fuente en la propiedad cuando no haya un destino de traducción.

Este es un elemento esencial en todo el ciclo de internacionalización, en mi opinión.

En mi tienda, estamos acostumbrados a una herramienta "similar a ng-xi18n" (una extensión de xgettext) que rastrea todo tipo de archivos fuente en busca de texto marcado para poner en archivos de diccionario para los traductores.

Me encanta el marcado i18n limpio y fácil en las plantillas HTML, y esperaba lo mismo para el código Typescript.

@vicb Además de sus casos de uso, estoy pensando en la posibilidad de admitir la localización de cadenas interpoladas en el código TS. Sin embargo, es probable que sea necesario volver a escribir el código TS para admitir tal escenario. ¿Será un enfoque válido?

Esta es la característica principal que nos impide utilizar el enfoque listo para usar para traducir las ofertas de Angular 2. Tenemos muchos componentes controlados por metadatos cuyas claves provienen de algunos metadatos no almacenados en HTML. Si pudiéramos traducir a través de una canalización o programáticamente contra las TRADUCCIONES disponibles, podríamos hacer que estos componentes mostraran las cadenas adecuadas.

Mientras tanto, estamos limitados a algo como ng-translate debido a esta limitación.

La forma en que solucioné este problema fue agregando un objeto 'lang' vacío en un servicio utilizado en toda mi aplicación. Luego aplico una directiva que lee todo el intervalo en un div y almaceno el valor en ese objeto. Coloco toda mi cadena en una plantilla en la parte inferior de la página con una propiedad oculta. A continuación, se puede acceder a la cadena desde la plantilla o el componente. Es feo y podría sobrescribir fácilmente una entrada con la misma identificación. Pero es mejor que nada.

SERVICIO

@Injectable()
export class AppService {

    //Language string object.
    private _lang:Object = new Object();
    get lang():Object {
        return this._lang;
    }
}

DIRECTIVA

@Directive({
    selector: '[lang]'
})
export class LangDirective implements OnInit {

    constructor(
        public element: ElementRef,
        public app: AppService) {
    }

    ngOnInit() {
        let ele = this.element.nativeElement;
        for (var i = 0; i < ele.children.length; i++) {
            let id = ele.children[i].getAttribute('id');
            let value = ele.children[i].innerHTML;
            this.app.lang[id]=value;
        }
    }
}

PLANTILLA

<button>{{app.lang.myButtonText}}</button>
<div lang hidden >
    <span id="myButtonText" i18n="Test Button">Testing</span>
</div>

Hola @lvlbmeunier

Gracias por brindarnos esta sugerencia de solución alternativa mientras esperamos la implementación oficial. Traté de implementar su solución, pero parece que no puedo obtener las claves de traducción dinámicas para ser reconocidas. Estaba tratando de hacerlo así:

<p *ngFor="let d of dataEntry">{{app.lang[d.name]}}</p>
<div lang hidden >
<span id="{{d.name}}" *ngFor="let d of dataEntry" i18n>{{d.name}}</span>
</div>

Esas claves nuevas no aparecen en mis archivos xliff. ¿Es posible lograr esto con su solución?

Nunca lo probé, pero estoy casi seguro de que la compilación del archivo xliff no ejecuta el código. Tener un valor dinámico en i18n sería contrario al concepto. Si sabe con certeza todos los nombres que estarían en su lista, todos deben declararse de forma independiente y no en un bucle for.

Agregar las claves manualmente funciona pero no es práctico. En mi caso, recibo cientos de claves de texto que necesitan traducción desde una API.

Puede ejecutar su código y tomar la fuente y copiarla en un archivo. La generación del archivo x18n se basa en un archivo estático.

Con 4.0.0-beta puede asignar una identificación a i18n , por ejemplo mainTitle:

<span i18n="title@@mainTitle">

Con esto podemos, al menos para el compilador JIT, crear un Componente ficticio (no es necesario agregarlo al html de la aplicación, solo al módulo de la aplicación) con todas nuestras traducciones "adicionales".

Para empezar, agregaremos los proveedores no solo al compilador sino también al módulo de la aplicación:

// bootstrap.ts
getTranslationProviders().then(providers => {
    const options = { providers };
    // here we pass "options.providers" to "platformBrowserDynamic" as extra providers.
    // otherwise when we inject the token TRANSLATIONS it will be empty. The second argument of
   // "bootstrapModule" will assign the providers to the compiler and not our AppModule
    platformBrowserDynamic(<Provider[]>options.providers).bootstrapModule(AppModule, options);
});

Luego, crearemos un componente ficticio para albergar nuestras traducciones adicionales, no olvide agregar el componente a declarations de AppModule . Esto es para que ng-xi18n pueda encontrar el html (creo) y agregarlo al archivo de traducción.

//tmpI18N.ts
import {Component} from '@angular/core';

@Component({
    selector: 'tmpI18NComponent',
    moduleId: module.id,
    templateUrl: 'tmp.i18n.html'
})
export class TmpI18NComponent {
}

Agregue nuestras traducciones a tmp.i18n.html :

<!-- tmp.i18n.html -->
<span i18n="test@@mainTitle">
    test {{something}}
</span>

Ahora podemos crear un servicio donde podemos buscar nuestras traducciones:

import {Injectable, Inject, TRANSLATIONS} from '@angular/core';
import {I18NHtmlParser, HtmlParser, Xliff} from '@angular/compiler';

@Injectable()
export class I18NService {
    private _source: string;
    private _translations: {[name: string]: any};

    constructor(
        @Inject(TRANSLATIONS) source: string
    ) {
        let xliff = new Xliff();
        this._source = source;
        this._translations = xliff.load(this._source, '');
    }

    get(key: string, interpolation: any[] = []) {
        let parser = new I18NHtmlParser(new HtmlParser(), this._source);
        let placeholders = this._getPlaceholders(this._translations[key]);
        let parseTree = parser.parse(`<div i18n="@@${key}">content ${this._wrapPlaceholders(placeholders).join(' ')}</div>`, 'someI18NUrl');

        return this._interpolate(parseTree.rootNodes[0]['children'][0].value, this._interpolationWithName(placeholders, interpolation));
    }

    private _getPlaceholders(nodes: any[]): string[] {
        return nodes
            .filter((node) => node.hasOwnProperty('name'))
            .map((node) => `${node.name}`);
    }

    private _wrapPlaceholders(placeholders: string[]): string[] {
        return placeholders
            .map((node) => `{{${node}}}`);
    }

    private _interpolationWithName(placeholders: string[], interpolation: any[]): {[name: string]: any} {
        let asObj = {};

        placeholders.forEach((name, index) => {
            asObj[name] = interpolation[index];
        });

        return asObj;
    }

    private _interpolate(pattern: string, interpolation: {[name: string]: any}) {
        let compiled = '';
        compiled += pattern.replace(/{{(\w+)}}/g, function (match, key) {
            if (interpolation[key] && typeof interpolation[key] === 'string') {
                match = match.replace(`{{${key}}}`, interpolation[key]);
            }
            return match;
        });

        return compiled;
    }
}

Ahora podemos hacer algo como:

export class AppComponent {

    constructor(i18nService: I18NService) {
        // Here we pass value that should be interpolated in our tmp template as a array and 
        // not an object. This is due to the fact that interpolation in the translation files (xlf for instance)
        // are not named. They will have names such as `<x id="INTERPOLATION"/>
        // <x id="INTERPOLATION_1"/>`. And so on.
        console.log(i18nService.get('mainTitle', ['magic']));
    }
}

Esta es una solución alternativa. Pero al menos podemos aprovechar el archivo de traducción, obtener por clave, interpolar y no tener que tener un html oculto en nuestra aplicación.

NOTA: el paquete @angular/compiler-cli NPM actual de 4.0.0-beta tiene una versión de dependencia incorrecta de @angular/tsc-wrapped . Apunta a 0.4.2, debería ser 0.5.0. @vicb ¿ es esto fácil de arreglar? ¿O deberíamos esperar al próximo lanzamiento?

@fredrikredflag Genial! ¿Y qué hay de AOT?

@ghidoz AOT es otra historia. Lo que nos gustaría hacer es precompilar todas las traducciones para poder obtenerlas por clave. Pero dado que ngc reemplazará todos los i18n con la traducción correcta, no podemos aprovecharlo. No se puede encontrar ninguna opción/propiedad expuesta que contenga las traducciones analizadas de ngc . Podríamos usar el mismo enfoque dinámico que para JIT al obtener el archivo xlt de esa manera y aún así proporcionarlo en el token TRANSLATION . Sin embargo, esto va en contra del propósito de AOT.

NO LO HAGAS PARA NINGUNA APLICACIÓN DE PRODUCCIÓN .

/// bootstrap.aot.ts
function fetchLocale() {
    const locale = 'sv';
    const noProviders: Object[] = [];

    const translationFile = `./assets/locale/messages.${locale}.xlf`;
    return window['fetch'](translationFile)
        .then(resp => resp.text())
        .then( (translations: string ) => [
            { provide: TRANSLATIONS, useValue: translations },
            { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
            { provide: LOCALE_ID, useValue: locale }
        ])
        .catch(() => noProviders);
}

fetchLocale().then(providers => {
    const options = { providers };
    platformBrowser(<Provider[]>options.providers).bootstrapModuleFactory(AppModuleNgFactory);
});

Pensamiento actual sobre cómo implementar esto:

@Component()
class MyComp {
  // description, meaning and id are constants
  monday = __('Monday', {description?, meaning?, id?});
}
  • Debido a que no pudimos afectar la estructura DOM con tal construcción, podríamos admitir traducciones en tiempo de ejecución: habría una sola versión del binario y la resolución ocurriría en tiempo de ejecución,
  • también podemos admitir traducciones estáticas como lo hacemos hoy para las plantillas: las cadenas se reemplazarían en tiempo de compilación, mejor rendimiento pero una versión de la aplicación por configuración regional,
  • probablemente podríamos admitir __(...) en plantillas en algún momento posterior,
  • esto se implementaría a través de un transformador TS disponible desde 2.3; probablemente podríamos tener un prototipo antes.

/cc @ocombe

Supongo que __() es para un método que aún no tiene nombre (y el método en realidad no sería __ , ¿verdad?)

Es una buena idea para las traducciones estáticas que podría usar en sus clases, y creo que es bastante simple de implementar.

No __() es el nombre, no te gusta :)

Se usa comúnmente en marcos de traducción, ¡pero podrá import {__ as olivier} from '@angular/core' si prefiere otro nombre!

eeeeeeh no es muy autoexplicativo :D
Parece una función muy privada.

Tampoco me gusta el nombre del método ___ :) ¿Me había imaginado que sería un servicio?
De cualquier manera, es bueno ver el progreso 👍

Me gusta __()! :D Muy gettext-y y es corto.

En el mundo JS, solo tengo experiencia con @ocombes ng2-translate, donde marcar todo el texto con this._translateService.instant() hace que el código sea un poco más difícil de leer en comparación con una alternativa más corta, como la propuesta aquí.

nada te impide cambiar el nombre del servicio de traducción ng2 __ ya sabes :)

En realidad, no tengo idea de cómo envolver un método de servicio DI en una función simple; de ​​todos modos, no importa, eso está más allá del alcance de este problema:-) Mi comentario fue solo un +1 por usar __ como es bien sabido si alguna vez he usado otros marcos de traducción, al menos en el mundo de PHP.

vale, tal vez ___ esté bien, mejor que "this.translationService.getTranslation()", mucho más breve.
Y sí, puedes cambiarle el nombre si quieres.

¿Qué pasa con i18n(...) en lugar de __(...) ?

Detenga el debate sobre el nombre, ese no es el punto. Gracias.

@vicb con monday = __('Monday', {description: 'First day of the week', id: 'firstDatOfWeek'}); será posible resolverlo por id, es decir:

__('@<strong i="8">@firstDatOfWeek</strong>') // Monday

¿También sería Monday local para la clase definida o sería posible resolverlo desde cualquier lugar? Estoy pensando en traducciones comunes como "cerrar", "abrir", etc.

Me preguntaba cuál es la mejor solución actualmente que recomiendan usar con AOT hasta que el lanzamiento oficial lo admita.

Saludos,
sean

Angular 2 Fregadero de cocina: http://ng2.javascriptninja.io
y source@ https://github.com/born2net/Angular-kitchen-sink

@vicb alguna noticia, por allá ^

Hasta que se implemente esta función, usaré la función de traducción de atributos .

import {Component, Input, OnInit} from '@angular/core';

@Component({
    selector: 'app-sandbox',
    templateUrl: 'sandbox.html'
})
export class SandboxComponent implements OnInit {
    @Input()
    public title: string;

    constructor() {
    }

    ngOnInit() {
        console.log('Translated title ', this.title);
    }
}

Desde la plantilla del componente principal:

<app-sandbox i18n-title title="Sandbox"></app-sandbox>

Es una solución alternativa, pero aún así, creo que es la más limpia hasta ahora. Le da acceso al title traducido dentro ts .

Estoy empezando a trabajar en esta característica, espero un documento de diseño pronto :-)

esta será la función más esperada

Esa es una buena noticia. Gracias @ocombe .

El documento de diseño está disponible aquí: https://goo.gl/jQ6tQf
Cualquier comentario es apreciado, gracias.

dulce, leeré lo antes posible!

Gracias @ocombe

He leído el documento. Hermoso resumen.

Ser capaz de extraer cadenas de archivos ts suena increíble.

No estoy seguro de cuándo estará disponible la actualización de Typescript para Angular4.

Significa que esta función ya debería estar disponible durante meses porque casi todos se encontraron con esta limitación y no podrán usar esta solución antes de al menos 3/6 meses más.

Puede que no sea el único en este momento que usa ngx-translate para administrar las traducciones en mis controladores mientras confío en angular i18n para las plantillas.

El objetivo de fusionar todo en i18n es obviamente genial.

Pero aparte de la simplificación en términos de comprensión de cómo implementar i18n en el marco angular, ¿realmente este enfoque mejorará el rendimiento en comparación con la implementación actual de ngx-translate?

Según tengo entendido en este momento, la única ventaja sería poder extraer cadenas de los controladores.

También una gran limitación en este momento es la pluralización, asegúrese de que funcione correctamente cuando publique la actualización completa. He leído muchos tickets relacionados con i18n donde xliff y xmb no manejarían esto correctamente. Este es un caso más en el que necesito volver a ngx-translate para ofrecer una solución que funcione.

@ocombe Gracias por el documento de diseño detallado, parece una muy buena solución para esta solicitud de función. El diseño actual aborda los casos de uso que estoy tratando de resolver.

Una pregunta: El diseño habla de un servicio I18N para modo JIT, y un Transformador TS 2.2.x para modo AOT. ¿Tengo razón al suponer que el transformador reemplazará la llamada al método de servicio con una traducción estática y también eliminará todas las referencias restantes al servicio I18N?

@Thommas Angular 4 usará TypeScript 2.1 (lo que significa que tendrá que actualizar), pero en realidad ya puede usar cualquier versión más reciente de TypeScript (2.2.1, por ejemplo) con Angular 2 o 4.

En términos de ganancia de rendimiento sobre ngx-translate, depende de si usa AOT o no. Si usa AOT, entonces es una ganancia, pero probablemente no verá la diferencia. En JIT (sin AOT) no habrá ninguna ganancia (en realidad depende si usa el método observable get o el método sincrónico instant , el observable cuesta más que una simple llamada a función).
Estoy hablando de i18n en su código aquí. Si estamos hablando de las plantillas, hay una ganancia visible real si usa Angular i18n (en AOT y JIT) porque no usa enlaces. Cuantas más traducciones utilice, más ganará.

Me aseguraré de que la pluralización funcione exactamente igual que para las plantillas. ¿Hay algún problema en este momento con él en las plantillas?

@schmuli, la única vez que Angular puede reemplazar su código es cuando usa AOT. Si no lo hace, las llamadas de servicio seguirán siendo las mismas en su código.
Pero si usa AOT, la llamada de servicio se reemplazará con una traducción estática (solo las variables que podría usar permanecerán dinámicas). No estoy seguro de si eliminaremos las referencias al servicio I18n, porque podría usarse para otras cosas en el futuro, tendré que ver qué es posible con el transformador una vez que comience a escribir el código. ¿Está pensando en un caso de uso en el que esto sería un problema?

@ocombe No puedo pensar en un caso de uso en el que dejar el código sea un problema, a menos que consideremos una inyección DI adicional que no se utilizará (¿es este un problema real?).

Teniendo en cuenta lo que escribió que el servicio podría usarse para otras cosas en el futuro, y la posibilidad de que se introduzcan errores al cambiar el código del usuario, diría que probablemente sea mejor evitar eliminar el código por completo.

Tal vez sería útil usar el servicio para obtener la configuración regional actual en AOT. Considere, por ejemplo, el caso en el que tiene un servidor que puede devolver texto en varios idiomas, por lo tanto, necesitará la configuración regional actual para incluirla en la solicitud. Sin embargo, siempre puede usar una cadena traducida ficticia como solución alternativa.

@diego0020 ya puede obtener la configuración regional, simplemente inyecte LOCALE_ID desde el núcleo

@ocombe La pluralización no se implementa con xliff y nadie fuera de Google tiene idea de cómo usarlo con xmb tampoco. Ver también: https://github.com/angular/angular/issues/13780

De todos modos, nada está bloqueando nuestra implementación de i18n en este momento. ngx-translate con una canalización de pluralización servirá por ahora. Con suerte, todo se verá mejor en NG4 y la documentación reflejará las mejoras. Gracias.

@Thommas ICU con xliff se arreglará pronto: https://github.com/angular/angular/pull/15068 y si quieres saber cómo usarlo, está en los documentos: https://angular.io/docs/ ts/último/libro de cocina/i18n.html#! #cardinalidad

Disculpe, ¿hay alguna ETA? ¡Porque escuché que estará disponible en la versión ng4.0.0 pero no! Gracias

CC @ocombe

Todavía estamos trabajando en el diseño, hay muchas cosas inesperadas a tener en cuenta (como cómo las bibliotecas podrían enviar sus propias traducciones),...
Espere esto para 4.2, pero no está garantizado.

ok gracias @ocombe , tengo dos preguntas por favor:

  1. En realidad, ¿podemos traducir texto en una plantilla que incluya interpolación, como:
    <span i18n>This is {{myValue}}</span>
  1. Pregunto porque en realidad no puedo extraer, no sé por qué me sale este error:
    Could not mark an element as translatable inside a translatable section

@istiti

  1. sí tu puedes.
  2. debe prestar atención a la ubicación de su directiva i18n, debe colocarse directamente en el elemento que contiene el texto, no en ningún otro hermano.
    por ejemplo:
    <div i18n><span i18n>my text</span></div> - esto no es bueno
    <div><span i18n>my text</span></div> - esto es bueno

@royihalp
Gracias

  1. Ok, ¿cómo traducir con interpolación?
  2. Cuando extraiga ngc, obtenga el archivo, la línea y el fragmento de código, pero no tengo i18n envuelto dentro de otro i18n
    Es realmente difícil encontrar cuál de mis padres tiene accidentalmente el atributo i18n

@istiti

  1. lo haces como cualquier otro elemento, solo agrega la directiva i18n como lo hiciste:
    <span i18n>This is {{myValue}}</span>
    el resultado en el archivo message.xlf será:
    <source>This is <x id="INTERPOLATION"/></source>
    ahora, cuando lo traduzca a diferentes lugares, debe colocar <x id="INTERPOLATION"/> en el lugar correcto de la oración, para ayudar a otros a comprender su significado, puede agregar una descripción a la directiva i18n de esta manera:
  1. desde mi experiencia, el error Could not mark an element as translatable inside a translatable section es como expliqué, recuerdo que si leo el error detenidamente puedo notar en qué archivo tengo el problema.

@fredrikredflag ¡Muchas gracias!

¡Tu código es súper útil! Solo tuve que solucionar un problema porque parece que xliff.load devuelve un objeto diferente hoy en día, por lo que this._translations debe ajustarse a:

const loaded = xliff.load(this._source, '');
this._translations = loaded['i18nNodesByMsgId'] ? loaded['i18nNodesByMsgId'] : {};

y una validación menor en el método get si pedimos una clave inexistente:

const placeholders = this._getPlaceholders(this._translations[key] ? this._translations[key] : []);

Además, creo que el componente i18n vacío se sacudió o algo así, así que tuve que incluir las cadenas en las plantillas de componentes correspondientes con:

<span hidden i18n="@@MY_STRING_1">String 1</span>
<span hidden i18n="@@MY_STRING_2">String 2</span>

Afortunadamente, solo necesito una pequeña cantidad de cadenas para mi miniApp, por lo que funciona muy bien en producción con AoT.
¡¡¡Gracias de nuevo!!!

P/D: la herramienta xliffmerge de Martin Roob es imprescindible en este momento, y su TinyTranslator también B-)

Uso la compilación AoT y mi proyecto admite dos idiomas: inglés y ruso. Encontré una solución temporal para el problema usando la configuración del entorno.

El archivo environments/environment.ts contiene:

import { messagesEn } from '../messages/messages-en';

export const environment = {
  production: false
};

export const messages = messagesEn;

También hay otros dos archivos environment.prod-en.ts y environment.prod-ru.ts con el siguiente contenido:

import { messagesEn } from '../messages/messages-en';

export const environment = {
  production: true
};

export const messages = messagesEn;

Y para ruso:

import { messagesRu } from '../messages/messages-ru';

export const environment = {
  production: true
};

export const messages = messagesRu;

Cada archivo de mensaje puede contener algo como esto:

export const messages = {
  MessageKey: 'Translation',
  AnotherMessageKey: 'Translation',
  Group: {
    MessageKey: 'Translation',
    AnotherMessageKey: 'Translation',
  }
};

En mi código (componentes, servicios, etc.) solo importo mensajes:

import { messages } from '../../environments/environment';

Y úsalos:

alert(messages.MessageKey);

En .angular-cli.json he especificado los siguientes entornos para producción:

"environments": {
  "dev": "environments/environment.ts",
  "prod-en": "environments/environment.prod-en.ts",
  "prod-ru": "environments/environment.prod-ru.ts"
}

¡Funciona!

@ alex-chuev ¿Has probado esto con JIT?

@ocombe alguna estimación aproximada de cuándo estaría disponible?

Gran característica por cierto :)

Está en espera hasta que se realicen cambios en el compilador, así que no para 4.2, todavía espero hacer esto para 4.3

alguien sabe cómo implementar i18n en valores param por ejemplo en [título] en el siguiente ejemplo:
en otras palabras, agregue la traducción a la palabra HOLA

Saludos

sean

Si HOLA es solo una cadena que escribe en la plantilla HTML, puede hacer lo siguiente:
```html

````
La documentación tiene un ejemplo de esto. Mira aquí: https://angular.io/docs/ts/latest/cookbook/i18n.html#! #traducir-atributos

Si tiene que vincularse a una propiedad de cadena en el componente, debe esperar esta función o implementar una forma personalizada de traducir (que yo sepa).

@ocombe

Todavía estamos trabajando en el diseño, hay muchas cosas inesperadas a tener en cuenta (como cómo las bibliotecas podrían enviar sus propias traducciones),...

Esto es muy importante. Espero que sea parte de esta característica también. Porque en este momento no veo la forma en que la biblioteca de terceros puede proporcionar traducciones para su aplicación. Durante la compilación, puede especificar solo 1 archivo XLIFF, y parece que tiene que compilar previamente su biblioteca para que su idioma tenga la capacidad de traducirlo.

¡Sí, yo también estoy esperando eso! ¡Esto es MUY importante para proyectos destinados a audiencias que no hablan inglés!

Definitivamente es algo que queremos apoyar, el equipo está trabajando en la refactorización del compilador que nos permitirá hacer eso :-)

¿Hay una estimación de la versión a la que se orientará? Leí en alguna parte que podría ser alrededor de 4.3?

Debido a la refactorización (y los cambios importantes) necesarios, me temo que no será antes de v5

Queeeee 😳 Oh no, estoy esperando esta función para 4.2 que dijiste y ahora es para v5 ☹️ Estaba pensando que para v5 será un cambio de idioma dinámico, no se lanzará para cada versión, pero de todos modos espero que sea un día, incluso con 36k compilaciones diferentes para cada una idioma. Me pregunto para cuando es v5? Gracias

@ocombe

@istiti dije que no era una cita garantizada ;-)
El cronograma de lanzamiento está aquí: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md
El lanzamiento final para v5 es 2017-09-18, pero habrá versiones beta y RC antes

¿Hay algún cambio para crear un archivo de configuración regional para cada componente? significa, crear fragmentos de messages.xlf , por ejemplo: messages.{component}.{locale}.xlf y, por ejemplo, solo messages.{component}.xlf para el idioma predeterminado.

Aún no

El daño es estrictamente mínimo debido al tiempo de construcción @ocombe

Estoy confundido... ¿Esta solicitud de cambio/cambio será oficial o no?
Teniendo el mismo problema aquí, las traducciones simplemente no se aplican solo a las plantillas.
Tener redux, componentes personalizados de vista de árbol, etc., todo generado a partir de objetos javascript EN CÓDIGO, no por plantilla

Es oficial y está por llegar, pero primero tuvimos que hacer otros cambios profundos en el compilador, por lo que no estaba listo para 4.3.

¿Se sabe en qué versión exacta estará disponible/está prevista esta función? 4.3.1, 4.3.2 ... 4.3.X ?

No hay más versiones principales/secundarias para la rama 4.x (solo parches: https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md), lo que significa que será para 5.x , no estoy seguro de cuál.

¿Todavía se espera que esto entre en 5.x? No puedo verlo en las betas. Gracias

Podría estar en v50.x no v5.x 😂

5.x sí, pero lo más probable es que no sea en 5.0

Le jeu. 3 de agosto de 2017 a las 12:56, vltr [email protected] a écrit:

Podría estar en v50.x no v5.x 😂


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/angular/angular/issues/11405#issuecomment-319936876 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAQMorXMbyI8l6K3QA4jmXEKawiEC46xks5sUad0gaJpZM4J2pkr
.

Hola, @ocombe . Estoy muy interesado en el proceso para que esto funcione y la forma en que funciona el compilador actualmente hace que esta sea una tarea más difícil. ¿Tiene alguna claridad en cuanto a cómo se ve la línea de tiempo o todavía no es probable que sea 5.0 sino 5.x?

@arackow probablemente estará en 5.x, @vicb está trabajando en los últimos cambios en el compilador que finalmente lo harán posible

@ocombe ... ¿hay algún documento de diseño que describa un concepto de la solución para cadenas fuera de las plantillas? Estamos en una fase de desarrollo del proyecto donde sería genial saberlo, así podríamos preparar de alguna manera nuestra solución temporal y luego sería mucho más fácil cambiar a la sintaxis final de Angular.

Teníamos un documento de diseño, pero estaba basado en la versión anterior del compilador y probablemente no sea la implementación que terminaremos haciendo. Haremos un nuevo documento de diseño público una vez que tengamos una mejor idea sobre la nueva implementación.

@ocombe Tengo que hacer +1 en esta función. Realmente lo necesito en este momento jajaja :+1: ¡Gracias chicos por hacer herramientas increíbles! :)

Según entiendo el documento de diseño actual, un autor de una biblioteca AOT debería proporcionar las traducciones para todos los idiomas requeridos por las diversas aplicaciones que utilizan esta biblioteca.
¿He entendido esto correctamente?

Este es un buen punto @ gms1.
Probé esto aquí .
Como autor de la biblioteca, solo tiene que agregar las etiquetas i18n.
No debe compilar su biblioteca en " ngfactories " (consulte la charla de Jason Aden en ng-conf 2017), por lo que la etiqueta de traducción no se reemplazará. De esta manera, cuando ejecute el comando ng xi18n , también obtendrá una traducción en el xliff para los archivos en su carpeta node_modules.

Entonces, no tiene que proporcionar traducciones, sino agregar etiquetas i18n con significados útiles.

citado del documento de diseño:

Para AOT, el código fuente se transforma para reemplazar las llamadas de servicio por traducciones estáticas. Para hacer eso, usaremos un transformador TypeScript.

Entonces, ¿qué significaría esto si una biblioteca angular (AOT) se publicará generalmente en forma transpilada? No he encontrado ninguna referencia a .metadata.json en este documento

No debe compilar su biblioteca hasta el código final, sino prepararla para que el desarrollador la compile usando su código. Vea lo que @jasonaden menciona aquí . Esto también significa que puede hacer que su biblioteca sea traducible agregando la etiqueta i18n.

@ gms1 como dije:

Teníamos un documento de diseño, pero estaba basado en la versión anterior del compilador y probablemente no sea la implementación que terminaremos haciendo.

Y el compilador AOT se está cambiando ampliamente para v5, debería ser más fácil para libs publicar código "aot-ready".
Para i18n también queremos que esto sea lo más fácil/flexible posible, probablemente será algo como: las bibliotecas pueden publicar archivos de traducción que puede usar, pero que también puede anular si lo prefiere, y debería poder proporcionar idiomas adicionales también si la biblioteca no lo admite de forma predeterminada

¡Gracias @ocombe por esta aclaración!

@ocombe ¿Significa esto que las funciones de ngx-translate estarán disponibles en el propio angular?

@ montreal91 ninguna de las partes de ngx-translate se puede implementar tal como está en angular, mi lib tiene un enfoque muy ingenuo, funciona "principalmente", pero queremos ser mucho más eficientes con el marco.
Dicho esto, angular proporcionará características similares (incluso si la implementación final será diferente).

Este es mi enfoque (FLUX) mientras trabajo en un sistema de notificación de interfaz de usuario basado en (https://github.com/PointInside/ng2-toastr). El problema es que el contenido de la notificación se define en la llamada de servicio en lugar de una plantilla para ser administrada por el sistema angular i18n (xi18n)

No es lo que me gustaría, pero es una solución _funcional_. Puede _extraer_ la idea de los siguientes fragmentos de código. Espero eso ayude :)

en cualquier sitio

// this call in any other component, service... 
// "info" method parameter is the "id" of the HTML element in template NotificationComponent.html
this.notificationActionCreator.success("myMessage");

Componente de notificación.ts

@Component({
    selector: 'notification-cmp',
    templateUrl: '../../public/html/NotificationComponent.html'
})
export class NotificationComponent implements OnInit, OnDestroy, AfterViewInit {

    notificationMap: Map<string, any> = new Map();
    subscription: Subscription;

    constructor(private toastr: ToastsManager,
                private vcr: ViewContainerRef,
                private store: NotificationStore,
                private elementRef: ElementRef) {

        this.toastr.setRootViewContainerRef(vcr);
    }

    ngOnInit() {
        this.subscription = this.store.payload
            .subscribe((payload: NotificationStorePayload) => this.handleStorePayload(payload));
    }

    ngOnDestroy(): void {
        this.store.destroy();
        if (null != this.subscription) {
            this.subscription.unsubscribe();
        }
    }

    ngAfterViewInit(): void {
        this.elementRef.nativeElement.querySelectorAll("div[notification-title][notification-text]")
            .forEach(el => this.notificationMap.set(el.id, {
                    title: el.attributes["notification-title"].value,
                    text: el.attributes["notification-text"].value,
                })
            );
    }

    handleStorePayload(payload: NotificationStorePayload): void {

        if (null != payload.action) {
            let notification = this.notificationMap.get(payload.notification.id);

            switch (payload.notification.type) {
                case NotificationType.SUCCESS:
                    this.toastr.success(notification.text, notification.title);
                    break;
                case NotificationType.INFO:
                    this.toastr.info(notification.text, notification.title);
                    break;
                case NotificationType.WARNING:
                    this.toastr.warning(notification.text, notification.title);
                    break;
                case NotificationType.ERROR:
                    this.toastr.error(notification.text, notification.title);
                    break;
            }
        }
    }
}

Componente de notificación.html

<div hidden
     id="myMessage"
     i18n-notification-title="@@notificationTitleMyMessage"
     i18n-notification-text="@@notificationTextMyMessage"
     notification-title="Greeting"
     notification-text="Hello world"></div>

<div hidden
     id="error"
     i18n-notification-title="@@notificationTitleError"
     i18n-notification-text="@@notificationTextError"
     notification-title="Error"
     notification-text="Something went wrong!"></div>

Ahora que se lanzó Angular 5, ¿tenemos algún cambio sobre cuándo se integrarán los cambios en el módulo i18n?

Parece que esta característica depende de los cambios en el compilador angular, pero los equipos responsables del compilador parecen menos interesados. No parece que haya una tarea o un PR o compromisos:- (. Perdón por desahogarme, pero esta solicitud de función que describe una funcionalidad muy básica presente en todos los demás marcos de traducción ahora tiene más de un año. He dado Espero que llegue esta característica esencial. Al menos para 5.x...

Chicos mantengan la calma. No es una tontería implementarlo en un compilador AOT. Ten un poco de confianza, @ocombe dijo:

"lo más probable es que sea en 5.x, @vicb está trabajando en los últimos cambios en el compilador que finalmente lo harán posible"

Sí, estamos trabajando en el tiempo de ejecución i18n en este momento, que es el primer paso.
Runtime i18n significa: un paquete para todos los idiomas, las bibliotecas compiladas por AOT pueden usar i18n, y tal vez más adelante la capacidad de cambiar el idioma en tiempo de ejecución. También significa que podemos hacer traducciones en tiempo de ejecución, lo cual es necesario para las traducciones dentro del código (porque necesitamos un analizador en tiempo de ejecución para las traducciones, etc.).
Una vez hecho esto, la siguiente prioridad serán las traducciones dentro del código.

Pero no pudimos hacer el tiempo de ejecución i18n antes de cambiar el compilador para usar transformadores TypeScript (que se hizo para 5.0)

¿Alguna idea de qué versión 5.x tendrá qué mejoras i18n? ¿Algo que se lanzará con 5.0.0 en sí?

5.0:

  • nuevas canalizaciones i18n (fecha/número/porcentaje/moneda) que no usan la API internacional que solucionó algo así como 20 errores porque ahora funcionan igual en todos los navegadores + algunas otras mejoras (parámetro local, nuevos formatos adicionales, parámetro de zona horaria para el tubo de fecha, ...)
  • nueva función i18n api para bibliotecas y componentes: https://next.angular.io/api?query=getlocale
  • mejor integración con la cli

5.1 o 5.2 (si no hay un bloqueador inesperado):

  • tiempo de ejecución i18n

5.x:

  • Traducciones de código i18n (no solo plantilla)

Y otras cosas que agregaremos en el camino pero que aún no están decididas (puede seguir https://github.com/angular/angular/issues/16477).

Solo pensamientos curiosos, aunque llegué un poco tarde, solo considerando el soporte i18n en un archivo TS, ¿por qué no pensamos en la sintaxis de anotación? (Encontré que alguien lo ha mencionado anteriormente también)

Ejemplo sería:
@i18n (id='mensaje1')
mensaje1 = "Este es un mensaje que necesita ser traducido";

@i18n (id='Mensaje dinámico')
dynamicMessage = "Este es un mensaje dinámico con {0}";

Con la anotación para dynamicMessage, podemos inyectar una función a través de la anotación en esta instancia de cadena, cuyo nombre es format , luego podemos usar como se muestra a continuación:
var finalMessage = mensajedinámico.formato('valor1')

Un enfoque similar podría ser posible para cuidar los parámetros nombrados , etc.

Supongo que la pregunta no es cómo hacer una buena experiencia de desarrollador. La pregunta es acerca de la compilación.

Además, ¿qué sucede si cambia el mensaje 1 a otra cadena? Entonces, todas las variables i18n deben ser siempre constantes. No creo que usar variables funcione en absoluto. Por ejemplo, Symfony tiene un servicio de traducción con una función de traducción que funcionaría así en la sintaxis de JS: let translated = this.translator.trans('Hello %name%', [{'%name%': nameVariable}]); que dará como resultado: <source>Hello %name%</source> <target>Bonjour %name%</target>

@MickL el objetivo de la traducción actual -aot es hacer un programa mínimo y eficiente. Es por eso que aún no existe un enfoque para la traducción dinámica.
Creo firmemente que el enfoque actual es realmente bueno, en el sentido de que no estamos usando el servicio dinámico para traducir cadenas. Eso significa que si sabe que algún texto es estático, tradúzcalo de esa manera sin usar un servicio.

El problema con la traducción dinámica es simple, que es si va a traducir una cadena cada vez que la muestra. No es una muy buena manera,
¿Por qué?

  1. Porque tienes un diccionario de varios idiomas en la memoria cuando no lo estás usando.
  2. Cada vez que muestra un texto dinámico, debe ir al mapa y encontrar una clave y luego encontrar la traducción del idioma. CADA VEZ porque tienes un "idioma principal".

Desde mi punto de vista, la solución futura debería ser:

  1. Backend te da el texto que quieres traducir.
  2. Reemplace/(o descargue desde el backend, que es el enfoque actual) cada texto que está mostrando en el idioma actual/principal. (Reemplace todo, obtenga tiempo, pero no necesita encontrar dos teclas cada vez que quiera mostrar una etiqueta simple).
  3. Solo el texto verdaderamente dinámico puede ser reemplazado y/o solicitado al backend.

Piénselo, si realmente tiene texto dinámico para mostrar, puede recibirlo desde el backend, y si realmente necesita una copia de ese "texto dinámico", siempre puede usar el caché para eso.

En mi opinión, no hay necesidad de discutir más este tema. De hecho, hay un chico (Olivier Combe) trabajando A TIEMPO COMPLETO en i18n. AOT es muy especial y se tuvo que trabajar mucho antes de que este problema fuera posible. Pronto tendremos traducciones dinámicas: ¡Ya no es necesario construir cada idioma por separado! Cuando esto esté hecho, tendremos traducciones dentro del código (este problema) más adelante. Dijo que el camino hasta que se resuelva este problema es de esperar que tome medio año a partir de ahora.

Si está interesado, consulte su discurso en Angular Connect el 11/07/17 sobre el presente y el futuro de i18n en Angular: https://youtu.be/DWet6RvhHWI?t=21m12s

Esto huele como un buen caso de uso para cadenas de plantillas etiquetadas con mecanografiado...

Esto huele en general. Visito este hilo una vez al mes para verificar el progreso y he dejado de estar decepcionado debido a las bajas expectativas. Lo único que quieren los desarrolladores es tener las mismas opciones para la traducción de cadenas en el código que en las plantillas. Mi código está plagado de cadenas de plantillas traducidas ocultas debido a esta falta de funcionalidad. Si esto finalmente se logra con un servicio o anotaciones es irrelevante y no importa si toma un milisegundo extra. Ya estoy viendo algo en busca de cambios cuando elijo una cadena del código. El único requisito es que el código se analice y las cadenas relevantes terminen en los mismos archivos con el mismo formato que mis traducciones basadas en plantillas.

@eliasre puede probar https://github.com/ngx-translate/i18n-polyfill si tiene prisa por la traducción del código
Sin embargo, no promete que será lo mismo, en realidad probablemente será diferente (como más fácil de usar), hay limitaciones a lo que es posible en este momento... y agregará ~ 80ko a su aplicación para usar esa liberación

Puedes usar ngx-translate si no quieres esperar

@ocombe , ¿le importaría proporcionar actualizaciones sobre el progreso para que podamos realizar un seguimiento y planificar de acuerdo con los cronogramas de desarrollo cuando esperamos decisiones sobre qué complementos o marcos usar? seria muy util y agradecido

@eliasre Creo que Google quiere hacer una buena solución de una vez. Sin romper los cambios en el futuro. Estoy de acuerdo en que está tardando bastante más de lo que pensamos.

¡No molesten al pobre @ocombe , está trabajando MUY MUY duro!
¡Seguid así! :)

No soy el que está trabajando en esta función, y son las vacaciones, te lo haré saber tan pronto como sepa más

gracias @ocombe

gracias @ocombe , cualquier actualización sería muy apreciada aquí. Estuve esperando desesperadamente el tiempo de ejecución i18n durante los últimos meses, y la última compilación ETA fue 5.2. ¿Puede informarnos tan pronto como tenga una ETA actualizada aquí?

Perdón por ser tan persistente, pero compilar para 20 idiomas termina siendo insoportablemente lento en este momento.

Como Angular 5.2 está disponible y desafortunadamente no pude encontrar nada relacionado con i18n (¿o pasé por alto algo?) ... - @ocombe , ¿tal vez podría actualizarnos sobre el plan de lanzamiento? ¡Muchas gracias y muchas gracias por su esfuerzo en i18n!

@ocombe no es el tipo que estamos esperando aquí... mira el enlace de YouTube en este comentario: https://github.com/angular/angular/issues/11405#issuecomment -343933617

La planificación está en constante evolución. Cada vez que doy una fecha de lanzamiento probable, resulta que algo más tiene prioridad o se vuelve obligatorio y cambia la fecha una vez más. Sé lo decepcionante que es para todos los que están esperando esta función, y estoy haciendo todo lo posible para aumentar la prioridad.
Tenemos una reunión mañana para discutir el retraso/la planificación de i18n, les avisaré si obtengo algo nuevo.

@ocombe si lanzas i18n este mes te compro un paquete de 24 cervezas artesanales

Agregaré 24 botellas de cerveza alemana y otras 24 botellas si pregunta qué están haciendo Angular Elements y el soporte de la biblioteca. Maldita sea, no obtener información de lo que está pasando es horrible.

@ocombe , tiene esta rara oportunidad única en la vida de adquirir 72 botellas de cerveza artesanal costosa y hacer feliz a la comunidad de desarrollo. Cumpliremos nuestras promesas si cumples estas cosas, amigo mío.

@MickL Angualr Elments, según tengo entendido, nos permitirá crear páginas que no sean SPA y usar componentes angulares como elementos nativos (también como widgets propios)

Sí, lo sé. Estas son otras 2 características que todos están esperando, pero nadie sabe cuál es el estado y cuándo esperarlo...

Si alguien promete agregar las últimas 27 botellas de cerveza, ¡podemos comenzar la cuenta regresiva!
http://www.99-botellas-de-cerveza.net/language-javascript-1948.html

Los agregaré, @ocombe : nombra tu marca favorita: D

Editar: alguien crea un servicio similar a eth bounty llamado beerbounty: p

Tal como lo prometimos, una pequeña actualización: todavía tenemos como objetivo lanzar el tiempo de ejecución i18n en v6, lo que nos da 5 semanas. Será breve, probablemente se agregará en uno de los últimos lanzamientos y estará detrás de una bandera.
El tiempo de ejecución i18n debería venir con traducciones de código, porque así es como funcionará para las plantillas de todos modos (debería usar el mismo mecanismo).
Dicho esto, no es seguro que el servicio esté listo al 100 %, y podríamos posponerlo para asegurarnos de no romperlo justo después de lanzarlo, si creemos que es la elección correcta. Pero seguirá el tiempo de ejecución i18n en cualquier caso (esa es nuestra hoja de ruta), y no necesitamos una versión principal para lanzarlo porque estará detrás de una bandera, y no debería romper nada de todos modos).

Lo que podría impedirnos liberarlo a tiempo:

  • si nos topamos con un problema inesperado (ya sabes cómo funciona el desarrollo)
  • si rompe las aplicaciones internas de Google porque nos equivocamos en alguna parte
  • si surge algo de máxima prioridad y tenemos que cambiar nuestro enfoque
  • si una de las cosas nuevas de las que depende está bloqueada o retrasada (el tiempo de ejecución i18n depende de algunos cambios internos importantes en los que están trabajando otros miembros del equipo)
  • Desarrollador sénior de angularJS, ha estado usando la biblioteca de traducción de PascalPrecht durante 3 años.
  • me emocionó Angular 2 novato. Navegando ingenuamente https://angular.io/guide/i18n
  • Integrando con éxito i18n en mi proyecto profesional
  • Pasar un día entero jugando con todas las etiquetas codificadas de forma rígida del front-end, transfiriéndolas a un archivo xlf de más de 100 kb
  • En la necesidad de traducir etiquetas en bruto dentro de los servicios ng
  • Buscando en Google, estar aquí
  • Descubra que no hay solución antes de que Angular 6 envejezca.
  • yo rn
    mfw

@Macadoshis puedes usar mi biblioteca polyfill por ahora: https://github.com/ngx-translate/i18n-polyfill

¡@Macadoshis ahora imagina lo que hemos pasado desde alpha.46! ;)

Gracias por indicarme i18n-polyfill @ocombe , pero optaré por ngx-translate ya que admite la carga asíncrona de las claves de traducción.
La fábrica de i18n-polyfill para el proveedor TRANSLATIONS parece que solo admite la carga sin procesar sincronizada de una configuración regional fija conocida antes del arranque.

// sync loading
return require(`raw-loader!../locale/messages.${locale}.xlf`);
// @ngx-translate/i18n-polyfill/esm5/ngx-translate-i18n-polyfill.js
Tokenizer.prototype._advance = function () {
    //...
    this._index++;
    // "this._input" needs to be a string and can't handle a Promise or an Observable
    this._peek = this._index >= this._length ? $EOF : this._input.charCodeAt(this._index);
    this._nextPeek = this._index + 1 >= this._length ? $EOF : this._input.charCodeAt(this._index + 1);
}

@ocombe, ¿qué tan cerca está el polyfill que escribiste de lo que se está lanzando? ¿Algo que debamos tener en cuenta o para lo que debamos prepararnos? Además, ¿le importaría enumerar una lista de las funciones con i18n que se lanzarán en la versión 6 y cómo van las pruebas con i18n?

No tengo más detalles sobre el servicio de traducción de códigos por ahora, probablemente trabajaremos en ello la semana que viene (voy a viajar a Mountain View). Todo lo que sé es que detrás de escena será similar a goog.getMsg de la biblioteca de cierre (ya que es lo que Google está usando internamente por ahora): https://github.com/google/closure-library /blob/db9bc1a2e71d4b6ee8f57eebe37eb0c6494e9d7e/closure/goog/base.js#L2379 -L2387 que también es similar a mi polyfill.

En v6, lanzaremos el tiempo de ejecución i18n: un paquete para todas las configuraciones regionales, las traducciones se resolverán en el tiempo de ejecución y, tal vez, las traducciones del código si tenemos tiempo (de lo contrario, llegará poco después). Todo eso estará detrás de una bandera porque requiere usar el nuevo renderizador (llamado ng-ivy) que no será probado en batalla.

¡Gracias! @ocombe ... ¡eso suena muy bien!
¿Habrá cambios importantes en la sintaxis para la traducción de plantillas? Estoy pensando en agregar traducciones a nuestro proyecto ahora, pero no quiero rehacerlo por completo en unas pocas semanas.

No, la sintaxis de la plantilla será la misma

Gracias @ocombe por la gran noticia, esto es extremadamente prometedor. ¿Qué tipo de preparación para la producción podemos esperar del renderizador ng-ivy que se lanzaría con v6? Entiendo que no se probará en la batalla, pero aún estaría listo para su uso en producción y funcionaría en todos los principales navegadores de versiones casi actuales, ¿verdad?

Puede seguir el progreso aquí: https://github.com/angular/angular/issues/21706
No creo que todo esté listo para v6, ya que está bajo una bandera, seguiremos progresando en esto incluso después del lanzamiento de v6 (no es un cambio importante ni nada por el estilo)
Honestamente, no estoy seguro de qué son todas esas cosas: D
Sé que ya está funcionando una aplicación hello world de la cli.
Creo que algunas de esas cosas son necesarias para beneficiarse de las optimizaciones del nuevo renderizador, pero probablemente pueda funcionar sin tener todo comprobado.
Dicho esto, también significa que no estará listo para la producción, no apueste su producto todavía. No se probará en las aplicaciones internas de Google y es posible que tengamos que hacer algunos cambios importantes para solucionar el problema. El uso del nuevo renderizador es a su propia discreción y bajo su propio riesgo.

¿Algo de esto está presente en la v6-beta4?

No, no es. Consulte esta hoja de ruta, esta característica está bloqueada por el tiempo de ejecución de i18n.

actualiza @ocombe ?

El primer PR para el tiempo de ejecución i18n se fusionó con el maestro, junto con una aplicación de demostración hello world que usaremos para probar las funciones. Funciona en tiempo de ejecución y, en teoría, admite traducciones de código, incluso si aún no hay un servicio para ello.
Por ahora es un soporte mínimo (cadenas estáticas), estamos trabajando para agregar nuevas funciones (haré que la extracción funcione la próxima semana y luego la cadena dinámica con marcadores de posición y variables).
Después de eso, haremos el servicio de traducción de códigos.
Tan pronto como finaliza una nueva característica, se fusiona con la maestra, no tendrá que esperar por una nueva especialización.

¡Las características de @ocombe i heart i18n ya deberían estar aquí en v4.3! Tantos lanzamientos pero nada en i18n. ¿Puede el administrador del equipo angular asignar más trabajos/desarrolladores en él? Puedo entenderlo solo o dos desarrolladores no pueden avanzar rápidamente, esta característica i 18n es la característica imprescindible para fingir que angular es una aplicación comercial/aplicación grande con compilación rápida, por supuesto estas dos características son las más importantes para aplicaciones grandes, ¿no crees? Gracias

Creo que lo único que podemos decirle a @ocombe es agradecerle todo el esfuerzo que está poniendo en esta función. Estoy seguro de que si no hay más desarrolladores no es porque él no los pidió. Solo déjalo hacer, estoy seguro de que no nos arrepentiremos cuando se publique.

Solo para referencia...

Tengo una herramienta alternativa para importar y exportar cadenas, desarrollada originalmente para usar con Aurelia, que incluye soporte para cadenas almacenadas en archivos json ; es bastante útil, ya que Webpack le permite importar directamente json archivos en sus archivos ts , lo que le da a su código un fácil acceso a esas cadenas.

Esta herramienta también funciona con plantillas de Angular y tiene muchas otras características útiles: utilícela si lo desea, o siéntase libre de tomar prestadas ideas para mejorar las herramientas de Angular. También hay un cargador de paquetes web basado en esto: consulte el enlace en los documentos.

https://www.npmjs.com/package/gulp-translate

Tenemos un problema más simple y no estoy seguro de si necesitamos la próxima función (o el polyfill de @ocombe).

Definimos la estructura de todas las formas reactivas con constantes, en las que establecemos las propiedades de cada elemento de forma. Por ejemplo:

loginForm = [
  {
    type: 'email',
    placeholder: 'EMAILPLACEHOLDER' // "Your email"
  },
  {
    type: 'password,
    placeholder: 'PASSWORDPLACEHOLDER' // "Your password"
  }
];

Actualmente usamos ngx-translate , por lo que en la plantilla traducimos cadenas así:

<input *ngFor="let ele of loginForm" [type]="ele.type" [placeholder]="ele.placeholder | translate">

Ahora nos gustaría migrar a Angular i18n. Sin embargo, dado que no todas nuestras cadenas están en una plantilla, parece que no podemos usar Angular i18n de fábrica.

Sin embargo, nuestra situación parece más simple que aquella en la que las traducciones deben recuperarse en tiempo de ejecución. Todos nuestros textos están predefinidos en constantes y podrían reemplazarse en tiempo de compilación, tal como lo hace actualmente x18n para las cadenas en las plantillas.

Por ejemplo, podríamos tener una cadena más compleja como la siguiente

placeholder: 'I18N:description|meaning@<strong i="16">@PASSWORDPLACEHOLDER</strong>:Your password'

En tiempo de compilación, la cadena podría reemplazarse por:

placeholder: 'Your password'

¿Es esto algo que podría considerarse para su implementación?

definitivamente podría hacer eso con el tiempo de ejecución i18n, podría usar el nuevo servicio i18n en una tubería, por ejemplo, para transformar sus marcadores de posición en sus traducciones

Veo que este hilo se ha abierto durante algún tiempo, muestra el mayor interés por desarrollar sitios multilenguaje en Angular de una manera simple, abordando tanto HTML como textos de código de componente de cerca.
ocombe, por favor, no se olvide de enviar a todos los suscriptores una alerta cuando eso se haga. Tengo entendido que está a la vuelta de la esquina en mayo de 2018. ¡Y gracias por sus amables contribuciones!

@ocombe , ¿deberíamos usar Ivy para poder usar estos servicios de tiempo de ejecución o también funcionará con el motor antiguo?

solo sera con ivy, que por ahora no puedes usar ya que no esta terminado

¡Gracias por todo tu arduo trabajo @ocombe !

¿Algún comentario sobre cuándo podremos usar estas nuevas funciones?

Ivy se puede habilitar en angular 6 con un indicador de compilador en este momento, en un estado previo al lanzamiento. ¿Se pueden usar estas nuevas funciones 18n con la versión preliminar de Ivy en este momento?

Todavía no, pero estoy haciendo un buen progreso (trabajando a tiempo completo en este momento). Publicaré una actualización aquí una vez que esté disponible en el maestro para probar

muchas gracias @ocombe ! Muchas personas se están beneficiando de su arduo trabajo. ¡Todos lo apreciamos mucho!

@ocombe ¿Todavía están planeadas las traducciones estáticas en ts? Me refiero al reemplazo de expresión de tiempo de compilación, probablemente con transformación mecanografiada.
De lo contrario, ¿podremos conectar la transformación ts personalizada en la canalización ng build sin extraer?

No estoy seguro de seguir lo que quieres decir @TinyMan ? ¿Quiere decir poder fusionar traducciones en el momento de la compilación (como ahora) o poder usar traducciones en el código ts (además de las traducciones de plantillas que ya tenemos)?

@ocombe Me refiero a poder usar la traducción en ts, pero no a través de un servicio o traducción DI/runtime. Me refiero a la traducción en tiempo de compilación pero para mecanografiado. Como el preprocesador C. Pensé que estaba planeado según el comentario de vicb :

  • también podemos admitir traducciones estáticas como lo hacemos hoy para las plantillas: las cadenas se reemplazarían en tiempo de compilación, mejor rendimiento pero una versión de la aplicación por configuración regional,

Por ejemplo, quiero poder escribir:

export const Notifications = {
    newComment: i18n("New comment notification@@newComment", "New comment on your story !"),
    newStory: i18n("New story notification@@newStory", "{{0}} wrote a new story !"),
}

Y luego esto se traduce a algo como (en fr):

export const Notifications = {
    newComment: "Un nouveau commentaire a été ajouté a votre article !",
    newStory: "{{0}} a écrit un nouvel article !",
}

Actualmente, para ese propósito, uso ngx-translate con un marcador personalizado para la extracción ( i18n en este ejemplo), y cuando necesito mostrar el mensaje, debo llamar a this.translate.instant(Notifications.newStory, ["TinyMan"]) que hace la traducción. + la interpolación. Lo que quiero decir es que necesitaríamos poder escribir Notifications.newComment sin llamar al servicio de traducción. Y para la interpolación de cadenas, podríamos tener un método de interpolación que solo haga la ICU y la interpolación (la cadena de plantilla ya estaría traducida)

Notification.newStory // {{0}} a écrit un nouvel article, static string, no runtime translation
template(Notification.newStory, "TinyMan") // TinyMan a écrit un nouvel article !

Aquí simplemente nos deshacemos de la solicitud HTTP de traducción y la sobrecarga del servicio.

Espero que se aclare?

Lo que describe está, de hecho, en la hoja de ruta para i18n.
Por el momento, https://github.com/ngx-translate/i18n-polyfill hará el trabajo.

@TinyMan Todavía no estoy seguro de si será a través de un servicio o una función global. Ambos son posibles, pero un servicio también tiene muchas ventajas: puede simularlo para pruebas o reemplazarlo con el suyo propio, también puede cambiar su comportamiento para cada módulo/componente
Sé que internamente Google usará Closure i18n (a través goog.getMsg ), que es una función global, y lo más probable es que la función sea reemplazada por el servicio durante la compilación en función de una bandera global. Intentaré ver si esa bandera también se puede usar externamente, pero no veo por qué no. Pero si usa eso, será para plantillas y traducciones de código.

@ocombe Quiero expresar mi agradecimiento aquí también. Aprecio mucho el trabajo que está haciendo en esto que será increíblemente útil para mí en mi trabajo. Una pregunta: ¿hay alguna manera, o _habrá_ alguna manera, de hacer una compilación AOT que solo haga un conjunto de archivos de paquete que, al buscar texto, haga referencia al xlf en tiempo de ejecución para obtener la cadena correcta?

así que, en esencia, necesitaría 1 archivo xlf por idioma más los 5 o 6 archivos del paquete. En este momento, si tenemos 10 idiomas y la compilación AOT tiene más de 50 archivos: un conjunto de archivos de paquete por idioma...

No sé el esfuerzo o la complejidad de algo así, pero sería bueno tener una compilación pero con solo 1 conjunto de archivos.

sí, eso es lo que haremos con ivy, tiempo de ejecución i18n
empaque su aplicación una vez y cargue las traducciones en tiempo de ejecución (puede cargar las traducciones de forma diferida)

@ocombe eso. es. increíble.

Eso me hace tan increíblemente feliz. ¡GRACIAS!

Sin la capacidad de traducir plantillas externas, la función i18n es completamente inútil para mí.

@ocombe ¡Hola Olivier!
¿Alguna actualización?

¡Gracias!

Si se hace, no importaría, ya que tenemos que esperar a que se complete Ivy, que está programado para Angular 7 (septiembre/octubre de 2018)

Para Angular 7, este problema tendrá dos años LOL.
En cualquier caso Ivy ha sido lo que más ha retrasado esta nueva característica...

@ocombe , es genial escuchar eso. Actualmente estamos atascados usando un servicio i18n heredado que lanzamos desde cero simplemente por este motivo. No poder hacerlo en JS hace que sea extremadamente difícil hacer algunas cosas simples para nosotros:

  • Componentes dinámicos
  • Integración con servicios de terceros donde tenemos que proporcionar algún texto localizado para
  • Mostrando modales de confirmación dinámica
  • Nuestra API devuelve el error types . En nuestro contexto, necesitamos localizar dinámicamente estos errores y un enfoque basado en plantillas sería confuso.
  • Queremos usar TitleService como sugiere el equipo de Angular, ¡pero no hay forma de proporcionar texto localizado!

Tengo un poco de curiosidad sobre cómo el equipo de Angular se ocupa de esto actualmente...

Hola @vincentjames501 ,
En nuestra empresa tratamos de hacer lo mismo que está haciendo ahora, pero fue muy problemático, así que terminamos usando el i18n-polyfill mencionado anteriormente en este hilo, y hasta ahora funciona muy bien.
El único inconveniente que tenemos es el tamaño de los paquetes de nuestra aplicación. Tenemos tres archivos de traducción, y cada paquete los contiene todos adentro (no hemos descubierto una forma de generar el paquete solo con la traducción que usa). Pero todo esto son solo molestias que esperamos se resuelvan cuando Ivy esté fuera.
Salud,

Incluí un mapa de traducción y lo volví a exportar en el archivo environment.ts de cada idioma. Funciona sin problemas, no está incluido en todos los paquetes y no requiere una biblioteca externa. El único problema que tengo es que, dado que cada sitio es diferente, no puedo tener el mismo trabajador de servicio para todos los idiomas y si alguien cambia de idioma, mi sitio no puede saber si ya está registrado para recibir notificaciones automáticas o no...

@ocombe ¿ alguna noticia en angular 6?

No estará en Angular v6, como se explicó anteriormente. Dependemos de Ivy, que está planeado para v7.

@ocombe , ¿puedo sugerir que bloquee este hilo, para que solo el equipo pueda brindar actualizaciones significativas cuando corresponda y evitemos las preguntas repetitivas que sigue respondiendo?

Mi truco para usar con el Angular actual es usar un ng-template y crear la vista incrustada programáticamente:

<ng-template #messagetotranslate i18n>This message should be translated</ng-template>

y luego en el archivo ts del componente:

@ViewChild('messagetotranslate') messagetotranslate: TemplateRef<any>;

createTranslatedMessage(): string {
  return this.messagetotranslate.createEmbeddedView({}).rootNodes[0].textContent;
}

El método createTranslatedMessage devuelve el mensaje traducido. Aunque estoy usando la plantilla para declarar el mensaje que no es óptimo, esto hace posible que la herramienta de traducción CLI lo registre en los archivos xlf, y tengo una forma de obtener el mensaje traducido mediante programación para usarlo fuera de las plantillas.

¡Con suerte, la API también funcionará para las rutas! Por ejemplo

export const routes: Routes = [
 {
  path: '',
  component: HomeComponent,
  data: {
   title: i18n('Home'),
   breadcrumb: i18n('Home')
  }
 }
]

Si se lanza esta función, ¿habría un cambio significativo con respecto a la API i18n actual? ¿Me recomendaría comenzar mi proyecto con i18n ahora o debería esperar a la nueva i18n Api cuando se lance Angular 7?

Cualquier actualización ¿Cuándo obtendremos soporte de traducción dinámica y en tiempo de ejecución?

Las traducciones en tiempo de ejecución están hechas y fusionadas (con ivy), pero el lado del compilador aún no está terminado.
Estoy trabajando en las expresiones de la UCI en este momento.
Todavía no he comenzado a codificar las traducciones dinámicas (servicio), pero probablemente sea lo próximo que haré después de las expresiones ICU.

@ vincentjames501 ¿Podemos usar i18n-polyfills con la expresión ICU? No tengo solución para implementar eso

@ocombe , ¿puede aclarar la diferencia entre el tiempo de ejecución y las traducciones dinámicas?

probablemente no haya una denominación oficial, pero la forma en que lo veo es:

  • tiempo de ejecución: las traducciones se resuelven en tiempo de ejecución, es decir, no durante la compilación (como lo hacemos actualmente). Se aplica a todo tipo de traducciones (plantillas, o en código)
  • dinámico significa que solo sabe lo que quiere traducir en tiempo de ejecución y no puede hacerlo en tiempo de compilación. Se aplica principalmente a traducciones "en código", utilizando un servicio. Supongo que podría considerar que las expresiones ICU son dinámicas en el sentido de que dependen de una variable, pero aún puede calcular todas las posibles traducciones en el momento de la compilación porque el número de casos es finito.

Pospuse agregar soporte i18n al proyecto actual que estamos desarrollando, pero nos estamos acercando al lanzamiento, ¿alguna idea si esto será definitivo en angular 7? ¿O debería considerar otras formas de agregar traducciones?

@ andrei-tatar i18n funciona perfectamente desde Angular 2. Los únicos inconvenientes:

  • Sin traducciones de código (este problema) -> Si lo necesita, use i18n-polyfill
  • Si construye AOT (recomendado), la aplicación debe construirse para cada idioma por separado
  • Dado que cada aplicación se crea por separado, al cambiar el idioma debe volver a cargar la página

Para los dos últimos puntos, podría usar @ngx-translate en su lugar. Pero funciona de manera diferente al i18n integrado de Angular, por lo que una actualización posterior podría llevar algún tiempo. Para el polyfill, la actualización no tardará y probablemente no habrá cambios importantes.

@ocombe

Cómo podemos manejar el operador condicional usando la función Angular i18n

[email protected]> escribió:

@shobhit12345 https://github.com/shobhit12345

Usamos ngSwitch como plantilla para todos los mensajes, por lo que podemos adjuntar etiquetas i18n a
ellos individualmente.

EsconderShowHistoria

Usamos mucho este método para sortear las traducciones dinámicas que faltan.
Con un poco de reflexión, se puede expresar una cantidad sorprendente de texto en
de esta manera en las plantillas. Un patrón común es tener una matriz de mensajes,
y luego use esto con ngFor y ngSwitch para crear una plantilla de mensajes,
algo como esto:

t

mensajes = [ 'este es el primer mensaje', 'este es el segundo mensaje' ]

html


i18n="@@firstMesssage">Este es el primer mensaje
i18n="@@secondMesssage">Este es el segundo mensaje

Es algo detallado, ¡pero funciona!


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/angular/angular/issues/11405#issuecomment-415731284 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AGwM6jcWIpwtGxhkH1fwnVXNagRxmMnoks5uT-LxgaJpZM4J2pkr
.

Si se hace, no importaría, ya que tenemos que esperar a que se complete Ivy, que está programado para Angular 7 (septiembre/octubre de 2018)

Ya es octubre. ¿Crees que tendremos las nuevas funciones a finales de octubre?

@lizzymendivil según https://is-angular-ivy-ready.firebaseapp.com Ivy está completa en un 65 % y parece poco probable que se complete en solo 30 días

Sí, la hiedra no se terminará en un mes.

@ocombe , ¿puede bloquear esto para que solo usted pueda publicar actualizaciones? es un poco molesto recibir todas las notificaciones de todos los "¿cuándo se hace?" comentarios

@ocombe parece que Ivy ahora está en aproximadamente el 94 %, ¿crees que podría estar listo para fin de año?

No lo creo. Estar listo para funciones y libre de errores (= usable) es muy diferente. Estamos trabajando principalmente en arreglar las cosas en este momento.

@ocombe ¿podemos creer que i18n vino antes de angular 8?

No lo creo. Estar listo para funciones y libre de errores (= usable) es muy diferente. Estamos trabajando principalmente en arreglar las cosas en este momento.

Ok, gracias por la pronta respuesta, muy apreciada.

¿Alguna actualización de @ocombe que indique cuándo deberíamos esperar (fin de año, veo en los últimos comentarios) la parte de "Traducción de código" disponible junto con "Traducción de plantilla" para la compatibilidad con I18N con Angular? Pensamos en el club ngx-translate-polyfill para lo mismo junto con la función Angular I18n, pero también parece que el soporte xlf no está disponible para fusionar el archivo xlf existente usando https://github.com/biesbjerg/ngx-translate-extract CLI .

Gracias !

@Abekonge

Usamos ngSwitch para generar plantillas en todos los mensajes, por lo que podemos adjuntarles etiquetas i18n individualmente.
Es algo detallado, ¡pero funciona!

¡Gracias por la sugerencia! Parece lo más fácil de entender. Mi pregunta es, ¿todavía usa esta implementación en situaciones en las que la matriz tiene muchos valores, como 10 o más? Parece que el código se volvería muy voluminoso.

No sé si tenemos alguno con tantos, pero por qué no. Si se trata de mensajes que se utilizan en varios lugares, creamos pequeños componentes i18n que son básicamente el interruptor y las etiquetas i18n.

David

23 de enero. 2019 kl. 19.24 USD Andrew Bissada [email protected] :

@Abekonge

Usamos ngSwitch para generar plantillas en todos los mensajes, por lo que podemos adjuntarles etiquetas i18n individualmente.
Es algo detallado, ¡pero funciona!

¡Gracias por la sugerencia! Parece lo más fácil de entender. Mi pregunta es, ¿todavía usa esta implementación en situaciones en las que la matriz tiene muchos valores, como 10 o más? Parece que el código se volvería muy voluminoso.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub o silencie el hilo.

Cómo usar i18n-polifills en las clases de Validator. No puedo usar el mensaje del validador encubierto a través del servicio i18n.

//En componente
this.crForm= this.fb.group({
nombre de usuario: [''],
Contraseña electrónica: [''],
}, { validador: nuevo AccValidator(this.i18n).validate()}
);

// Validador

import { AbstractControl, ValidationErrors, FormGroup, FormControl } from '@angular/forms';
importar {I18n} desde '@ngx-translate/i18n-polyfill';
exportar clase AccValidator{
constructor(i18n:I18n)
{

}
validate() {       
    return (group: FormGroup): createAccountError => {
        if (group) {
            this.i18n("test");
}}}

obtener debajo del error

Error RROR: no capturado (en promesa): TypeError: i18n no es una función
TypeError: i18n no es una función
en FormGroup.eval [como validador] (acc-validator.ts:9)
en FormGroup.AbstractControl._runValidator (forms.js:3433)
en FormGroup.AbstractControl.updateValueAndValidity (forms.js:3387)
en el nuevo FormGroup (forms.js:4326)
en FormBuilder.group (forms.js:7864)

@ocombe

Cómo usar i18n-polyfills con const en archivos .ts

exportar const glossayModel= () => [
{
título: 'datos de prueba',
activo: cierto,
datos: [

        [
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'Past Due',
                data: "test data."
            }

]]}];


{VAR_SELECT, select, Médico {Médico} Dental {Dental} Médico y dental {Médico y dental} Catastrófico y dental {Catastrófico y dental} Catastrófico {Catastrófico} }
{VAR_SELECT, select, Médico {Médico} Dental {Dental} Médico### & Dental {Médico y Dental}
Catastrófico ### & Dental{Catastrófico y Dental} Catastrófico {Catastrófico} }

Cuando estoy usando la expresión ICU con un carácter especial, no se está convirtiendo.

@ocombe ¿Cómo manejar las migas de pan usando i18n-polyfills?

exportar rutas const: Rutas = [
{
sendero: '',
componente: componente de inicio,
datos: {
título: 'Inicio',
ruta de navegación: 'Inicio'
}
}
]

@ocombe

Cómo usar i18n-polyfills con const en archivos .ts

exportar const glossayModel= () => [
{
título: 'datos de prueba',
activo: cierto,
datos: [

        [
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data"
            },
            {
                title: 'test data',
                data: "test data."
            },
            {
                title: 'Past Due',
                data: "test data."
            }

]]}];

Puedes usar así
{
datos: 'datos de prueba',
título: this.i18n({ valor: 'Nombre', id: 'nombre' }),
}
inyecte I18n polyfill en el constructor de componentes como este
privado i18n: I18n
Al usar traducciones en el archivo ts, debe usar ngx-extractor y xliffmerge para traducir esos archivos ts. https://www.npmjs.com/package/ngx-i18nsupport

@JanneHarju
no funciona, no obtiene los datos en el archivo xlf.

Aquí está mi guión de traducción:
"translate-i18n": "ng xi18n --output-path locale && ngx-extractor -i src/**/*.ts projects/**/*.ts -f xlf -o src/locale/messages.xlf && xliffmerge --profile xliffmerge.json fi en",

y aquí está xliffmerge.json

{
  "xliffmergeOptions": {
    "srcDir": "src/locale",
    "genDir": "src/locale",
    "i18nFile": "messages.xlf",
    "defaultLanguage": "en",
    "useSourceAsTarget": true
  }
}

@JanneHarju
Sí, estoy usando la misma configuración y puedo extraer mensajes .ts en un archivo xlf.

Pero constante que tengo en diferentes archivos .ts

exportar const glossayModel= () => [
{
}

estoy importando en componente, cuando intento usar i18n con const, no está extrayendo los valores.

¿Qué sucede si usa valores constantes como proveedor.

{
    provide: glossayModel,
    useFactory: () => glossayModel()
}

el código puede estar roto, pero tal vez obtenga el punto.

como traducir migas de pan

const rutas: Rutas = [
{
ruta: './inscribir-nuevo.componente',
componente: InscribirNuevoComponente,
datos: {
ruta de navegación: 'Inscripción'
},
}
]

¿Pueden dejar de usar este hilo como hilo de soporte para i18n-polyfill u otros problemas? si tiene alguna pregunta sobre i18n-polyfill, plantee un problema en ese repositorio.
@ocombe , ¿quizás puedas bloquear este tema? casi todo lo importante debe ser cubierto.
¿Cuál es la versión angular que planea lanzar el soporte i18n mencionado en este tema?

Sí, bloqueado por ahora.
Estamos trabajando arduamente para que ivy esté disponible con v8 como una versión beta opcional. El tiempo de ejecución i18n se podrá usar con el cierre de Google (lo que Google usa internamente), lo que nos permitirá depurarlo (es un cambio muy grande). Para todos los demás, podrá probar ivy con i18n pero no podrá cargar las traducciones. La aplicación se ejecutará con el idioma original utilizado para codificar la aplicación.
El servicio de tiempo de ejecución que se necesita para traducir actualmente devuelve el texto sin traducir. Dado que todos estamos trabajando para corregir errores con el código existente, las nuevas funciones se limitarán a después del lanzamiento. Trabajaremos en ello una vez que v8 esté disponible, debería ser mi primera tarea.
Agregaré una actualización y desbloquearé este hilo una vez que tengamos algunas noticias.

Por lo que vale, la nueva etiqueta $localize en la que estamos trabajando se puede usar programáticamente.

P.ej

const name = 'World';
$localize `Hello ${name}:name!`;

Y luego podrá proporcionar traducciones para Hello {$name}! que se pueden reemplazar en tiempo de compilación (o tiempo de ejecución).

Esto ya está disponible (si no está documentado).

¿Fue útil esta página
0 / 5 - 0 calificaciones