public static async Task <T> TranslateAsync <T>(
            T card,
            TranslateManyDelegate translateManyAsync,
            AdaptiveCardTranslatorSettings settings = null,
            CancellationToken cancellationToken     = default)
        {
            if (card == null)
            {
                throw new ArgumentNullException(nameof(card));
            }

            if (translateManyAsync is null)
            {
                throw new ArgumentNullException(nameof(translateManyAsync));
            }

            JObject cardJObject;

            if (card is JObject jObject)
            {
                // If the card is already a JObject then we want to make sure
                // it gets copied instead of modified in place
                cardJObject = (JObject)jObject.DeepClone();
            }
            else
            {
                cardJObject = card.ToJObject(true) ?? throw new ArgumentException(
                                        "The Adaptive Card is not an appropriate type or is serialized incorrectly.",
                                        nameof(card));
            }

            var tokens = GetTokensToTranslate(cardJObject, settings ?? DefaultSettings);

            var translations = await translateManyAsync(
                tokens.Select(Convert.ToString).ToList(),
                cancellationToken).ConfigureAwait(false);

            if (translations != null)
            {
                for (int i = 0; i < tokens.Count && i < translations.Count; i++)
                {
                    var item           = tokens[i];
                    var translatedText = translations[i];

                    if (!string.IsNullOrWhiteSpace(translatedText))
                    {
                        // Modify each stored JToken with the translated text
                        item.Replace(translatedText);
                    }
                }
            }

            return(card.FromJObject(cardJObject));
        }
        private static List <JToken> GetTokensToTranslate(
            JObject cardJObject,
            AdaptiveCardTranslatorSettings settings)
        {
            var tokens = new List <JToken>();

            // Find potential strings to translate
            foreach (var token in cardJObject.Descendants().Where(token => token.Type == JTokenType.String))
            {
                var parent = token.Parent;

                if (parent != null)
                {
                    var shouldTranslate = false;
                    var container       = parent.Parent;

                    switch (parent.Type)
                    {
                    // If the string is the value of a property...
                    case JTokenType.Property:

                        var propertyName = (parent as JProperty).Name;

                        // container is assumed to be a JObject because it's the parent of a JProperty in this case
                        if (settings.PropertiesToTranslate?.Contains(propertyName) == true &&
                            (propertyName != AdaptiveProperties.Value || IsValueTranslatable(container as JObject)))
                        {
                            shouldTranslate = true;
                        }

                        break;

                    // If the string is in an array...
                    case JTokenType.Array:

                        if (IsArrayElementTranslatable(container))
                        {
                            shouldTranslate = true;
                        }

                        break;
                    }

                    if (shouldTranslate)
                    {
                        tokens.Add(token);
                    }
                }
            }

            return(tokens);
        }
        public static async Task <T> TranslateAsync <T>(
            T card,
            string targetLocale,
            string subscriptionKey,
            HttpClient httpClient = null,
            AdaptiveCardTranslatorSettings settings = null,
            CancellationToken cancellationToken     = default)
        {
            if (string.IsNullOrWhiteSpace(subscriptionKey))
            {
                throw new ArgumentNullException(nameof(subscriptionKey));
            }

            if (string.IsNullOrWhiteSpace(targetLocale))
            {
                throw new ArgumentNullException(nameof(targetLocale));
            }

            return(await TranslateAsync(
                       card,
                       async (inputs, innerCancellationToken) =>
            {
                // From Cognitive Services translation documentation:
                // https://docs.microsoft.com/en-us/azure/cognitive-services/translator/quickstart-csharp-translate
                var requestBody = JsonConvert.SerializeObject(inputs.Select(input => new { Text = input }));

                using (var request = new HttpRequestMessage())
                {
                    var client = httpClient ?? LazyClient.Value;
                    var baseUri = client.BaseAddress ?? DefaultBaseAddress;

                    request.Method = HttpMethod.Post;
                    request.RequestUri = new Uri(baseUri, $"translate?api-version=3.0&to={targetLocale}");
                    request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
                    request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

                    var response = await client.SendAsync(request, innerCancellationToken).ConfigureAwait(false);

                    response.EnsureSuccessStatusCode();

                    var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                    var result = JsonConvert.DeserializeObject <TranslatorResponse[]>(responseBody);

                    return result.Select(translatorResponse => translatorResponse?.Translations?.FirstOrDefault()?.Text).ToList();
                }
            },
                       settings,
                       cancellationToken).ConfigureAwait(false));
        }
        public static async Task <T> TranslateAsync <T>(
            T card,
            MicrosoftTranslatorConfig config,
            AdaptiveCardTranslatorSettings settings = null,
            CancellationToken cancellationToken     = default)
        {
            if (config is null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            return(await TranslateAsync(
                       card,
                       config.TargetLocale,
                       config.SubscriptionKey,
                       config.HttpClient,
                       settings,
                       cancellationToken).ConfigureAwait(false));
        }
        public static async Task <T> TranslateAsync <T>(
            T card,
            TranslateOneDelegate translateOneAsync,
            AdaptiveCardTranslatorSettings settings = null,
            CancellationToken cancellationToken     = default)
        {
            if (translateOneAsync is null)
            {
                throw new ArgumentNullException(nameof(translateOneAsync));
            }

            return(await TranslateAsync(
                       card,
                       async (inputs, innerCancellationToken) =>
            {
                var tasks = inputs.Select(async input => await translateOneAsync(input, innerCancellationToken).ConfigureAwait(false));
                return await Task.WhenAll(tasks).ConfigureAwait(false);
            },
                       settings,
                       cancellationToken).ConfigureAwait(false));
        }