Condividi tramite


Creare un pacchetto e distribuire risorse nelle app .NET

Le applicazioni si basano su .NET Framework Resource Manager, rappresentato dalla ResourceManager classe , per recuperare le risorse localizzate. Resource Manager presuppone che venga usato un modello hub-spoke per creare un pacchetto e distribuire le risorse. L'hub è l'assembly principale che contiene il codice eseguibile non localizzato e le risorse per una singola cultura, denominata cultura neutra o predefinita. L'impostazione culturale predefinita è l'impostazione culturale di riserva per l'applicazione; è l'impostazione i cui risorse vengono usate se non è possibile trovare risorse localizzate. Ogni spoke si connette a un assembly satellite che contiene le risorse per una singola lingua, ma non contiene codice.

Questo modello presenta diversi vantaggi:

  • È possibile aggiungere risorse per le nuove culture in modo incrementale dopo aver distribuito un'applicazione. Poiché lo sviluppo successivo di risorse specifiche per la cultura può richiedere una notevole quantità di tempo, ciò consente di rilasciare prima l'applicazione principale e di distribuire le risorse specifiche per la cultura in un secondo momento.
  • È possibile aggiornare e modificare gli assembly satellite di un'applicazione senza ricompilare l'applicazione.
  • Un'applicazione deve caricare solo gli assembly satellite che contengono le risorse necessarie per una cultura particolare. Ciò può ridurre significativamente l'uso delle risorse di sistema.

Tuttavia, esistono anche svantaggi per questo modello:

  • È necessario gestire più set di risorse.
  • Il costo iniziale di test di un'applicazione aumenta perché è necessario testare diverse configurazioni. Si noti che a lungo termine sarà più semplice e meno costoso testare un'applicazione core con diversi satelliti, piuttosto che testare e mantenere diverse versioni internazionali parallele.

Convenzioni di denominazione delle risorse

Quando si crea un pacchetto delle risorse dell'applicazione, è necessario denominarli usando le convenzioni di denominazione delle risorse previste da Common Language Runtime. Il runtime identifica una risorsa in base al nome della cultura. A ogni cultura viene assegnato un nome univoco, che in genere è una combinazione di un nome cultura a due lettere minuscole associato a una lingua e, se necessario, un nome di sottocultura in due lettere maiuscole associato a un paese o un'area geografica. Il nome della sottocultura segue il nome della cultura, separato da un trattino (-). Gli esempi includono ja-JP per il giapponese parlato in Giappone, en-US per l'inglese parlato negli Stati Uniti, de-DE per il tedesco come parlato in Germania o de-AT per il tedesco parlato in Austria. Vedere la colonna Tag linguanell'elenco dei nomi di lingua/area geografica supportati da Windows. I nomi delle culture seguono lo standard definito da BCP 47.

Annotazioni

Esistono alcune eccezioni per i nomi cultura a due lettere, come zh-Hans per il cinese (semplificato).

Per ulteriori informazioni, vedere Creazione di file di risorse e Creazione di assembly satellite.

Processo di ripiego delle risorse

Il modello hub-spoke per la creazione di pacchetti e la distribuzione delle risorse usa un processo di fallback per individuare le risorse appropriate. Se un'applicazione richiede una risorsa localizzata non disponibile, il Common Language Runtime cerca nella gerarchia delle culture una risorsa di fallback appropriata che corrisponda il più strettamente possibile alla richiesta dell'utente e genera un'eccezione solo come ultima possibilità. A ogni livello della gerarchia, se viene trovata una risorsa appropriata, il runtime lo usa. Se la risorsa non viene trovata, la ricerca continua al livello successivo.

Per migliorare le prestazioni di ricerca, applicare l'attributo NeutralResourcesLanguageAttribute al proprio assembly principale e passare il nome della lingua neutra che verrà utilizzata con l'assembly principale.

Processo di fallback delle risorse .NET Framework

Il processo di fallback delle risorse di .NET Framework prevede i passaggi seguenti:

Suggerimento

Potresti essere in grado di usare l'elemento <di configurazione relativeBindForResources> per ottimizzare il processo di fallback delle risorse e il processo attraverso il quale il runtime sonda gli assembly di risorse. Per altre informazioni, vedere Ottimizzazione del processo di fallback delle risorse.

  1. Il runtime verifica innanzitutto la presenza di un assembly nella Global Assembly Cache che corrisponda alla cultura richiesta per l'applicazione.

    La Global Assembly Cache può archiviare gli assembly di risorse condivisi da molte applicazioni. Questo ti libera dal dover includere set specifici di risorse nella struttura di directory di ogni applicazione che crei. Se il runtime trova un riferimento all'assembly, cerca la risorsa richiesta nell'assembly. Se trova la voce nell'assembly, usa la risorsa richiesta. Se non trova l'elemento, continua la ricerca.

  2. Il runtime controlla quindi la directory dell'assembly attualmente in esecuzione alla ricerca di una sottodirectory che corrisponda alla cultura richiesta. Se trova la sottodirectory, cerca in quella sottodirectory un assembly satellite valido per la cultura richiesta. Il runtime cerca quindi nell'assembly satellite la risorsa richiesta. Se trova la risorsa nell'assembly, la usa. Se non trova la risorsa, continua la ricerca.

  3. Il runtime esegue poi una query su Windows Installer per determinare se l'assembly satellite deve essere installato su richiesta. In tal caso, gestisce l'installazione, carica l'assembly e effettua una ricerca dell'assembly o della risorsa richiesta. Se trova la risorsa nell'assembly, la usa. Se non trova la risorsa, continua la ricerca.

  4. Il runtime genera l'evento AppDomain.AssemblyResolve per indicare che non è in grado di trovare l'assembly satellite. Se si sceglie di gestire l'evento, il gestore eventi può restituire un riferimento all'assembly satellite le cui risorse verranno usate per la ricerca. In caso contrario, il gestore eventi restituisce null e la ricerca continua.

  5. Il runtime esegue di nuovo la ricerca nella cache globale degli assembly, questa volta per l'assembly principale della cultura richiesta. Se l'assembly padre esiste nella cache di assembly globale, il runtime cerca la risorsa richiesta nell'assembly.

    La cultura madre è definita come cultura di fallback appropriata. Considerare i genitori come candidati di fallback, perché fornire qualsiasi risorsa è preferibile a lanciare un'eccezione. Questo processo consente anche di riutilizzare le risorse. È consigliabile includere una particolare risorsa a livello del genitore solo se la cultura figlio non deve localizzare la risorsa richiesta. Ad esempio, se si forniscono assembly satellite per en (inglese neutro), en-GB (inglese parlato nel Regno Unito) e en-US (inglese parlato negli Stati Uniti), il en satellite conterrà la terminologia comune e i en-GB satelliti e en-US potrebbero fornire sostituzioni solo per i termini che differiscono.

  6. Il runtime controlla quindi la directory dell'assembly attualmente in esecuzione per verificare se contiene una directory padre. Se esiste una directory padre, il runtime cerca nella directory un satellite assembly valido per la cultura padre. Se l'assembly viene trovato, il runtime cerca nell'assembly la risorsa richiesta. Se trova la risorsa, la usa. Se non trova la risorsa, continua la ricerca.

  7. Il runtime interroga quindi Windows Installer per determinare se l'assembly satellite padre deve essere installato su richiesta. In tal caso, gestisce l'installazione, carica l'assembly e effettua una ricerca dell'assembly o della risorsa richiesta. Se trova la risorsa nell'assembly, la usa. Se non trova la risorsa, continua la ricerca.

  8. Il runtime genera l'evento AppDomain.AssemblyResolve per indicare che non è in grado di trovare una risorsa di fallback appropriata. Se si sceglie di gestire l'evento, il gestore eventi può restituire un riferimento all'assembly satellite le cui risorse verranno usate per la ricerca. In caso contrario, il gestore eventi restituisce null e la ricerca continua.

  9. Il runtime cerca gli assembly padre, come nei tre passaggi precedenti, attraverso molti livelli potenziali. Ogni cultura ha un solo genitore, definito dalla proprietà CultureInfo.Parent, ma un genitore potrebbe avere il proprio genitore. La ricerca delle culture padre si arresta quando la proprietà di Parent di una cultura restituisce CultureInfo.InvariantCulture; per il fallback delle risorse, la cultura invariante non è considerata una cultura padre o una cultura che possa avere risorse.

  10. Se la cultura specificata in origine e tutte le culture padre sono state cercate e la risorsa ancora non viene trovata, viene usata la risorsa per la cultura predefinita di fallback. In genere, le risorse per la cultura predefinita sono incluse nell'assemblaggio principale dell'applicazione. È tuttavia possibile specificare un valore di Satellite per la proprietà Location dell'attributo NeutralResourcesLanguageAttribute per indicare che il percorso di fallback finale per le risorse è un assembly satellite, anziché l'assembly principale.

    Annotazioni

    La risorsa predefinita è l'unica risorsa che può essere compilata con l'assembly principale. A meno che non si specifichi un assembly satellite usando l'attributo NeutralResourcesLanguageAttribute , si tratta del fallback finale (padre finale). È pertanto consigliabile includere sempre un set predefinito di risorse nell'assembly principale. Ciò consente di evitare che vengano generate eccezioni. Includendo una risorsa predefinita, il file fornisce un fallback per tutte le risorse e assicura che almeno una risorsa sia sempre presente per l'utente, anche se non è legata a specifiche culturali.

  11. Infine, se il runtime non trova una risorsa per la cultura predefinita (fallback), viene generata un'eccezione MissingManifestResourceException o MissingSatelliteAssemblyException per indicare che la risorsa non è stata trovata.

Supponiamo, ad esempio, che l'applicazione richieda una risorsa localizzata per lo spagnolo (Messico) (la cultura es-MX). Il runtime cerca prima nella Global Assembly Cache l'assembly che corrisponde a es-MX, ma non lo trova. Il runtime cerca quindi nella directory dell'assembly attualmente in esecuzione la directory es-MX. In caso contrario, il runtime cerca nuovamente nella global assembly cache un assembly padre che riflette la cultura di riserva appropriata, in questo caso es (spagnolo). Se l'assembly padre non viene trovato, il runtime cerca a tutti i potenziali livelli di assembly padre per la cultura es-MX finché non trova una risorsa corrispondente. Se una risorsa non viene trovata, il runtime usa la risorsa della cultura predefinita.

Ottimizzare il processo di fallback delle risorse di .NET Framework

Nelle condizioni seguenti è possibile ottimizzare il processo in base al quale il runtime cerca le risorse negli assembly satellite:

  • Gli assembly satellitari vengono distribuiti nella stessa posizione dell'assembly di codice. Se l'assembly di codice viene installato nella Global Assembly Cache, anche gli assembly satellite vengono installati nella Global Assembly Cache. Se l'assembly di codice viene installato in una directory, gli assembly satellite vengono installati in cartelle specifiche per la cultura di tale directory.

  • Gli assembly satellite non vengono installati su richiesta.

  • Il codice dell'applicazione non gestisce l'evento AppDomain.AssemblyResolve .

Puoi ottimizzare il probe per gli assembly satellite includendo l'elemento <relativeBindForResources> e impostando il suo attributo enabled a true nel file di configurazione dell'applicazione, come illustrato nel seguente esempio.

<configuration>
   <runtime>
      <relativeBindForResources enabled="true" />
   </runtime>
</configuration>

La sonda ottimizzata per gli assemblaggi satellitari è una funzionalità opzionale. Ovvero, il runtime segue i passaggi descritti in Processo di fallback delle risorse a meno che l'elemento <relativeBindForResources> non sia presente nel file di configurazione dell'applicazione e il relativo enabled attributo sia impostato su true. In questo caso, il processo di sondaggio per un assemblaggio satellite viene modificato come segue:

  • Il runtime usa il percorso dell'assembly principale per cercare l'assembly satellite. Se l'assembly padre è installato nella Global Assembly Cache (Cache globale delle assembly), il runtime esegue il sondaggio nella cache ma non nella directory dell'applicazione. Se l'assembly padre è installato in una directory dell'applicazione, il runtime esegue il controllo nella directory dell'applicazione ma non nella cache globale degli assembly.

  • Il runtime non interroga Windows Installer per l'installazione su richiesta di assembly satellite.

  • Se la sonda per un determinato assembly di risorse ha esito negativo, il runtime non attiva l'evento AppDomain.AssemblyResolve.

Processo di fallback delle risorse .NET Core

Il processo di fallback delle risorse .NET Core prevede i passaggi seguenti:

  1. Il runtime tenta di caricare un assembly satellite per la cultura richiesta.

    • Controlla nella directory dell'assembly in esecuzione una sottodirectory che corrisponda alla cultura richiesta. Se trova la sottodirectory, cerca nella sottodirectory un satellite assembly valido per la cultura richiesta e lo carica.

      Annotazioni

      Nei sistemi operativi con file system con distinzione tra maiuscole e minuscole, ovvero Linux e macOS, la ricerca della sottodirectory dei nomi delle impostazioni cultura fa distinzione tra maiuscole e minuscole. Il nome della sottodirectory deve corrispondere esattamente al maiuscolo/minuscolo di CultureInfo.Name, ad esempio es o es-MX.

      Annotazioni

      Se il programmatore ha derivato un contesto di caricamento di assembly personalizzato da AssemblyLoadContext, la situazione è complicata. Se l'assembly in esecuzione è stato caricato nel contesto personalizzato, il runtime carica l'assembly satellite nel contesto personalizzato. I dettagli non rientrano nell'ambito di questo documento. Vedi AssemblyLoadContext.

    • Se un assemblaggio satellite non è stato trovato, AssemblyLoadContext genera l'evento AssemblyLoadContext.Resolving indicando che non è in grado di trovare l'assemblaggio satellite. Se si sceglie di gestire l'evento, il gestore eventi può caricare e restituire un riferimento all'assembly satellite.

    • Se non è ancora stato trovato un assembly satellite, AssemblyLoadContext fa sì che AppDomain attivi un AppDomain.AssemblyResolve evento per indicare che non è in grado di trovare l'assembly satellite. Se si sceglie di gestire l'evento, il gestore eventi può caricare e restituire un riferimento all'assembly satellite.

  2. Quando viene trovato un assembly satellite, il runtime cerca la risorsa richiesta. Se trova la risorsa nell'assembly, la usa. Se non trova la risorsa, continua la ricerca.

    Annotazioni

    Per trovare una risorsa nell'assembly satellite, il runtime cerca il file di risorse richiesto dall'oggetto ResourceManager per il CultureInfo.Name corrente. All'interno del file di risorse cerca il nome della risorsa richiesto. Se nessuno dei due viene trovato, la risorsa viene considerata come non trovata.

  3. Il runtime cerca quindi gli assembly delle culture padre attraverso vari livelli potenziali, ripetendo ogni volta i passaggi 1 e 2.

    La cultura principale è definita come cultura di riserva appropriata. Considerare i genitori come candidati di fallback, perché fornire qualsiasi risorsa è preferibile a lanciare un'eccezione. Questo processo consente anche di riutilizzare le risorse. È consigliabile includere una particolare risorsa a livello del genitore solo se la cultura figlio non deve localizzare la risorsa richiesta. Ad esempio, se si forniscono assembly satellitari per en (inglese neutro), en-GB (inglese parlato nel Regno Unito) e en-US (inglese parlato negli Stati Uniti), il satellite en contiene la terminologia comune, mentre i satelliti en-GB e en-US offrono sostituzioni solo per i termini che differiscono.

    Ogni cultura ha un solo genitore, definito dalla proprietà CultureInfo.Parent, ma un genitore potrebbe avere il proprio genitore. La ricerca delle culture genitore si arresta quando la proprietà di una cultura restituisce Parent. Per il fallback delle risorse, la cultura invariante non è considerata una cultura madre o una cultura che può contenere risorse.

  4. Se la cultura specificata in origine e tutte le culture padre sono state cercate e la risorsa ancora non viene trovata, viene usata la risorsa per la cultura predefinita di fallback. In genere, le risorse per la cultura predefinita sono incluse nell'assemblaggio principale dell'applicazione. Tuttavia, è possibile specificare un valore di Satellite per la proprietà Location per indicare che il percorso di fallback finale per le risorse è un assembly satellite anziché l'assembly principale.

    Annotazioni

    La risorsa predefinita è l'unica risorsa che può essere compilata con l'assembly principale. A meno che non si specifichi un assembly satellite usando l'attributo NeutralResourcesLanguageAttribute , si tratta del fallback finale (padre finale). È pertanto consigliabile includere sempre un set predefinito di risorse nell'assembly principale. Ciò consente di evitare che vengano generate eccezioni. Includendo un file di risorse predefinito, si fornisce un fallback per tutte le risorse e si garantisce che almeno una risorsa sia sempre presente per l'utente, anche se non è specifica a livello culturale.

  5. Infine, se il runtime non trova un file di risorse per una cultura predefinita (fallback), viene generata un'eccezione MissingManifestResourceException o MissingSatelliteAssemblyException per indicare che non è stato possibile trovare la risorsa. Se il file di risorse viene trovato ma la risorsa richiesta non è presente, la richiesta restituisce null.

Ultima risorsa all'assemblaggio del modulo satellite

È possibile rimuovere, se si desidera, le risorse dall'assembly principale e specificare di caricare le risorse di fallback finali da un assembly satellite che corrisponde a una cultura specifica nel runtime. Per controllare il processo di fallback, usare il NeutralResourcesLanguageAttribute(String, UltimateResourceFallbackLocation) costruttore e specificare un valore per il UltimateResourceFallbackLocation parametro che specifica se Resource Manager deve estrarre le risorse di fallback dall'assembly principale o da un assembly satellite.

Nell'esempio di .NET Framework seguente viene usato l'attributo NeutralResourcesLanguageAttribute per archiviare le risorse di fallback di un'applicazione in un assembly satellite per la lingua francese (fr). L'esempio include due file di risorse basati su testo che definiscono una singola risorsa stringa denominata Greeting. La prima, resources.fr.txt, contiene una risorsa di lingua francese.

Greeting=Bon jour!

La seconda, risorse,ru.txt, contiene una risorsa di lingua russa.

Greeting=Добрый день

Questi due file vengono compilati in file con estensione resources eseguendo generatore di file di risorse (resgen.exe) dalla riga di comando. Per la risorsa francese, il comando è:

resgen.exe resources.fr.txt

Per la risorsa lingua russa, il comando è:

resgen.exe resources.ru.txt

I file con estensione resources sono incorporati in librerie di collegamento dinamico eseguendo Assembly Linker (al.exe) dalla riga di comando per la risorsa in lingua francese come indicato di seguito:

al /t:lib /embed:resources.fr.resources /culture:fr /out:fr\Example1.resources.dll

e per la risorsa lingua russa come indicato di seguito:

al /t:lib /embed:resources.ru.resources /culture:ru /out:ru\Example1.resources.dll

Il codice sorgente dell'applicazione si trova in un file denominato Example1.cs o Example1.vb. Include l'attributo NeutralResourcesLanguageAttribute per indicare che la risorsa applicazione predefinita si trova nella sottodirectory fr. Crea un'istanza di Resource Manager, recupera il valore della Greeting risorsa e la visualizza nella console.

using System;
using System.Reflection;
using System.Resources;

[assembly:NeutralResourcesLanguage("fr", UltimateResourceFallbackLocation.Satellite)]

public class Example
{
   public static void Main()
   {
      ResourceManager rm = new ResourceManager("resources",
                                               typeof(Example).Assembly);
      string greeting = rm.GetString("Greeting");
      Console.WriteLine(greeting);
   }
}
Imports System.Reflection
Imports System.Resources

<Assembly: NeutralResourcesLanguage("fr", UltimateResourceFallbackLocation.Satellite)>
Module Example
    Public Sub Main()
        Dim rm As New ResourceManager("resources", GetType(Example).Assembly)
        Dim greeting As String = rm.GetString("Greeting")
        Console.WriteLine(greeting)
    End Sub
End Module

È quindi possibile compilare il codice sorgente C# dalla riga di comando come indicato di seguito:

csc Example1.cs

Il comando per il compilatore Visual Basic è molto simile:

vbc Example1.vb

Poiché non sono presenti risorse incorporate nell'assembly principale, non è necessario compilare usando l'opzione /resource .

Quando si esegue l'esempio da un sistema la cui lingua è diversa dal russo, viene visualizzato l'output seguente:

Bon jour!

Alternativa di confezionamento suggerita

I vincoli relativi al tempo o al budget potrebbero impedire la creazione di un set di risorse per ogni sottoculture supportata dall'applicazione. È possibile creare un singolo assembly satellite per una cultura principale che tutte le sottoculture correlate possono utilizzare. Ad esempio, è possibile fornire un singolo assembly satellite inglese (en) recuperato dagli utenti che richiedono risorse in inglese specifiche dell'area geografica e un singolo assembly satellite tedesco (de) per gli utenti che richiedono risorse tedesche specifiche dell'area. Ad esempio, le richieste di tedesco, così come parlato in Germania (de-DE), Austria (de-AT) e Svizzera (de-CH) rientrerebbero nell'assembly satellite della lingua tedesca (de). Le risorse predefinite sono il fallback finale e pertanto devono essere le risorse richieste dalla maggior parte degli utenti dell'applicazione, quindi scegliere attentamente queste risorse. Questo approccio distribuisce le risorse meno specifiche della cultura, ma può ridurre significativamente i costi di localizzazione dell'applicazione.

Vedere anche