Move AzureConnection's strings into localizable resources (#3463)

This also sets up TerminalConnection to _have_ resources, which will be useful for the messages in #3461.
This commit is contained in:
Dustin L. Howett (MSFT) 2019-11-07 12:26:45 -08:00 committed by GitHub
parent 357e835f5d
commit d26865f460
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 298 additions and 92 deletions

View file

@ -4,9 +4,9 @@
#include "pch.h"
#include "AzureConnection.h"
#include "AzureClientID.h"
#include "AzureConnectionStrings.h"
#include <sstream>
#include <stdlib.h>
#include <LibraryResources.h>
#include "AzureConnection.g.cpp"
@ -24,6 +24,8 @@ using namespace concurrency::streams;
using namespace winrt::Windows::Security::Credentials;
static constexpr int CurrentCredentialVersion = 1;
static constexpr auto PasswordVaultResourceName = L"Terminal";
static constexpr auto HttpUserAgent = L"Terminal/0.0";
namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
@ -42,6 +44,15 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
}
// Method description:
// - helper that will write an unterminated string (generally, from a resource) to the output stream.
// Arguments:
// - str: the string to write.
void AzureConnection::_WriteStringWithNewline(const winrt::hstring& str)
{
_outputHandlers(str + L"\r\n");
}
// Method description:
// - ascribes to the ITerminalConnection interface
// - registers an output event handler
@ -131,29 +142,29 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
catch (...)
{
if (s != "n" && s != "r")
std::lock_guard<std::mutex> lg{ _commonMutex };
if (data == RS_(L"AzureUserEntry_RemoveStored"))
{
_outputHandlers(winrt::to_hstring(invalidAccessInput));
return;
}
else if (s == "r")
{
std::lock_guard<std::mutex> lg{ _commonMutex };
_removeOrNew = true;
}
else if (data == RS_(L"AzureUserEntry_NewLogin"))
{
_removeOrNew = false;
}
if (_removeOrNew.has_value())
{
_canProceed.notify_one();
return;
}
else
{
std::lock_guard<std::mutex> lg{ _commonMutex };
_removeOrNew = false;
_canProceed.notify_one();
return;
_WriteStringWithNewline(RS_(L"AzureInvalidAccessInput"));
}
return;
}
if (storeNum >= _maxStored)
{
_outputHandlers(winrt::to_hstring(numOutOfBoundsError));
_WriteStringWithNewline(RS_(L"AzureNumOutOfBoundsError"));
return;
}
std::lock_guard<std::mutex> lg{ _commonMutex };
@ -171,12 +182,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
catch (...)
{
_outputHandlers(winrt::to_hstring(nonNumberError));
_WriteStringWithNewline(RS_(L"AzureNonNumberError"));
return;
}
if (tenantNum >= _maxSize)
{
_outputHandlers(winrt::to_hstring(numOutOfBoundsError));
_WriteStringWithNewline(RS_(L"AzureNumOutOfBoundsError"));
return;
}
std::lock_guard<std::mutex> lg{ _commonMutex };
@ -187,22 +198,23 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// User has the option to save their connection settings for future logins
case State::StoreTokens:
{
std::string s = winrt::to_string(data);
if (s != "y" && s != "n")
std::lock_guard<std::mutex> lg{ _commonMutex };
if (data == RS_(L"AzureUserEntry_Yes"))
{
_outputHandlers(winrt::to_hstring(invalidStoreInput));
}
else if (s == "y")
{
std::lock_guard<std::mutex> lg{ _commonMutex };
_store = true;
}
else if (data == RS_(L"AzureUserEntry_No"))
{
_store = false;
}
if (_store.has_value())
{
_canProceed.notify_one();
}
else
{
std::lock_guard<std::mutex> lg{ _commonMutex };
_store = false;
_canProceed.notify_one();
_WriteStringWithNewline(RS_(L"AzureInvalidStoreInput"));
}
return;
}
@ -284,7 +296,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
static std::tuple<utility::string_t, utility::string_t> _crackTenant(const json::value& tenant)
{
auto tenantId{ tenant.at(L"tenantId").as_string() };
auto displayName{ tenant.has_string_field(L"displayName") ? tenant.at(L"displayName").as_string() : unknownTenantName };
std::wstring displayName{ tenant.has_string_field(L"displayName") ? tenant.at(L"displayName").as_string() : static_cast<std::wstring>(RS_(L"AzureUnknownTenantName")) };
return { tenantId, displayName };
}
@ -382,7 +394,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
case State::NoConnect:
{
_outputHandlers(winrt::to_hstring(internetOrServerIssue));
_WriteStringWithNewline(RS_(L"AzureInternetOrServerIssue"));
_disconnectHandlers();
return E_FAIL;
}
@ -409,7 +421,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// FindAllByResource throws an exception if there are no credentials stored under the given resource so we wrap it in a try-catch block
try
{
credList = vault.FindAllByResource(resource);
credList = vault.FindAllByResource(PasswordVaultResourceName);
}
catch (...)
{
@ -435,8 +447,8 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
continue;
}
auto tenantLine{ wil::str_printf<std::wstring>(ithTenant, _maxStored, nameJson.at(L"displayName").as_string().c_str(), nameJson.at(L"tenantID").as_string().c_str()) };
_outputHandlers(tenantLine);
winrt::hstring tenantLine{ wil::str_printf<std::wstring>(RS_(L"AzureIthTenant").c_str(), _maxStored, nameJson.at(L"displayName").as_string().c_str(), nameJson.at(L"tenantID").as_string().c_str()) };
_WriteStringWithNewline(tenantLine);
_maxStored++;
}
@ -444,16 +456,16 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
if (oldVersionEncountered)
{
_outputHandlers(winrt::to_hstring(oldCredentialsFlushedMessage));
_WriteStringWithNewline(RS_(L"AzureOldCredentialsFlushedMessage"));
}
// No valid up-to-date credentials were found, so start the device flow
_state = State::DeviceFlow;
return S_FALSE;
}
_outputHandlers(winrt::to_hstring(enterTenant));
_outputHandlers(winrt::to_hstring(newLogin));
_outputHandlers(winrt::to_hstring(removeStored));
_WriteStringWithNewline(RS_(L"AzureEnterTenant"));
_WriteStringWithNewline(RS_(L"AzureNewLogin"));
_WriteStringWithNewline(RS_(L"AzureRemoveStored"));
std::unique_lock<std::mutex> storedLock{ _commonMutex };
_canProceed.wait(storedLock, [=]() {
@ -518,8 +530,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const auto deviceCodeResponse = _GetDeviceCode();
// Print the message and store the device code, polling interval and expiry
const auto message = deviceCodeResponse.at(L"message").as_string();
_outputHandlers(message + codeExpiry);
const auto message = winrt::to_hstring(deviceCodeResponse.at(L"message").as_string().c_str());
_WriteStringWithNewline(message);
_WriteStringWithNewline(RS_(L"AzureCodeExpiry"));
const auto devCode = deviceCodeResponse.at(L"device_code").as_string();
const auto pollInterval = std::stoi(deviceCodeResponse.at(L"interval").as_string());
const auto expiresIn = std::stoi(deviceCodeResponse.at(L"expires_in").as_string());
@ -532,7 +545,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
catch (...)
{
_outputHandlers(winrt::to_hstring(exitStr));
_WriteStringWithNewline(RS_(L"AzureExitStr"));
return E_FAIL;
}
@ -545,7 +558,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const auto tenantListAsArray = _tenantList.as_array();
if (tenantListAsArray.size() == 0)
{
_outputHandlers(winrt::to_hstring(noTenants));
_WriteStringWithNewline(RS_(L"AzureNoTenants"));
return E_FAIL;
}
else if (_tenantList.size() == 1)
@ -583,10 +596,10 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
const auto& tenant = tenantListAsArray.at(i);
const auto [tenantId, tenantDisplayName] = _crackTenant(tenant);
auto tenantLine{ wil::str_printf<std::wstring>(ithTenant, i, tenantDisplayName.c_str(), tenantId.c_str()) };
_outputHandlers(tenantLine);
winrt::hstring tenantLine{ wil::str_printf<std::wstring>(RS_(L"AzureIthTenant").c_str(), i, tenantDisplayName.c_str(), tenantId.c_str()) };
_WriteStringWithNewline(tenantLine);
}
_outputHandlers(winrt::to_hstring(enterTenant));
_WriteStringWithNewline(RS_(L"AzureEnterTenant"));
// Use a lock to wait for the user to input a valid number
std::unique_lock<std::mutex> tenantNumberLock{ _commonMutex };
_canProceed.wait(tenantNumberLock, [=]() {
@ -620,7 +633,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// - S_OK otherwise
HRESULT AzureConnection::_StoreHelper()
{
_outputHandlers(winrt::to_hstring(storePrompt));
_WriteStringWithNewline(RS_(L"AzureStorePrompt"));
// Wait for user input
std::unique_lock<std::mutex> storeLock{ _commonMutex };
_canProceed.wait(storeLock, [=]() {
@ -636,7 +649,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
{
// User has opted to store the connection settings
_StoreCredential();
_outputHandlers(winrt::to_hstring(tokensStored));
_WriteStringWithNewline(RS_(L"AzureTokensStored"));
}
_state = State::TermConnecting;
@ -654,14 +667,14 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
const auto settingsResponse = _GetCloudShellUserSettings();
if (settingsResponse.has_field(L"error"))
{
_outputHandlers(winrt::to_hstring(noCloudAccount));
_WriteStringWithNewline(RS_(L"AzureNoCloudAccount"));
return E_FAIL;
}
// Request for a cloud shell
_outputHandlers(winrt::to_hstring(requestingCloud));
_WriteStringWithNewline(RS_(L"AzureRequestingCloud"));
_cloudShellUri = _GetCloudShell();
_outputHandlers(winrt::to_hstring(success));
_WriteStringWithNewline(RS_(L"AzureSuccess"));
// Request for a terminal for said cloud shell
// We only support bash for now, so don't bother with the user's preferred shell
@ -669,9 +682,9 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// TODO: GitHub #1883
//const auto shellType = settingsResponse.at(L"properties").at(L"preferredShellType").as_string();
const auto shellType = L"bash";
_outputHandlers(winrt::to_hstring(requestingTerminal));
_WriteStringWithNewline(RS_(L"AzureRequestingTerminal"));
const auto socketUri = _GetTerminal(shellType);
_outputHandlers(winrt::to_hstring("\r\n"));
_outputHandlers(L"\r\n");
// Step 8: connecting to said terminal
const auto connReqTask = _cloudShellSocket.connect(socketUri);
@ -702,7 +715,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
catch (...)
{
_outputHandlers(winrt::to_hstring(internetOrServerIssue));
_WriteStringWithNewline(RS_(L"AzureInternetOrServerIssue"));
}
return jsonResult;
}
@ -764,7 +777,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
else
{
_outputHandlers(winrt::to_hstring("Authenticated.\r\n"));
_WriteStringWithNewline(RS_(L"AzureSuccessfullyAuthenticated"));
break; // Authentication is done, break from loop
}
}
@ -807,7 +820,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
refreshRequest.set_request_uri(_tenantID + L"/oauth2/token");
const auto body = L"client_id=" + AzureClientID + L"&resource=" + _wantedResource + L"&grant_type=refresh_token" + L"&refresh_token=" + _refreshToken;
refreshRequest.set_body(body, L"application/x-www-form-urlencoded");
refreshRequest.headers().add(L"User-Agent", userAgent);
refreshRequest.headers().add(L"User-Agent", HttpUserAgent);
// Send the request and return the response as a json value
return _RequestHelper(refreshClient, refreshRequest);
@ -886,7 +899,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
theRequest.headers().add(L"Accept", L"application/json");
theRequest.headers().add(L"Content-Type", L"application/json");
theRequest.headers().add(L"Authorization", L"Bearer " + _accessToken);
theRequest.headers().add(L"User-Agent", userAgent);
theRequest.headers().add(L"User-Agent", HttpUserAgent);
}
// Method description:
@ -903,7 +916,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
passWord[U("accessToken")] = json::value::string(_accessToken);
passWord[U("refreshToken")] = json::value::string(_refreshToken);
passWord[U("expiry")] = json::value::string(std::to_wstring(_expiry));
auto newCredential = PasswordCredential(resource, userName.serialize(), passWord.serialize());
auto newCredential = PasswordCredential(PasswordVaultResourceName, userName.serialize(), passWord.serialize());
vault.Add(newCredential);
}
@ -916,12 +929,12 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
// FindAllByResource throws an exception if there are no credentials stored under the given resource so we wrap it in a try-catch block
try
{
credList = vault.FindAllByResource(resource);
credList = vault.FindAllByResource(PasswordVaultResourceName);
}
catch (...)
{
// No credentials are stored, so just return
_outputHandlers(winrt::to_hstring(noTokens));
_WriteStringWithNewline(RS_(L"AzureNoTokens"));
return;
}
while (credList.Size() > 0)
@ -932,7 +945,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
}
catch (...)
{
_outputHandlers(winrt::to_hstring(tokensRemoved));
_WriteStringWithNewline(RS_(L"AzureTokensRemoved"));
return;
}
}

View file

@ -82,6 +82,7 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
utility::string_t _cloudShellUri;
utility::string_t _terminalID;
void _WriteStringWithNewline(const winrt::hstring& str);
web::json::value _RequestHelper(web::http::client::http_client theClient, web::http::http_request theRequest);
web::json::value _GetDeviceCode();
web::json::value _WaitForUser(utility::string_t deviceCode, int pollInterval, int expiresIn);

View file

@ -1,32 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
// Messages to the user
const auto resource = L"Terminal";
const auto userAgent = L"Terminal/0.0";
const auto codeExpiry = L"\r\nThis code will expire in 15 minutes.\r\n";
const auto enterTenant = L"Please enter the desired tenant number\r\n";
const auto newLogin = L"or enter n to login with a different account\r\n";
const auto removeStored = L"or enter r to remove the above saved connection settings.\r\n";
const auto invalidAccessInput = L"Please enter a valid number to access the stored connection settings, n to make a new one, or r to remove the stored ones.\r\n";
const auto nonNumberError = L"Please enter a number.\r\n";
const auto numOutOfBoundsError = L"Number out of bounds. Please enter a valid number. \r\n";
const auto noTenants = L"Could not find any tenants.\r\n";
const auto noCloudAccount = L"You have not set up your cloud shell account yet. Please go to https://shell.azure.com to set it up.\r\n";
const auto storePrompt = L"Do you want to save these connection settings for future logins? [y/n]\r\n";
const auto invalidStoreInput = L"Please enter y or n\r\n";
const auto requestingCloud = L"Requesting for a cloud shell...";
const auto success = L"Succeeded.\r\n";
const auto requestingTerminal = L"Requesting for a terminal (this might take a while)...";
const auto tokensStored = L"Your connection settings have been saved for future logins.\r\n";
const auto noTokens = L"No tokens to remove. \r\n";
const auto tokensRemoved = L"Tokens removed!\r\n";
const auto exitStr = L"Exit.\r\n";
const auto authString = L"Authenticated.\r\n";
const auto internetOrServerIssue = L"Could not connect to Azure. You may not have internet or the server might be down.\r\n";
const auto oldCredentialsFlushedMessage = L"Authentication parameters changed. You'll need to log in again.\r\n";
const auto unknownTenantName = L"<unknown tenant name>";
const auto ithTenant = L"Tenant %d: %s (%s)\r\n";

View file

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AzureCodeExpiry" xml:space="preserve">
<value>This code will expire in 15 minutes.</value>
</data>
<data name="AzureEnterTenant" xml:space="preserve">
<value>Please enter the desired tenant number.</value>
</data>
<data name="AzureNewLogin" xml:space="preserve">
<value>Enter "n" to login with a different account.</value>
</data>
<data name="AzureRemoveStored" xml:space="preserve">
<value>Enter "r" to remove the above saved connection settings.</value>
</data>
<data name="AzureInvalidAccessInput" xml:space="preserve">
<value>Please enter a valid number to access the stored connection settings, n to make a new one, or r to remove the stored ones.</value>
</data>
<data name="AzureNonNumberError" xml:space="preserve">
<value>Please enter a number.</value>
</data>
<data name="AzureNumOutOfBoundsError" xml:space="preserve">
<value>Number out of bounds. Please enter a valid number.</value>
</data>
<data name="AzureNoTenants" xml:space="preserve">
<value>Could not find any tenants.</value>
</data>
<data name="AzureNoCloudAccount" xml:space="preserve">
<value>You have not set up your cloud shell account yet. Please go to https://shell.azure.com to set it up.</value>
</data>
<data name="AzureStorePrompt" xml:space="preserve">
<value>Do you want to save these connection settings for future logins? [y/n]</value>
</data>
<data name="AzureInvalidStoreInput" xml:space="preserve">
<value>Please enter y or n</value>
</data>
<data name="AzureRequestingCloud" xml:space="preserve">
<value>Requesting a cloud shell instance...</value>
</data>
<data name="AzureSuccess" xml:space="preserve">
<value>Succeeded.</value>
</data>
<data name="AzureRequestingTerminal" xml:space="preserve">
<value>Requesting a terminal (this might take a while)...</value>
</data>
<data name="AzureTokensStored" xml:space="preserve">
<value>Your connection settings have been saved for future logins.</value>
</data>
<data name="AzureNoTokens" xml:space="preserve">
<value>No tokens to remove.</value>
</data>
<data name="AzureTokensRemoved" xml:space="preserve">
<value>Saved connection settings removed.</value>
</data>
<data name="AzureExitStr" xml:space="preserve">
<value>Exit.</value>
</data>
<data name="AzureAuthString" xml:space="preserve">
<value>Authenticated.</value>
</data>
<data name="AzureInternetOrServerIssue" xml:space="preserve">
<value>Could not connect to Azure. You may not have internet or the server might be down.</value>
</data>
<data name="AzureOldCredentialsFlushedMessage" xml:space="preserve">
<value>Authentication parameters changed. You'll need to log in again.</value>
</data>
<data name="AzureUnknownTenantName" xml:space="preserve">
<value>&lt;unknown tenant name&gt;</value>
</data>
<data name="AzureIthTenant" xml:space="preserve">
<value>Tenant %d: %s (%s)</value>
</data>
<data name="AzureSuccessfullyAuthenticated" xml:space="preserve">
<value>Authenticated.</value>
</data>
<data name="AzureUserEntry_NewLogin" xml:space="preserve">
<value>n</value>
<comment>The user must enter this character to say NEW LOGIN (AzureInvalidAccessInput, AzureNewLogin)</comment>
</data>
<data name="AzureUserEntry_RemoveStored" xml:space="preserve">
<value>r</value>
<comment>The user must enter this character to say REMOVE SAVED LOGINS (AzureRemoveStored, AzureInvalidAccessInput)</comment>
</data>
<data name="AzureUserEntry_Yes" xml:space="preserve">
<value>y</value>
<comment>The user must enter this character to signify YES</comment>
</data>
<data name="AzureUserEntry_No" xml:space="preserve">
<value>n</value>
<comment>The user must enter this character to signify NO</comment>
</data>
</root>

View file

@ -33,7 +33,6 @@
<ClInclude Include="AzureClientID.h" Condition="'$(Platform)'!='ARM64'" />
<ClInclude Include="AzureConnection.h" Condition="'$(Platform)'!='ARM64'" />
<ClInclude Include="AzureConnection-ARM64.h" Condition="'$(Platform)'=='ARM64'" />
<ClInclude Include="AzureConnectionStrings.h" Condition="'$(Platform)'!='ARM64'" />
<ClInclude Include="pch.h" />
<ClInclude Include="ConptyConnection.h">
<DependentUpon>ConptyConnection.idl</DependentUpon>
@ -64,6 +63,7 @@
<Midl Include="AzureConnection.idl" />
</ItemGroup>
<ItemGroup>
<PRIResource Include="Resources/en-US/Resources.resw" />
<None Include="packages.config" />
</ItemGroup>
@ -77,6 +77,12 @@
<ProjectReference Include="$(OpenConsoleDir)src\types\lib\types.vcxproj">
<Project>{18D09A24-8240-42D6-8CB6-236EEE820263}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\cascadia\WinRTUtils\WinRTUtils.vcxproj">
<Project>{CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\winconpty\winconpty.vcxproj">
<Project>{58a03bb2-df5a-4b66-91a0-7ef3ba01269a}</Project>
</ProjectReference>

View file

@ -8,6 +8,9 @@
<Filter Include="Generated Files">
<UniqueIdentifier>{926ab91d-31b4-48c3-b9a4-e681349f27f0}</UniqueIdentifier>
</Filter>
<Filter Include="Resources\en-US">
<UniqueIdentifier>{ee3ff32f-d013-49cb-8eb9-1ec084585086}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp" />
@ -21,7 +24,6 @@
<ClInclude Include="EchoConnection.h" />
<ClInclude Include="AzureConnection.h" />
<ClInclude Include="AzureClientID.h" />
<ClInclude Include="AzureConnectionStrings.h" />
</ItemGroup>
<ItemGroup>
<Midl Include="ITerminalConnection.idl" />
@ -35,4 +37,9 @@
<ItemGroup>
<Natvis Include="$(SolutionDir)tools\ConsoleTypes.natvis" />
</ItemGroup>
</Project>
<ItemGroup>
<PRIResource Include="Resources/en-US/Resources.resw">
<Filter>Resources\en-US</Filter>
</PRIResource>
</ItemGroup>
</Project>

View file

@ -2,6 +2,7 @@
// Licensed under the MIT license.
#include "pch.h"
#include <LibraryResources.h>
// Note: Generate GUID using TlgGuid.exe tool
TRACELOGGING_DEFINE_PROVIDER(
@ -29,3 +30,5 @@ BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID /*reserved*/)
return TRUE;
}
UTILS_DEFINE_LIBRARY_RESOURCE_SCOPE(L"Microsoft.Terminal.TerminalConnection/Resources");