Поделиться через


Получение ресурсов в приложениях .NET

При работе с локализованными ресурсами в приложениях .NET, в идеале, необходимо упаковать ресурсы для стандартной или нейтральной культуры вместе с основной сборкой. Для каждого языка или культуры, которые поддерживает ваше приложение, следует создать отдельные спутниковые сборки. Затем можно использовать ResourceManager класс, как описано в следующем разделе, чтобы получить доступ к именованным ресурсам. Если вы решили не внедрять ресурсы в основные сборки и вспомогательные сборки, вы также можете получить доступ к двоичным файлам ресурсов напрямую, как описано в разделе "Извлечение ресурсов из файлов ресурсов " далее в этой статье.

Получение ресурсов из сборок

Класс ResourceManager предоставляет доступ к ресурсам во время выполнения. Используйте метод ResourceManager.GetString для извлечения строковых ресурсов и метод ResourceManager.GetObject или ResourceManager.GetStream для извлечения нестроковых ресурсов. Каждый метод имеет две перегрузки:

  • Перегрузка, единственным параметром которой является строка, содержащая имя ресурса. Метод пытается получить этот ресурс для текущей культуры. Для получения дополнительной информации, смотрите методы GetString(String), GetObject(String) и GetStream(String).

  • Перегрузка с двумя параметрами: строка, содержащая имя ресурса, и CultureInfo объект, представляющий культуру, из которой необходимо получить ресурс. Если набор ресурсов для этой культуры не найден, менеджер ресурсов использует правила резервирования для получения соответствующего ресурса. Дополнительные сведения см. в методах GetString(String, CultureInfo), GetObject(String, CultureInfo) и GetStream(String, CultureInfo).

Менеджер ресурсов использует процесс резервного копирования ресурсов для управления тем, как приложение получает ресурсы, специфичные для данной культуры. Дополнительные сведения см. в разделе "Процесс резервирования ресурсов" в "Пакет и развертывание ресурсов". Сведения о создании экземпляра объекта ResourceManager см. в разделе «Создание экземпляра объекта ResourceManager» темы класса ResourceManager.

Пример получения строковых данных

В следующем примере вызывается метод GetString(String) для получения строковых ресурсов текущей культуры пользовательского интерфейса. Он включает нейтральный строковый ресурс для культуры английского языка (США) и локализованные строковые ресурсы для французской (Франция) и русской (Россия) культур. Следующий ресурс на американском английском находится в файле с именем Strings.txt:

TimeHeader=The current time is

Французский ресурс (Франция) находится в файле с именем Strings.fr-FR.txt:

TimeHeader=L'heure actuelle est

Ресурс России (Россия) находится в файле с именем Strings.ru-RU.txt:

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

Исходный код для этого примера, который находится в файле с именем GetString.cs для версии кода C# и GetString.vb для версии Visual Basic, определяет массив строк, содержащий названия четырех культур: трех культур, для которых доступны ресурсы, и испанской культуры (Испания). Цикл, который выполняется пять раз, случайным образом выбирает одну из этих культур и назначает её свойствам Thread.CurrentCulture и CultureInfo.CurrentUICulture. Затем он вызывает GetString(String) метод для получения локализованной строки, которая отображается вместе с временем дня.

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

Следующий пакетный файл (.bat) компилирует пример и создает спутниковые сборки в соответствующих каталогах. Команды предоставляются для языка C# и компилятора. Для Visual Basic измените csc на vbc, а GetString.cs на 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

Если текущим языком пользовательского интерфейса является испанский (Испания), обратите внимание, что в примере отображаются ресурсы английского языка, так как ресурсы испанского языка недоступны, а по умолчанию используется английская культура.

Получение примеров данных объекта

Вы можете использовать GetObject методы и GetStream методы для получения данных объекта. К ним относятся примитивные типы данных, сериализуемые объекты и объекты, хранящиеся в двоичном формате (например, изображения).

В следующем примере метод используется GetStream(String) для получения растрового изображения, используемого в открываемом окне заставки приложения. Следующий исходный код в файле с именем CreateResources.cs (для C#) или CreateResources.vb (для Visual Basic) создает RESX-файл, содержащий сериализованный образ. В этом случае изображение загружается из файла с именем SplashScreen.jpg; Имя файла можно изменить, чтобы заменить собственный образ.

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

Следующий код извлекает ресурс и отображает изображение в элементе управления 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

Для создания примера C# можно использовать следующий пакетный файл. Для Visual Basic измените #D0 на #B1 и измените расширение файла исходного кода с #D2 на #B3.

csc CreateResources.cs
CreateResources

resgen AppResources.resx

csc GetStream.cs -resource:AppResources.resources

В следующем примере используется метод ResourceManager.GetObject(String) для десериализации пользовательского объекта. В примере содержится файл исходного кода с именем UIElements.cs (UIElements.vb для Visual Basic), который определяет следующую структуру с именем PersonTable. Эта структура предназначена для использования обычной подпрограммой отображения таблицы, отображающей локализованные имена столбцов таблиц. Обратите внимание, что структура PersonTable помечена атрибутом 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

Следующий код из файла с именем CreateResources.cs (CreateResources.vb для Visual Basic) создает XML-файл ресурсов с именем UIResources.resx, который хранит заголовок таблицы и PersonTable объект, содержащий сведения для приложения, локализованного на английском языке.

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

Следующий код в файле исходного кода с именем GetObject.cs (GetObject.vb) затем извлекает ресурсы и отображает их в консоли.

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

Вы можете создать необходимый файл ресурсов и сборки и запустить приложение, выполнив следующий пакетный файл. Вы должны использовать опцию /r для передачи Resgen.exe ссылки на UIElements.dll, чтобы оно могло получить доступ к информации о структуре PersonTable. Если вы используете C#, замените имя компилятора с vbc на csc, а расширение с .vb на .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

Поддержка версий сателлитных сборок

По умолчанию, когда ResourceManager объект получает запрошенные ресурсы, он ищет вспомогательные сборки с номерами версий, которые соответствуют номеру версии основной сборки. После развертывания приложения может потребоваться обновить основную сборку или специальные вспомогательные сборки ресурсов. Платформа .NET Framework поддерживает управление версиями основных сборок и вспомогательных сборок.

Атрибут SatelliteContractVersionAttribute предоставляет поддержку управления версиями для основной сборки. Указание этого атрибута в основной сборке приложения позволяет обновлять и развертывать основную сборку без обновления вспомогательных сборок. После обновления основной сборки увеличьте номер версии основной сборки, но оставьте номер версии вспомогательного контракта без изменений. Когда менеджер ресурсов извлекает запрошенные ресурсы, он загружает версию сателлитной сборки, указанную этим атрибутом.

Сборки политики поставщика обеспечивают поддержку версий сателлитных сборок. Вы можете обновить и повторно развернуть спутниковую сборку без обновления основной сборки. После обновления сателлитной сборки увеличьте номер версии и выпустите её вместе со сборкой политики издателя. В сборке политики издателя укажите, что новая спутниковая сборка является обратно совместимой с предыдущей версией. Диспетчер ресурсов будет использовать SatelliteContractVersionAttribute атрибут для определения версии вспомогательной сборки, но загрузчик сборок привязывается к вспомогательной версии сборки, указанной политикой издателя. Дополнительные сведения о сборках политик издателя см. в разделе "Создание файла политики издателя".

Чтобы включить полную поддержку управления версиями сборок, рекомендуется развертывать сборки с строгими именами в глобальном кэше сборок и развертывать сборки, не имеющие строгих имен в каталоге приложений. Если вы хотите развернуть сборки с строгим именем в каталоге приложения, вы не сможете увеличить номер версии сателлитной сборки при обновлении основной сборки. Вместо этого необходимо выполнить обновление на месте, в котором необходимо заменить существующий код обновленным кодом и сохранить тот же номер версии. Например, если вы хотите обновить версию 1.0.0.0 ресурсной сборки с полным именем сборки "myApp.resources, Version=1.0.0.0, Culture=de, PublicKeyToken=b03f5f11d50a3a", перезапишите её обновлённым myApp.resources.dll, который был скомпилирован с тем же полным именем сборки "myApp.resources, Version=1.0.0.0, Culture=de, PublicKeyToken=b03f5f11d50a3a". Обратите внимание, что использование локальных обновлений в спутниковых файлах сборок затрудняет точное определение версии спутниковой сборки.

Дополнительные сведения об использовании версий сборок см. в разделе "Управление версиями сборок " и " Как среда выполнения находит сборки".

Получение ресурсов из файлов .resources

Если вы решили не развертывать ресурсы в сателлитных сборках, вы по-прежнему можете использовать ResourceManager объект напрямую для доступа к ресурсам из файлов .resources. Для этого необходимо правильно развернуть файлы .resources. Затем вы используете ResourceManager.CreateFileBasedResourceManager метод, чтобы создать экземпляр ResourceManager объекта и указать каталог, содержащий автономные файлы ресурсов.

Развертывание файлов .ресурсов

При встраивании файлов .resources в сборку приложения и спутниковые сборки, каждая спутниковая сборка имеет то же имя файла, но помещается в подкаталог, который отражает культуру спутниковой сборки. В отличие от этого, при прямом доступе к ресурсам из файлов ресурсов, все файлы ресурсов можно разместить в одном каталоге, который обычно является подкаталогом каталога приложения. Имя файла .resources по умолчанию приложения состоит только из корневого имени без указания культуры (например, strings.resources). Ресурсы для каждой локализованной культуры хранятся в файле, имя которого состоит из основного имени, за которым следует название культуры (как, например, strings.ja.resources или strings.de-DE.resources).

На следующем рисунке показано, где файлы ресурсов должны находиться в структуре каталогов. Он также предоставляет соглашения об именовании для файлов .resource.

Иллюстрация, показывающая основной каталог для приложения.

Использование диспетчера ресурсов

Создав ресурсы и поместив их в соответствующий ResourceManager каталог, создайте объект для использования ресурсов путем вызова CreateFileBasedResourceManager(String, String, Type) метода. Первый параметр указывает корневое имя файла .resources по умолчанию для приложения (это будет "строки" для примера в предыдущем разделе). Второй параметр указывает расположение ресурсов ("Resources" для предыдущего примера). Третий параметр указывает реализацию, используемую ResourceSet . Если третий параметр имеет значение null, используется среда выполнения ResourceSet по умолчанию.

Примечание.

Не развертывайте ASP.NET приложения с помощью автономных файлов ресурсов. Это может привести к возникновению проблем с блокировкой и прерыванию развертывания XCOPY. Рекомендуется развертывать ASP.NET ресурсы в вспомогательных сборках. Дополнительные сведения см. в разделе ASP.NET Обзор ресурсов веб-страницы.

После создания экземпляра ResourceManager объекта используйте методы GetString, GetObject и GetStream, как описано ранее, для получения ресурсов. Однако извлечение ресурсов непосредственно из файлов .resources отличается от извлечения внедренных ресурсов из сборок. При получении ресурсов из файлов ресурсов, методы GetString(String), GetObject(String) и GetStream(String) всегда получают ресурсы культуры по умолчанию независимо от текущей культуры. Чтобы получить ресурсы текущей культуры приложения или определенной культуры, необходимо вызвать GetString(String, CultureInfo), GetObject(String, CultureInfo) или GetStream(String, CultureInfo) метод и указать культуру, ресурсы которой необходимо извлечь. Чтобы получить ресурсы текущей культуры, укажите значение свойства CultureInfo.CurrentCulture в качестве аргумента culture. Если диспетчер ресурсов не может получить ресурсы culture, он использует стандартные резервные правила для получения соответствующих ресурсов.

Пример

В следующем примере показано, как диспетчер ресурсов извлекает ресурсы непосредственно из файлов ресурсов.resources. Пример состоит из трех текстовых файлов ресурсов для культур английского (США), французского (Франция) и русского (Россия) языков. Английский (США) — это культура по умолчанию. Его ресурсы хранятся в следующем файле с именемStrings.txt:

Greeting=Hello
Prompt=What is your name?

Ресурсы для культуры Франции хранятся в следующем файле, который называется Strings.fr-FR.txt:

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

Ресурсы для российской культуры (Россия) хранятся в следующем файле, который называется Strings.ru-RU.txt:

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

Ниже приведен исходный код для примера. Пример создает CultureInfo экземпляры объектов для английского языка (США), английского языка (Канада), французского языка (Франция) и русского языка (Россия), и делает каждый текущей культурой. Затем метод ResourceManager.GetString(String, CultureInfo) предоставляет значение свойства CultureInfo.CurrentCulture в качестве аргумента culture для получения соответствующих ресурсов, зависящих от языка и региональных параметров.

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!

Вы можете скомпилировать версию примера C#, выполнив следующий пакетный файл. Если вы используете Visual Basic, замените csc на vbc, и замените расширение .cs на .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

См. также