PSTranslate.psm1
function New-AzureTranslation { <# .SYNOPSIS Uses Azure Cognitive Services to translate text. .DESCRIPTION Uses Azure Cognitive Services to translate text. .PARAMETER Value The text to translate. .PARAMETER From The language to translate from. .PARAMETER To The language to translate to. .PARAMETER ApiVersion The API version to use. .EXAMPLE PS C:\> $text | New-AzureTranslation -From $From -To $To Converts the text stored in the $text from one language to another #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string] $Value, [Parameter(Mandatory = $true)] [CultureInfo] $From, [Parameter(Mandatory = $true)] [CultureInfo] $To, [Parameter()] [String] $ApiVersion = '3.0' ) begin { $azureUri = 'https://api.cognitive.microsofttranslator.com/translate?api-version={0}&from={1}&to={2}' -f $ApiVersion, $From.TwoLetterISOLanguageName, $To.TwoLetterISOLanguageName $providerOptions = Get-PSFConfigValue -FullName PSTranslate.Azure.Options $key = Get-TranslationApiKey -Provider Azure if (-not $key) { Stop-PSFFunction -String 'New-AzureTranslation.ApiKey.NotFound' return } $header = @{ 'Ocp-Apim-Subscription-Key' = $key } if ($providerOptions.ExtraHeader) { $header += $providerOptions.ExtraHeader } Write-PSFMessage -String 'New-AzureTranslation.Preparing' -StringValues $From.TwoLetterISOLanguageName, $To.TwoLetterISOLanguageName, $($(-join $key[0, 1]) + $('*' * 28) + $(-join $key[-2, -1])), $azureUri $requestCollector = New-Object -TypeName System.Collections.Specialized.OrderedDictionary $count = 0 $requestCollector.Add($count, @()) $currentLength = 0 $charactersPerSecond = [Math]::Floor($providerOptions.CharacterLimit / $providerOptions.LimitWindow.TotalSeconds) } process { if ($requestCollector[$count].Count -gt 999 -or ($currentLength + $Value.Length) -ge $charactersPerSecond) { $count ++ $requestCollector.Add($count, @()) $currentLength = 0 } Write-PSFMessage -String 'New-AzureTranslation.AddingInput' -StringValues $Value, $requestCollector[$count].Count $requestCollector[$count] += @{ Text = $Value } $currentLength += $Value.Length } end { Write-PSFMessage -String 'New-AzureTranslation.ExecutingBatches' -StringValues $requestCollector.Count, $charactersPerSecond foreach ($entry in $requestCollector.GetEnumerator()) { $jsonBody = ConvertTo-Json -InputObject $entry.Value $(Invoke-RestMethod -Method Post -Uri $azureUri -Body $jsonBody -Headers $header -ContentType application/json).translations.text [Threading.Thread]::Sleep(1000) # Having calculated chars/second, we can just wait a second } } } function New-GoogleTranslation { <# .SYNOPSIS Uses Google Translation API to translate text. .DESCRIPTION Uses Google Translation API to translate text. .PARAMETER Value The text to translate. .PARAMETER From The language to translate from. .PARAMETER To The language to translate to. .PARAMETER ApiVersion The API version to use. .EXAMPLE PS C:\> $text | New-GoogleTranslation -From $From -To $To Converts the text stored in the $text from one language to another #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string] $Value, [Parameter(Mandatory = $true)] [CultureInfo] $From, [Parameter(Mandatory = $true)] [CultureInfo] $To, [Parameter()] [String] $ApiVersion = '2' ) begin { $googleUri = 'https://translation.googleapis.com/language/translate/v{0}' -f $ApiVersion $key = Get-TranslationApiKey -Provider Google if (-not $key) { Stop-PSFFunction -String 'New-GoogleTranslation.ApiKey.NotFound' return } $header = @{ Authorization = "Bearer $key" } $body = @{ source = $From.TwoLetterISOLanguageName target = $To.TwoLetterISOLanguageName q = New-Object -TypeName 'System.Collections.Generic.List[string]' } Write-PSFMessage -String 'New-GoogleTranslation.Preparing' -StringValues $From.TwoLetterISOLanguageName, $To.TwoLetterISOLanguageName, $($(-join $key[0, 1]) + $('*' * 28) + $(-join $key[-2, -1])), $googleUri } process { Write-PSFMessage -String 'New-GoogleTranslation.AddingInput' -StringValues $Value $body.q.Add($Value) } end { Write-PSFMessage -String 'New-GoogleTranslation.ExecutingBatches' -StringValues $body.q.Count $jsonBody = ConvertTo-Json -InputObject $body (Invoke-RestMethod -Method Post -Uri $googleUri -Headers $header -Body $jsonBody -UseBasicParsing -ContentType 'application/json; charset=utf-8').Content } } function Add-TranslationApiKey { <# .SYNOPSIS Stores API Keys for the APIs used to translate text. .DESCRIPTION Stores API Keys for the APIs used to translate text. .PARAMETER ApiKey The API Key to store. .PARAMETER Provider The provider for which to store the API Key .PARAMETER Force Overwrite existing API Keys .PARAMETER Register Persist the API key, so it will be remembered in future sessions. On Windows, this is written to registry using windows encryption. On Linux this is stored in plaintext in file. .EXAMPLE PS C:\> Add-TranslationApiKey -ApiKey 'c01d33ba-5af9-4528-b6be-61cdb94820c1' -Provider 'azure' Adds an API key to connect to azure with. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $ApiKey, [Parameter(Mandatory = $true)] [PsfValidateSet(TabCompletion = 'PSTranslate.Provider')] [string] $Provider, [switch] $Force, [switch] $Register ) process { switch ($Provider) { 'Azure' { $cred = Get-PSFConfigValue -FullName 'PSTranslate.Azure.ApiKey' if ($cred -and -not $Force) { Write-PSFMessage -Level Warning -String 'Add-TranslationApiKey.ApiKey.Present' -StringValues $Provider return } if (Test-PSFPowerShell -OperatingSystem Windows) { $secureKey = $ApiKey | ConvertTo-SecureString -AsPlainText -Force $cred = New-Object PSCredential($Provider, $secureKey) Set-PSFConfig -Module PSTranslate -Name Azure.ApiKey -Value $cred } else { Set-PSFConfig -Module PSTranslate -Name Azure.ApiKey -Value $ApiKey } if ($Register) { Register-PSFConfig -Module PSTranslate -Name Azure.ApiKey } break } default { Write-PSFMessage -Level Warning -String 'Add-TranslationApiKey.BadProvider' -StringValues $Provider } } } } function Get-Translation { <# .SYNOPSIS Translates text from one language to another. .DESCRIPTION Translates text from one language to another. .PARAMETER Value The text to translate. .PARAMETER From THe language to translate the text from. .PARAMETER To The language to translate the text to. .PARAMETER Provider The translation service to use. .EXAMPLE PS C:\> Get-Content .\essay.md | Get-Translation -From en -To de Translates the content of essay.md from English to German. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [String[]] $Value, [Parameter(Mandatory = $true)] [CultureInfo] $From, [Parameter(Mandatory = $true)] [CultureInfo] $To, [Parameter()] [PsfValidateSet(TabCompletion = 'PSTranslate.Provider')] [string] $Provider = (Get-PSFConfigValue -FullName 'PSTranslate.DefaultProvider') ) begin { $pipeCollection = New-Object -TypeName 'System.Collections.Generic.List[string]' } process { if ($Value.Count -eq 1) { $pipeCollection.Add($Value) } else { $pipeCollection.AddRange($Value) } } end { switch ($Provider) { 'Azure' { $pipeCollection | New-AzureTranslation -From $From -To $To } default { Write-PSFMessage -Level Warning -String 'Get-Translation.BadProvider' -StringValues $Provider } } } } function Get-TranslationApiKey { <# .SYNOPSIS Returns an API key used for translation services. .DESCRIPTION Returns an API key used for translation services. .PARAMETER Provider The provider to return the API key for. .EXAMPLE PS C:\> Get-TranslationApiKey -Provider 'Azure' Returns the API key for connectign to azure translation services. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [PsfValidateSet(TabCompletion = 'PSTranslate.Provider')] [string] $Provider ) process { switch ($Provider) { 'Azure' { $cred = Get-PSFConfigValue -FullName 'PSTranslate.Azure.ApiKey' if ($cred) { if (Test-PSFPowerShell -OperatingSystem Windows) { $cred.GetNetworkCredential().Password } else { $cred } } break } default { Write-PSFMessage -Level Warning -String 'Get-TranslationApiKey.BadProvider' -StringValues $Provider } } } } <# .SYNOPSIS Set provider-specific options. .DESCRIPTION Set provider-specific options to use with Invoke-RestMethod. Know options for Azure would be the regionality of the Cognitive Services that is passed in the header Ocp-Apim-Subscription-Region .PARAMETER Provider The translation service to use. .PARAMETER ExtraHeader The additional headers to add. .PARAMETER ExtraQueryParameter The query parameters to add. .PARAMETER ExtraPostBody The extra body content to add to a post if post is used. .PARAMETER Register Persist the provider options, so they will be remembered in future sessions. .PARAMETER CharacterLimit How many characters per defined Window will be sent to the API .PARAMETER LimitWindow What Window is used? .EXAMPLE Set-TranslationProviderOption -Provider Azure -ExtraHeader @{'Ocp-Apim-Subscription-Region' = 'westeurope'} -Register Adds regional header for Azure Cognitive Services #> function Set-TranslationProviderOption { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")] [CmdletBinding()] param ( [Parameter()] [PsfValidateSet(TabCompletion = 'PSTranslate.Provider')] [string] $Provider = (Get-PSFConfigValue -FullName 'PSTranslate.DefaultProvider'), [hashtable] $ExtraHeader, [hashtable] $ExtraQueryParameter, [hashtable] $ExtraPostBody, [uint64] $CharacterLimit = 33000, # Using Azure defaults... [timespan] $LimitWindow = '00:01:00', [switch] $Register ) $config = Set-PSFConfig -Module PSTranslate -Name "$Provider.Options" -Value @{ ExtraHeader = $ExtraHeader ExtraQueryParameter = $ExtraQueryParameter ExtraPostBody = $ExtraPostBody CharacterLimit = $CharacterLimit LimitWindow = $LimitWindow } -PassThru if (-not $Register.IsPresent) { return } $config | Register-PSFConfig } <# This file loads the strings documents from the respective language folders. This allows localizing messages and errors. Load psd1 language files for each language you wish to support. Partial translations are acceptable - when missing a current language message, it will fallback to English or another available language. #> $root = Get-Item -Path $PSScriptRoot if ($root.BaseName -eq 'scripts') { $root = $root.Parent.Parent} Import-PSFLocalizedString -Path (Join-Path -Path $root.FullName -ChildPath /en-us/*.psd1) -Module 'PSTranslate' -Language 'en-US' Register-PSFTeppScriptblock -Name "PSTranslate.Provider" -ScriptBlock { 'Azure', 'Google' } Register-PSFTeppScriptblock -Name 'PSTranslate.Culture' -ScriptBlock { [cultureinfo]::GetCultures('AllCultures').Name } Register-PSFTeppArgumentCompleter -Command Get-TranslationApiKey -Parameter Provider -Name PSTranslate.Provider Register-PSFTeppArgumentCompleter -Command Add-TranslationApiKey -Parameter Provider -Name PSTranslate.Provider Register-PSFTeppArgumentCompleter -Command Get-Translation -Parameter Provider -Name PSTranslate.Provider Register-PSFTeppArgumentCompleter -Command Get-Translation -Parameter To,From -Name PSTranslate.Culture # General Set-PSFConfig -Module 'PSTranslate' -Name 'DefaultProvider' -Value 'Azure' -Initialize -Validation String -Description 'The default service to contact for translation services.' # Azure Cognitive Services if (Test-PSFPowerShell -OperatingSystem Windows) { Set-PSFConfig -Module 'PSTranslate' -Name 'Azure.ApiKey' -Value $null -Initialize -Validation credential -Description 'The API key used to connect to the Azure Cognitive Translation Services' } else { Set-PSFConfig -Module 'PSTranslate' -Name 'Azure.ApiKey' -Value $null -Initialize -Validation string -Description 'The API key used to connect to the Azure Cognitive Translation Services' } # Google Translation API if (Test-PSFPowerShell -OperatingSystem Windows) { Set-PSFConfig -Module 'PSTranslate' -Name 'Google.ApiKey' -Value $null -Initialize -Validation credential -Description 'The API key used to connect to the Azure Cognitive Translation Services' } else { Set-PSFConfig -Module 'PSTranslate' -Name 'Google.ApiKey' -Value $null -Initialize -Validation string -Description 'The API key used to connect to the Azure Cognitive Translation Services' } |