您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

教程:使用 WPF 创建翻译应用Tutorial: Create a translation app with WPF

在本教程中,你将生成一个使用 Azure 认知服务通过单个订阅密钥进行文本翻译、语言检测和拼写检查的 Windows Presentation Foundation (WPF) 应用。In this tutorial, you'll build a Windows Presentation Foundation (WPF) app that uses Azure Cognitive Services for text translation, language detection, and spell checking with a single subscription key. 具体而言,该应用将调用文本翻译和必应拼写检查中的 API。Specifically, your app will call APIs from Translator Text and Bing Spell Check.

什么是 WPF?What is WPF? WPF 是可以创建桌面客户端应用的 UI 框架。It's a UI framework that creates desktop client apps. WPF 开发平台支持广泛的应用开发功能,包括应用模型、资源、控件、图形、布局、数据绑定、文档和安全性。The WPF development platform supports a broad set of app development features, including an app model, resources, controls, graphics, layout, data binding, documents, and security. 它是 .NET Framework 的一个子集,因此,如果你以前曾经在 .NET Framework 中使用 ASP.NET 或 Windows 窗体生成过应用,则应会熟悉该编程体验。It's a subset of the .NET Framework, so if you have previously built apps with the .NET Framework using ASP.NET or Windows Forms, the programming experience should be familiar. WPF 使用可扩展应用标记语言 (XAML) 为应用编程提供声明性模型,后续部分将提供相关介绍。WPF uses the Extensible app Markup Language (XAML) to provide a declarative model for app programming, which we'll review in the coming sections.

本教程介绍以下操作:In this tutorial, you'll learn how to:

  • 在 Visual Studio 中创建 WPF 项目Create a WPF project in Visual Studio
  • 将程序集和 NuGet 包添加到项目Add assemblies and NuGet packages to your project
  • 使用 XAML 创建应用 UICreate your app's UI with XAML
  • 使用文本翻译 API 获取语言、翻译文本以及检测源语言Use the Translator Text API to get languages, translate text, and detect the source language
  • 使用必应拼写检查 API 验证输入和提高翻译准确度Use the Bing Spell Check API to validate your input and improve translation accuracy
  • 运行 WPF 应用Run your WPF app

本教程中使用的认知服务Cognitive Services used in this tutorial

以下列表包含本教程中使用的认知服务。This list includes the Cognitive Services used in this tutorial. 请单击链接浏览每项功能的 API 参考。Follow the link to browse the API reference for each feature.

服务Service FeatureFeature 说明Description
文本翻译Translator Text 获取语言Get Languages 检索文本翻译支持的语言的完整列表。Retrieve a complete list of supported languages for text translation.
文本翻译Translator Text TranslateTranslate 将文本翻译成 60 多种语言。Translate text into more than 60 languages.
文本翻译Translator Text DetectDetect 检测输入文本的语言。Detect the language of the input text. 包含检测置信度评分。Includes confidence score for detection.
必应拼写检查Bing Spell Check 拼写检查Spell Check 更正拼写错误以提高翻译准确度。Correct spelling errors to improve translation accuracy.

先决条件Prerequisites

在继续之前,需要准备好以下各项:Before we continue, you'll need the following:

备注

对于本教程,我们建议在美国西部区域创建订阅。We recommend creating the subscription in the West US region for this tutorial. 否则,在完成本练习的过程中,需要在代码中更改终结点和区域。Otherwise, you'll need to change endpoints and regions in the code as you work through this exercise.

在 Visual Studio 中创建 WPF 应用Create a WPF app in Visual Studio

要做的第一件事是在 Visual Studio 中设置项目。The first thing we need to do is set up our project in Visual Studio.

  1. 打开 Visual Studio。Open Visual Studio. 然后选择“文件”>“新建”>“项目”。Then select File > New > Project.
  2. 在左侧面板中,找到并选择“Visual C#”。In the left panel, locate and select Visual C#. 然后在中间面板中选择“WPF 应用(.NET Framework)”。Then, select WPF App (.NET Framework) in the center panel. 在 Visual Studio 中创建 WPF 应用Create a WPF app in Visual Studio
  3. 为项目命名,将框架版本设置为 .NET Framework 4.5.2 或更高版本,然后单击“确定”。Name your project, set the framework version to .NET Framework 4.5.2 or later, then click OK.
  4. 现已创建项目。Your project has been created. 你会注意到,有两个选项卡已打开:MainWindow.xamlMainWindow.xaml.csYou'll notice that there are two tabs open: MainWindow.xaml and MainWindow.xaml.cs. 在整个教程中,我们会将代码添加到这两个文件。Throughout this tutorial, we'll be adding code to these two files. 第一个文件用于应用的用户界面;第二个文件用于调用文本翻译和必应拼写检查。The first for the app's user interface; the latter for our calls to Translator Text and Bing Spell Check. 检查环境Review your environment

在下一部分,我们会将程序集和 NuGet 包添加到项目以实现附加的功能,例如 JSON 分析。In the next section we're going to add assemblies and a NuGet package to our project for additional functionality, like JSON parsing.

将引用和 NuGet 包添加到项目Add references and NuGet packages to your project

我们的项目需要几个 .NET Framework 程序集,以及要使用 NuGet 包管理器安装的 NewtonSoft.Json。Our project requires a handful of .NET Framework assemblies and NewtonSoft.Json, which we'll install using the NuGet package manager.

添加 .NET Framework 程序集Add .NET Framework assemblies

将程序集添加到项目,以序列化和反序列化对象,以及管理 HTTP 请求和响应。Let's add assemblies to our project to serialize and deserialize objects, and to manage HTTP requests and responses.

  1. 在 Visual Studio 的解决方案资源管理器中找到你的项目(在右侧面板中)。Locate your project in Visual Studio's Solution Explorer (right panel). 右键单击该项目,然后选择“添加”>“引用...”打开“引用管理器”。Right click on your project, then select Add > Reference..., which opens Reference Manager. 添加程序集引用Add assembly references
  2. “程序集”选项卡列出了可供引用的所有 .NET Framework 程序集。The assemblies tab lists all .NET Framework assemblies that are available to reference. 使用屏幕右上方的搜索栏来搜索这些引用,并将其添加到项目:Use the search bar in the upper right of the screen to search for these references and add them to your project:
  3. 添加对项目的这些引用后,可以单击“确定”关闭“引用管理器”。After you've added these references to your project, you can click OK to close Reference Manager.

备注

若要详细了解程序集引用,请参阅如何:使用引用管理器添加或删除引用If you'd like to learn more about assembly references, see How to: Add or remove reference using the Reference Manager.

安装 NewtonSoft.JsonInstall NewtonSoft.Json

我们的应用将使用 NewtonSoft.Json 来反序列化 JSON 对象。Our app will use NewtonSoft.Json to deserialize JSON objects. 遵照以下说明安装相应的包。Follow these instructions to install the package.

  1. 在 Visual Studio 的解决方案资源管理器中找到你的项目,并右键单击该项目。Locate your project in Visual Studio's Solution Explorer and right click on your project. 选择“管理 NuGet 包...”。Select Manage NuGet Packages....
  2. 找到并选择“浏览”选项卡。Locate and select the Browse tab.
  3. 在搜索栏中键入 NewtonSoft.JsonType NewtonSoft.Json into the search bar. 找到并安装 NewtonSoft.JsonLocate and install NewtonSoft.Json
  4. 选择该包并单击“安装”。Select the package and click Install.
  5. 安装完成后,关闭该选项卡。When the installation is complete, close the tab.

使用 XAML 创建 WPF 窗体Create a WPF form using XAML

若要使用该应用,需要创建一个用户界面。To use your app, you're going to need a user interface. 我们将使用 XAML 创建一个窗体,使用户能够选择输入和翻译语言、输入要翻译的文本,并显示翻译输出。Using XAML, we'll create a form that allows users to select input and translation languages, enter text to translate, and displays the translation output.

让我们看看所要生成的对象。Let's take a look at what we're building.

WPF XAML 用户界面

用户界面包括以下组件:The user interfacer includes these components:

NameName 类型Type 说明Description
FromLanguageComboBox 组合框ComboBox 显示 Microsoft 文本翻译支持的语言列表。Displays a list of the languages supported by Microsoft Translator for text translation. 用户选择他们要进行翻译的语言。The user selects the language they are translating from.
ToLanguageComboBox 组合框ComboBox 显示与 FromComboBox 相同的语言列表,但用于选择用户要翻译到的语言。Displays the same list of languages as FromComboBox, but is used to select the language the user is translating to.
TextToTranslate TextBoxTextBox 让用户输入要翻译的文本。Allows the user to enter text to be translated.
TranslateButton 按钮Button 使用此按钮翻译文本。Use this button to translate text.
TranslatedTextLabel LabelLabel 显示翻译。Displays the translation.
DetectedLanguageLabel LabelLabel 显示检测到的待翻译文本 (TextToTranslate) 语言。Displays the detected language of the text to be translated (TextToTranslate).

备注

我们将使用 XAML 源代码创建此窗体,但是,你也可以使用 Visual Studio 中的编辑器创建此窗体。We're creating this form using the XAML source code, however, you can create the form with the editor in Visual Studio.

将代码添加到项目。Let's add the code to our project.

  1. 在 Visual Studio 中,选择 MainWindow.xaml 对应的选项卡。In Visual Studio, select the tab for MainWindow.xaml.
  2. 将以下代码复制到项目中并保存。Copy this code into your project and save.
    <Window x:Class="MSTranslatorTextDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:MSTranslatorTextDemo"
            mc:Ignorable="d"
            Title="Microsoft Translator" Height="400" Width="700" BorderThickness="0">
        <Grid>
            <Label x:Name="label" Content="Microsoft Translator" HorizontalAlignment="Left" Margin="39,6,0,0" VerticalAlignment="Top" Height="49" FontSize="26.667"/>
            <TextBox x:Name="TextToTranslate" HorizontalAlignment="Left" Height="23" Margin="42,160,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="600" FontSize="14" TabIndex="3"/>
            <Label x:Name="EnterTextLabel" Content="Text to translate:" HorizontalAlignment="Left" Margin="40,129,0,0" VerticalAlignment="Top" FontSize="14"/>
            <Label x:Name="toLabel" Content="Translate to:" HorizontalAlignment="Left" Margin="304,58,0,0" VerticalAlignment="Top" FontSize="14"/>
    
            <Button x:Name="TranslateButton" Content="Translate" HorizontalAlignment="Left" Margin="39,206,0,0" VerticalAlignment="Top" Width="114" Height="31" Click="TranslateButton_Click" FontSize="14" TabIndex="4" IsDefault="True"/>
            <ComboBox x:Name="ToLanguageComboBox"
                    HorizontalAlignment="Left"
                    Margin="306,88,0,0"
                    VerticalAlignment="Top"
                    Width="175" FontSize="14" TabIndex="2">
    
            </ComboBox>
            <Label x:Name="fromLabel" Content="Translate from:" HorizontalAlignment="Left" Margin="40,58,0,0" VerticalAlignment="Top" FontSize="14"/>
            <ComboBox x:Name="FromLanguageComboBox"
                HorizontalAlignment="Left"
                Margin="42,88,0,0"
                VerticalAlignment="Top"
                Width="175" FontSize="14" TabIndex="1"/>
            <Label x:Name="TranslatedTextLabel" Content="Translation is displayed here." HorizontalAlignment="Left" Margin="39,255,0,0" VerticalAlignment="Top" Width="620" FontSize="14" Height="85" BorderThickness="0"/>
            <Label x:Name="DetectedLanguageLabel" Content="Autodetected language is displayed here." HorizontalAlignment="Left" Margin="39,288,0,0" VerticalAlignment="Top" Width="620" FontSize="14" Height="84" BorderThickness="0"/>
        </Grid>
    </Window>
    
  3. 现在,Visual Studio 中应会显示该应用的用户界面预览,You should now see a preview of the app's user interface in Visual Studio. 如上图所示。It should look similar to the image above.

窗体现已准备就绪。That's it, your form is ready. 接下来,让我们编写一些代码来使用文本翻译和必应拼写检查。Now let's write some code to use Text Translation and Bing Spell Check.

备注

可以随意调整此窗体或创建自己的窗体。Feel free to tweak this form or create your own.

创建应用Create your app

MainWindow.xaml.cs 包含用于控制应用的代码。MainWindow.xaml.cs contains the code that controls our app. 在接下来的几个部分,我们将添加代码以填充下拉菜单,并调用文本翻译和必应拼写检查公开的几个 API。In the next few sections, we're going to add code to populate our drop-down menus, and to call a handful of API exposed by Translator Text and Bing Spell Check.

  • 启动程序并实例化 MainWindow 时,将调用文本翻译 API 的 Languages 方法来检索和填充语言选择下拉菜单。When the program starts and MainWindow is instantiated, the Languages method of the Translator Text API is called to retrieve and populate our language selection drop-downs. 此操作只会在每个会话开始时发生一次。This happens once at the beginning of each session.
  • 单击“翻译”按钮时,将检索用户选择的语言和文本、针对输入执行拼写检查,然后向用户显示翻译内容和检测到的语言。When the Translate button is clicked, the user's language selection and text are retrieved, spell check is performed on the input, and the translation and detected language are displayed for the user.
    • 调用文本翻译 API 的 Translate 方法来翻译 TextToTranslate 中的文本。The Translate method of the Translator Text API is called to translate text from TextToTranslate. 此调用还包括使用下拉菜单选择的 tofrom 语言。This call also includes the to and from languages selected using the drop-down menus.
    • 调用文本翻译 API 的 Detect 方法来确定 TextToTranslate 的文本语言。The Detect method of the Translator Text API is called to determine the text language of TextToTranslate.
    • 使用必应拼写检查来验证 TextToTranslate 并调整拼写错误。Bing Spell Check is used to validate TextToTranslate and adjust misspellings.

整个项目封装在 MainWindow : Window 类中。All of our project is encapsulated in the MainWindow : Window class. 让我们先添加代码以设置订阅密钥、为文本翻译和必应拼写检查声明终结点,并初始化应用。Let's start by adding code to set your subscription key, declare endpoints for Translator Text and Bing Spell Check, and initialize the app.

  1. 在 Visual Studio 中,选择 MainWindow.xaml.cs 对应的选项卡。In Visual Studio, select the tab for MainWindow.xaml.cs.
  2. 将预先填充的 using 语句替换为以下内容。Replace the pre-populated using statements with the following.
    using System;
    using System.Windows;
    using System.Net;
    using System.Net.Http;
    using System.IO;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Newtonsoft.Json;
    
  3. 找到 MainWindow : Window 类,并将其替换为以下代码:Locate the MainWindow : Window class, and replace it with this code:
    {
        // This sample uses the Cognitive Services subscription key for all services. To learn more about
        // authentication options, see: https://docs.microsoft.com/azure/cognitive-services/authentication.
        const string COGNITIVE_SERVICES_KEY = "YOUR_COG_SERVICES_KEY";
        // Endpoints for Translator Text and Bing Spell Check
        public static readonly string TEXT_TRANSLATION_API_ENDPOINT = "https://api.cognitive.microsofttranslator.com/{0}?api- version=3.0";
        const string BING_SPELL_CHECK_API_ENDPOINT = "https://westus.api.cognitive.microsoft.com/bing/v7.0/spellcheck/";
        // An array of language codes
        private string[] languageCodes;
    
        // Dictionary to map language codes from friendly name (sorted case-insensitively on language name)
        private SortedDictionary<string, string> languageCodesAndTitles =
            new SortedDictionary<string, string>(Comparer<string>.Create((a, b) => string.Compare(a, b, true)));
    
        // Global exception handler to display error message and exit
        private static void HandleExceptions(object sender, UnhandledExceptionEventArgs args)
        {
            Exception e = (Exception)args.ExceptionObject;
            MessageBox.Show("Caught " + e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            System.Windows.app.Current.Shutdown();
        }
        // MainWindow constructor
        public MainWindow()
        {
            // Display a message if unexpected error is encountered
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(HandleExceptions);
    
            if (COGNITIVE_SERVICES_KEY.Length != 32)
            {
                MessageBox.Show("One or more invalid API subscription keys.\n\n" +
                    "Put your keys in the *_API_SUBSCRIPTION_KEY variables in MainWindow.xaml.cs.",
                    "Invalid Subscription Key(s)", MessageBoxButton.OK, MessageBoxImage.Error);
                System.Windows.app.Current.Shutdown();
            }
            else
            {
                // Start GUI
                InitializeComponent();
                // Get languages for drop-downs
                GetLanguagesForTranslate();
                // Populate drop-downs with values from GetLanguagesForTranslate
                PopulateLanguageMenus();
            }
        }
    // NOTE:
    // In the following sections, we'll add code below this.
    }
    
    1. 添加认知服务订阅密钥并保存。Add your Cognitive Services subscription key and save.

在此代码块中,我们已声明两个成员变量,其中包含有关可用翻译语言的信息:In this code block, we've declared two member variables that contain information about available languages for translation:

变量Variable TypeType 说明Description
languageCodes 字符串数组Array of strings 缓存语言代码。C aches the language codes. Translator 服务使用短代码(例如英语为 en)来标识语言。The Translator service uses short codes, such as en for English, to identify languages.
languageCodesAndTitles 排序的字典Sorted dictionary 将用户界面中的“友好”名称映射回 API 中使用的短代码。Maps the "friendly" names in the user interface back to the short codes used in the API. 始终按字母顺序排序,不考虑大小写。Kept sorted alphabetically without regard for case.

然后,在 MainWindow 构造函数中,我们添加了使用 HandleExceptions 的错误处理机制。Then, within the MainWindow constructor, we've added error handling with HandleExceptions. 这可以确保在异常未经处理时提供警报。This ensures that an alert is provided if an exception isn't handled. 然后运行检查,以确认提供的订阅密钥长度是否为 32 个字符。Then a check is run to confirm the subscription key provided is 32 characters in length. 如果该密钥小于/大于 32 个字符,将引发错误。An error is thrown if the key is less than/greater than 32 characters.

如果密钥至少长度正确,则 InitializeComponent() 调用通过定位、加载和实例化主应用窗口的 XAML 说明来运转用户界面。If there are keys that are at least the right length, the InitializeComponent() call gets the user interface rolling by locating, loading, and instantiating the XAML description of the main app window.

最后,我们添加了用于调用相应方法的代码,以检索要翻译的语言,以及填充应用用户界面的下拉菜单。Last, we've added code to call methods to retrieve languages for translation and to populate the drop-down menus for our app's user interface. 不要担心,我们稍后就会剖析这些调用背后的代码。Don't worry, we'll get to the code behind these calls soon.

获取支持的语言Get supported languages

文本翻译 API 目前支持 60 多种语言。The Translator Text API currently supports more than 60 languages. 由于支持的新语言会不会增加,我们建议调用文本翻译公开的语言资源,而不要对应用中的语言列表进行硬编码。Since new language support will be added over time, we recommend calling the Languages resource exposed by Translator Text rather than hardcoding the language list in your app.

在本部分,我们将对语言资源创建 GET 请求,并指定我们希望提供可用于翻译的语言列表。In this section, we'll create a GET request to the Languages resource, specifying that we want a list of languages available for translation.

备注

使用语言资源可以结合以下查询参数筛选语言支持:音译、字典和翻译。The Languages resource allows you to filter language support with the following query parameters: transliteration, dictionary, and translation. 有关详细信息,请参阅 API 参考For more information, see API reference.

在继续之前,让我们查看调用语言资源后的示例输出:Before we go any further, let's take a look at a sample output for a call to the Languages resource:

{
  "translation": {
    "af": {
      "name": "Afrikaans",
      "nativeName": "Afrikaans",
      "dir": "ltr"
    },
    "ar": {
      "name": "Arabic",
      "nativeName": "العربية",
      "dir": "rtl"
    }
    // Additional languages are provided in the full JSON output.
}

在此输出中,可以提取特定语言的语言代码和 nameFrom this output, we can extract the language code and the name of a specific language. 我们的应用将使用 NewtonSoft.Json 来反序列化 JSON 对象 (JsonConvert.DeserializeObject)。Our app uses NewtonSoft.Json to deserialize the JSON object (JsonConvert.DeserializeObject).

从最后一部分离开的位置着手,添加一个方法用于获取应用支持的语言。Picking up where we left off in the last section, let's add a method to get supported languages to our app.

  1. 在 Visual Studio 中,打开 MainWindow.xaml.cs 对应的选项卡。In Visual Studio, open the tab for MainWindow.xaml.cs.
  2. 将以下代码添加到项目:Add this code to your project:
    // ***** GET TRANSLATABLE LANGUAGE CODES
    private void GetLanguagesForTranslate()
    {
        // Send request to get supported language codes
        string uri = String.Format(TEXT_TRANSLATION_API_ENDPOINT, "languages") + "&scope=translation";
        WebRequest WebRequest = WebRequest.Create(uri);
        WebRequest.Headers.Add("Accept-Language", "en");
        WebResponse response = null;
        // Read and parse the JSON response
        response = WebRequest.GetResponse();
        using (var reader = new StreamReader(response.GetResponseStream(), UnicodeEncoding.UTF8))
        {
            var result = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, Dictionary<string, string>>>>(reader.ReadToEnd());
            var languages = result["translation"];
    
            languageCodes = languages.Keys.ToArray();
            foreach (var kv in languages)
            {
                languageCodesAndTitles.Add(kv.Value["name"], kv.Key);
            }
        }
    }
    // NOTE:
    // In the following sections, we'll add code below this.
    

GetLanguagesForTranslate() 方法创建 HTTP GET 请求,并使用 scope=translation 查询字符串参数来限制支持的翻译语言的请求范围。The GetLanguagesForTranslate() method creates an HTTP GET request, and uses the scope=translation query string parameter is used to limit the scope of the request to supported languages for translation. 将添加值为 enAccept-Language 标头,以便以英语返回受支持的语言。The Accept-Language header with the value en is added so that the supported languages are returned in English.

分析 JSON 响应并将其转换为字典。The JSON response is parsed and converted to a dictionary. 然后将语言代码添加到 languageCodes 成员变量。Then the language codes are added to the languageCodes member variable. 将循环访问包含语言代码和友好语言名称的键/值对,并将它们添加到 languageCodesAndTitles 成员变量中。The key/value pairs that contain the language codes and the friendly language names are looped through and added to the languageCodesAndTitles member variable. 窗体中的下拉菜单显示友好名称,但需要使用代码来请求翻译。The drop-down menus in the form display the friendly names, but the codes are needed to request the translation.

填充语言下拉菜单Populate language drop-down menus

用户界面是使用 XAML 定义的,因此除了调用 InitializeComponent() 以外,不需要执行过多的操作即可对其进行设置。The user interface is defined using XAML, so you don't need to do much to set it up besides call InitializeComponent(). 需要做的一件事是使用 PopulateLanguageMenus() 方法将友好的语言名称添加到“翻译源语言”和“翻译目标语言”下拉菜单。The one thing you need to do is add the friendly language names to the Translate from and Translate to drop-down menus, this is done with the PopulateLanguageMenus() method.

  1. 在 Visual Studio 中,打开 MainWindow.xaml.cs 对应的选项卡。In Visual Studio, open the tab for MainWindow.xaml.cs.
  2. 将以下代码添加到项目中的 GetLanguagesForTranslate() 方法下面:Add this code to your project below the GetLanguagesForTranslate() method:
    private void PopulateLanguageMenus()
    {
        // Add option to automatically detect the source language
        FromLanguageComboBox.Items.Add("Detect");
    
        int count = languageCodesAndTitles.Count;
        foreach (string menuItem in languageCodesAndTitles.Keys)
        {
            FromLanguageComboBox.Items.Add(menuItem);
            ToLanguageComboBox.Items.Add(menuItem);
        }
    
        // Set default languages
        FromLanguageComboBox.SelectedItem = "Detect";
        ToLanguageComboBox.SelectedItem = "English";
    }
    // NOTE:
    // In the following sections, we'll add code below this.
    

此方法循环访问 languageCodesAndTitles 字典并将每个密钥添加到两个菜单。This method iterates over the languageCodesAndTitles dictionary and adds each key to both menus. 填充菜单后,默认的源语言和目标语言将分别设置为“检测”和“英语”。After the menus are populated, the default from and to languages are set to Detect and English respectively.

提示

如果没有为菜单设置默认选择,则用户可以单击“翻译”而无需选择“目标语言”或“源语言”。Without a default selection for the menus, the user can click Translate without first choosing a "to" or "from" language. 默认设置消除了处理此问题的需要。The defaults eliminate the need to deal with this problem.

初始化 MainWindow 并创建用户界面后,只有在单击“翻译”按钮之后,此代码才会运行。Now that MainWindow has been initialized and the user interface created, this code won't run until the Translate button is clicked.

检测源文本的语言Detect language of source text

现在,我们将创建一个方法用于通过文本翻译 API 检测源文本(在文本区域中输入的文本)的语言。Now we're going to create method to detect the language of the source text (text entered into our text area) using the Translator Text API. 此请求返回的值将在稍后的翻译请求中使用。The value returned by this request will be used in our translation request later.

  1. 在 Visual Studio 中,打开 MainWindow.xaml.cs 对应的选项卡。In Visual Studio, open the tab for MainWindow.xaml.cs.
  2. 将以下代码添加到项目中的 PopulateLanguageMenus() 方法下面:Add this code to your project below the PopulateLanguageMenus() method:
    // ***** DETECT LANGUAGE OF TEXT TO BE TRANSLATED
    private string DetectLanguage(string text)
    {
        string detectUri = string.Format(TEXT_TRANSLATION_API_ENDPOINT ,"detect");
    
        // Create request to Detect languages with Translator Text
        HttpWebRequest detectLanguageWebRequest = (HttpWebRequest)WebRequest.Create(detectUri);
        detectLanguageWebRequest.Headers.Add("Ocp-Apim-Subscription-Key", COGNITIVE_SERVICES_KEY);
        detectLanguageWebRequest.Headers.Add("Ocp-Apim-Subscription-Region", "westus");
        detectLanguageWebRequest.ContentType = "app/json; charset=utf-8";
        detectLanguageWebRequest.Method = "POST";
    
        // Send request
        var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        string jsonText = serializer.Serialize(text);
    
        string body = "[{ \"Text\": " + jsonText + " }]";
        byte[] data = Encoding.UTF8.GetBytes(body);
    
        detectLanguageWebRequest.ContentLength = data.Length;
    
        using (var requestStream = detectLanguageWebRequest.GetRequestStream())
            requestStream.Write(data, 0, data.Length);
    
        HttpWebResponse response = (HttpWebResponse)detectLanguageWebRequest.GetResponse();
    
        // Read and parse JSON response
        var responseStream = response.GetResponseStream();
        var jsonString = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")).ReadToEnd();
        dynamic jsonResponse = serializer.DeserializeObject(jsonString);
    
        // Fish out the detected language code
        var languageInfo = jsonResponse[0];
        if (languageInfo["score"] > (decimal)0.5)
        {
            DetectedLanguageLabel.Content = languageInfo["language"];
            return languageInfo["language"];
        }
        else
            return "Unable to confidently detect input language.";
    }
    // NOTE:
    // In the following sections, we'll add code below this.
    

此方法对“检测”资源创建 HTTP POST 请求。This method creates an HTTP POST request to the Detect resource. 此方法采用单个参数 text,该参数作为请求正文连同请求一起传递。It takes a single argument, text, which is passed along as the body of the request. 稍后当我们创建翻译请求时,在 UI 中输入的文本将传递到此方法用于语言检测。Later, we when we create our translation request, the text entered into our UI will be passed to this method for language detection.

此外,此方法会评估响应的置信度评分。Additionally, this method evaluates the confidence score of the response. 如果评分大于 0.5,则在用户界面中显示检测到的语言。If the score is greater than 0.5, then the detected language is displayed in our user interface.

对源文本执行拼写检查Spell check the source text

现在,我们将创建一个方法,用于通过必应拼写检查 API 对源文本执行拼写检查。Now we're going to create a method to spell check our source text using the Bing Spell Check API. 这可以确保文本翻译 API 返回准确的翻译。This ensures that we'll get back accurate translations from Translator Text API. 单击“翻译”按钮时,对源文本所做的任何更正将连同翻译请求一起传递。Any corrections to the source text are passed along in our translation request when the Translate button is clicked.

  1. 在 Visual Studio 中,打开 MainWindow.xaml.cs 对应的选项卡。In Visual Studio, open the tab for MainWindow.xaml.cs.
  2. 将以下代码添加到项目中的 DetectLanguage() 方法下面:Add this code to your project below the DetectLanguage() method:
// ***** CORRECT SPELLING OF TEXT TO BE TRANSLATED
private string CorrectSpelling(string text)
{
    string uri = BING_SPELL_CHECK_API_ENDPOINT + "?mode=spell&mkt=en-US";

    // Create a request to Bing Spell Check API
    HttpWebRequest spellCheckWebRequest = (HttpWebRequest)WebRequest.Create(uri);
    spellCheckWebRequest.Headers.Add("Ocp-Apim-Subscription-Key", COGNITIVE_SERVICES_KEY);
    spellCheckWebRequest.Method = "POST";
    spellCheckWebRequest.ContentType = "app/x-www-form-urlencoded"; // doesn't work without this

    // Create and send the request
    string body = "text=" + System.Web.HttpUtility.UrlEncode(text);
    byte[] data = Encoding.UTF8.GetBytes(body);
    spellCheckWebRequest.ContentLength = data.Length;
    using (var requestStream = spellCheckWebRequest.GetRequestStream())
        requestStream.Write(data, 0, data.Length);
    HttpWebResponse response = (HttpWebResponse)spellCheckWebRequest.GetResponse();

    // Read and parse the JSON response; get spelling corrections
    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var responseStream = response.GetResponseStream();
    var jsonString = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")).ReadToEnd();
    dynamic jsonResponse = serializer.DeserializeObject(jsonString);
    var flaggedTokens = jsonResponse["flaggedTokens"];

    // Construct sorted dictionary of corrections in reverse order (right to left)
    // This ensures that changes don't impact later indexes
    var corrections = new SortedDictionary<int, string[]>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
    for (int i = 0; i < flaggedTokens.Length; i++)
    {
        var correction = flaggedTokens[i];
        var suggestion = correction["suggestions"][0];  // Consider only first suggestion
        if (suggestion["score"] > (decimal)0.7)         // Take it only if highly confident
            corrections[(int)correction["offset"]] = new string[]   // dict key   = offset
                { correction["token"], suggestion["suggestion"] };  // dict value = {error, correction}
    }

    // Apply spelling corrections, in order, from right to left
    foreach (int i in corrections.Keys)
    {
        var oldtext = corrections[i][0];
        var newtext = corrections[i][1];

        // Apply capitalization from original text to correction - all caps or initial caps
        if (text.Substring(i, oldtext.Length).All(char.IsUpper)) newtext = newtext.ToUpper();
        else if (char.IsUpper(text[i])) newtext = newtext[0].ToString().ToUpper() + newtext.Substring(1);

        text = text.Substring(0, i) + newtext + text.Substring(i + oldtext.Length);
    }
    return text;
}
// NOTE:
// In the following sections, we'll add code below this.

单击后翻译文本Translate text on click

要做的最后一件事是,创建一个在用户界面中单击“翻译”按钮时要调用的方法。The last thing that we need to do is create a method that is invoked when the Translate button in our user interface is clicked.

  1. 在 Visual Studio 中,打开 MainWindow.xaml.cs 对应的选项卡。In Visual Studio, open the tab for MainWindow.xaml.cs.
  2. 将以下代码添加到项目中的 CorrectSpelling() 方法下面并保存:Add this code to your project below the CorrectSpelling() method and save:
    // ***** PERFORM TRANSLATION ON BUTTON CLICK
    private async void TranslateButton_Click(object sender, EventArgs e)
    {
        string textToTranslate = TextToTranslate.Text.Trim();
    
        string fromLanguage = FromLanguageComboBox.SelectedValue.ToString();
        string fromLanguageCode;
    
        // auto-detect source language if requested
        if (fromLanguage == "Detect")
        {
            fromLanguageCode = DetectLanguage(textToTranslate);
            if (!languageCodes.Contains(fromLanguageCode))
            {
                MessageBox.Show("The source language could not be detected automatically " +
                    "or is not supported for translation.", "Language detection failed",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
        }
        else
            fromLanguageCode = languageCodesAndTitles[fromLanguage];
    
        string toLanguageCode = languageCodesAndTitles[ToLanguageComboBox.SelectedValue.ToString()];
    
        // spell-check the source text if the source language is English
        if (fromLanguageCode == "en")
        {
            if (textToTranslate.StartsWith("-"))    // don't spell check in this case
                textToTranslate = textToTranslate.Substring(1);
            else
            {
                textToTranslate = CorrectSpelling(textToTranslate);
                TextToTranslate.Text = textToTranslate;     // put corrected text into input field
            }
        }
        // handle null operations: no text or same source/target languages
        if (textToTranslate == "" || fromLanguageCode == toLanguageCode)
        {
            TranslatedTextLabel.Content = textToTranslate;
            return;
        }
    
        // send HTTP request to perform the translation
        string endpoint = string.Format(TEXT_TRANSLATION_API_ENDPOINT, "translate");
        string uri = string.Format(endpoint + "&from={0}&to={1}", fromLanguageCode, toLanguageCode);
    
        System.Object[] body = new System.Object[] { new { Text = textToTranslate } };
        var requestBody = JsonConvert.SerializeObject(body);
    
        using (var client = new HttpClient())
        using (var request = new HttpRequestMessage())
        {
            request.Method = HttpMethod.Post;
            request.RequestUri = new Uri(uri);
            request.Content = new StringContent(requestBody, Encoding.UTF8, "app/json");
            request.Headers.Add("Ocp-Apim-Subscription-Key", COGNITIVE_SERVICES_KEY);
            request.Headers.Add("Ocp-Apim-Subscription-Region", "westus");
            request.Headers.Add("X-ClientTraceId", Guid.NewGuid().ToString());
    
            var response = await client.SendAsync(request);
            var responseBody = await response.Content.ReadAsStringAsync();
    
            var result = JsonConvert.DeserializeObject<List<Dictionary<string, List<Dictionary<string, string>>>>>(responseBody);
            var translation = result[0]["translations"][0]["text"];
    
            // Update the translation field
            TranslatedTextLabel.Content = translation;
        }
    }
    

第一步是获取“源”和“目标”语言,以及用户在窗体中输入的文本。The first step is to get the "from" and "to" languages, and the text the user entered into our form. 如果源语言设置为“检测”,则调用 DetectLanguage() 来确定源文本的语言。If the source language is set to Detect, DetectLanguage() is called to determine the language of the source text. 文本可能采用了翻译 API 不支持的语言。The text might be in a language that the Translator API doesn't support. 在这种情况下,会显示一条消息来通知用户,并返回且不翻译文本。In that case, display a message to inform the user, and return without translating the text.

如果源语言是英语(无论是指定的还是检测到的),将使用 CorrectSpelling() 进行文本拼写检查并应用任何更正。If the source language is English (whether specified or detected), check the spelling of the text with CorrectSpelling() and apply any corrections. 更正的文本将添加回到文本区域,使用户能够看到已做出更正。The corrected text is added back into the text area so that the user sees that a correction was made.

你应该很熟悉用于翻译文本的代码:生成 URI、创建请求、发送请求,并分析响应。The code to translate text should look familiar: build the URI, create a request, send it, and parse the response. JSON 数组可以包含多个要翻译的对象,但是,我们的应用只需要一个对象。The JSON array may contain more than one object for translation, however, our app only requires one.

成功请求之后,TranslatedTextLabel.Content 将替换为 translation,这会更新用户界面以显示翻译的文本。After a successful request, TranslatedTextLabel.Content is replaced with the translation, which updates the user interface to display the translated text.

运行 WPF 应用Run your WPF app

现已使用 WPF 生成了一个可正常运行的翻译应用。That's it, you have a working translation app built using WPF. 若要运行该应用,请在 Visual Studio 中单击“启动”按钮。To run your app, click the Start button in Visual Studio.

源代码Source code

此项目的源代码已在 GitHub 中提供。Source code for this project is available on GitHub.

后续步骤Next steps