Partilhar via


Recuperar recursos em aplicativos .NET

Quando você trabalha com recursos localizados em aplicativos .NET, idealmente deve empacotar os recursos para a cultura padrão ou neutra com o assembly principal e criar um assembly satélite separado para cada idioma ou cultura suportada pelo seu aplicativo. Em seguida, você pode usar a classe ResourceManager conforme descrito na próxima seção para acessar recursos nomeados. Se você optar por não incorporar seus recursos no assembly principal e nos assemblies satélite, também poderá acessar arquivos binários .resources diretamente, conforme discutido na seção Recuperar recursos de arquivos .resources mais adiante neste artigo.

Recuperar recursos a partir de assemblies

A ResourceManager classe proporciona acesso a recursos em tempo de execução. Use o método ResourceManager.GetString para recuperar recursos de cadeia de caracteres e o método ResourceManager.GetObject ou ResourceManager.GetStream para recuperar recursos que não sejam de cadeia de caracteres. Cada método tem duas sobrecargas:

O gerenciador de recursos usa o processo de fallback de recursos para controlar como o aplicativo recupera recursos específicos da cultura. Para obter mais informações, consulte a seção "Processo de fallback de recursos" em Pacote e implantar recursos. Para obter informações sobre como instanciar um objeto ResourceManager, consulte a seção "Instanciando um objeto ResourceManager" no tópico da classe ResourceManager.

Exemplo de recuperação de dados de cadeia de caracteres

O exemplo a seguir chama o método GetString(String) para recuperar os recursos de cadeia de caracteres da cultura atual da interface do usuário. Inclui um recurso de cadeia de caracteres neutro para a cultura inglesa (Estados Unidos) e recursos localizados para as culturas francesa (França) e russa (Rússia). O seguinte recurso em inglês (Estados Unidos) está em um arquivo chamado Strings.txt:

TimeHeader=The current time is

O recurso francês (França) está em um arquivo chamado Strings.fr-FR.txt:

TimeHeader=L'heure actuelle est

O recurso russo (Rússia) está em um arquivo chamado Strings.ru-RU.txt:

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

O código-fonte deste exemplo, que está em um arquivo chamado GetString.cs para a versão C# do código e GetString.vb para a versão do Visual Basic, define uma matriz de cadeia de caracteres que contém o nome de quatro culturas: as três culturas para as quais os recursos estão disponíveis e a cultura espanhola (Espanha). Um loop que executa cinco vezes aleatoriamente seleciona uma dessas culturas e a atribui às propriedades Thread.CurrentCulture e CultureInfo.CurrentUICulture. Em seguida, ele chama o método GetString(String) para recuperar a cadeia de caracteres localizada, que ele exibe junto com a hora do dia.

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

O seguinte arquivo de lote (.bat) compila o exemplo e gera assemblies satélite nos diretórios apropriados. Os comandos são fornecidos para a linguagem C# e compilador. Para Visual Basic, altere csc para vbce altere GetString.cs para 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 a cultura atual da interface do usuário é espanhol (Espanha), observe que o exemplo exibe recursos do idioma inglês, porque os recursos do idioma espanhol não estão disponíveis, e o inglês é a cultura padrão do exemplo.

Recuperar exemplos de dados de objeto

Você pode usar os métodos GetObject e GetStream para recuperar dados de objeto. Isso inclui tipos de dados primitivos, objetos serializáveis e objetos armazenados em formato binário (como imagens).

O exemplo a seguir usa o método GetStream(String) para recuperar um bitmap que é usado na janela inicial de abertura de um aplicativo. O código-fonte a seguir em um arquivo chamado CreateResources.cs (para C#) ou CreateResources.vb (para Visual Basic) gera um arquivo .resx que contém a imagem serializada. Nesse caso, a imagem é carregada a partir de um arquivo chamado SplashScreen.jpg; Você pode modificar o nome do arquivo para substituir sua própria imagem.

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

O código a seguir recupera o recurso e exibe a imagem em um controle 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

Você pode usar o seguinte arquivo em lotes para criar o exemplo em C#. Para Visual Basic, altere csc para vbce altere a extensão do arquivo de código-fonte de .cs para .vb.

csc CreateResources.cs
CreateResources

resgen AppResources.resx

csc GetStream.cs -resource:AppResources.resources

O exemplo a seguir usa o método ResourceManager.GetObject(String) para desserializar um objeto personalizado. O exemplo inclui um arquivo de código-fonte chamado UIElements.cs (UIElements.vb para Visual Basic) que define a seguinte estrutura chamada PersonTable. Essa estrutura destina-se a ser usada por uma rotina geral de exibição de tabela que exibe os nomes localizados das colunas da tabela. Observe que a estrutura PersonTable está marcada com o atributo 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

O código a seguir de um arquivo chamado CreateResources.cs (CreateResources.vb para Visual Basic) cria um arquivo de recurso XML chamado UIResources.resx que armazena um título de tabela e um objeto PersonTable que contém informações para um aplicativo localizado para o idioma inglês.

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

O código a seguir em um arquivo de código-fonte chamado GetObject.cs (GetObject.vb) recupera os recursos e os exibe no 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

Você pode criar o arquivo de recursos e assemblies necessários e executar o aplicativo executando o seguinte arquivo em lotes. Você deve usar a opção /r para fornecer Resgen.exe uma referência a UIElements.dll para que ele possa acessar informações sobre a estrutura PersonTable. Se você estiver usando C#, substitua o nome do compilador vbc por csce substitua a extensão .vb por .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

Suporte de versão para montagens satélite

Por padrão, quando o objeto ResourceManager recupera recursos solicitados, ele procura assemblies satélite que tenham números de versão que correspondam ao número de versão do assembly principal. Depois de implantar um aplicativo, convém atualizar o assembly principal ou assemblies satélites de recursos específicos. O .NET Framework fornece suporte para versionamento do assembly principal e assemblies satélite.

O atributo SatelliteContractVersionAttribute fornece suporte de controle de versão para um assembly principal. Especificar esse atributo no assembly principal de um aplicativo permite que você atualize e reimplante um assembly principal sem atualizar seus assemblies satélite. Depois de atualizar o assembly principal, incremente o número da versão do assembly principal, mas deixe o número da versão do contrato satélite inalterado. Quando o gerenciador de recursos recupera os recursos solicitados, ele carrega a versão do assembly satélite especificada por esse atributo.

Os assemblies de política do editor fornecem suporte para versionamento de assemblies satélites. Você pode atualizar e redistribuir uma assemblagem satélite sem atualizar a assemblagem principal. Depois de atualizar um assembly satélite, incremente seu número de versão e envie-o com um assembly de política do editor. Na assemblagem da política da editora, especifique que a nova assemblagem satélite é compatível com a sua versão anterior. O gestor de recursos usará o atributo SatelliteContractVersionAttribute para determinar a versão da assemblagem satélite, mas o carregador de assemblagem vincular-se-á à versão da assemblagem satélite especificada pela política do editor. Para obter mais informações sobre assemblies de política do editor, consulte Criar um arquivo de política do editor.

Para habilitar o suporte total ao controle de versão de assembly, recomendamos que você implante assemblies de nome forte no de cache de assembly global e implante assemblies que não tenham nomes fortes no diretório do aplicativo. Se desejar implantar assemblies de nome forte no diretório do aplicativo, não poderá aumentar o número de versão de um assembly satélite ao atualizar o assembly. Em vez disso, deves executar uma actualização no local onde substituis o código existente pelo código actualizado e manténs o mesmo número de versão. Por exemplo, se você quiser atualizar a versão 1.0.0.0 de um assembly satélite com o nome de assembly totalmente especificado "myApp.resources, Version=1.0.0.0, Culture=de, PublicKeyToken=b03f5f11d50a3a", substitua-o pelo myApp.resources.dll atualizado que foi compilado com o mesmo nome de assembly totalmente especificado "myApp.resources, Version=1.0.0.0, Culture=de, PublicKeyToken=b03f5f11d50a3a". Note que o uso de atualizações no local em ficheiros de assembly de satélite torna difícil para uma aplicação determinar com precisão a versão de uma assembly de satélite.

Para obter mais informações sobre o controle de versão de assembly, consulte Assembly versioning e How the Runtime locates assemblies.

Recuperar recursos de ficheiros .resources

Caso optes por não implementar recursos em conjuntos satélite, ainda poderás utilizar um objeto ResourceManager para aceder diretamente aos recursos a partir de ficheiros .resources. Para fazer isso, você deve implantar os arquivos .resources corretamente. Em seguida, use o método ResourceManager.CreateFileBasedResourceManager para instanciar um objeto ResourceManager e especificar o diretório que contém os arquivos .resources autônomos.

Implantar ficheiros .resources

Quando você incorpora arquivos .resources em um assembly de aplicativo e assemblies satélite, cada assembly satélite tem o mesmo nome de arquivo, mas é colocado em um subdiretório que reflete a cultura do assembly satélite. Por outro lado, quando você acessa recursos de arquivos .resources diretamente, você pode colocar todos os arquivos .resources em um único diretório, geralmente um subdiretório do diretório do aplicativo. O nome do arquivo .resources padrão do aplicativo consiste apenas em um nome de raiz, sem indicação de sua cultura (por exemplo, strings.resources). Os recursos para cada cultura localizada são armazenados em um arquivo cujo nome consiste no nome da raiz seguido pela cultura (por exemplo, strings.ja.resources ou strings.de-DE.resources).

A ilustração a seguir mostra onde os arquivos de recursos devem estar localizados na estrutura de diretórios. Ele também fornece as convenções de nomenclatura para arquivos .resource.

Ilustração que mostra o diretório principal do seu aplicativo.

Utilizar o gestor de recursos

Depois de criar seus recursos e colocá-los no diretório apropriado, você cria um objeto ResourceManager para usar os recursos chamando o método CreateFileBasedResourceManager(String, String, Type). O primeiro parâmetro especifica o nome raiz do arquivo .resources padrão do aplicativo (isso seria "strings" para o exemplo na seção anterior). O segundo parâmetro especifica o local dos recursos ("Resources" para o exemplo anterior). O terceiro parâmetro especifica a implementação ResourceSet a ser usada. Se o terceiro parâmetro for null, o ResourceSet de tempo de execução padrão será usado.

Observação

Não implante aplicativos ASP.NET usando arquivos .resources autônomos. Isso pode causar problemas de bloqueio e interromper a implantação do XCOPY. Recomendamos que você implante recursos ASP.NET em assemblies satélites. Para obter mais informações, consulte Visão Geral dos Recursos de Página da Web ASP.NET.

Depois de instanciar o objeto ResourceManager, use os métodos GetString, GetObjecte GetStream, conforme discutido anteriormente, para recuperar os recursos. No entanto, a recuperação de recursos diretamente de arquivos .resources difere da recuperação de recursos incorporados de assemblies. Quando você recupera recursos de arquivos .resources, os métodos GetString(String), GetObject(String)e GetStream(String) sempre recuperam os recursos da cultura padrão, independentemente da cultura atual. Para recuperar os recursos da cultura atual do aplicativo ou de uma cultura específica, você deve chamar o método GetString(String, CultureInfo), GetObject(String, CultureInfo)ou GetStream(String, CultureInfo) e especificar a cultura cujos recursos devem ser recuperados. Para recuperar os recursos da cultura atual, especifique o valor da propriedade CultureInfo.CurrentCulture como o argumento culture. Se o gerenciador de recursos não puder recuperar os recursos do culture, ele usará as regras de fallback de recursos padrão para recuperar os recursos apropriados.

Um exemplo

O exemplo a seguir ilustra como o gerenciador de recursos recupera recursos diretamente de arquivos .resources. O exemplo consiste em três arquivos de recursos baseados em texto para as culturas inglesa (Estados Unidos), francesa (França) e russa (Rússia). Inglês (Estados Unidos) é a cultura padrão do exemplo. Seus recursos são armazenados no seguinte arquivo chamado Strings.txt:

Greeting=Hello
Prompt=What is your name?

Os recursos para a cultura francesa (França) são armazenados no seguinte arquivo, que é chamado Strings.fr-FR.txt:

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

Recursos para a cultura russa (Rússia) são armazenados no seguinte arquivo, que é chamado Strings.ru-RU.txt:

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

A seguir está o código-fonte para o exemplo. O exemplo instancia CultureInfo objetos para as culturas inglesa (Estados Unidos), inglesa (Canadá), francesa (França) e russa (Rússia) e torna cada uma a cultura atual. Em seguida, o método ResourceManager.GetString(String, CultureInfo) fornece o valor da propriedade CultureInfo.CurrentCulture como o argumento culture para recuperar os recursos apropriados específicos da cultura.

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!

Você pode compilar a versão C# do exemplo executando o seguinte arquivo em lotes. Se você estiver usando o Visual Basic, substitua csc por vbce substitua a extensão .cs por .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

Ver também