Angular: i18n : Capable d'utiliser des chaînes de traduction en dehors d'un modèle

Créé le 7 sept. 2016  ·  204Commentaires  ·  Source: angular/angular

Je soumets un ... (cochez-en un avec "x")

[x] feature request

Comportement actuel
https://github.com/angular/angular/issues/9104#issuecomment -244909246

Je ne pense pas que ce soit possible, comme je l'ai déjà dit, cela ne fonctionne qu'avec du texte statique, il n'analysera pas le texte sur le code js, uniquement les modèles

Comportement attendu/souhaité
Être capable de traduire les chaînes utilisées n'importe où dans le code, à l'aide d'une API.

Reproduction du problème

Quel est le comportement attendu ?
Je fais référence à l'utilisation de $translate.instant pour exposer des cas d'utilisation réels :

  • Texte rendu personnalisé :
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);

Plus d'exemples :

  • Obtenir le nom de fichier de l'image à partir de l'image exportée d'un rapport rendu 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;
    }
  • Parfois, vous traduisez, parfois utilisez des données de modèle (peuvent être très détaillées dans un modèle) :
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', '');
        }
    }
  • Utilisation d'un plug-in de graphique tiers (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')
                    }
                }
            }
        });
  • Pour configurer les variables de configuration et rendre le texte sans tuyaux car ce n'est pas toujours une chaîne traduite
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')
        };
  • Pour définir window.title :) :
SetWindowTitle(title:string) {
        if (!!title) {
            this.$window.document.title = this.$translate.instant(title);
        }
    }
  • Format de date personnalisé :
dateHuman(date:Date):string {
        return date.getDate() + ' ' + this.$translate.instant('GLOBAL_CALENDAR_MONTH_' + date.getMonth())
            + ' ' + date.getFullYear();
    }
  • Triez les éléments en fonction des valeurs traduites :
// 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();
        });
    }
  • Exportez les données brutes vers CSV ou Excel avec les valeurs traduites :
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;
    }
  • Définissez les chaînes de configuration sur les plug-ins tiers :
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')
                ]
            }
        });
    }


Quelle est la motivation / le cas d'utilisation pour changer le comportement ?
Être capable de traduire des chaînes en dehors des modèles.

Veuillez nous parler de votre environnement :

  • Version angulaire : 2.0.0-rc.6
  • Navigateur : [tous]
  • Langage : [TypeScript 2.0.2 | ES5 | SystemJS]

@vicb

i18n feature high

Commentaire le plus utile

Je pense que c'est un véritable écueil, i18n n'est pas prêt à être utilisé tant que cela n'est pas implémenté.
Par exemple, je ne suis pas en mesure de définir des messages de validation traduits dans le code

Tous les 204 commentaires

Je pense que c'est un véritable écueil, i18n n'est pas prêt à être utilisé tant que cela n'est pas implémenté.
Par exemple, je ne suis pas en mesure de définir des messages de validation traduits dans le code

@Mattes83 Avez-vous essayé de cette façon ?

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

:confused: La documentation vous dit à quel point il est agréable d'avoir des messages d'erreur dans le code et la prise en charge de la traduction nécessite quoi que ce soit dans le modèle. On dirait qu'il y a plus besoin de communication.

@marcalj Je sais de cette façon... mais j'ai besoin d'avoir des chaînes localisées dans mes fichiers ts.
@manklu je suis totalement d'accord

Je pense que c'est un véritable écueil, i18n n'est pas prêt à être utilisé tant que cela n'est pas implémenté.
Par exemple, je ne suis pas en mesure de définir des messages de validation traduits dans le code

Ouais pareil ici, je viens de passer de ng2-translate à Angular2 i18n car je préfère utiliser les modules OOTB, et c'est beaucoup plus facile d'extraire les traductions (ng2-translate prend plus de temps IMO)
À ce stade, je ne peux pas traduire les messages d'erreur générés par mes services. Pas de solution de contournement non plus.

Si quelqu'un veut commencer une spécification de conception, ce serait utile (c'est-à-dire sur Google Docs).

Il faudrait lister tous les cas. En y réfléchissant rapidement, je vois un besoin de

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

Salut les gars, super demande de fonctionnalité :+1:

Existe-t-il une solution de contournement suggérée pour traduire les textes *.ts ?

@fbobbio Ce que j'ai fait, c'est créer des éléments cachés dans le modèle, ex.
<span class="translation" #trans-foo i18n>foo</span> .

Reliez-les à l'aide de :
@ViewChild('trans-foo) transFoo : ElementRef; .

Ensuite, récupérez la valeur traduite
transFoo.nativeElement.textContent .

Semble retardé, mais fonctionne pour mes besoins.

Comme ng-xi18n traite déjà l'intégralité du code TS, pourquoi ne pas implémenter un décorateur comme @i18n() pour les propriétés (string-) ? Ceux-ci pourraient ensuite être remplis avec la valeur traduite, comme @Input() est utilisé avec une liaison de données unidirectionnelle.
Si la valeur non traduite ne peut pas être facilement extraite du code, placez-la simplement dans l'argument comme suit :

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

et introduisez la source dans la propriété lorsqu'il n'y a pas de cible de traduction.

Il s'agit d'un élément essentiel dans l'ensemble du cycle d'internationalisation, IMO.

Dans ma boutique, nous sommes habitués à un outil "ng-xi18n - like" (une extension de xgettext) qui explore tous les types de fichiers source à la recherche de texte marqué à mettre dans des fichiers de dictionnaire pour les traducteurs.

J'adore le balisage i18n propre et facile dans les modèles HTML, et je m'attendais à la même chose pour le code Typescript.

@vicb En plus de vos cas d'utilisation, je réfléchis à la possibilité de prendre en charge la localisation de la chaîne interpolée dans le code TS. Cependant, il sera probablement nécessaire de réécrire le code TS pour prendre en charge un tel scénario. Sera-ce une approche valable?

C'est la principale caractéristique qui nous empêche d'utiliser l'approche prête à l'emploi des offres de traduction Angular 2. Nous avons de nombreux composants pilotés par les métadonnées dont les clés proviennent de certaines métadonnées non stockées en HTML. Si nous pouvions traduire via pipe ou par programmation par rapport aux TRANSLATIONS disponibles, nous pourrions obtenir que ces composants affichent les chaînes appropriées.

En attendant, nous sommes limités à quelque chose comme ng-translate à cause de cette limitation.

La façon dont j'ai contourné ce problème consiste à ajouter un objet 'lang' vide dans un service utilisé dans toute mon application. J'applique ensuite une directive qui lit tout le span dans un div et stocke la valeur dans cet objet. Je place toute ma chaîne dans un modèle en bas de la page avec une propriété masquée. La chaîne est alors accessible depuis le modèle ou le composant. C'est moche et vous pouvez facilement écraser une entrée avec le même identifiant. Mais c'est mieux que rien.

SERVICE

@Injectable()
export class AppService {

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

DIRECTIF

@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;
        }
    }
}

MODÈLE

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

Bonjour @lvlbmeunier

Merci d'avoir fourni cette suggestion de solution de contournement en attendant la mise en œuvre officielle. J'ai essayé d'implémenter votre solution mais je n'arrive pas à obtenir les clés de traduction dynamiques pour être reconnues. J'essayais de faire comme ça :

<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>

Ces nouvelles clés n'apparaissent pas dans mes fichiers xliff. Est-il possible d'y parvenir avec votre solution ?

Je ne l'ai jamais essayé mais je suis presque certain que la construction du fichier xliff n'exécute pas de code. Avoir une valeur dynamique dans i18n serait contraire au concept. Si vous connaissez avec certitude tous les noms qui figureraient dans votre liste, ils doivent tous être déclarés indépendamment et non dans une boucle for.

L'ajout manuel des clés fonctionne, mais ce n'est pas pratique. Dans mon cas, je reçois des centaines de clés de texte nécessitant une traduction à partir d'une API.

Vous pouvez exécuter votre code et prendre la source et la copier dans un fichier. La génération du fichier x18n est basée sur un fichier statique.

Avec 4.0.0-beta vous pouvez attribuer un identifiant à i18n , par exemple mainTitle :

<span i18n="title@@mainTitle">

Avec cela, nous pouvons, au moins pour le compilateur JIT, créer un composant factice (il n'a pas besoin d'être ajouté au html de l'application, juste le module de l'application) avec toutes nos traductions "supplémentaires".

Pour commencer, nous ajouterons les fournisseurs non seulement au compilateur, mais également au module d'application :

// 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);
});

Ensuite, nous allons créer un composant factice pour héberger nos traductions supplémentaires, n'oubliez pas d'ajouter le composant à declarations of AppModule . C'est pour que ng-xi18n puisse trouver le html (je pense) et l'ajouter au fichier de traduction.

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

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

Ajoutez nos traductions à tmp.i18n.html :

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

Nous pouvons maintenant créer un service où nous pouvons récupérer nos traductions :

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;
    }
}

Maintenant, nous pouvons faire quelque chose comme :

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']));
    }
}

Il s'agit d'une solution de contournement hacky. Mais au moins, nous pouvons tirer parti du fichier de traduction, obtenir par clé, interpoler et ne pas avoir de code HTML caché dans notre application.

REMARQUE : le package NPM @angular/compiler-cli actuel de 4.0.0-beta a une version de dépendance incorrecte de @angular/tsc-wrapped . Il pointe vers 0.4.2, il devrait être 0.5.0. @vicb est-ce facile à réparer ? Ou devrions-nous attendre la prochaine version?

@fredrikredflag Génial ! Et qu'en est-il de l'AOT ?

@ghidoz AOT est une autre histoire. Ce que nous aimerions faire, c'est précompiler toutes les traductions afin de pouvoir les obtenir par clé. Mais comme le ngc remplacera tous les i18n par la traduction correcte, nous ne pouvons pas en tirer parti. Impossible de trouver les options/propriétés exposées contenant les traductions analysées de ngc . Nous pourrions utiliser la même approche dynamique que pour JIT en récupérant le fichier xlt de cette façon, tout en le fournissant sur le jeton TRANSLATION . Cependant, cela va à l'encontre de l'objectif de l'AOT.

NE LE FAITES PAS POUR LES APPLICATIONS DE PRODUCTION .

/// 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);
});

Réflexion actuelle sur la façon de mettre en œuvre ceci :

@Component()
class MyComp {
  // description, meaning and id are constants
  monday = __('Monday', {description?, meaning?, id?});
}
  • parce que nous ne pourrions pas affecter la structure DOM avec une telle construction, nous pourrions prendre en charge les traductions d'exécution - il y aurait une seule version du binaire et la résolution se produirait au moment de l'exécution,
  • nous pouvons également prendre en charge les traductions statiques comme nous le faisons aujourd'hui pour les modèles - les chaînes seraient remplacées au moment de la compilation, de meilleures performances mais une version de l'application par paramètre régional,
  • nous pourrions probablement prendre en charge __(...) dans les modèles ultérieurement,
  • cela serait implémenté via un transformateur TS disponible à partir de la version 2.3 - nous pourrions probablement avoir un prototype avant.

/cc @ocombe

Je suppose que __() est pour une méthode qui n'a pas encore de nom (et la méthode ne serait pas vraiment __ , non ?)

C'est une bonne idée pour les traductions statiques que vous pourriez utiliser dans vos cours, et assez simple à mettre en œuvre je pense.

Non __() est le nom, tu ne l'aimes pas :)

Il est couramment utilisé dans les frameworks de traduction - mais vous pourrez import {__ as olivier} from '@angular/core' si vous préférez un autre nom !

eeeeeh c'est pas très explicite :D
Cela ressemble à une fonction très privée

Je n'aime pas non plus le nom de la méthode ___ :) J'avais imaginé que ce serait un service ?
En tout cas, ça fait du bien de voir des progrès 👍

J'apprécie __()! :D Très gettext-y et c'est court.

Dans le monde JS, je n'ai d'expérience qu'avec @ocombes ng2-translate, où marquer tout le texte avec this._translateService.instant() rend le code un peu plus difficile à lire par rapport à une alternative plus courte, comme proposé ici.

rien ne vous empêche de renommer le service de traduction ng2 __ vous savez :)

En fait, je n'ai aucune idée de comment encapsuler une méthode de service DI dans une fonction simple - de toute façon, tant pis, cela dépasse le cadre de ce problème :-) Mon commentaire était juste un +1 pour l'utilisation de __ car il est bien connu si vous ' J'ai déjà utilisé d'autres frameworks de traduction, du moins dans le monde PHP.

d'accord, peut-être que ___ est bien, mieux que "this.translationService.getTranslation()", beaucoup plus court.
Et oui, vous pouvez le renommer si vous le souhaitez.

Qu'en est-il de i18n(...) au lieu de __(...) ?

S'il vous plaît arrêtez le débat sur le nom, ce n'est pas le sujet. Merci.

@vicb avec monday = __('Monday', {description: 'First day of the week', id: 'firstDatOfWeek'}); sera-t-il possible de le résoudre par id, c'est à dire :

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

De plus, Monday serait-il local à la classe définie ou serait-il possible de résoudre de n'importe où? Je pense aux traductions courantes telles que "fermer", "ouvrir" etc.

Je me demandais quelle est la meilleure solution de contournement actuellement que vous recommandez d'utiliser avec AOT jusqu'à ce que la version officielle la prenne en charge ?

Salutations,
Sean

Évier de cuisine angulaire 2 : http://ng2.javascriptninja.io
et source @ https://github.com/born2net/Angular-kitchen-sink

@vicb any news, par là ^

Jusqu'à ce que cette fonctionnalité soit implémentée, j'utilise la fonctionnalité de traduction d'attributs .

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);
    }
}

À partir du modèle de composant parent :

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

C'est une solution de contournement, mais je pense quand même que c'est la plus propre jusqu'à présent. Il vous donne accès aux title traduits dans ts .

Je commence à travailler sur cette fonctionnalité, attendez-vous à une doc de conception bientôt :-)

ce sera la fonctionnalité la plus attendue

C'est une bonne nouvelle. Merci @ocombe .

La doc de conception est disponible ici : https://goo.gl/jQ6tQf
Tout commentaire est apprécié, merci.

doux, sera lu dès que possible!

Merci @ocombe

J'ai lu le document. Beau résumé.

Pouvoir extraire une chaîne à partir de fichiers ts semble génial.

Je ne sais pas quand la mise à niveau de Typescript sera disponible pour Angular4.

Cela signifie que cette fonctionnalité qui devrait déjà être disponible depuis des mois car à peu près tout le monde a rencontré cette limitation ne pourra pas utiliser cette solution avant au moins 3/6 mois de plus.

Je ne suis peut-être pas le seul en ce moment à utiliser ngx-translate pour gérer les traductions dans mes contrôleurs alors que je compte sur angular i18n pour les modèles.

L'objectif de tout fusionner dans i18n est évidemment génial.

Mais en dehors de la simplification en termes de compréhension de la mise en œuvre d'i18n dans le cadre angulaire, cette approche va-t-elle vraiment améliorer les performances par rapport à l'implémentation actuelle de ngx-translate ?

D'après ce que j'ai compris en ce moment, le seul bonus serait de pouvoir extraire les chaînes des contrôleurs.

La pluralisation est également une grande limitation en ce moment, veuillez vous assurer qu'elle fonctionne correctement lorsque vous publiez la mise à jour complète. J'ai lu beaucoup de tickets liés à i18n où xliff et xmb ne géreraient pas cela correctement. C'est un cas de plus où je dois revenir à ngx-translate pour fournir une solution de travail.

@ocombe Merci pour le document de conception détaillé, cela ressemble à une très bonne solution pour cette demande de fonctionnalité. La conception actuelle répond aux cas d'utilisation que j'essaie de résoudre.

Une question : la conception parle d'un service I18N pour le mode JIT et d'un transformateur TS 2.2.x pour le mode AOT. Ai-je raison de supposer que le transformateur remplacera à la fois l'appel à la méthode de service par une traduction statique et supprimera également toutes les références restantes au service I18N?

@Thommas Angular 4 utilisera TypeScript 2.1 (ce qui signifie que vous devrez mettre à niveau), mais vous pouvez déjà utiliser n'importe quelle version plus récente de TypeScript (2.2.1 par exemple) avec Angular 2 ou 4.

En termes de gain de performances par rapport à ngx-translate, cela dépend si vous utilisez AOT ou non. Si vous utilisez AOT, c'est un gain, mais vous ne verrez probablement pas la différence. En JIT (pas d'AOT) il n'y aura pas de gain (en fait cela dépend si vous utilisez l'observable get ou la méthode synchrone instant , l'observable coûte plus cher qu'un simple appel de fonction).
Je parle de i18n dans votre code ici. Si nous parlons des modèles, il y a un réel gain visible si vous utilisez Angular i18n (en AOT et JIT) car il n'utilise pas de liaisons. Plus vous utilisez de traductions, plus vous gagnez.

Je vais m'assurer que la pluralisation fonctionne exactement de la même manière que pour les modèles. Y a-t-il un problème en ce moment avec cela dans les modèles ?

@schmuli, la seule fois où Angular peut remplacer votre code, c'est lorsque vous utilisez AOT. Si vous ne le faites pas, les appels de service resteront les mêmes dans votre code.
Mais si vous utilisez AOT alors l'appel de service sera remplacé par une traduction statique (seules les variables que vous pourriez utiliser resteront dynamiques). Je ne sais pas si nous supprimerons les références au service I18n, car il pourrait être utilisé pour d'autres choses à l'avenir, je devrai voir ce qui est possible avec le transformateur une fois que j'aurai commencé à écrire le code. Pensez-vous à un cas d'utilisation où cela poserait problème ?

@ocombe Je ne peux pas penser à un cas d'utilisation où laisser le code serait un problème, à moins que nous n'envisagions une injection DI supplémentaire qui ne sera pas utilisée (est-ce un vrai problème ?).

Compte tenu de ce que vous avez écrit que le service pourrait être utilisé pour d'autres choses à l'avenir et du risque d'introduction d'erreurs en modifiant le code de l'utilisateur, je dirais qu'il est probablement préférable d'éviter de supprimer complètement le code.

Il serait peut-être utile d'utiliser le service pour obtenir les paramètres régionaux actuels dans AOT. Considérez par exemple le cas où vous avez un serveur qui peut renvoyer du texte dans plusieurs langues, vous aurez donc besoin de la locale actuelle à inclure dans la requête. Cependant, vous pouvez toujours utiliser une chaîne factice traduite comme solution de contournement.

@ diego0020 vous pouvez déjà obtenir les paramètres régionaux, injectez simplement LOCALE_ID depuis le noyau

@ocombe La pluralisation n'est pas implémentée avec xliff et personne en dehors de Google ne sait non plus comment l'utiliser avec xmb. Voir aussi : https://github.com/angular/angular/issues/13780

Quoi qu'il en soit, rien ne bloque notre implémentation i18n pour le moment. ngx-translate avec un canal de pluralisation fera l'affaire pour l'instant. Espérons que tout ira mieux dans NG4 et que la documentation reflétera les améliorations. Merci.

@Thommas ICU avec xliff sera bientôt corrigé : https://github.com/angular/angular/pull/15068 et si vous voulez savoir comment l'utiliser, c'est dans la doc : https://angular.io/docs/ ts/latest/cookbook/i18n.html# ! #cardinalité

Veuillez m'excuser, y a-t-il une ETA ? Parce que j'ai entendu dire qu'il serait disponible dans la version ng4.0.0 mais non! Merci

Cc @ocombe

Nous travaillons toujours sur la conception, il y a beaucoup de choses inattendues à prendre en compte (comme la façon dont les bibliothèques pourraient expédier leurs propres traductions), ...
Attendez-vous à cela pour 4.2, mais ce n'est pas garanti.

ok merci @ocombe , j'ai deux questions s'il vous plait:

  1. En fait, pouvons-nous traduire du texte dans un modèle qui inclut une interpolation, comme :
    <span i18n>This is {{myValue}}</span>
  1. Je demande parce que je ne peux pas extraire, je ne sais pas pourquoi j'obtiens cette erreur:
    Could not mark an element as translatable inside a translatable section

@istiti

  1. Oui, vous pouvez.
  2. vous devez faire attention à l'emplacement de votre directive i18n, elle doit être placée directement sur l'élément qui contient le texte, pas sur d'autres frères et sœurs.
    par exemple:
    <div i18n><span i18n>my text</span></div> - ce n'est pas bon
    <div><span i18n>my text</span></div> - c'est bon

@royiHalp
Merci

  1. Ok comment traduire avec interpolation ?
  2. Lorsque l'extrait ngc me donne un fichier, une ligne et un extrait de code, mais je n'ai pas i18n enveloppé dans un autre i18n
    C'est vraiment difficile de trouver lequel de mes parents a accidentellement l'attribut i18n

@istiti

  1. vous le faites comme n'importe quel autre élément, ajoutez simplement la directive i18n comme vous l'avez fait :
    <span i18n>This is {{myValue}}</span>
    le résultat dans le fichier messages.xlf sera :
    <source>This is <x id="INTERPOLATION"/></source>
    maintenant, lorsque vous le traduisez dans différents paramètres régionaux, vous devez placer le <x id="INTERPOLATION"/> au bon endroit dans la phrase, pour aider les autres à comprendre votre sens, vous pouvez ajouter une description à la directive i18n comme ceci :
  1. d'après mon expérience, l'erreur Could not mark an element as translatable inside a translatable section est comme je l'ai expliqué, je me souviens que si je lis attentivement l'erreur, je peux remarquer dans quel fichier j'ai le problème.

@fredrikredflag Merci beaucoup !

Votre code est super utile! Je devais juste résoudre un problème car il semble que xliff.load renvoie un objet différent de nos jours, donc this._translations doit être ajusté à :

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

et une validation mineure dans la méthode get si on demande une clé inexistante :

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

De plus, je pense que le composant i18n vide était arboré ou quelque chose du genre, donc j'ai dû inclure les chaînes sur les modèles de composants correspondants avec :

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

Heureusement, j'ai juste besoin de quelques chaînes pour ma miniApp, donc ça marche très bien en production avec AoT.
Merci encore!!!

P/S : l'outil xliffmerge de Martin Roob est incontournable en ce moment, et son TinyTranslator aussi B-)

J'utilise la compilation AoT et mon projet prend en charge deux langues : l'anglais et le russe. J'ai trouvé une solution temporaire au problème en utilisant la configuration de l'environnement.

Le fichier environments/environment.ts contient :

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

export const environment = {
  production: false
};

export const messages = messagesEn;

Il existe également deux autres fichiers environment.prod-en.ts et environment.prod-ru.ts avec le contenu suivant :

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

export const environment = {
  production: true
};

export const messages = messagesEn;

Et pour le russe :

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

export const environment = {
  production: true
};

export const messages = messagesRu;

Chaque fichier de message peut contenir quelque chose comme ceci :

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

Dans mon code (composants, services, etc) j'importe juste des messages :

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

Et utilisez-les :

alert(messages.MessageKey);

Dans .angular-cli.json , j'ai spécifié les prochains environnements de production :

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

Ça marche!

@alex-chuev Avez-vous essayé cela avec JIT ?

@ocombe une estimation approximative quand cela serait-il disponible ?

Grande fonctionnalité d'ailleurs :)

Il est en attente jusqu'à ce que des modifications soient apportées au compilateur, donc pas pour 4.2, j'espère toujours le faire pour 4.3

quelqu'un sait comment implémenter i18n dans les valeurs param par exemple dans [title] dans l'exemple suivant :
donc en d'autres termes, ajoutez la traduction au mot BONJOUR

Cordialement

Sean

Si HELLO n'est qu'une chaîne que vous saisissez dans le modèle HTML, vous pouvez procéder comme suit :
```html

````
La documentation en donne un exemple. Regardez ici : https://angular.io/docs/ts/latest/cookbook/i18n.html# ! #translate-attributs

Si vous devez vous lier à une propriété de chaîne dans le composant, vous devez attendre cette fonctionnalité ou implémenter une méthode de traduction personnalisée (à ma connaissance).

@ocombe

Nous travaillons toujours sur la conception, il y a beaucoup de choses inattendues à prendre en compte (comme la façon dont les bibliothèques pourraient expédier leurs propres traductions), ...

C'est très important. J'espère que cela fait partie de cette fonctionnalité aussi. Parce que pour le moment, je ne vois pas comment une bibliothèque tierce peut fournir des traductions pour votre application. Pendant la construction, vous ne pouvez spécifier qu'un seul fichier XLIFF, et il semble que vous deviez pré-construire votre bibliothèque pour que votre langue puisse la traduire.

Oui, j'attends ça aussi ! Ceci est TRÈS important pour les projets destinés à un public non anglophone !

C'est définitivement quelque chose que nous voulons supporter, l'équipe travaille sur le refactoring du compilateur qui nous permettra de faire ça :-)

Existe-t-il une estimation de la version qui sera ciblée ? J'ai lu quelque part qu'il pourrait être autour de 4,3 ?

En raison de la refactorisation (et des changements de rupture) nécessaires, ce ne sera pas avant la v5 j'ai bien peur

Whaaaat 😳 Oh non, j'attends cette fonctionnalité pour 4.2 vous avez dit et maintenant c'est pour la v5 ☹️ Je pensais que pour la v5 le changement de langage dynamique ne sortira pas pour chaque version mais j'espère de toute façon que ce sera un jour même avec 36 000 versions différentes pour chacune Langue. Je me demande juste pour quand est la v5? Merci

@ocombe

@istiti j'ai dit que ce n'était pas une date garantie ;-)
Le calendrier de publication est ici : https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md
La version finale pour la v5 est 2017-09-18, mais il y aura des bêtas et des RC avant

Y a-t-il des changements pour créer un fichier de paramètres régionaux pour chaque composant ? signifie, créer des morceaux de messages.xlf , par exemple : messages.{component}.{locale}.xlf et par exemple seulement messages.{component}.xlf pour la langue par défaut.

Pas encore

Dommage c'est strict minimu en raison du temps de construction @ocombe

Je suis confus... Cette demande de changement / ce changement est-il officiel ou non ?
Ayant le même problème ici, les traductions ne s'appliquent tout simplement pas uniquement aux modèles.
Avoir des composants redux, des arborescences personnalisées, etc., tous générés à partir d'objets javascript EN CODE, pas par modèle

C'est officiel, et ça arrive, mais nous avons d'abord dû apporter d'autres changements profonds au compilateur, c'est pourquoi il n'était pas prêt pour la version 4.3

Sait-on à quelle version exacte cette fonctionnalité sera disponible / est prévue ? 4.3.1, 4.3.2 ... 4.3.X ?

Il n'y a plus de version majeure/mineure pour la branche 4.x (uniquement les correctifs : https://github.com/angular/angular/blob/master/docs/RELEASE_SCHEDULE.md) ce qui signifie que ce sera pour la 5.x , je ne sais pas lequel.

Est-ce que cela devrait toujours entrer dans 5.x? Je ne le vois pas dans les bêtas. Merci

Peut-être dans v50.x pas v5.x 😂

5.x oui, mais ce ne sera probablement pas dans 5.0

Le jeu. 3 août 2017 à 12:56, vltr [email protected] a écrit :

Peut-être dans v50.x pas v5.x 😂


Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/angular/angular/issues/11405#issuecomment-319936876 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAQMorXMbyI8l6K3QA4jmXEKawiEC46xks5sUad0gaJpZM4J2pkr
.

Salut @ocombe Je suis très intéressé par le processus pour que cela fonctionne et qu'en est-il de la façon dont le compilateur fonctionne actuellement rend cette tâche plus difficile. Avez-vous des éclaircissements sur ce à quoi ressemble la chronologie ou s'agit-il toujours d'une version 5.0 mais d'une version 5.x ?

@arackow ce sera très probablement en 5.x, @vicb travaille sur les dernières modifications du compilateur qui rendront enfin cela possible

@ocombe ... existe-t-il un document de conception décrivant un concept de solution pour les chaînes en dehors des modèles? Nous sommes dans une phase de développement de projet où il serait bon de le savoir, nous serions donc en mesure de préparer d'une manière ou d'une autre notre solution temporaire et plus tard, il serait beaucoup plus facile de passer à la syntaxe finale d'Angular.

Nous avions un document de conception mais il était basé sur la version précédente du compilateur et ce n'est probablement pas l'implémentation que nous finirons par faire. Nous ferons un nouveau document de conception public une fois que nous aurons une meilleure idée de la nouvelle implémentation

@ocombe Je dois +1 cette fonctionnalité. j'en ai sérieusement besoin en ce moment lol :+1: Merci les gars d'avoir créé des outils incroyables ! :)

Si je comprends bien le document de conception actuel, un auteur d'une bibliothèque AOT devrait fournir les traductions pour toutes les langues requises par les différentes applications qui utilisent cette bibliothèque.
Ai-je bien compris ?

C'est un bon point @gms1.
J'ai testé ça ici .
En tant qu'auteur de bibliothèque, vous n'avez qu'à ajouter les balises i18n.
Vous ne devez pas compiler votre bibliothèque vers " ngfactories " (voir la conférence de Jason Aden à ng-conf 2017), ainsi la balise de traduction ne sera pas remplacée. De cette façon, lorsque vous exécutez la commande ng xi18n , vous obtiendrez également une traduction dans le xliff pour les fichiers de votre dossier node_modules.

Donc non vous n'êtes pas obligé de fournir des traductions, mais d'ajouter des balises i18n avec des significations utiles.

cité de la doc de conception :

Pour AOT le code source est transformé pour remplacer les appels de service par des traductions statiques. Pour ce faire, nous utiliserons un transformateur TypeScript.

Alors, qu'est-ce que cela signifierait si une bibliothèque angulaire (AOT) était publiée généralement sous forme transpilée ? Je n'ai trouvé aucune référence à .metadata.json dans ce document

Vous ne devez pas compiler votre bibliothèque dans le code final, mais la préparer pour qu'elle soit compilée par le développeur à l'aide de votre code. Voir ce que @jasonaden mentionne ici . Cela signifie également que vous pouvez rendre votre bibliothèque traduisible en ajoutant la balise i18n.

@ gms1 comme je l'ai dit:

Nous avions un document de conception mais il était basé sur la version précédente du compilateur et ce n'est probablement pas l'implémentation que nous finirons par faire.

Et le compilateur AOT est considérablement modifié pour la v5, il devrait être plus facile pour les bibliothèques de publier du code "aot-ready".
Pour i18n, nous voulons rendre cela aussi simple/flexible que possible, ce sera probablement quelque chose comme : les bibliothèques peuvent publier des fichiers de traduction que vous pouvez utiliser, mais que vous pouvez également remplacer si vous préférez, et vous devriez être en mesure de fournir langues supplémentaires également si la bibliothèque ne les prend pas en charge par défaut

Merci @ocombe pour cette précision !

@ocombe Cela signifie-t-il que les fonctionnalités de ngx-translate seront disponibles dans l'angle lui-même ?

@montreal91 aucune des parties de ngx-translate ne peut être implémentée telle quelle dans angular, ma bibliothèque a une approche très naïve, cela fonctionne "surtout" mais nous voulons être beaucoup plus efficaces avec le framework.
Cela dit, angular fournira des fonctionnalités similaires (même si l'implémentation finale sera différente).

C'est mon approche (FLUX) alors que je travaille sur un système de notification d'interface utilisateur basé sur (https://github.com/PointInside/ng2-toastr). Le problème est que le contenu de la notification est défini dans l'appel de service au lieu d'un modèle à gérer par le système angulaire i18n (xi18n)

Ce n'est pas ce que j'aimerais, mais c'est une solution _de travail_. Vous pouvez _extraire_ l'idée à partir des fragments de code suivants. J'espère que ça aide :)

partout

// 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");

NotificationComponent.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;
            }
        }
    }
}

NotificationComponent.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>

Maintenant que Angular 5 est sorti, avons-nous une idée de quand les changements sur le module i18n seront-ils intégrés ?

Il semble que cette fonctionnalité dépende des modifications apportées au compilateur angulaire, mais les équipes responsables du compilateur semblent moins intéressées. Il ne semble pas qu'il y ait une tâche ou un PR ou des commits : - (. Désolé pour la ventilation, mais cette demande de fonctionnalité qui décrit des fonctionnalités très basiques présentes dans tous les autres cadres de traduction a maintenant plus d'un an. J'ai donné j'espère que cette fonctionnalité essentielle arrivera. Au moins pour 5.x...

Les gars, restez calmes. Ce n'est pas une chose idiote à implémenter dans un compilateur AOT. Ayez un peu confiance, @ocombe a dit :

"ce sera probablement en 5.x, @vicb travaille sur les dernières modifications du compilateur qui rendront enfin cela possible"

Oui, nous travaillons actuellement sur le runtime i18n, ce qui est la première étape.
Runtime i18n signifie : un bundle pour toutes les langues, les bibliothèques compilées par AOT peuvent utiliser i18n, et peut-être plus tard la possibilité de changer de langue lors de l'exécution. Cela signifie également que nous pouvons effectuer des traductions au moment de l'exécution, ce qui est nécessaire pour les traductions à l'intérieur du code (car nous avons besoin d'un analyseur d'exécution pour les traductions, etc.).
Une fois cela fait, la prochaine priorité sera les traductions à l'intérieur du code.

Mais nous ne pouvions pas faire d'exécution i18n avant de changer le compilateur pour utiliser des transformateurs de type script (ce qui a été fait pour 5.0)

Une idée de quelle version 5.x aura quelles améliorations i18n ? Quelque chose sort avec la 5.0.0 elle-même ?

5.0 :

  • nouveaux canaux i18n (date/nombre/pourcentage/devise) qui n'utilisent pas l'API intl qui a corrigé quelque chose comme 20 bogues car maintenant ils fonctionnent de la même manière sur tous les navigateurs + quelques autres améliorations (paramètre de paramètres régionaux, nouveaux formats supplémentaires, paramètre de fuseau horaire pour le tuyau de date, ...)
  • nouvelle fonction api i18n pour les bibliothèques et les composants : https://next.angular.io/api?query=getlocale
  • meilleure intégration avec la cli

5.1 ou 5.2 (s'il n'y a pas de bloqueur inattendu) :

  • exécution i18n

5.x :

  • Traductions de code i18n (pas seulement le modèle)

Et d'autres choses que nous ajouterons en cours de route mais qui ne sont pas encore décidées (vous pouvez suivre https://github.com/angular/angular/issues/16477).

Juste des pensées curieuses, bien que je sois un peu en retard, juste en considérant le support i18n dans un fichier TS, pourquoi ne pensons-nous pas à la syntaxe d'annotation ? (j'ai trouvé que quelqu'un l'a mentionné ci-dessus aussi)

Exemple serait:
@i18n (id='message1')
message1 = "Ceci est un message qui doit être traduit" ;

@i18n (id='dynamicMessage')
dynamicMessage = "Ceci est un message dynamique avec {0}" ;

Avec l'annotation pour dynamicMessage, nous pouvons injecter une fonction via une annotation à cette instance de chaîne, dont le nom est format , puis nous pouvons utiliser comme ci-dessous :
var message final = message dynamique. format('value1')

Une approche similaire pourrait être possible pour prendre en charge les paramètres nommés , etc.

Je suppose que la question n'est pas de savoir comment faire une bonne expérience de développeur. La question porte sur la compilation.

Que se passe-t-il également si vous remplacez message1 par une autre chaîne ? Toutes les variables i18n doivent alors toujours être des constantes. Je ne pense pas que l'utilisation de variables fonctionnerait du tout. Par exemple, Symfony a un service de traduction avec une fonction de traduction qui fonctionnerait comme ceci dans la syntaxe JS : let translated = this.translator.trans('Hello %name%', [{'%name%': nameVariable}]); qui se traduira par : <source>Hello %name%</source> <target>Bonjour %name%</target>

@MickL le but de la traduction -aot actuelle est de créer un programme minimal et efficace. C'est pourquoi une approche de traduction dynamique n'existe pas encore.
Je crois fermement que l'approche actuelle est vraiment bonne, dans le sens où nous n'utilisons pas de service dynamique pour traduire les chaînes. Cela signifie que si vous savez qu'un texte est statique, veuillez le traduire de cette manière sans utiliser de service.

Le problème avec la traduction dynamique est simple, c'est-à-dire si vous allez traduire une chaîne à chaque fois que vous l'affichez. n'est pas vraiment une bonne façon,
Pourquoi?

  1. Parce que vous avez un dictionnaire de plusieurs langues en mémoire lorsque vous ne l'utilisez pas.
  2. Chaque fois que vous affichez un texte dynamique, vous devez aller sur la carte et trouver une clé, puis trouver la traduction de la langue. A CHAQUE FOIS parce que vous avez une "langue principale".

De mon point de vue, la future solution devrait être :

  1. Le backend vous donne le texte que vous souhaitez traduire.
  2. Remplacez/(ou téléchargez depuis le backend qui est l'approche actuelle) chaque texte que vous affichez dans la langue actuelle/principale. (remplacez tout le temps, mais vous n'avez pas besoin de trouver deux clés à chaque fois que vous voulez afficher une étiquette simple).
  3. Seul le texte véritablement dynamique peut être remplacé et/ou demandé au backend.

Pensez-y, si vous avez vraiment du texte dynamique à afficher, vous pouvez le recevoir du backend, et si vous avez vraiment besoin d'une copie de ce "texte dynamique", vous pouvez toujours utiliser le cache pour cela.

À mon avis, il n'est plus nécessaire de discuter de cette question. En fait, il y a un gars (Olivier Combe) qui travaille à PLEIN TEMPS sur i18n. AOT est très spécial et beaucoup de travail a dû être fait avant de rendre ce problème encore plus proche du possible. Bientôt nous aurons des traductions dynamiques : Plus besoin de construire chaque langue séparément ! Lorsque cela sera fait, nous aurons des traductions dans le code (ce numéro) plus tard. Il a dit que la route jusqu'à ce que ce problème soit résolu prendra, espérons-le, six mois à partir de maintenant.

Si vous êtes intéressé, consultez son discours sur Angular Connect le 07.11.17 sur le présent et l'avenir d'i18n dans Angular : https://youtu.be/DWet6RvhHWI?t=21m12s

Cela ressemble à un bon cas d'utilisation pour les chaînes de modèle taguées dactylographiées ...

Cela sent en général. Je visite ce fil une fois par mois pour vérifier les progrès et j'ai cessé d'être déçu à cause de la baisse des attentes. La seule chose que les développeurs veulent, c'est avoir les mêmes options de traduction de chaînes dans le code que dans les modèles. Mon code est truffé de chaînes de modèle traduites cachées à cause de cette fonctionnalité manquante. Que cela soit finalement accompli avec un service ou des annotations n'est pas pertinent et peu importe si cela prend une milliseconde supplémentaire. Je regarde déjà quelque chose pour les changements lorsque je choisis une chaîne à partir du code. La seule exigence est que le code soit analysé et que les chaînes pertinentes se retrouvent dans les mêmes fichiers avec le même format que mes traductions basées sur des modèles.

@eliasre vous pouvez essayer https://github.com/ngx-translate/i18n-polyfill si vous êtes pressé pour la traduction du code
aucune promesse que ce sera la même chose, en fait ce sera probablement différent (comme plus facile à utiliser), il y a des limites à ce qui est possible en ce moment... et cela ajoutera ~80ko à votre application à utiliser cette bibliothèque

Vous pouvez utiliser ngx-translate si vous ne voulez pas attendre

@ocombe cela vous dérangerait-il de fournir des mises à jour sur les progrès afin que nous puissions suivre et planifier en conséquence les délais de développement en attendant les décisions sur les plugins ou les frameworks à utiliser ? ce serait très utile et apprécié

@eliasre Je pense que google veut faire une bonne solution à la fois. Sans casser les changements à l'avenir. Je suis d'accord que cela prend plus de temps que nous ne le pensons.

Ne vous embêtez pas pauvre @ocombe il travaille TRES TRES dur !
Continue comme ça! :)

Ce n'est pas moi qui travaille sur cette fonctionnalité, et c'est les vacances, je vous tiens au courant dès que j'en sais plus

merci @ocombe

merci @ocombe , toute mise à jour serait grandement appréciée ici. J'attendais désespérément le runtime i18n depuis quelques mois, et la dernière version ETA était 5.2. Pouvez-vous s'il vous plaît nous faire savoir dès que vous avez une ETA mise à jour ici ?

Désolé d'être si persistant, mais la construction pour 20 langues finit par être atrocement lente pour le moment.

Comme Angular 5.2 est sorti et malheureusement je n'ai rien trouvé lié à i18n (ou ai-je oublié quelque chose?) ... - @ocombe peut-être pourriez-vous nous mettre à jour sur le plan de publication? Merci beaucoup et merci beaucoup pour vos efforts sur i18n !

@ocombe n'est pas le gars que nous attendons ici... consultez le lien youtube dans ce commentaire : https://github.com/angular/angular/issues/11405#issuecomment -343933617

La planification est en constante évolution. Chaque fois que je donne une date de sortie probable, il s'avère que quelque chose d'autre obtient la priorité ou devient nécessaire et cela change à nouveau la date. Je sais à quel point c'est décevant pour vous tous qui attendez cette fonctionnalité, et je fais tout ce que je peux pour augmenter la priorité.
Nous avons une réunion demain pour discuter du backlog/planning de l'i18n, je vous ferai savoir si j'obtiens quelque chose de nouveau.

@ocombe si vous sortez i18n ce mois-ci, je vous achèterai un pack de 24 bières artisanales

J'ajouterai 24 bouteilles de bière allemande et 24 autres bouteilles si vous demandez ce que font Angular Elements et le support de la bibliothèque. Merde de ne pas avoir d'informations sur ce qui se passe, c'est horrible.

@ocombe , vous avez cette rare opportunité d'acquérir 72 bouteilles de bière artisanale chère et de rendre la communauté du développement heureuse. Nous remplirons nos promesses si vous accomplissez ces choses mon ami.

@MickL Angualr Elments, si je comprends bien, cela nous permettra de créer des pages non-SPA et d'utiliser des composants angulaires comme éléments natifs (également comme widgets autonomes)

Oui je sais. Ce sont 2 autres fonctionnalités que tout le monde attend mais personne ne sait quel est le statut et quand s'y attendre...

Si seulement quelqu'un promet d'ajouter les 27 dernières bouteilles de bière, nous pouvons commencer à les compter !
http://www.99-bottles-of-beer.net/language-javascript-1948.html

Je vais les ajouter, @ocombe : nomme ta marque préférée :D

Edit : quelqu'un crée un service similaire à eth bounty nommé beerbounty :p

Comme promis, une petite mise à jour : nous visons toujours à sortir le runtime i18n en v6, ce qui nous donne 5 semaines. Ça va être court, ça sera probablement ajouté dans une des dernières releases, et ce sera derrière un drapeau.
Le runtime i18n devrait être livré avec des traductions de code, car c'est ainsi que cela fonctionnera également pour les modèles de toute façon (il devrait utiliser le même mécanisme).
Cela étant dit, il n'est pas certain que le service soit prêt à 100%, et nous pourrions le reporter pour nous assurer de ne pas le casser juste après sa sortie, si nous estimons que c'est le bon choix. Mais il suivra dans tous les cas le runtime i18n (c'est notre feuille de route), et nous n'avons pas besoin d'une version majeure pour le publier car il sera derrière un drapeau, et il ne devrait rien casser de toute façon).

Qu'est-ce qui pourrait nous empêcher de le sortir à temps :

  • si nous tombons sur un problème inattendu (vous savez comment fonctionne le développement)
  • si cela casse les applications google internes parce que nous nous sommes trompés quelque part
  • si quelque chose de prioritaire se présente et que nous devons changer d'orientation
  • si l'une des nouvelles choses dont il dépend est bloquée ou retardée (le runtime i18n dépend de certains changements internes majeurs sur lesquels d'autres membres de l'équipe travaillent)
  • Développeur angularJS senior, utilise la bibliothèque de traduction de PascalPrecht depuis 3 ans.
  • m'a excité. Recrue angulaire 2. Navigation naïve sur https://angular.io/guide/i18n
  • Réussir l'intégration d'i18n dans mon projet professionnel
  • Passer une journée entière à jouer avec toutes les étiquettes frontales codées en dur, en les portant sur un fichier xlf de plus de 100 Ko
  • Besoin de traduire des étiquettes brutes au sein de ng services
  • En cherchant sur Google, soyez ici
  • Découvrez qu'il n'y a pas de solution avant Angular 6 ans.
  • moi rn
    mfw

@Macadoshis , vous pouvez utiliser ma bibliothèque polyfill pour l'instant : https://github.com/ngx-translate/i18n-polyfill

@Macadoshis imaginez maintenant ce que nous avons traversé depuis l'alpha.46 ! ;)

Merci d'avoir pointé i18n-polyfill vers moi @ocombe , mais j'opterai pour ngx-translate car il prend en charge le chargement asynchrone des clés de traduction.
L'usine de i18n-polyfill pour le fournisseur TRANSLATIONS semble ne prendre en charge que le chargement brut de synchronisation d'un paramètre régional fixe connu avant le démarrage.

// 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 à quel point le polyfill que vous avez écrit est-il proche de ce qui est publié ? Y a-t-il quelque chose dont nous devrions être conscients ou auxquels nous devrions nous préparer ? En outre, pourriez-vous dresser la liste des fonctionnalités avec i18n qui sont publiées dans la version 6, et comment se déroulent les tests avec i18n ?

Je n'ai pas plus de détails sur le service de traduction de code pour l'instant, nous y travaillerons probablement la semaine prochaine (je voyage à Mountain View). Tout ce que je sais, c'est que derrière la scène, ce sera similaire à goog.getMsg de la bibliothèque de fermeture (puisque c'est ce que google utilise en interne pour l'instant): https://github.com/google/closure-library /blob/db9bc1a2e71d4b6ee8f57eebe37eb0c6494e9d7e/closure/goog/base.js#L2379 -L2387 qui est également similaire à mon polyfill.

Dans la v6, nous publierons le runtime i18n : un bundle pour toutes les locales, les traductions résolues au moment de l'exécution, et peut-être des traductions de code si nous avons le temps (sinon cela viendra peu de temps après). Tout cela sera derrière un drapeau car cela nécessite d'utiliser le nouveau moteur de rendu (appelé ng-ivy) qui ne sera pas testé au combat.

THX! @ocombe ... ça a l'air vraiment sympa !
Y aura-t-il des changements de rupture dans la syntaxe pour la traduction des modèles ? Je pense à ajouter des traductions à notre projet maintenant - mais je ne veux pas le refaire complètement dans quelques semaines.

Non, la syntaxe du modèle sera la même

Merci @ocombe pour la bonne nouvelle, c'est extrêmement prometteur. Quel type de préparation à la production pouvons-nous attendre du moteur de rendu ng-ivy qui sortira avec la v6 ? Je comprends qu'il ne sera pas testé au combat, mais il serait toujours prêt pour une utilisation en production et fonctionnerait sur tous les principaux navigateurs de version presque actuelle, n'est-ce pas ?

Vous pouvez suivre les progrès ici : https://github.com/angular/angular/issues/21706
Je ne pense pas que tout sera prêt pour la v6, car c'est sous un drapeau que nous continuerons à progresser même après la sortie de la v6 (ce n'est pas un changement de rupture ou quoi que ce soit)
Honnêtement, je ne sais pas ce que sont toutes ces choses :D
Je sais qu'une application hello world de la cli fonctionne déjà.
Je pense que certaines de ces choses sont nécessaires pour bénéficier des optimisations du nouveau moteur de rendu, mais cela peut probablement fonctionner sans que tout soit vérifié
Cela étant dit, cela signifie également qu'il ne sera pas prêt pour la production, ne pariez pas encore votre produit dessus. Il ne sera pas testé sur les applications Google internes, et nous devrons peut-être apporter des modifications radicales pour corriger les choses. L'utilisation du nouveau moteur de rendu est à votre discrétion et à vos risques et périls

Est-ce que tout cela est présent dans la v6-beta4 ?

Non ce n'est pas. Consultez cette feuille de route , cette fonctionnalité est bloquée par le runtime i18n.

met à jour @ocombe ?

Le premier PR pour le runtime i18n a été fusionné dans master, avec une application de démonstration hello world que nous utiliserons pour tester les fonctionnalités. Il fonctionne au moment de l'exécution et prend en charge théoriquement les traductions de code, même s'il n'y a pas encore de service pour cela.
Pour l'instant, c'est un support très minimal (chaînes statiques), nous travaillons sur l'ajout de nouvelles fonctionnalités (je ferai fonctionner l'extraction la semaine prochaine, puis la chaîne dynamique avec des espaces réservés et des variables).
Après cela, nous ferons le service pour les traductions de code.
Dès qu'une nouvelle fonctionnalité est terminée, elle est fusionnée dans master, vous n'aurez pas à attendre une nouvelle majeure.

Les fonctionnalités de @ocombe i heart i18n devraient déjà être ici dans la v4.3 !! Tant de versions mais rien sur i18n. Le chef d'équipe angulaire peut-il allouer plus de travaux/développeurs dessus, je peux vous comprendre seul ou deux développeurs ne peuvent pas aller de l'avant rapidement, cette fonctionnalité i 18n est la fonctionnalité indispensable pour prétendre qu'Angular est une application commerciale/grande application avec une construction rapide bien sûr ces deux fonctionnalités sont les plus importantes pour les grandes applications, n'est-ce pas ? Merci

Je pense que la seule chose que nous pouvons dire à @ocombe est de le remercier pour tous les efforts qu'il met dans cette fonctionnalité. Je suis sûr que s'il n'y a plus de développeurs, ce n'est pas parce qu'il ne les a pas demandés. Laissez-le faire, je suis sûr que nous ne le regretterons pas quand il sortira.

Juste pour référence...

J'ai un outil alternatif pour importer et exporter des chaînes, développé à l'origine pour être utilisé avec Aurelia, qui inclut la prise en charge des chaînes stockées dans des fichiers json - c'est très pratique, car Webpack vous permet d'importer directement json dans vos fichiers ts , donnant à votre code un accès facile à ces chaînes.

Cet outil fonctionne également avec les modèles Angular et possède de nombreuses autres fonctionnalités pratiques - utilisez-le si vous le souhaitez ou n'hésitez pas à lui emprunter des idées pour améliorer l'outillage Angular. Il existe également un chargeur Webpack basé sur cela - voir le lien dans la documentation.

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

Nous avons un problème plus simple et je ne sais pas si nous avons besoin de la fonctionnalité à venir (ou du polyfill de @ocombe).

Nous définissons la structure de toutes les formes réactives avec des constantes, dans lesquelles nous définissons les propriétés de chaque élément de forme. Par exemple:

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

Actuellement, nous utilisons ngx-translate , donc dans le modèle, nous traduisons les chaînes comme ceci :

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

Nous aimerions maintenant migrer vers Angular i18n. Cependant, comme toutes nos chaînes ne sont pas dans un modèle, il semble que nous ne puissions pas utiliser Angular i18n prêt à l'emploi.

Notre situation semble cependant plus simple que celle dans laquelle les traductions doivent être récupérées au moment de l'exécution. Tous nos textes sont prédéfinis dans des constantes et pourraient être remplacés au moment de la compilation, tout comme x18n le fait actuellement pour les chaînes dans les modèles.

Par exemple, nous pourrions avoir une chaîne plus complexe comme la suivante

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

Au moment de la compilation, la chaîne pourrait être remplacée par :

placeholder: 'Your password'

Est-ce quelque chose qui pourrait être envisagé pour la mise en œuvre ?

vous pouvez certainement le faire avec le runtime i18n, vous pouvez utiliser le nouveau service i18n dans un tube par exemple pour transformer vos espaces réservés en leurs traductions

Je remarque que ce fil de discussion est ouvert depuis un certain temps, il montre l'intérêt majeur de développer des sites multilingues en Angular de manière simple, en abordant à la fois les textes HTML et les textes en code composant.
ocombe, s'il vous plaît, n'oubliez pas d'envoyer une alerte à tous les abonnés lorsque cela sera fait - j'ai compris que c'était au coin de la rue en mai 2018. Et merci pour vos aimables contributions !

@ocombe devons-nous utiliser Ivy pour pouvoir utiliser ces services d'exécution ou cela fonctionnera-t-il également avec l'ancien moteur?

ce ne sera qu'avec du lierre, que vous ne pouvez pas utiliser pour l'instant car ce n'est pas fini

Merci pour tout votre travail acharné @ocombe !

Un mot sur combien de temps nous pourrons utiliser ces nouvelles fonctionnalités ?

Ivy peut être activé dans angular 6 avec un indicateur de compilateur dès maintenant, dans un état de pré-version. Ces nouvelles fonctionnalités 18n peuvent-elles être utilisées avec la pré-version Ivy pour le moment ?

Pas encore, mais je fais de bons progrès (je travaille à plein temps là-dessus en ce moment). Je posterai une mise à jour ici une fois qu'elle sera disponible en master pour tester

merci beaucoup @ocombe ! Tant de personnes bénéficient de votre travail acharné. Nous l'apprécions tous grandement !

@ocombe Des traductions statiques dans ts sont-elles toujours prévues ? Je veux dire le remplacement de l'expression de temps de compilation, probablement avec une transformation dactylographiée.
Sinon, allons-nous pouvoir brancher la transformation ts personnalisée dans le pipeline ng build sans extraire ?

Je ne suis pas sûr de comprendre ce que tu veux dire @TinyMan ? Vous voulez dire être capable de fusionner des traductions au moment de la construction (comme c'est le cas actuellement), ou être capable d'utiliser des traductions dans le code ts (en plus des traductions de modèles que nous avons déjà) ?

@ocombe Je veux dire pouvoir utiliser la traduction dans ts, mais pas via un service ou une traduction DI / runtime. Je veux dire la traduction au moment de la compilation, mais pour le tapuscrit. Comme le préprocesseur C. Je pensais que c'était prévu selon le commentaire de vicb :

  • nous pouvons également prendre en charge les traductions statiques comme nous le faisons aujourd'hui pour les modèles - les chaînes seraient remplacées au moment de la compilation, de meilleures performances mais une version de l'application par paramètre régional,

Par exemple, je veux pouvoir écrire :

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 !"),
}

Et puis ça se transpile en quelque chose comme (en fr):

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

Actuellement, à cette fin, j'utilise ngx-translate avec un marqueur personnalisé pour l'extraction ( i18n dans cet exemple), et quand j'ai besoin d'afficher le message, je dois appeler this.translate.instant(Notifications.newStory, ["TinyMan"]) qui fait la traduction + l'interpolation. Ce que je veux dire, c'est que nous aurions besoin de pouvoir écrire Notifications.newComment sans appeler le service de traduction. Et pour l'interpolation de chaîne, nous pourrions avoir une méthode d'interpolation qui ne fait que l'ICU et l'interpolation (la chaîne de modèle serait déjà traduite)

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

Ici, nous nous débarrassons simplement de la requête HTTP de traduction et de la surcharge du service.

J'espère que ça clarifie ?

Ce que vous décrivez est en effet sur la feuille de route pour i18n.
Pour le moment, https://github.com/ngx-translate/i18n-polyfill fera le travail.

@TinyMan Je ne sais pas encore si ce sera via un service ou une fonction globale. Les deux sont possibles, mais un service a aussi beaucoup d'avantages : vous pouvez vous moquer de lui pour des tests, ou le remplacer par le vôtre, vous pouvez aussi changer son comportement pour chaque module/composant
Je sais qu'en interne Google utilisera Closure i18n (via goog.getMsg ) qui est une fonction globale, et la fonction sera très probablement remplacée par le service lors de la compilation basée sur un indicateur global. Je vais essayer de voir si ce drapeau peut également être utilisé en externe, mais je ne vois pas pourquoi. Mais si vous l'utilisez, ce sera pour les modèles et les traductions de code

@ocombe Je tiens également à remercier ici. J'apprécie énormément le travail que vous faites là-dessus, qui me sera incroyablement utile dans mon travail. Une question : existe-t-il un moyen, ou y aura-t-il un moyen, de faire une compilation AOT qui ne crée qu'un seul ensemble de fichiers groupés qui, lors de la recherche de texte, référence le xlf au moment de l'exécution pour obtenir la chaîne correcte ?

donc, en substance, vous auriez besoin d'un fichier xlf par langue plus les 5 ou 6 fichiers de bundle. À l'heure actuelle, si nous avons 10 langues et une compilation AOT, c'est plus de 50 fichiers : un ensemble de fichiers groupés par langues...

Je ne connais pas l'effort ou la complexité de quelque chose comme ça, mais ce serait bien d'avoir une compilation mais avec seulement 1 jeu de fichiers.

oui, c'est ce qu'on va faire avec ivy, runtime i18n
regroupez votre application une fois et chargez les traductions au moment de l'exécution (vous pouvez charger les traductions paresseusement)

@ocombe ça. est. incroyable.

Cela me rend incroyablement heureux. MERCI!

Sans possibilité de traduire des modèles extérieurs, la fonctionnalité i18n est complètement inutile pour moi.

@ocombe Bonjour Olivier !
Les mises à jour?

Merci!

Si c'est fait, cela n'aurait pas d'importance puisque nous devons attendre qu'Ivy soit terminé, ce qui est prévu pour Angular 7 (sept/oct 2018)

Par Angular 7, ce problème aura deux ans LOL.
En tout cas, Ivy a été la chose qui a le plus retardé cette nouvelle fonctionnalité...

@ocombe , c'est bon à entendre. Nous sommes actuellement bloqués en utilisant un service i18n hérité que nous avons lancé à partir de zéro uniquement pour cette raison. Ne pas pouvoir le faire en JS rend extrêmement difficile de faire des choses simples pour nous :

  • Composants dynamiques
  • Intégration avec des services tiers où nous devons fournir du texte localisé à
  • Affichage des modaux de confirmation dynamiques
  • Notre API renvoie l'erreur types . Dans notre contexte, nous devons localiser dynamiquement ces erreurs et une approche basée sur un modèle serait maladroite.
  • Nous voulons utiliser le TitleService comme le suggère l'équipe Angular, mais il n'y a aucun moyen de fournir du texte localisé !

Je suis un peu curieux de savoir comment l'équipe Angular gère cela actuellement ...

Bonjour @vincentjames501 ,
Dans notre entreprise, nous avons essayé de faire la même chose que vous faites maintenant, mais c'était très gênant, nous avons donc fini par utiliser le polyfill i18n mentionné précédemment dans ce fil, et jusqu'à présent, cela fonctionne très bien.
Le seul inconvénient que nous avons est la taille des bundles de notre application. Nous avons trois fichiers de traduction, et chaque bundle les contient tous (nous n'avons pas trouvé de moyen de générer le bundle uniquement avec la traduction qu'il utilise). Mais tout cela ne sont que des nuisances qui, nous l'espérons, seront résolues lors de la sortie d'Ivy.
Acclamations,

J'ai inclus une carte de traduction et l'ai réexportée dans le fichier environment.ts de chaque langue. Il fonctionne sans problème, n'est pas inclus dans tous les bundles et ne nécessite pas de bibliothèque externe. Le seul problème que j'ai est que chaque site est différent, je ne peux pas avoir le même travailleur de service pour toutes les langues et si quelqu'un change de langue, mon site ne peut pas dire s'il est déjà enregistré pour les notifications push ou non...

@ocombe des nouvelles d'angular 6 ?

Ce ne sera pas dans Angular v6, comme expliqué ci-dessus. Nous dépendons d'Ivy qui est prévu pour la v7.

@ocombe puis-je vous suggérer de verrouiller ce fil, afin que seule l'équipe puisse donner des mises à jour significatives le cas échéant et nous éviter les questions répétitives auxquelles vous continuez à répondre ?

Mon hack à utiliser avec l'actuel Angular utilise un ng-template et crée la vue intégrée par programme :

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

puis dans le fichier ts du composant :

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

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

La méthode createTranslatedMessage renvoie le message traduit. Bien que j'utilise le modèle pour déclarer le message qui n'est pas optimal, cela permet à l'outil de traduction CLI de l'enregistrer dans les fichiers xlf, et j'ai un moyen d'obtenir le message traduit par programme pour une utilisation en dehors des modèles.

Espérons que l'API fonctionnera également pour les routes! Par exemple

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

Si cette fonctionnalité est publiée, y aurait-il un changement significatif par rapport à l'API i18n actuelle ? Recommanderiez-vous que je commence mon projet avec i18n maintenant ou devrais-je attendre la nouvelle API i18n lors de la sortie d'Angular 7 ?

Toute mise à jour Quand aurons-nous accès à la prise en charge de la traduction dynamique et à l'exécution ?

Les traductions d'exécution sont faites et fusionnées (avec ivy), mais le côté compilateur n'est pas encore terminé.
Je travaille sur les expressions ICU en ce moment.
Je n'ai pas encore commencé à coder les traductions dynamiques (service) mais c'est probablement la prochaine chose que je ferai après les expressions ICU.

@ vincentjames501 Pouvons-nous utiliser i18n-polyfills avec l'expression ICU? Je n'ai aucune solution pour implémenter cela

@ocombe , pouvez-vous s'il vous plaît clarifier la différence entre les traductions d'exécution et les traductions dynamiques ?

il n'y a probablement pas de dénomination officielle, mais la façon dont je le vois est:

  • runtime : les traductions sont résolues au moment de l'exécution, c'est-à-dire pas pendant la construction (comme nous le faisons actuellement). Elle s'applique à tous les types de traductions (modèles, ou en code)
  • dynamique signifie que vous ne savez que ce que vous voulez traduire au moment de l'exécution et que vous ne pouvez pas le faire au moment de la construction. Cela s'applique principalement aux traductions "en code", en utilisant un service. Je suppose que vous pourriez considérer les expressions ICU comme dynamiques dans le sens où elles dépendent d'une variable, mais vous pouvez toujours calculer toutes les traductions possibles au moment de la construction car le nombre de cas est fini.

J'ai reporté l'ajout du support i18n au projet actuel que nous développons mais nous nous rapprochons de la sortie, une idée si ce sera définitif dans angular 7 ? Ou devrais-je envisager d'autres façons d'ajouter des traductions ?

@andrei-tatar i18n fonctionne parfaitement depuis Angular 2. Seuls bémols :

  • Pas de traduction de code (ce problème) -> Si vous en avez besoin, utilisez i18n-polyfill
  • Si vous créez AOT (recommandé), l'application doit être créée pour chaque langue séparément
  • Étant donné que chaque application est construite séparément, lorsque vous changez de langue, vous devez recharger la page

Pour les deux derniers points, vous pouvez utiliser @ngx-translate à la place. Mais cela fonctionne différemment de l'i18n intégré d'Angular, donc une mise à jour ultérieure pourrait prendre un certain temps. Pour le polyfill, la mise à jour se fera en un rien de temps sans probablement aucun changement de rupture.

@ocombe

Comment pouvons-nous gérer l'opérateur conditionnel à l'aide de la fonctionnalité Angular i18n

[email protected]> a écrit :

@ shobhit12345 https://github.com/shobhit12345

Nous utilisons ngSwitch pour modéliser tous les messages, afin que nous puissions attacher des balises i18n à
eux individuellement.

CacherMontrerHistoire

Nous utilisons beaucoup cette méthode pour contourner les traductions dynamiques manquantes.
Gaprès un peu de réflexion, une quantité surprenante de texte peut être exprimée dans
de cette façon dans les modèles. Un modèle courant consiste à avoir un tableau de messages,
puis utilisez-le avec ngFor et ngSwitch pour modéliser les messages,
quelque chose comme ça:

ts

messages = [ 'ceci est le premier message', 'ceci est le deuxième message' ]

html


i18n="@@firstMesssage">Ceci est le premier message
i18n="@@secondMesssage">Ceci est le deuxième message

C'est un peu verbeux - mais ça marche !


Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/angular/angular/issues/11405#issuecomment-415731284 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AGwM6jcWIpwtGxhkH1fwnVXNagRxmMnoks5uT-LxgaJpZM4J2pkr
.

Si c'est fait, cela n'aurait pas d'importance puisque nous devons attendre qu'Ivy soit terminé, ce qui est prévu pour Angular 7 (sept/oct 2018)

C'est déjà octobre. Pensez-vous que nous aurons les nouvelles fonctionnalités d'ici la fin octobre ?

@lizzymendivil selon https://is-angular-ivy-ready.firebaseapp.com Ivy est terminé à 65% et il semble peu probable qu'il soit terminé en seulement 30 jours

Oui, le lierre ne sera pas terminé dans un mois.

@ocombe pouvez-vous s'il vous plaît verrouiller ceci afin que vous seul puissiez publier des mises à jour. c'est un peu ennuyeux de recevoir toutes les notifications de tous les "quand c'est fait ?" commentaires

@ocombe , il semble qu'Ivy soit maintenant à environ 94 %, pensez-vous que cela pourrait être prêt d'ici la fin de l'année ?

Je ne pense pas. Être prêt pour les fonctionnalités et sans bogue (= utilisable) est très différent. Nous travaillons principalement à réparer les choses en ce moment.

@ocombe pouvons-nous croire que i18n est venu avant angular 8?

Je ne pense pas. Être prêt pour les fonctionnalités et sans bogue (= utilisable) est très différent. Nous travaillons principalement à réparer les choses en ce moment.

Ok, merci pour la réponse rapide, très apprécié.

Toute mise à jour @ocombe à laquelle nous devrions nous attendre (Fin de l'année, je vois dans les derniers commentaires) la partie "Code Translation" disponible avec "Template Translation" pour le support I18N avec Angular? Nous avons pensé à associer ngx-translate-polyfill pour la même chose avec la fonctionnalité Angular I18n, mais il semble également que le support xlf ne soit pas disponible pour fusionner un fichier xlf existant en utilisant https://github.com/biesbjerg/ngx-translate-extract CLI .

Merci !

@Abekonge

Nous utilisons ngSwitch pour modéliser tous les messages, afin que nous puissions leur attacher des balises i18n individuellement.
C'est un peu verbeux - mais ça marche !

Merci pour la suggestion! Cela semble le plus facile à comprendre. Ma question est la suivante: utilisez-vous toujours cette implémentation dans des situations où le tableau a "beaucoup" de valeurs, comme 10 ou plus? On dirait que le code deviendrait très volumineux.

Je ne sais pas si nous en avons autant, mais pourquoi pas. Si ce sont des messages utilisés à plusieurs endroits, nous fabriquons de petits composants i18n qui ne sont essentiellement que le commutateur et les balises i18n.

David

Den 23. janv. 2019 kilo. 19.24 skrev Andrew Bissada [email protected] :

@Abekonge

Nous utilisons ngSwitch pour modéliser tous les messages, afin que nous puissions leur attacher des balises i18n individuellement.
C'est un peu verbeux - mais ça marche !

Merci pour la suggestion! Cela semble le plus facile à comprendre. Ma question est la suivante: utilisez-vous toujours cette implémentation dans des situations où le tableau a "beaucoup" de valeurs, comme 10 ou plus? On dirait que le code deviendrait très volumineux.


Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub ou désactivez le fil de discussion.

Comment utiliser i18n-polifills dans les classes Validator. Je ne suis pas en mesure d'utiliser le message de validateur secret via le service i18n.

//Dans le composant
this.crForm= this.fb.group({
nom d'utilisateur: [''],
eMot de passe : [''],
}, { validateur : new AccValidator(this.i18n).validate()}
);

//Validateur

import { AbstractControl, ValidationErrors, FormGroup, FormControl } de '@angular/forms' ;
importer { I18n } de '@ngx-translate/i18n-polyfill' ;
classe d'exportation AccValidator{
constructeur(i18n:I18n)
{

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

obtenir en dessous de l'erreur

RROR Error : Uncaught (in promise) : TypeError : i18n n'est pas une fonction
TypeError : i18n n'est pas une fonction
à FormGroup.eval [en tant que validateur] (acc-validator.ts:9)
à FormGroup.AbstractControl._runValidator (forms.js:3433)
à FormGroup.AbstractControl.updateValueAndValidity (forms.js:3387)
au nouveau FormGroup (forms.js:4326)
sur FormBuilder.group (forms.js:7864)

@ocombe

Comment utiliser i18n-polyfills avec const dans les fichiers .ts

export const glossayModel= () => [
{
titre : "données de test",
actif : vrai,
Les données: [

        [
            {
                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, sélectionnez, Médical {Médical} Dentaire {Dentaire} Médical & Dentaire {Médical & Dentaire} Catastrophique & Dentaire {Catastrophique & Dentaire} Catastrophique {Catastrophique} }
{VAR_SELECT, sélectionnez, Médical {Médical} Dentaire {Dentaire} Médical### & Dentaire {Médical et Dentaire}
Catastrophique ### & Dentaire{Catastrophique et Dentaire} Catastrophique {Catastrophique} }

Lorsque j'utilise l'expression ICU avec un caractère spécial, ce n'est pas converti.

@ocombe Comment gérer la chapelure avec i18n-polyfills ?

exporter les routes const : Routes = [
{
chemin: '',
composant : HomeComponent,
Les données: {
titre : 'Accueil',
fil d'Ariane : 'Accueil'
}
}
]

@ocombe

Comment utiliser i18n-polyfills avec const dans les fichiers .ts

export const glossayModel= () => [
{
titre : "données de test",
actif : vrai,
Les données: [

        [
            {
                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."
            }

]]}] ;

Vous pouvez utiliser comme ça
{
données : 'données de test',
titre : this.i18n({ valeur : 'Nom', id : 'nom' }),
}
injecter le polyfill I18n dans le constructeur de composants comme celui-ci
i18n privé : I18n
Lorsque vous utilisez des traductions dans un fichier ts, vous devez utiliser ngx-extractor et xliffmerge pour traduire ces fichiers ts. https://www.npmjs.com/package/ngx-i18nsupport

@ JanneHarju
ça ne marche pas, je n'obtiens pas les données dans le fichier xlf.

Voici mon script de traduction :
"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",

et voici xliffmerge.json

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

@ JanneHarju
Oui, j'utilise la même configuration et je suis capable d'extraire des messages .ts dans un fichier xlf.

Mais const j'ai dans différents fichiers .ts

export const glossayModel= () => [
{
}

J'importe dans le composant, lorsque j'essaie d'utiliser i18n avec const, il n'extrait pas les valeurs.

Et si vous utilisiez des valeurs const comme provider.

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

le code peut être cassé mais vous obtenez peut-être un point.

comment traduire le fil d'Ariane

itinéraires const : itinéraires = [
{
chemin : './enroll-new.component',
composant : EnrollNewComponent,
Les données: {
fil d'Ariane : 'Inscription'
},
}
]

pouvez-vous arrêter d'utiliser ce fil comme fil de support pour i18n-polyfill ou d'autres problèmes ? si vous avez une question concernant i18n-polyfill, posez un problème dans ce dépôt.
@ocombe peut-être pouvez-vous verrouiller ce sujet ? à peu près tout ce qui est important devrait être couvert.
quelle est la version angulaire que vous prévoyez de publier le support i18n mentionné dans ce sujet ?

Oui, verrouillé pour l'instant.
Nous travaillons dur pour que ivy soit disponible avec la v8 en version bêta opt-in. Le runtime i18n sera utilisable avec la fermeture de google (ce que google utilise en interne) qui nous permettra de le déboguer (c'est un très gros changement). Pour tous les autres vous pourrez tester ivy avec i18n mais vous ne pourrez pas charger les traductions. L'application fonctionnera avec la langue d'origine utilisée pour coder l'application.
Le service d'exécution qui est nécessaire pour traduire réellement renvoie actuellement le texte non traduit. Étant donné que nous travaillons tous à corriger les bogues avec le code existant, les nouvelles fonctionnalités seront limitées après la publication. Nous y travaillerons une fois la v8 sortie, cela devrait être ma première tâche.
J'ajouterai une mise à jour et déverrouillerai ce fil une fois que nous aurons des nouvelles.

Pour ce que ça vaut, la nouvelle balise $localize laquelle nous travaillons peut être utilisée par programmation.

Par exemple

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

Et puis sera en mesure de fournir des traductions pour Hello {$name}! qui peuvent être remplacées au moment de la compilation (ou de l'exécution).

Ceci est maintenant disponible (si non documenté).

Cette page vous a été utile?
0 / 5 - 0 notes