If you are fortunate enough to be bilingual, you’ll quickly understand the shortcomings of Android OS (others too) when it comes to speech. True, the options for most popular languages are there, however Android does very little to help to switch from one another like it does for the keyboard input. This is surprising considering the entire Google Translate API is available to us, mortals. I decided to take the advantage of that and improve one of my car profiles WhatsApp Voice Notifications. In that tutorial, I’d assign the spoken language to the contact name. Google’s text to speech system (TTS) would set the language based on the nationality of my contact. It worked well enough until some of my friends would send me lines in other than assigned, languages.
Thanks to the Google Translate API I can not only change the language of the text-to-speak engine on the fly but also incorporate on-the-fly translations. The best thing about it is that the delay isn’t significant. The whole system works great and I can enjoy the spoken notifications in my car yet again.
Google Translate API & WhatsApp Voice Notifications
To determine the language and translate the text, you are going to need the API key for the Google Translate service. Log in to the Google Console, enable Google Translate API and generate an API key. You are going to need this to authenticate the HTTP calls.
The basic use of Google Translate API is free, but do check the usage data, as excessive calls can lead to a bill issued to you by Google.
WhatsApp Voice Notifications Types
I’m going to show you how to achieve this on WhatsApp, but the same can be applied to other messengers that store the text of the message in the Android notification. The Tasker profile will have 2 modes.
Capture the language of the message and set a correct TTS
Translate the message to your preferred language
In the next write up, I will also show you, how to achieve this with Google Home.
Querying language with Tasker
TASKER TASK: WhatsApp Get Language
A1: HTTP Post [ Server:Port:https://translation.googleapis.com/language/translate/v2/detect?key=%TranslateAPI
Path: Data / File:
q=%par1
Cookies: User Agent: Timeout:10
Content Type:application/x-www-form-urlencoded
Output File:Download/lang.txt
Trust Any Certificate:On ]
A2: AutoTools Json Read [ Configuration:Input Format: Json
Simple Mode: true
Json: /storage/emulated/0/Download/lang.txt
Fields: language
Separator: , Timeout (Seconds):60 ]
A3: Return [ Value:%language Stop:On ]
To get the language info, we have to submit the test sample using Google Translate API and HTTP Post request. The URL has to be authorised with your API key, and contain the JSON object with the message sample.
The message sample is submitted under the “q” key and to do this in Tasker simply add:
q=enter_text_to_sample
in your data field. Once the request is submitted, you will receive a JSON (want to know more about JSON in Tasker – tutorial here)formatted object which looks like this:
Of course, we are interested in the language detection and the code that comes with it. You can look up all the ISO language codes here:
ISO Language codes
Language
ISO-639-1 Code
Afrikaans
af
Albanian
sq
Amharic
am
Arabic
ar
Armenian
hy
Azeerbaijani
az
Basque
eu
Belarusian
be
Bengali
bn
Bosnian
bs
Bulgarian
bg
Catalan
ca
Cebuano
ceb
Chinese (Simplified)
zh-CN
Chinese (Traditional)
zh-TW
Corsican
co
Croatian
hr
Czech
cs
Danish
da
Dutch
nl
English
en
Esperanto
eo
Estonian
et
Finnish
fi
French
fr
Frisian
fy
Galician
gl
Georgian
ka
German
de
Greek
el
Gujarati
gu
Haitian Creole
ht
Hausa
ha
Hawaiian
haw
Hebrew
iw
Hindi
hi
Hmong
hmn
Hungarian
hu
Icelandic
is
Igbo
ig
Indonesian
id
Irish
ga
Italian
it
Japanese
ja
Javanese
jw
Kannada
kn
Kazakh
kk
Khmer
km
Korean
ko
Kurdish
ku
Kyrgyz
ky
Lao
lo
Latin
la
Latvian
lv
Lithuanian
lt
Luxembourgish
lb
Macedonian
mk
Malagasy
mg
Malay
ms
Malayalam
ml
Maltese
mt
Maori
mi
Marathi
mr
Mongolian
mn
Myanmar (Burmese)
my
Nepali
ne
Norwegian
no
Nyanja (Chichewa)
ny
Pashto
ps
Persian
fa
Polish
pl
Portuguese (Portugal, Brazil)
pt
Punjabi
pa
Romanian
ro
Russian
ru
Samoan
sm
Scots Gaelic
gd
Serbian
sr
Sesotho
st
Shona
sn
Sindhi
sd
Sinhala (Sinhalese)
si
Slovak
sk
Slovenian
sl
Somali
so
Spanish
es
Sundanese
su
Swahili
sw
Swedish
sv
Tagalog (Filipino)
tl
Tajik
tg
Tamil
ta
Telugu
te
Thai
th
Turkish
tr
Ukrainian
uk
Urdu
ur
Uzbek
uz
Vietnamese
vi
Welsh
cy
Xhosa
xh
Yiddish
yi
Yoruba
yo
Zulu
zu
To make our life complicated, the TTS engine codes for individual languages do not correspond with the ISO standard (why? dialects and localisations) so each TTS setting will have to come with defined IF condition. It’s ok, I’d rather do this that way as realistically speaking, you will only need 2-5 languages at best. If you want to create a full conversion table in Tasker, be my guest!
TTS Language codes
Language
languageCode
Language (English name)
Afrikaans (Suid-Afrika)
af-ZA
Afrikaans (South Africa)
አማርኛ (ኢትዮጵያ)
am-ET
Amharic (Ethiopia)
Հայ (Հայաստան)
hy-AM
Armenian (Armenia)
Azərbaycan (Azərbaycan)
az-AZ
Azerbaijani (Azerbaijan)
Bahasa Indonesia (Indonesia)
id-ID
Indonesian (Indonesia)
Bahasa Melayu (Malaysia)
ms-MY
Malay (Malaysia)
বাংলা (বাংলাদেশ)
bn-BD
Bengali (Bangladesh)
বাংলা (ভারত)
bn-IN
Bengali (India)
Català (Espanya)
ca-ES
Catalan (Spain)
Čeština (Česká republika)
cs-CZ
Czech (Czech Republic)
Dansk (Danmark)
da-DK
Danish (Denmark)
Deutsch (Deutschland)
de-DE
German (Germany)
English (Australia)
en-AU
English (Australia)
English (Canada)
en-CA
English (Canada)
English (Ghana)
en-GH
English (Ghana)
English (Great Britain)
en-GB
English (United Kingdom)
English (India)
en-IN
English (India)
English (Ireland)
en-IE
English (Ireland)
English (Kenya)
en-KE
English (Kenya)
English (New Zealand)
en-NZ
English (New Zealand)
English (Nigeria)
en-NG
English (Nigeria)
English (Philippines)
en-PH
English (Philippines)
English (South Africa)
en-ZA
English (South Africa)
English (Tanzania)
en-TZ
English (Tanzania)
English (United States)
en-US
English (United States)
Español (Argentina)
es-AR
Spanish (Argentina)
Español (Bolivia)
es-BO
Spanish (Bolivia)
Español (Chile)
es-CL
Spanish (Chile)
Español (Colombia)
es-CO
Spanish (Colombia)
Español (Costa Rica)
es-CR
Spanish (Costa Rica)
Español (Ecuador)
es-EC
Spanish (Ecuador)
Español (El Salvador)
es-SV
Spanish (El Salvador)
Español (España)
es-ES
Spanish (Spain)
Español (Estados Unidos)
es-US
Spanish (United States)
Español (Guatemala)
es-GT
Spanish (Guatemala)
Español (Honduras)
es-HN
Spanish (Honduras)
Español (México)
es-MX
Spanish (Mexico)
Español (Nicaragua)
es-NI
Spanish (Nicaragua)
Español (Panamá)
es-PA
Spanish (Panama)
Español (Paraguay)
es-PY
Spanish (Paraguay)
Español (Perú)
es-PE
Spanish (Peru)
Español (Puerto Rico)
es-PR
Spanish (Puerto Rico)
Español (República Dominicana)
es-DO
Spanish (Dominican Republic)
Español (Uruguay)
es-UY
Spanish (Uruguay)
Español (Venezuela)
es-VE
Spanish (Venezuela)
Euskara (Espainia)
eu-ES
Basque (Spain)
Filipino (Pilipinas)
fil-PH
Filipino (Philippines)
Français (Canada)
fr-CA
French (Canada)
Français (France)
fr-FR
French (France)
Galego (España)
gl-ES
Galician (Spain)
ქართული (საქართველო)
ka-GE
Georgian (Georgia)
ગુજરાતી (ભારત)
gu-IN
Gujarati (India)
Hrvatski (Hrvatska)
hr-HR
Croatian (Croatia)
IsiZulu (Ningizimu Afrika)
zu-ZA
Zulu (South Africa)
Íslenska (Ísland)
is-IS
Icelandic (Iceland)
Italiano (Italia)
it-IT
Italian (Italy)
Jawa (Indonesia)
jv-ID
Javanese (Indonesia)
ಕನ್ನಡ (ಭಾರತ)
kn-IN
Kannada (India)
ភាសាខ្មែរ (កម្ពុជា)
km-KH
Khmer (Cambodia)
ລາວ (ລາວ)
lo-LA
Lao (Laos)
Latviešu (latviešu)
lv-LV
Latvian (Latvia)
Lietuvių (Lietuva)
lt-LT
Lithuanian (Lithuania)
Magyar (Magyarország)
hu-HU
Hungarian (Hungary)
മലയാളം (ഇന്ത്യ)
ml-IN
Malayalam (India)
मराठी (भारत)
mr-IN
Marathi (India)
Nederlands (Nederland)
nl-NL
Dutch (Netherlands)
नेपाली (नेपाल)
ne-NP
Nepali (Nepal)
Norsk bokmål (Norge)
nb-NO
Norwegian Bokmål (Norway)
Polski (Polska)
pl-PL
Polish (Poland)
Português (Brasil)
pt-BR
Portuguese (Brazil)
Português (Portugal)
pt-PT
Portuguese (Portugal)
Română (România)
ro-RO
Romanian (Romania)
සිංහල (ශ්රී ලංකාව)
si-LK
Sinhala (Sri Lanka)
Slovenčina (Slovensko)
sk-SK
Slovak (Slovakia)
Slovenščina (Slovenija)
sl-SI
Slovenian (Slovenia)
Urang (Indonesia)
su-ID
Sundanese (Indonesia)
Swahili (Tanzania)
sw-TZ
Swahili (Tanzania)
Swahili (Kenya)
sw-KE
Swahili (Kenya)
Suomi (Suomi)
fi-FI
Finnish (Finland)
Svenska (Sverige)
sv-SE
Swedish (Sweden)
தமிழ் (இந்தியா)
ta-IN
Tamil (India)
தமிழ் (சிங்கப்பூர்)
ta-SG
Tamil (Singapore)
தமிழ் (இலங்கை)
ta-LK
Tamil (Sri Lanka)
தமிழ் (மலேசியா)
ta-MY
Tamil (Malaysia)
తెలుగు (భారతదేశం)
te-IN
Telugu (India)
Tiếng Việt (Việt Nam)
vi-VN
Vietnamese (Vietnam)
Türkçe (Türkiye)
tr-TR
Turkish (Turkey)
اردو (پاکستان)
ur-PK
Urdu (Pakistan)
اردو (بھارت)
ur-IN
Urdu (India)
Ελληνικά (Ελλάδα)
el-GR
Greek (Greece)
Български (България)
bg-BG
Bulgarian (Bulgaria)
Русский (Россия)
ru-RU
Russian (Russia)
Српски (Србија)
sr-RS
Serbian (Serbia)
Українська (Україна)
uk-UA
Ukrainian (Ukraine)
עברית (ישראל)
he-IL
Hebrew (Israel)
العربية (إسرائيل)
ar-IL
Arabic (Israel)
العربية (الأردن)
ar-JO
Arabic (Jordan)
العربية (الإمارات)
ar-AE
Arabic (United Arab Emirates)
العربية (البحرين)
ar-BH
Arabic (Bahrain)
العربية (الجزائر)
ar-DZ
Arabic (Algeria)
العربية (السعودية)
ar-SA
Arabic (Saudi Arabia)
العربية (العراق)
ar-IQ
Arabic (Iraq)
العربية (الكويت)
ar-KW
Arabic (Kuwait)
العربية (المغرب)
ar-MA
Arabic (Morocco)
العربية (تونس)
ar-TN
Arabic (Tunisia)
العربية (عُمان)
ar-OM
Arabic (Oman)
العربية (فلسطين)
ar-PS
Arabic (State of Palestine)
العربية (قطر)
ar-QA
Arabic (Qatar)
العربية (لبنان)
ar-LB
Arabic (Lebanon)
العربية (مصر)
ar-EG
Arabic (Egypt)
فارسی (ایران)
fa-IR
Persian (Iran)
हिन्दी (भारत)
hi-IN
Hindi (India)
ไทย (ประเทศไทย)
th-TH
Thai (Thailand)
한국어 (대한민국)
ko-KR
Korean (South Korea)
國語 (台灣)
cmn-Hant-TW
Chinese, Mandarin (Traditional, Taiwan)
廣東話 (香港)
yue-Hant-HK
Chinese, Cantonese (Traditional, Hong Kong)
日本語(日本)
ja-JP
Japanese (Japan)
普通話 (香港)
cmn-Hans-HK
Chinese, Mandarin (Simplified, Hong Kong)
普通话 (中国大陆)
cmn-Hans-CN
Chinese, Mandarin (Simplified, China)
Since response comes as a JSON, I’m going to use AutoTools JSON Read action to extract the value and identify the language. At this stage, all I need is to set the variable %language, which will determine the TTS engine later on using IF statements. The correct Say Tasker action is selected, and the sample text is spoken with the properly picked TTS engine.
Translating a message with Tasker
TASKER TASK: WhatsApp Translate
A1: HTTP Post [ Server:Port:https://translation.googleapis.com/language/translate/v2/?key=%TranslateAPI
Path: Data / File:
q=%par1
target=en
Cookies: User Agent: Timeout:10
Content Type:application/x-www-form-urlencoded
Output File:Download/translated.txt
Trust Any Certificate:On ]
A2: [X] HTTP Post [ Server:Port:https://translation.googleapis.com/language/translate/v2/?key=%TranslateAPI
Path: Data / File:
q=%par1
target=zh-CN
Cookies: User Agent: Timeout:10
Content Type:application/x-www-form-urlencoded
Output File:Download/translated.txt
Trust Any Certificate:On ]
A3: [X] HTTP Post [ Server:Port:https://translation.googleapis.com/language/translate/v2/?key=%TranslateAPI
Path: Data / File:
q=%par1
target=pl
Cookies: User Agent: Timeout:10
Content Type:application/x-www-form-urlencoded
Output File:Download/translated.txt
Trust Any Certificate:On ]
A4: AutoTools Json Read [ Configuration:Input Format: Json
Simple Mode: true
Json: /storage/emulated/0/Download/translated.txt
Fields: translatedText
Separator: , Timeout (Seconds):60 ]
A5: Return [ Value:%translatedtext Stop:On ]
The second option assumes that we are going to translate every message to a default language. For the sake of this tutorial I will use English, but feel free to pick your own native language instead.
To submit the data to Google Translate API, once again, I’m going to send an HTTP Post to the authenticated URL:
This time the data has to contain the sample text and the language we are going to translate the text to.
q=your_sample_message
target=language (ISO language code)
The return message is a JSON response which looks like this:
{
"data":{
"translations":[
{
"translatedText":"This is just a test",
"detectedSourceLanguage":"pl"
}
]
}
}
In the same manner, AutoTools JON Read action will extract the value translatedtext and set it in %translatedtext for a later use.
International WhatsApp Voice Notifications
TASKER PROFILE: WhatsApp Translations
Profile: WhatsApp Translations
Event: AutoNotification Intercept [ Configuration:Event Behaviour: true
Notification Type: Only Created Notifications
Has Reply Action: true
Notification Apps: WhatsApp
Notification App: WhatsApp
Package Name: com.whatsapp ]
Enter: WhatsApp Spoken International
A1: If [ %WhatsAppMode eq 0 ]
A2: Perform Task [ Name:WhatsApp Get Language
Priority:%priority
Parameter 1 (%par1):%antext
Parameter 2 (%par2):
Return Value Variable:%sayit Stop:Off ]
A3: Say [ Text:%antext Engine:Voice:default:default
Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off
Continue Task Immediately:Off ]
If [ %sayit ~ en ]
A4: Say [ Text:%antext Engine:Voice:com.google.android.tts:pol-pol
Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off
Continue Task Immediately:Off ]
If [ %sayit ~ pl ]
A5: Say [ Text:%antext Engine:Voice:com.google.android.tts:zho-chn
Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off
Continue Task Immediately:Off ]
If [ %sayit ~ zh-CN ]
A6: End If
A7: If [ %WhatsAppMode eq 1 ]
A8: Perform Task [ Name:WhatsApp Translate
Priority:%priority
Parameter 1 (%par1):%antext
Parameter 2 (%par2):
Return Value Variable:%sayit Stop:Off ]
A9: Say [ Text:%sayit Engine:Voice:com.google.android.tts:eng-gbr
Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off
Continue Task Immediately:Off ]
A10: [X] Say [ Text:%sayit Engine:Voice:com.google.android.tts:pol-pol
Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off
Continue Task Immediately:Off ]
A11: [X] Say [ Text:%sayit Engine:Voice:com.google.android.tts:zho-chn
Stream:3 Pitch:5 Speed:5 Respect Audio Focus:On Network:Off
Continue Task Immediately:Off ]
A12: End If
We have the full know-how to create the on-the-fly adjustments. The profile is very simple actually. I’m going to capture WhatsApp notifications using AutoNotification (intercept Whatsapp notifications with a “reply”), and then use Say action after the language or translation has been determined.
To get the language or translation, I will use the Perform Task action and send the %antext as %par1. The language detection task will return the %language code and the translate task will return the %translatedtext to the main task.
The returned value will be passed over to the Say action with a specified TTS either by the IF condition (%sayit) or predefined language setting for your translations.
TASKER TASK: WhatsApp Mode
A1: Profile Status [ Name:WhatsApp Translations Set:On ]
A2: Variable Add [ Name:%WhatsAppMode Value:1 Wrap Around:2 ]
A3: Flash [ Text:Native language mode enabled Long:On ]
If [ %WhatsAppMode eq 0 ]
A4: Flash [ Text:Translating to another language Long:On ]
If [ %WhatsAppMode eq 1 ]
If you want to hardcode your option into the task (and you don’t need another one) – feel free to do so. I’m going to wrap both actions in an additional IF condition which will determine what behaviour I want from my profile. A variable %WhatsAppMode becomes 1 or 0 thanks to the Variable Add action with a wrap around 2.
A toggle will set a global variable and flash the confirmation of the selected behaviour. And with that done, you can decide for yourself how you want to enable it. You can trigger the profile from a home shortcut, voice command or the notification bar tiles.
Conclusion
This is a much-improved version of my previous voice notification profile. WhatsApp Voice Notifications are not perfect, as foreign words in a single message won’t get the same treatment, but as long as your contact sticks to a single language per sentence – everything should be fine. The translated data can be also used in custom notifications which would have the translated messages. This is something I’m not going to cover in this tutorial. Be aware I have not included any exceptions for URL handling. If your friend sends you a link, this profile will read it out!
Lastly, I will be looking into adding this to my Google Home Notifications too. This way messages received to your phone can be passed over, translated and spoken by the smart speaker.
Project Download
Download project files here. Bear in mind that Patreon supporters have early access to project files and videos.
While you could wake up your PC from a mobile directly, having a dedicated server capable of doing so is the best solution. The reason is simple. You can hook up as many devices as you wish with a single endpoint. This is why Raspberry Pi is perfect for this.
This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.
Strictly Necessary Cookies
Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.
If you disable this cookie, we will not be able to save your preferences. This means that every time you visit this website you will need to enable or disable cookies again.