Question

Probably could be a rare petition, but here is the issue.

I am adapting an excel of a third-party to my organization. The excel is developed in English and the people of my organization just speaks Spanish. I want to use exactly the same code that the original worksheet have, I prefer don't touch it (although I can do it), so I want to use a function that every time that a msgbox appears (with the text in English), I translate the msgbox messages but without touching the original script. I am looking for a mask that could be called every time that a msgbox is invoked in the original code.

I prefer don't touch the original code because the third-party developer could change it frequently, and it could be very annoying to change the code every time that they do any little change.

Is that possible?

Was it helpful?

Solution

Here you go.

Sub test()
    Dim s As String
    s = "hello world"
    MsgBox translate_using_vba(s)

End Sub

Function translate_using_vba(str) As String
' Tools Refrence Select Microsoft internet Control


    Dim IE As Object, i As Long
    Dim inputstring As String, outputstring As String, text_to_convert As String, result_data As String, CLEAN_DATA

    Set IE = CreateObject("InternetExplorer.application")
    '   TO CHOOSE INPUT LANGUAGE

    inputstring = "auto"

    '   TO CHOOSE OUTPUT LANGUAGE

    outputstring = "es"

    text_to_convert = str

    'open website

    IE.Visible = False
    IE.navigate "http://translate.google.com/#" & inputstring & "/" & outputstring & "/" & text_to_convert

    Do Until IE.ReadyState = 4
        DoEvents
    Loop

    Application.Wait (Now + TimeValue("0:00:5"))

    Do Until IE.ReadyState = 4
        DoEvents
    Loop

    CLEAN_DATA = Split(Application.WorksheetFunction.Substitute(IE.Document.getElementById("result_box").innerHTML, "</SPAN>", ""), "<")

    For j = LBound(CLEAN_DATA) To UBound(CLEAN_DATA)
        result_data = result_data & Right(CLEAN_DATA(j), Len(CLEAN_DATA(j)) - InStr(CLEAN_DATA(j), ">"))
    Next


    IE.Quit
    transalte_using_vba = result_data


End Function

OTHER TIPS

This is how I would do it. It's function with optional enumeration objects that point to language codes used by google translate. For simplicity I only included a few language codes. Also, in this sample I selected the Microsoft Internet Controls reference so instead of creating an object, there's an InternetExplorer object used. And finally, to get rid of having to clean up the output, I just used .innerText rather than .innerHTML. Keep in mind, there's a character limit of around 3000 or so with google translate, and also, you must set IE=nothing especially if you will be using this multiple times, otherwise you will create multiple IE processes and eventually it won't work anymore.

Setup...

Option Explicit

Const langCode = ("auto,en,fr,es")

Public Enum LanguageCode
    InputAuto = 0
    InputEnglish = 1
    InputFrench = 2
    InputSpanish = 3
End Enum

Public Enum LanguageCode2
    ReturnEnglish = 1
    ReturnFrench = 2
    ReturnSpanish = 3
End Enum

Test...

Sub Test()

Dim msg As String

msg = "Hello World!"

MsgBox AutoTranslate(msg, InputEnglish, ReturnSpanish)

End Sub

Function...

Public Function AutoTranslate(ByVal Text As String, Optional LanguageFrom As LanguageCode, Optional LanguageTo As LanguageCode2) As String

Dim langFrom As String, langTo As String, IE As InternetExplorer, URL As String, myArray

If IsMissing(LanguageFrom) Then
    LanguageFrom = InputAuto
End If
If IsMissing(LanguageTo) Then
    LanguageTo = ReturnEnglish
End If

myArray = Split(langCode, ",")
langFrom = myArray(LanguageFrom)
langTo = myArray(LanguageTo)

URL = "https://translate.google.com/#" & langFrom & "/" & langTo & "/" & Text

Set IE = New InternetExplorer

IE.Visible = False
IE.Navigate URL

    Do Until IE.ReadyState = 4
        DoEvents
    Loop

    Application.Wait (Now + TimeValue("0:00:5"))

    Do Until IE.ReadyState = 4
        DoEvents
    Loop

    AutoTranslate = IE.Document.getElementByID("result_box").innerText

    IE.Quit

    Set IE = Nothing


End Function

Here is a more streamlined way to use Excel VBA and Google... to translate text.

This VBA User Defined Function should be entered into a standard code module.

Function Translate$(sText$, FromLang$, ToLang$)
    Dim p1&, p2&, url$, resp$
    Const DIV_RESULT$ = "<div class=""result-container"">"
    Const URL_TEMPLATE$ = "https://translate.google.com/m?hl=[from]&sl=[from]&tl=[to]&ie=UTF-8&prev=_m&q="
    url = URL_TEMPLATE & WorksheetFunction.EncodeURL(sText)
    url = Replace(url, "[to]", ToLang)
    url = Replace(url, "[from]", FromLang)
    resp = WorksheetFunction.WebService(url)
    p1 = InStr(resp, DIV_RESULT)
    If p1 Then
        p1 = p1 + Len(DIV_RESULT)
        p2 = InStr(p1, resp, "</div>")
        Translate = Mid$(resp, p1, p2 - p1)
    End If
End Function

With the following text in cell A1: Every moment is a fresh beginning.

In cell B1 enter this formula:

=Translate(A1, "en", "fr")    '<--translates text in A1 from English to French.

The result in cell B1: Chaque instant est un nouveau départ.

Of course this Translate() function can be used directly from VBA as well:

MsgBox Translate([A1], "en", "de")  '<--displays: Jeder Moment ist ein Neuanfang.

Of course you may also manually use the Translate functionality built into Excel, which can be found on the Review tab of the Ribbon. But the UDF above provides a quick and streamlined method to translate text programmatically. Excel's translation capability is not exposed via the Excel Object Model, so a function like the above can be quite useful.

The FromLang and ToLang arguments must be codes from the following table:

 CODE   LANGUAGE
 en     English
 fr     French
 es     Spanish
 it     Italian
 de     German
 af     Afrikaans
 sq     Albanian
 am     Amharic
 ar     Arabic
 hy     Armenian
 az     Azerbaijani
 eu     Basque
 be     Belarusian
 bn     Bengali
 bs     Bosnian
 bg     Bulgarian
 ca     Catalan
 ceb    Cebuano
 ny     Chichewa
 zh-CN  Chinese (Simplified)
 zh-TW  Chinese (Traditional)
 co     Corsican
 hr     Croatian
 cs     Czech
 da     Danish
 nl     Dutch
 eo     Esperanto
 et     Estonian
 tl     Filipino
 fi     Finnish
 fy     Frisian
 gl     Galician
 ka     Georgian
 el     Greek
 gu     Gujarati
 ht     Haitian Creole
 ha     Hausa
 haw    Hawaiian
 iw     Hebrew
 hi     Hindi
 hmn    Hmong
 hu     Hungarian
 is     Icelandic
 ig     Igbo
 id     Indonesian
 ga     Irish
 ja     Japanese
 jw     Javanese
 kn     Kannada
 kk     Kazakh
 km     Khmer
 rw     Kinyarwanda
 ko     Korean
 ku     Kurdish (Kurmanji)
 ky     Kyrgyz
 lo     Lao
 la     Latin
 lv     Latvian
 lt     Lithuanian
 lb     Luxembourgish
 mk     Macedonian
 mg     Malagasy
 ms     Malay
 ml     Malayalam
 mt     Maltese
 mi     Maori
 mr     Marathi
 mn     Mongolian
 my     Myanmar (Burmese)
 ne     Nepali
 no     Norwegian
 or     Odia (Oriya)
 ps     Pashto
 fa     Persian
 pl     Polish
 pt     Portuguese
 pa     Punjabi
 ro     Romanian
 ru     Russian
 sm     Samoan
 gd     Scots Gaelic
 sr     Serbian
 st     Sesotho
 sn     Shona
 sd     Sindhi
 si     Sinhala
 sk     Slovak
 sl     Slovenian
 so     Somali
 su     Sundanese
 sw     Swahili
 sv     Swedish
 tg     Tajik
 ta     Tamil
 tt     Tatar
 te     Telugu
 th     Thai
 tr     Turkish
 tk     Turkmen
 uk     Ukrainian
 ur     Urdu
 ug     Uyghur
 uz     Uzbek
 vi     Vietnamese
 cy     Welsh
 xh     Xhosa
 yi     Yiddish
 yo     Yoruba
 zu     Zulu

One of the modern solution using Google Translation API To Enable Google Translation API, first you should create the project and credentials. If you receive 403 (Daily Limit), you need to add payment method into your Google Cloud Account, then you will get results instantly.

Private Function GoogleTranslateJ(ByVal text, ByVal resLang, ByVal srcLang) As String
Dim jsonProvider As Object

Dim jsonResult As Object
Dim jsonResultText As String

Dim googleApiUrl As String
Dim googleApiKey As String

Dim resultText As String

Set jsonProvider = CreateObject("MSXML2.ServerXMLHTTP")

text = Replace(text, " ", "%20")
googleApiKey = "ijHF28h283fjijefiwjeofij90f2h923" 'YOUR GOOGLE API KEY

googleApiUrl = "https://translation.googleapis.com/language/translate/v2?key=" & googleApiKey & "&source=" & srcLang & "&target=" & resLang & "&q=" & text

jsonProvider.Open "POST", googleApiUrl, False
jsonProvider.setRequestHeader "Content-type", "application/text"
jsonProvider.send ("")
jsonResultText = jsonProvider.responseText

Set jsonResult = JsonConverter.ParseJson(jsonResultText)
Set jsonResult = jsonResult("data")
Set jsonResult = jsonResult("translations")
Set jsonResult = jsonResult(1)

resultText = jsonResult("translatedText")

GoogleTranslateJ = resultText
End Function

Update: Improved For Each v In arr_Response-iteration, allowing special charactors. Added mouse-cursor change, when translation is processing. Added an example on how to improve the translated output_string.

There are a majority of free translation API's outthere, but none really seems to beat Googles Translation Service, GTS (in my opinion). As a result of Googles' restrictions on the free GTS-usage, the best VBA-approach seems to be narrowed down to the IE.navigation - as Santosh's answer also emphasizes.

Using this approach, causes some problematics. The IE-instans doesn't know when the page is fully loaded, and IE.ReadyState is really not trusthworthy. Therefore the coder has to add "delays" using the Application.Wait function. When using this function, you are just guessing how long it would take, before the page is fully loaded. In situations where the internet is really slow, this hardcoded time, might not be enough. The following code fixes this, with the ImprovedReadyState.

In situations where a sheet has different columns, and you want to add different translation into every cell, I find the best approach where the translation-string is assigned to the ClipBoard, rather then calling a VBA-Function from within the formula. Thereby you can easily paste the translation, and modify it as a string.

Columns in Excel

How to use:

  1. Insert the procedures into a custom VBA-Module
  2. Change the 4 Const's to your desire (see upper TranslationText)
  3. Assign a shortkey to fire the TranslationText-procedure

Shortkey Excel

  1. Activate the cell you want to translate. Required the first row to end with a language-tag. Etc. "_da", "_en", "_de". If you want another functionality, you change ws_ActiveWS.Cells(r_ActiveCell.Row, r_InputRange.Column)

enter image description here

  1. Press the shortkey from 4. (etc. CTRL + SHIRT + S). See proces in your processbar (bottom of excel). Paste (CTRL+V) when translation done is displayed:

enter image description here Translation done

    Option Explicit

    'Description: Translates content, and put the translation into ClipBoard
    'Required References: MIS (Microsoft Internet Control)
    Sub TranslateText()

    'Change Const's to your desire
    Const INPUT_RANGE As String = "table_products[productname_da]"
    Const INPUT_LANG As String = "da"
    Const PROCESSBAR_INIT_TEXT As String = "Processing translation. Please wait... "
    Const PROCESSBAR_DONE_TEXT As String = "Translation done. "

    Dim ws_ActiveWS As Worksheet
    Dim r_ActiveCell As Range, r_InputRange As Range
    Dim s_InputStr As String, s_InputLang As String, s_OutputLang As String, arr_Response() As String, s_Translation As String
    Dim o_IE As Object, o_MSForms_DataObject As Object
    Dim i As Long
    Dim v As Variant

    Set o_MSForms_DataObject = CreateObject("new:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
    Set ws_ActiveWS = ThisWorkbook.ActiveSheet
    Set r_ActiveCell = ActiveCell
    Set o_IE = CreateObject("InternetExplorer.Application")
    Set r_InputRange = ws_ActiveWS.Range(INPUT_RANGE)

    'Update statusbar ("Processing translation"), and change cursor
    Application.Statusbar = PROCESSBAR_INIT_TEXT
    Application.Cursor = xlWait

    'Declare inputstring (The string you want to translate from)
    s_InputStr = ws_ActiveWS.Cells(r_ActiveCell.Row, r_InputRange.Column)

    'Find the output-language
    s_OutputLang = Right(ws_ActiveWS.Cells(1, r_ActiveCell.Column).Value, 2)

    'Navigate to translate.google.com
    With o_IE

        .Visible = False 'Run IE in background
        .Navigate "http://translate.google.com/#" & INPUT_LANG & "/" _
            & s_OutputLang & "/" & s_InputStr

        'Call improved IE.ReadyState
        Do
            ImprovedReadyState
        Loop Until Not .Busy

        'Split the responseText from Google
        arr_Response = Split(.Document.getElementById("result_box").innerHTML, "<span class")

        'Remove html from response, and construct full-translation-string
        For Each v In arr_Response
            s_Translation = s_Translation & Replace(v, "<span>", "")
            s_Translation = Replace(s_Translation, "</span>", "")
            s_Translation = Replace(s_Translation, """", "")
            s_Translation = Replace(s_Translation, "=hps>", "")
            s_Translation = Replace(s_Translation, "=atn>", "")
            s_Translation = Replace(s_Translation, "=hps atn>", "")

            'Improve translation.
            'This could etc. be moved to seperate sheets (containing every language), and make the lookup in a dynamic table/sheet. Futurely it'd be possible to hook on the changeevent, and automatically improve the translation-algoritmen.
            'If Google can't translate the etc. the word "Lys", you can extend the translation, with an auto correction. This example shows to autocorrect the word "Lys" -> "ljus". 
            If (s_OutputLang = "sv") Then
                s_Translation = Replace(s_Translation, "lys", "ljus")
            End if
        Next v

        'Put Translation into Clipboard
        o_MSForms_DataObject.SetText s_Translation
        o_MSForms_DataObject.PutInClipboard

        If (s_Translation <> vbNullString) Then
            'Put Translation into Clipboard
            o_MSForms_DataObject.SetText s_Translation
            o_MSForms_DataObject.PutInClipboard

            'Update statusbar ("Translation done"). If the input_string is above 70 chars (which is roughly the limitation in processbar), then cut the string, and extend with "...".
            Application.Statusbar = PROCESSBAR_DONE_TEXT & """" & IIf(Len(s_InputStr) < 70, s_InputStr, Mid(s_InputStr, 1, 70) & "...") & """"
        Else
            'Update statusbar ("Error")
            Application.Statusbar = PROCESSBAR_ERROR_TEXT
        End If

        'Cleanup
        .Quit

        'Change cursor back to default
        Application.Cursor = xlDefault

        Set o_MSForms_DataObject = Nothing
        Set ws_ActiveWS = Nothing
        Set r_ActiveCell = Nothing
        Set o_IE = Nothing

    End With

End Sub

Sub ImprovedReadyState()

    Dim si_PauseTime As Single: si_PauseTime = 1 'Set duration
    Dim si_Start As Single: si_Start = Timer 'Set start-time
    Dim si_Finish As Single 'Set end-time
    Dim si_TotalTime As Single 'Calculate total time.

    Do While Timer < (si_Start + si_PauseTime)
        DoEvents
    Loop

    si_Finish = Timer

    si_TotalTime = (si_Finish - si_Start)

End Sub

The answer posted by Unicco is great!

I removed the table stuff and made it work off a single cell, but the result is the same.

With some of the text I translate (operation instructions in a manufacturing context) Google occasionally adds crap to the return string, sometimes even doubling the response, using additional <"span"> constructs.

I added the following line to the code right after 'Next v':

s_Translation = RemoveSpan(s_Translation & "")

And created this function (add to the same module):

Private Function RemoveSpan(Optional InputString As String = "") As String

Dim sVal As String
Dim iStart As Integer
Dim iEnd As Integer
Dim iC As Integer
Dim iL As Integer

If InputString = "" Then
    RemoveSpan = ""
    Exit Function
End If

sVal = InputString

' Look for a "<span"
iStart = InStr(1, sVal, "<span")

Do While iStart > 0 ' there is a "<span"
    iL = Len(sVal)
    For iC = iStart + 5 To iL
        If Mid(sVal, iC, 1) = ">" Then Exit For ' look for the first ">" following the "<span"
    Next
    If iC < iL Then ' then we found a "<"
        If iStart > 1 Then ' the "<span" was not in the beginning of the string
            sVal = Left(sVal, iStart - 1) & Right(sVal, iL - iC) ' grab to the left of the "<span" and to the right of the ">"
        Else ' the "<span" was at the beginning
            sVal = Right(sVal, iL - iC) ' grap to the right of the ">"
        End If
    End If
    iStart = InStr(1, sVal, "<span") ' look for another "<span"
Loop
    RemoveSpan = sVal
End Function

In retrospect, I realize I could have done this more efficiently, but, it works and I am moving on!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top