Partager via


Localisation dans .NET

La localisation est le processus de traduction des ressources d’une application en versions localisées pour chaque culture prise en charge par l’application. Vous devez passer à l’étape de localisation uniquement après avoir effectué l’étape de révision de localisabilité pour vérifier que l’application globalisée est prête pour la localisation.

Une application prête pour la localisation est séparée en deux blocs conceptuels : un bloc qui contient tous les éléments d’interface utilisateur et un bloc qui contient du code exécutable. Le bloc d’interface utilisateur contient uniquement des éléments d’interface utilisateur localisables tels que des chaînes, des messages d’erreur, des boîtes de dialogue, des menus, des ressources d’objet incorporées, etc. pour la culture neutre. Le bloc de code contient uniquement le code d’application à utiliser par toutes les cultures prises en charge. Le Common Language Runtime prend en charge un modèle de ressource d’assembly satellite qui sépare le code exécutable d’une application de ses ressources. Pour plus d’informations sur l’implémentation de ce modèle, consultez Ressources dans .NET.

Pour chaque version localisée de votre application, ajoutez un nouvel assembly satellite qui contient le bloc d’interface utilisateur localisé traduit dans la langue appropriée pour la culture cible. Le bloc de code pour toutes les cultures doit rester le même. La combinaison d’une version localisée du bloc d’interface utilisateur avec le bloc de code produit une version localisée de votre application.

Dans cet article, vous apprendrez à utiliser les implémentations IStringLocalizer<T> et IStringLocalizerFactory. Tout le code source d'exemple dans cet article s'appuie sur les packages NuGet Microsoft.Extensions.Localization et Microsoft.Extensions.Hosting. Pour plus d’informations sur l’hébergement, consultez l’hôte générique .NET.

Fichiers de ressources

Le mécanisme principal pour isoler les chaînes localisables est avec les fichiers de ressources. Un fichier de ressources est un fichier XML avec l’extension de fichier .resx . Les fichiers de ressources sont traduits avant l’exécution de l’application consommatrice, en d’autres termes, ils représentent le contenu traduit au repos. Un nom de fichier de ressources contient généralement un identificateur de paramètres régionaux et prend la forme suivante :

<FullTypeName><.Locale>.resx

Où :

  • <FullTypeName> représente les ressources localisables pour un type spécifique.
  • Le paramètre facultatif <.Locale> représente les paramètres régionaux du contenu du fichier de ressources.

Spécification des paramètres régionaux

Les paramètres régionaux doivent définir la langue, au minimum, mais elles peuvent également définir la culture (langue régionale) et même le pays ou la région. Ces segments sont généralement délimités par le - caractère. Avec la spécificité supplémentaire d’une culture, les règles de « secours pour la culture » sont appliquées où les meilleures correspondances sont hiérarchisées. Les paramètres régionaux doivent être mappés à une balise de langue connue. Pour plus d’informations, consultez CultureInfo.Name.

Scénarios de repli culturels

Imagine que votre application localisée prend en charge différents paramètres régionaux serbe et dispose des fichiers de ressources suivants pour son MessageService :

Fichier Langue régionale Code de pays
MessageService.sr-Cyrl-RS.resx (Cyrillique, Serbie) RS
MessageService.sr-Cyrl.resx Cyrillique
MessageService.sr-Latn-BA.resx (Latin, Bosnie-et-Herzégovine) BA
MessageService.sr-Latn-ME.resx (Latin, Monténégro) moi
MessageService.sr-Latn-RS.resx (Latin, Serbie) RS
MessageService.sr-Latn.resx Latin
MessageService.sr.resx Latin
MessageService.resx

Langue régionale par défaut pour la langue.

Lorsque votre application s’exécute avec le CultureInfo.CurrentCulture défini sur une culture de "sr-Cyrl-RS" localisation tente de résoudre les fichiers dans l’ordre suivant :

  1. MessageService.sr-Cyrl-RS.resx
  2. MessageService.sr-Cyrl.resx
  3. MessageService.sr.resx
  4. MessageService.resx

Toutefois, si votre application s’exécutait avec le CultureInfo.CurrentCulture défini sur une culture de "sr-Latn-BA" localisation tente de résoudre les fichiers dans l’ordre suivant :

  1. MessageService.sr-Latn-BA.resx
  2. MessageService.sr-Latn.resx
  3. MessageService.sr.resx
  4. MessageService.resx

La règle de « secours pour la culture » ignore les paramètres régionaux lorsqu’il n’existe aucune correspondance correspondante, ce qui signifie que le numéro de fichier de ressource quatre est sélectionné s’il ne parvient pas à trouver une correspondance. Si la culture était définie "fr-FR", la localisation finirait par dépendre du fichier MessageService.resx, ce qui peut être problématique. Pour plus d’informations, consultez la procédure de remplacement des ressources.

Recherche de ressources

Les fichiers de ressources sont automatiquement résolus dans le cadre d’une routine de recherche. Si le nom de fichier de votre projet est différent de l’espace de noms racine de votre projet, le nom de l’assembly peut différer. Cela peut empêcher la recherche de ressources d’être correctement effectuée. Pour résoudre cette incompatibilité, utilisez la RootNamespaceAttribute méthode pour fournir un indicateur aux services de localisation. Lorsqu’elle est fournie, elle est utilisée lors de la recherche de ressources.

L’exemple de projet est nommé example.csproj, qui crée une example.dll et example.exe, mais l’espace Localization.Example de noms est utilisé. Appliquez un attribut de assembly niveau pour corriger cette incompatibilité :

[assembly: RootNamespace("Localization.Example")]

Inscrire les services de localisation

Pour inscrire des services de localisation, appelez une des méthodes d’extension AddLocalization pendant la configuration des services. Cela permet l’injection de dépendances (DI) des types suivants :

Configurer les options de localisation

La surcharge AddLocalization(IServiceCollection, Action<LocalizationOptions>) accepte un paramètre setupAction de type Action<LocalizationOptions>. Cela vous permet de configurer les options de localisation.

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddLocalization(options =>
{
    options.ResourcesPath = "Resources";
});

// Omitted for brevity.

Les fichiers de ressources peuvent vivre n’importe où dans un projet, mais il existe des pratiques courantes en place qui se sont avérées réussies. Plus souvent que non, le chemin de la moindre résistance est suivi. Le code C# précédent :

  • Crée le générateur d’application hôte par défaut.
  • Appelle AddLocalization dans la collection de services en spécifiant LocalizationOptions.ResourcesPath en tant que "Resources".

Cela entraînerait la recherche par les services de localisation dans le répertoire Ressources pour les fichiers de ressources.

Utiliser IStringLocalizer<T> et IStringLocalizerFactory

Une fois que vous avez inscrit (et éventuellement configuré) les services de localisation, vous pouvez utiliser les types suivants avec DI :

Pour créer un service de message capable de retourner des chaînes localisées, tenez compte des éléments suivants MessageService:

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;

namespace Localization.Example;

public sealed class MessageService(IStringLocalizer<MessageService> localizer)
{
    [return: NotNullIfNotNull(nameof(localizer))]
    public string? GetGreetingMessage()
    {
        LocalizedString localizedString = localizer["GreetingMessage"];

        return localizedString;
    }
}

Dans le code C# précédent :

  • Un IStringLocalizer<MessageService> localizer champ est déclaré.
  • Le constructeur principal définit un IStringLocalizer<MessageService> paramètre et le capture en tant qu’argument localizer .
  • La GetGreetingMessage méthode invoque le IStringLocalizer.Item[String] en passant "GreetingMessage" en tant qu’argument.

Le IStringLocalizer prend également en charge les ressources de chaîne paramétrables, considérez ce qui suit ParameterizedMessageService:

using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Localization;

namespace Localization.Example;

public class ParameterizedMessageService(IStringLocalizerFactory factory)
{
    private readonly IStringLocalizer _localizer =
        factory.Create(typeof(ParameterizedMessageService));

    [return: NotNullIfNotNull(nameof(_localizer))]
    public string? GetFormattedMessage(DateTime dateTime, double dinnerPrice)
    {
        LocalizedString localizedString = _localizer["DinnerPriceFormat", dateTime, dinnerPrice];

        return localizedString;
    }
}

Dans le code C# précédent :

  • Un IStringLocalizer _localizer champ est déclaré.
  • Le constructeur principal prend le paramètre IStringLocalizerFactory, utilisé pour créer un IStringLocalizer à partir du type ParameterizedMessageService et l'assigne au champ _localizer.
  • La GetFormattedMessage méthode appelle IStringLocalizer.Item[String, Object[]], passe "DinnerPriceFormat", objet dateTime et dinnerPrice en tant qu’arguments.

Importante

Ce IStringLocalizerFactory n’est pas obligatoire. Au lieu de cela, il est préférable que les services consommés nécessitent le IStringLocalizer<T>.

Les deux indexeurs IStringLocalizer.Item[] retournent un LocalizedString, qui a des conversions implicites en string?.

Mets tout ensemble

Pour illustrer une application à l’aide des deux services de message, ainsi que des fichiers de localisation et de ressources, tenez compte du fichier Program.cs suivant :

using System.Globalization;
using Localization.Example;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using static System.Console;
using static System.Text.Encoding;

[assembly: RootNamespace("Localization.Example")]

OutputEncoding = Unicode;

if (args is [var cultureName])
{
    CultureInfo.CurrentCulture =
        CultureInfo.CurrentUICulture =
            CultureInfo.GetCultureInfo(cultureName);
}

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddLocalization();
builder.Services.AddTransient<MessageService>();
builder.Services.AddTransient<ParameterizedMessageService>();
builder.Logging.SetMinimumLevel(LogLevel.Warning);

using IHost host = builder.Build();

IServiceProvider services = host.Services;

ILogger logger =
    services.GetRequiredService<ILoggerFactory>()
        .CreateLogger("Localization.Example");

MessageService messageService =
    services.GetRequiredService<MessageService>();
logger.LogWarning(
    "{Msg}",
    messageService.GetGreetingMessage());

ParameterizedMessageService parameterizedMessageService =
    services.GetRequiredService<ParameterizedMessageService>();
logger.LogWarning(
    "{Msg}",
    parameterizedMessageService.GetFormattedMessage(
        DateTime.Today.AddDays(-3), 37.63));

await host.RunAsync();

Dans le code C# précédent :

  • Le RootNamespaceAttribute définit "Localization.Example" en tant qu’espace de noms racine.
  • La Console.OutputEncoding est affectée à Encoding.Unicode.
  • Lorsque un seul argument est passé à args, CultureInfo.CurrentCulture et CultureInfo.CurrentUICulture reçoivent le résultat de CultureInfo.GetCultureInfo(String) donné par arg[0].
  • Le Host fichier est créé avec les valeurs par défaut.
  • Les services de localisation, MessageService, et ParameterizedMessageService sont inscrits auprès de IServiceCollection pour DI.
  • Pour éliminer les interférences, la journalisation est configurée pour ignorer tout niveau de journalisation inférieur à un avertissement.
  • L’élément MessageService est résolu à partir de l’instance IServiceProvider et le message résultant est consigné.
  • Le ParameterizedMessageService est résolu à partir de l’instance IServiceProvider et son message mis en forme résultant est enregistré.

Chacune des *MessageService classes définit un ensemble de fichiers .resx , chacun avec une entrée unique. Voici l’exemple de contenu des MessageService fichiers de ressources, en commençant par MessageService.resx :

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Hi friends, the ".NET" developer community is excited to see you here!</value>
  </data>
</root>

MessageService.sr-Cyrl-RS.resx :

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!</value>
  </data>
</root>

MessageService.sr-Latn.resx :

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="GreetingMessage" xml:space="preserve">
    <value>Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!</value>
  </data>
</root>

Voici l’exemple de contenu des ParameterizedMessageService fichiers de ressources, en commençant par ParameterizedMessageService.resx :

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>On {0:D} my dinner cost {1:C}.</value>
  </data>
</root>

ParameterizedMessageService.sr-Cyrl-RS.resx :

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>У {0:D} моја вечера је коштала {1:C}.</value>
  </data>
</root>

ParameterizedMessageService.sr-Latn.resx :

<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="DinnerPriceFormat" xml:space="preserve">
    <value>U {0:D} moja večera je koštala {1:C}.</value>
  </data>
</root>

Conseil / Astuce

Tous les commentaires XML du fichier de ressources, le schéma et les éléments <resheader> sont intentionnellement omis par souci de concision.

Exemples d’exécutions

L’exemple d’exécution suivant montre les différentes sorties localisées, en fonction des paramètres régionaux ciblés.

Prenons l’exemple "sr-Latn"suivant :

dotnet run --project .\example\example.csproj sr-Latn

warn: Localization.Example[0]
      Zdravo prijatelji, ".NET" developer zajednica je uzbuđena što vas vidi ovde!
warn: Localization.Example[0]
      U utorak, 03. avgust 2021. moja večera je koštala 37,63 ¤.

Lors de l’omission d’un argument à l’interface CLI .NET pour exécuter le projet, la culture système par défaut est utilisée dans ce cas "en-US":

dotnet run --project .\example\example.csproj

warn: Localization.Example[0]
      Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
      On Tuesday, August 3, 2021 my dinner cost $37.63.

Lors de la transmission "sr-Cryl-RS", les fichiers de ressources correspondants corrects sont trouvés et la localisation appliquée :

dotnet run --project .\example\example.csproj sr-Cryl-RS

warn: Localization.Example[0]
      Здраво пријатељи, ".NЕТ" девелопер заједница је узбуђена што вас види овде!
warn: Localization.Example[0]
      У уторак, 03. август 2021. моја вечера је коштала 38 RSD.

L’exemple d’application ne fournit pas de fichiers de ressources pour "fr-CA", mais lorsqu’il est appelé avec cette culture, les fichiers de ressources non localisés sont utilisés.

Avertissement

Étant donné que la culture est trouvée, mais que les fichiers de ressources corrects ne le sont pas, lorsque la mise en forme est appliquée, cela aboutit à une localisation partielle.

dotnet run --project .\example\example.csproj fr-CA

warn: Localization.Example[0]
     Hi friends, the ".NET" developer community is excited to see you here!
warn: Localization.Example[0]
     On mardi 3 août 2021 my dinner cost 37,63 $.

Voir aussi