Condividi tramite


Recuperare le risorse nelle app .NET

Quando si lavora con le risorse localizzate nelle app .NET, è consigliabile idealmente impacchettare le risorse per la cultura predefinita o neutrale con l'assembly principale e creare un assembly satellite separato per ogni lingua o cultura supportata dall'app. È quindi possibile usare la ResourceManager classe come descritto nella sezione successiva per accedere alle risorse denominate. Se si sceglie di non incorporare le risorse negli assembly principali e negli assembly satellite, è anche possibile accedere direttamente ai file binari con estensione resources , come illustrato nella sezione Recuperare le risorse dai file con estensione resources più avanti in questo articolo.

Recuperare risorse dagli assembly

La ResourceManager classe fornisce l'accesso alle risorse in fase di esecuzione. Usare il ResourceManager.GetString metodo per recuperare le risorse stringa e il ResourceManager.GetObject metodo o ResourceManager.GetStream per recuperare le risorse non stringa. Ogni metodo ha due sovraccarichi:

Il gestore delle risorse utilizza il processo di fallback delle risorse per controllare il modo in cui l'app recupera le risorse specifiche culturali. Per altre informazioni, vedere la sezione "Processo di fallback delle risorse" in Pacchetto e distribuzione delle risorse. Per informazioni sulla creazione di un'istanza di un oggetto ResourceManager, vedere la sezione "Creazione di un'istanza di un oggetto ResourceManager" nell'argomento della classe ResourceManager.

Esempio di recupero di dati di stringa

Nell'esempio seguente viene chiamato il metodo GetString(String) per recuperare le risorse stringa della cultura UI corrente. Include una risorsa stringa neutra per la cultura inglese (Stati Uniti) e le risorse localizzate per le culture francese (Francia) e russa (Russia). La risorsa inglese (Stati Uniti) seguente si trova in un file denominato Strings.txt:

TimeHeader=The current time is

La risorsa francese (Francia) si trova in un file denominato Strings.fr-FR.txt:

TimeHeader=L'heure actuelle est

La risorsa russa (Russia) si trova in un file denominato Strings.ru-RU.txt:

TimeHeader=Текущее время —

Il codice sorgente per questo esempio, che si trova in un file denominato GetString.cs per la versione C# del codice e GetString.vb per la versione Visual Basic, definisce un array di stringhe che contiene i nomi di quattro culture: le tre culture per le quali sono disponibili risorse e la cultura spagnola (Spagna). Un ciclo che viene eseguito cinque volte seleziona casualmente una di queste culture e la assegna alle proprietà Thread.CurrentCulture e CultureInfo.CurrentUICulture. Chiama quindi il GetString(String) metodo per recuperare la stringa localizzata, visualizzata insieme all'ora del giorno.

using System;
using System.Globalization;
using System.Resources;
using System.Threading;

[assembly: NeutralResourcesLanguageAttribute("en-US")]

public class Example
{
   public static void Main()
   {
      string[] cultureNames = { "en-US", "fr-FR", "ru-RU", "es-ES" };
      Random rnd = new Random();
      ResourceManager rm = new ResourceManager("Strings",
                               typeof(Example).Assembly);

      for (int ctr = 0; ctr <= cultureNames.Length; ctr++) {
         string cultureName = cultureNames[rnd.Next(0, cultureNames.Length)];
         CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);
         Thread.CurrentThread.CurrentCulture = culture;
         Thread.CurrentThread.CurrentUICulture = culture;

         Console.WriteLine($"Current culture: {culture.NativeName}");
         string timeString = rm.GetString("TimeHeader");
         Console.WriteLine($"{timeString} {DateTime.Now:T}\n");
      }
   }
}
// The example displays output like the following:
//    Current culture: English (United States)
//    The current time is 9:34:18 AM
//
//    Current culture: Español (España, alfabetización internacional)
//    The current time is 9:34:18
//
//    Current culture: русский (Россия)
//    Текущее время — 9:34:18
//
//    Current culture: français (France)
//    L'heure actuelle est 09:34:18
//
//    Current culture: русский (Россия)
//    Текущее время — 9:34:18
Imports System.Globalization
Imports System.Resources
Imports System.Threading

<Assembly: NeutralResourcesLanguageAttribute("en-US")>

Module Example
    Public Sub Main()
        Dim cultureNames() As String = {"en-US", "fr-FR", "ru-RU", "es-ES"}
        Dim rnd As New Random()
        Dim rm As New ResourceManager("Strings", GetType(Example).Assembly)

        For ctr As Integer = 0 To cultureNames.Length
            Dim cultureName As String = cultureNames(rnd.Next(0, cultureNames.Length))
            Dim culture As CultureInfo = CultureInfo.CreateSpecificCulture(cultureName)
            Thread.CurrentThread.CurrentCulture = culture
            Thread.CurrentThread.CurrentUICulture = culture

            Console.WriteLine("Current culture: {0}", culture.NativeName)
            Dim timeString As String = rm.GetString("TimeHeader")
            Console.WriteLine("{0} {1:T}", timeString, Date.Now)
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays output similar to the following:
'    Current culture: English (United States)
'    The current time is 9:34:18 AM
'    
'    Current culture: Español (España, alfabetización internacional)
'    The current time is 9:34:18
'    
'    Current culture: русский (Россия)
'    Текущее время — 9:34:18
'    
'    Current culture: français (France)
'    L'heure actuelle est 09:34:18
'    
'    Current culture: русский (Россия)
'    Текущее время — 9:34:18

Il file batch seguente (.bat) compila l'esempio e genera assembly satellitari nelle directory adatte. I comandi vengono forniti per il linguaggio e il compilatore C#. Per Visual Basic, passare csc a vbce passare GetString.cs a GetString.vb.

resgen strings.txt
csc GetString.cs -resource:strings.resources

resgen strings.fr-FR.txt
md fr-FR
al -embed:strings.fr-FR.resources -culture:fr-FR -out:fr-FR\GetString.resources.dll

resgen strings.ru-RU.txt
md ru-RU
al -embed:strings.ru-RU.resources -culture:ru-RU -out:ru-RU\GetString.resources.dll

Quando le impostazioni cultura dell'interfaccia utente correnti sono spagnolo (Spagna), si noti che nell'esempio vengono visualizzate le risorse in lingua inglese, perché le risorse della lingua spagnola non sono disponibili e l'inglese è la lingua predefinita dell'esempio.

Recuperare esempi di dati oggetto

È possibile utilizzare i GetObject metodi e GetStream per recuperare i dati dell'oggetto. Sono inclusi i tipi di dati primitivi, gli oggetti serializzabili e gli oggetti archiviati in formato binario , ad esempio immagini.

L'esempio seguente usa il GetStream(String) metodo per recuperare una bitmap usata nella finestra iniziale di apertura di un'app. Il codice sorgente seguente in un file denominato CreateResources.cs (per C#) o CreateResources.vb (per Visual Basic) genera un file resx che contiene l'immagine serializzata. In questo caso, l'immagine viene caricata da un file denominato SplashScreen.jpg; è possibile modificare il nome del file in modo da sostituire la propria immagine.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Resources;

public class Example
{
   public static void Main()
   {
      Bitmap bmp = new Bitmap(@".\SplashScreen.jpg");
      MemoryStream imageStream = new MemoryStream();
      bmp.Save(imageStream, ImageFormat.Jpeg);

      ResXResourceWriter writer = new ResXResourceWriter("AppResources.resx");
      writer.AddResource("SplashScreen", imageStream);
      writer.Generate();
      writer.Close();
   }
}
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Resources

Module Example
    Public Sub Main()
        Dim bmp As New Bitmap(".\SplashScreen.jpg")
        Dim imageStream As New MemoryStream()
        bmp.Save(imageStream, ImageFormat.Jpeg)

        Dim writer As New ResXResourceWriter("AppResources.resx")
        writer.AddResource("SplashScreen", imageStream)
        writer.Generate()
        writer.Close()
    End Sub
End Module

Il codice seguente recupera la risorsa e visualizza l'immagine in un controllo PictureBox.

using System;
using System.Drawing;
using System.IO;
using System.Resources;
using System.Windows.Forms;

public class Example
{
   public static void Main()
   {
      ResourceManager rm = new ResourceManager("AppResources", typeof(Example).Assembly);
      Bitmap screen = (Bitmap) Image.FromStream(rm.GetStream("SplashScreen"));

      Form frm = new Form();
      frm.Size = new Size(300, 300);

      PictureBox pic = new PictureBox();
      pic.Bounds = frm.RestoreBounds;
      pic.BorderStyle = BorderStyle.Fixed3D;
      pic.Image = screen;
      pic.SizeMode = PictureBoxSizeMode.StretchImage;

      frm.Controls.Add(pic);
      pic.Anchor = AnchorStyles.Top | AnchorStyles.Bottom |
                   AnchorStyles.Left | AnchorStyles.Right;

      frm.ShowDialog();
   }
}
Imports System.Drawing
Imports System.IO
Imports System.Resources
Imports System.Windows.Forms

Module Example
    Public Sub Main()
        Dim rm As New ResourceManager("AppResources", GetType(Example).Assembly)
        Dim screen As Bitmap = CType(Image.FromStream(rm.GetStream("SplashScreen")), Bitmap)

        Dim frm As New Form()
        frm.Size = new Size(300, 300)

        Dim pic As New PictureBox()
        pic.Bounds = frm.RestoreBounds
        pic.BorderStyle = BorderStyle.Fixed3D
        pic.Image = screen
        pic.SizeMode = PictureBoxSizeMode.StretchImage

        frm.Controls.Add(pic)
        pic.Anchor = AnchorStyles.Top Or AnchorStyles.Bottom Or
                     AnchorStyles.Left Or AnchorStyles.Right

        frm.ShowDialog()
    End Sub
End Module

È possibile usare il file batch seguente per compilare l'esempio C#. Per Visual Basic modificare csc in vbce modificare l'estensione del file di codice sorgente da .cs a .vb.

csc CreateResources.cs
CreateResources

resgen AppResources.resx

csc GetStream.cs -resource:AppResources.resources

Nell'esempio seguente viene utilizzato il ResourceManager.GetObject(String) metodo per deserializzare un oggetto personalizzato. L'esempio include un file di codice sorgente denominato UIElements.cs (UIElements.vb per Visual Basic) che definisce la struttura seguente denominata PersonTable. Questa struttura deve essere utilizzata da una routine di visualizzazione tabella generale che visualizza i nomi localizzati delle colonne della tabella. Si noti che la PersonTable struttura è contrassegnata con l'attributo SerializableAttribute .

using System;

[Serializable] public struct PersonTable
{
   public readonly int nColumns;
   public readonly string column1;
   public readonly string column2;
   public readonly string column3;
   public readonly int width1;
   public readonly int width2;
   public readonly int width3;

   public PersonTable(string column1, string column2, string column3,
                  int width1, int width2, int width3)
   {
      this.column1 = column1;
      this.column2 = column2;
      this.column3 = column3;
      this.width1 = width1;
      this.width2 = width2;
      this.width3 = width3;
      this.nColumns = typeof(PersonTable).GetFields().Length / 2;
   }
}
<Serializable> Public Structure PersonTable
    Public ReadOnly nColumns As Integer
    Public Readonly column1 As String
    Public ReadOnly column2 As String
    Public ReadOnly column3 As String
    Public ReadOnly width1 As Integer
    Public ReadOnly width2 As Integer
    Public ReadOnly width3 As Integer

    Public Sub New(column1 As String, column2 As String, column3 As String,
                   width1 As Integer, width2 As Integer, width3 As Integer)
        Me.column1 = column1
        Me.column2 = column2
        Me.column3 = column3
        Me.width1 = width1
        Me.width2 = width2
        Me.width3 = width3
        Me.nColumns = Me.GetType().GetFields().Count \ 2
    End Sub
End Structure

Il codice seguente da un file denominato CreateResources.cs (CreateResources.vb per Visual Basic) crea un file di risorse XML denominato UIResources.resx che archivia un titolo di tabella e un PersonTable oggetto che contiene informazioni per un'app localizzata per la lingua inglese.

using System;
using System.Resources;

public class CreateResource
{
   public static void Main()
   {
      PersonTable table = new PersonTable("Name", "Employee Number",
                                          "Age", 30, 18, 5);
      ResXResourceWriter rr = new ResXResourceWriter(@".\UIResources.resx");
      rr.AddResource("TableName", "Employees of Acme Corporation");
      rr.AddResource("Employees", table);
      rr.Generate();
      rr.Close();
   }
}
Imports System.Resources

Module CreateResource
    Public Sub Main()
        Dim table As New PersonTable("Name", "Employee Number", "Age", 30, 18, 5)
        Dim rr As New ResXResourceWriter(".\UIResources.resx")
        rr.AddResource("TableName", "Employees of Acme Corporation")
        rr.AddResource("Employees", table)
        rr.Generate()
        rr.Close()
    End Sub
End Module

Il codice seguente in un file di codice sorgente denominato GetObject.cs (GetObject.vb) recupera le risorse e le visualizza nella console.

using System;
using System.Resources;

[assembly: NeutralResourcesLanguageAttribute("en")]

public class Example
{
   public static void Main()
   {
      string fmtString = String.Empty;
      ResourceManager rm = new ResourceManager("UIResources", typeof(Example).Assembly);
      string title = rm.GetString("TableName");
      PersonTable tableInfo = (PersonTable) rm.GetObject("Employees");

      if (! String.IsNullOrEmpty(title)) {
         fmtString = "{0," + ((Console.WindowWidth + title.Length) / 2).ToString() + "}";
         Console.WriteLine(fmtString, title);
         Console.WriteLine();
      }

      for (int ctr = 1; ctr <= tableInfo.nColumns; ctr++) {
         string columnName = "column"  + ctr.ToString();
         string widthName = "width" + ctr.ToString();
         string value = tableInfo.GetType().GetField(columnName).GetValue(tableInfo).ToString();
         int width = (int) tableInfo.GetType().GetField(widthName).GetValue(tableInfo);
         fmtString = "{0,-" + width.ToString() + "}";
         Console.Write(fmtString, value);
      }
      Console.WriteLine();
   }
}
Imports System.Resources

<Assembly: NeutralResourcesLanguageAttribute("en")>

Module Example
    Public Sub Main()
        Dim fmtString As String = String.Empty
        Dim rm As New ResourceManager("UIResources", GetType(Example).Assembly)
        Dim title As String = rm.GetString("TableName")
        Dim tableInfo As PersonTable = DirectCast(rm.GetObject("Employees"), PersonTable)

        If Not String.IsNullOrEmpty(title) Then
            fmtString = "{0," + ((Console.WindowWidth + title.Length) \ 2).ToString() + "}"
            Console.WriteLine(fmtString, title)
            Console.WriteLine()
        End If

        For ctr As Integer = 1 To tableInfo.nColumns
            Dim columnName As String = "column" + ctr.ToString()
            Dim widthName As String = "width" + ctr.ToString()
            Dim value As String = CStr(tableInfo.GetType().GetField(columnName).GetValue(tableInfo))
            Dim width As Integer = CInt(tableInfo.GetType().GetField(widthName).GetValue(tableInfo))
            fmtString = "{0,-" + width.ToString() + "}"
            Console.Write(fmtString, value)
        Next
        Console.WriteLine()
    End Sub
End Module

È possibile compilare il file di risorse e gli assembly necessari ed eseguire l'app eseguendo il file batch seguente. È necessario utilizzare l'opzione /r per fornire Resgen.exe con un riferimento a UIElements.dll in modo che possa accedere alle informazioni sulla PersonTable struttura. Se si usa C#, sostituire il nome del vbc compilatore con csce sostituire l'estensione .vb con .cs.

vbc -t:library UIElements.vb
vbc CreateResources.vb -r:UIElements.dll
CreateResources

resgen UIResources.resx  -r:UIElements.dll
vbc GetObject.vb -r:UIElements.dll -resource:UIResources.resources

GetObject.exe

Supporto della versione per gli assembly satellite

Per impostazione predefinita, quando l'oggetto ResourceManager recupera le risorse richieste, cerca gli assembly satellite con numeri di versione corrispondenti al numero di versione dell'assembly principale. Dopo aver distribuito un'app, potresti voler aggiornare l'assembly principale o gli assembly satellite di risorse specifici. .NET Framework offre il supporto per il controllo delle versioni degli assembly principali e degli assembly satellite.

L'attributo SatelliteContractVersionAttribute fornisce il supporto del controllo delle versioni per un assembly principale. La specifica di questo attributo nell'assembly principale di un'app consente di aggiornare e ridistribuire un assembly principale senza aggiornare gli assembly satellite. Dopo aver aggiornato l'assembly principale, incrementa il numero di versione dell'assembly principale, ma lascia invariato il numero di versione del contratto satellite. Quando il gestore delle risorse recupera le risorse richieste, carica la versione dell'assembly satellite specificata da questo attributo.

Gli assembly dei criteri del server di pubblicazione forniscono il supporto per il controllo delle versioni degli assembly satellite. È possibile aggiornare e ridistribuire un assembly satellite senza aggiornare l'assembly principale. Dopo aver aggiornato un assembly satellite, incrementa il suo numero di versione e invialo con un assemblaggio dei criteri di pubblicazione. Nell'assembly delle politiche dell'editore, specifica che il nuovo assembly satellite è retrocompatibile con la versione precedente. Il gestore delle risorse userà l'attributo SatelliteContractVersionAttribute per determinare la versione dell'assembly satellite, ma il caricatore dell'assembly si assocerà alla versione dell'assembly satellite specificata dalle politiche del publisher. Per altre informazioni sugli assembly dei criteri dell'editore, vedere Creare un file di criteri dell'editore.

Per abilitare il supporto completo del controllo delle versioni degli assembly, è consigliabile distribuire assembly con nome sicuro nella Global Assembly Cache e distribuire assembly che non dispongono di nomi sicuri nella directory dell'applicazione. Se si desidera distribuire assembly con nome sicuro nella directory dell'applicazione, non sarà possibile incrementare il numero di versione di un assembly satellite quando si aggiorna l'assembly. È invece necessario eseguire un aggiornamento sul posto in cui sostituire il codice esistente con il codice aggiornato e mantenere lo stesso numero di versione. Ad esempio, se si vuole aggiornare la versione 1.0.0.0 di un assembly satellite con il nome di assembly completamente specificato "myApp.resources, Version=1.0.0.0, Culture=de, PublicKeyToken=b03f5f11d50a3a", sovrascriverlo con il myApp.resources.dll aggiornato compilato con lo stesso nome di assembly completamente specificato "myApp.resources, Version=1.0.0.0, Culture=de, PublicKeyToken=b03f5f11d50a3a". Si noti che l'uso degli aggiornamenti in loco nei file di assembly satellite rende difficile per un'app determinare con precisione la versione di un assembly satellite.

Per altre informazioni sul controllo delle versioni degli assembly, vedere Controllo delle versioni degli assembly e Modalità di individuazione degli assembly da parte del runtime.

Recuperare risorse da file .resources

Se scegli di non distribuire le risorse negli assembly satellite, puoi comunque usare l'oggetto ResourceManager per accedere direttamente alle risorse dai file .resources. Al fine di farlo, è necessario distribuire correttamente i file .resources. Quindi usare il ResourceManager.CreateFileBasedResourceManager metodo per creare un'istanza di un ResourceManager oggetto e specificare la directory che contiene i file autonomi con estensione .resources.

Distribuire i file .resources

Quando si incorporano file .resources in un assembly dell'applicazione e in assembly satellite, ogni assembly satellite ha lo stesso nome di file, ma viene inserito in una sottodirectory che riflette la cultura dell'assembly satellite. Al contrario, quando si accede direttamente alle risorse dai file con estensione resources, è possibile inserire tutti i file con estensione resources in una singola directory, in genere una sottodirectory della directory dell'applicazione. Il nome del file .resources predefinito dell'app consiste solo in un nome radice, senza alcuna indicazione della sua cultura (ad esempio, strings.resources). Le risorse per ciascuna cultura specifica vengono archiviate in un file il cui nome è costituito dal nome radice seguito dalla cultura, ad esempio strings.ja.resources o strings.de-DE.resources.

La figura seguente mostra dove devono trovarsi i file di risorse nella struttura di directory. Fornisce anche le convenzioni di denominazione per i file con estensione resource.

Illustrazione che mostra la directory principale della tua applicazione.

Usare il gestore delle risorse

Dopo aver creato le risorse e inserirle nella directory appropriata, creare un ResourceManager oggetto per usare le risorse chiamando il CreateFileBasedResourceManager(String, String, Type) metodo . Il primo parametro specifica il nome radice del file .resources predefinito dell'app (si tratta di "stringhe" per l'esempio nella sezione precedente). Il secondo parametro specifica la posizione delle risorse ("Resources" per l'esempio precedente). Il terzo parametro specifica l'implementazione ResourceSet da usare. Se il terzo parametro è null, viene usato il runtime ResourceSet predefinito.

Annotazioni

Non distribuire applicazioni ASP.NET utilizzando file con estensione .resources. Ciò può causare problemi di blocco e interrompe la distribuzione di XCOPY. È consigliabile distribuire le risorse ASP.NET negli assembly satellite. Per altre informazioni, vedere Panoramica delle risorse delle pagine Web ASP.NET.

Dopo aver creato un'istanza dell'oggetto ResourceManager, devi usare i metodi GetString, GetObject e GetStream come descritto in precedenza per recuperare le risorse. Tuttavia, il recupero delle risorse direttamente dai file .resources differisce dal recupero delle risorse incorporate dagli assembly. Quando si recuperano risorse dai file .resources, i metodi GetString(String), GetObject(String) e GetStream(String) recuperano sempre le risorse della cultura predefinita, a prescindere dalla cultura corrente. Per recuperare le risorse della cultura corrente dell'app o di una cultura specifica, è necessario chiamare il metodo GetString(String, CultureInfo), GetObject(String, CultureInfo) o GetStream(String, CultureInfo) e specificare la cultura le cui risorse devono essere recuperate. Per recuperare le risorse della cultura corrente, specificare il valore della CultureInfo.CurrentCulture proprietà come culture argomento. Se il gestore delle risorse non riesce a recuperare le risorse di culture, utilizza le regole standard di fallback delle risorse per recuperare le risorse appropriate.

Esempio

Nell'esempio seguente viene illustrato come resource manager recupera le risorse direttamente dai file con estensione resources. L'esempio è costituito da tre file di risorse testuali per le culture inglese (Stati Uniti), francese (Francia) e russa (Russia). Inglese (Stati Uniti) è la cultura predefinita dell'esempio. Le relative risorse vengono archiviate nel file seguente denominato Strings.txt:

Greeting=Hello
Prompt=What is your name?

Le risorse per la cultura francese (Francia) sono archiviate nel seguente file, denominato Strings.fr-FR.txt:

Greeting=Bon jour
Prompt=Comment vous appelez-vous?

Le risorse per la cultura russa (Russia) vengono archiviate nel file seguente, denominato Strings.ru-RU.txt:

Greeting=Здравствуйте
Prompt=Как вас зовут?

Di seguito è riportato il codice sorgente per l'esempio. L'esempio crea istanze degli oggetti CultureInfo per le culture inglese (Stati Uniti), inglese (Canada), francese (Francia) e russa (Russia) e rende ciascuna la cultura corrente. Il ResourceManager.GetString(String, CultureInfo) metodo fornisce quindi il valore della CultureInfo.CurrentCulture proprietà come culture argomento per recuperare le risorse specifiche culturali appropriate.

using System;
using System.Globalization;
using System.Resources;
using System.Threading;

[assembly: NeutralResourcesLanguage("en-US")]

public class Example
{
   public static void Main()
   {
      string[] cultureNames = { "en-US", "en-CA", "ru-RU", "fr-FR" };
      ResourceManager rm = ResourceManager.CreateFileBasedResourceManager("Strings", "Resources", null);

      foreach (var cultureName in cultureNames) {
         Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
         string greeting = rm.GetString("Greeting", CultureInfo.CurrentCulture);
         Console.WriteLine($"\n{greeting}!");
         Console.Write(rm.GetString("Prompt", CultureInfo.CurrentCulture));
         string name = Console.ReadLine();
         if (! String.IsNullOrEmpty(name))
            Console.WriteLine("{0}, {1}!", greeting, name);
      }
      Console.WriteLine();
   }
}
// The example displays output like the following:
//       Hello!
//       What is your name? Dakota
//       Hello, Dakota!
//
//       Hello!
//       What is your name? Koani
//       Hello, Koani!
//
//       Здравствуйте!
//       Как вас зовут?Samuel
//       Здравствуйте, Samuel!
//
//       Bon jour!
//       Comment vous appelez-vous?Yiska
//       Bon jour, Yiska!
Imports System.Globalization
Imports System.Resources
Imports System.Threading

<Assembly: NeutralResourcesLanguageAttribute("en-US")>

Module Example
    Public Sub Main()
        Dim cultureNames() As String = {"en-US", "en-CA", "ru-RU", "fr-FR"}
        Dim rm As ResourceManager = ResourceManager.CreateFileBasedResourceManager("Strings", "Resources", Nothing)

        For Each cultureName In cultureNames
            Console.WriteLine()
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName)
            Dim greeting As String = rm.GetString("Greeting", CultureInfo.CurrentCulture)
            Console.WriteLine("{0}!", greeting)
            Console.Write(rm.GetString("Prompt", CultureInfo.CurrentCulture))
            Dim name As String = Console.ReadLine()
            If Not String.IsNullOrEmpty(name) Then
                Console.WriteLine("{0}, {1}!", greeting, name)
            End If
        Next
        Console.WriteLine()
    End Sub
End Module
' The example displays output like the following:
'       Hello!
'       What is your name? Dakota
'       Hello, Dakota!
'       
'       Hello!
'       What is your name? Koani
'       Hello, Koani!
'       
'       Здравствуйте!
'       Как вас зовут?Samuel
'       Здравствуйте, Samuel!
'       
'       Bon jour!
'       Comment vous appelez-vous?Yiska
'       Bon jour, Yiska!

È possibile compilare la versione C# dell'esempio eseguendo il file batch seguente. Se si usa Visual Basic, sostituire csc con vbce sostituire l'estensione .cs con .vb.

md Resources
resgen Strings.txt Resources\Strings.resources
resgen Strings.fr-FR.txt Resources\Strings.fr-FR.resources
resgen Strings.ru-RU.txt Resources\Strings.ru-RU.resources

csc Example.cs

Vedere anche