#!/usr/bin/env bash

read -r -d '' TRANS_PROGRAM << 'EOF'
# This is free and unencumbered software released into the
# public domain.
#
# This software is provided for the purpose of personal, reasonable
# and convenient human use of the Google Translate Service, i.e.,
# only for those who feel that their terminal is more accessible
# than a web browser. For other purposes, please use the official
# Google Translate API <https://developers.google.com/translate/>.
#
# By using this software, you ("the user") agree that:
#
# 1. Neither this software nor its author is affiliated with
# Google Inc. ("Google").
#
# 2. By using this software, the user is de facto using web
# services provided by Google, therefore they are obliged to
# follow the Google Terms of Service.
#
# 3. This software is provided "as is". The user of this software
# shall be fully liable for any possible infringement of, including
# but not limited to, the Google Terms of Service; per contra,
# the user must be aware that their data might be collected by
# Google, therefore they shall be liable for their own privacy
# concern, including but not limited to, possible disclosure of
# personal information. See the (un)LICENSE file for more details.
BEGIN {
Name        = "Translate Shell"
Description = "Google Translate to serve as a command-line tool"
Version     = "0.8.21"
Command     = "trans"
EntryPoint  = "translate.awk"
}
function initUrlEncoding() {
UrlEncoding["\n"] = "%0A"
UrlEncoding[" "]  = "%20"
UrlEncoding["!"]  = "%21"
UrlEncoding["\""] = "%22"
UrlEncoding["#"]  = "%23"
UrlEncoding["$"]  = "%24"
UrlEncoding["%"]  = "%25"
UrlEncoding["&"]  = "%26"
UrlEncoding["'"]  = "%27"
UrlEncoding["("]  = "%28"
UrlEncoding[")"]  = "%29"
UrlEncoding["*"]  = "%2A"
UrlEncoding["+"]  = "%2B"
UrlEncoding[","]  = "%2C"
UrlEncoding["-"]  = "%2D"
UrlEncoding["."]  = "%2E"
UrlEncoding["/"]  = "%2F"
UrlEncoding[":"]  = "%3A"
UrlEncoding[";"]  = "%3B"
UrlEncoding["<"]  = "%3C"
UrlEncoding["="]  = "%3D"
UrlEncoding[">"]  = "%3E"
UrlEncoding["?"]  = "%3F"
UrlEncoding["@"]  = "%40"
UrlEncoding["["]  = "%5B"
UrlEncoding["\\"] = "%5C"
UrlEncoding["]"]  = "%5D"
UrlEncoding["^"]  = "%5E"
UrlEncoding["_"]  = "%5F"
UrlEncoding["`"]  = "%60"
UrlEncoding["{"]  = "%7B"
UrlEncoding["|"]  = "%7C"
UrlEncoding["}"]  = "%7D"
UrlEncoding["~"]  = "%7E"
}
# Example: escapeChar("n") returns "\n".
function escapeChar(char) {
switch (char) {
case "b":
return "\b"
case "f":
return "\f"
case "n":
return "\n"
case "r":
return "\r"
case "t":
return "\t"
case "v":
return "\v"
default:
return char
}
}
function literal(string,
c, escaping, i, s) {
if (string !~ /^".*"$/)
return string
split(string, s, "")
string = ""
escaping = 0
for (i = 2; i < length(s); i++) {
c = s[i]
if (escaping) {
string = string escapeChar(c)
escaping = 0
} else {
if (c == "\\")
escaping = 1
else
string = string c
}
}
return string
}
function escape(string) {
gsub(/"/, "\\\"", string)
gsub(/\\/, "\\\\", string)
return string
}
function parameterize(string, quotationMark) {
if (!quotationMark)
quotationMark = "'"
if (quotationMark == "'") {
gsub(/'/, "'\\''", string)
return "'" string "'"
} else {
return "\"" escape(string) "\""
}
}
function quote(string,    i, r, s) {
r = ""
split(string, s, "")
for (i = 1; i <= length(s); i++)
r = r (s[i] in UrlEncoding ? UrlEncoding[s[i]] : s[i])
return r
}
function replicate(string, len,
i, temp) {
temp = ""
for (i = 0; i < len; i++)
temp = temp string
return temp
}
function squeeze(line) {
gsub(/^[[:space:]]+/, "", line)
gsub(/#[^"]*$/, "", line)
gsub(/[[:space:]]+$/, "", line)
return line
}
function anything(array,
i) {
for (i in array)
if (array[i]) return 1
return 0
}
function append(array, element) {
array[anything(array) ? length(array) : 0] = element
}
function belongsTo(element, array,
i) {
for (i in array)
if (element == array[i]) return element
return ""
}
function startsWithAny(string, substrings,
i) {
for (i in substrings)
if (index(string, substrings[i]) == 1) return substrings[i]
return ""
}
function matchesAny(string, patterns,
i) {
for (i in patterns)
if (string ~ "^" patterns[i]) return patterns[i]
return ""
}
function join(array, separator, sortedIn, preserveNull,
i, j, saveSortedIn, temp) {
if (!separator)
separator = " "
if (!sortedIn)
sortedIn = "@ind_num_asc"
temp = ""
j = 0
saveSortedIn = PROCINFO["sorted_in"]
PROCINFO["sorted_in"] = sortedIn
for (i in array)
if (preserveNull || array[i] != "")
temp = j++ ? temp separator array[i] : array[i]
PROCINFO["sorted_in"] = saveSortedIn
return temp
}
function initAnsiCode() {
if(ENVIRON["TERM"] == "dumb") return
AnsiCode["reset"]         = AnsiCode[0] = "\33[0m"
AnsiCode["bold"]          = "\33[1m"
AnsiCode["underline"]     = "\33[4m"
AnsiCode["negative"]      = "\33[7m"
AnsiCode["no bold"]       = "\33[21m"
AnsiCode["no underline"]  = "\33[24m"
AnsiCode["positive"]      = "\33[27m"
AnsiCode["black"]         = "\33[30m"
AnsiCode["red"]           = "\33[31m"
AnsiCode["green"]         = "\33[32m"
AnsiCode["yellow"]        = "\33[33m"
AnsiCode["blue"]          = "\33[34m"
AnsiCode["magenta"]       = "\33[35m"
AnsiCode["cyan"]          = "\33[36m"
AnsiCode["gray"]          = "\33[37m"
AnsiCode["default"]       = "\33[39m"
AnsiCode["dark gray"]     = "\33[90m"
AnsiCode["light red"]     = "\33[91m"
AnsiCode["light green"]   = "\33[92m"
AnsiCode["light yellow"]  = "\33[93m"
AnsiCode["light blue"]    = "\33[94m"
AnsiCode["light magenta"] = "\33[95m"
AnsiCode["light cyan"]    = "\33[96m"
AnsiCode["white"]         = "\33[97m"
}
function w(text) {
print AnsiCode["yellow"] text AnsiCode[0] > "/dev/stderr"
}
function e(text) {
print AnsiCode["red"] AnsiCode["bold"] text AnsiCode[0] > "/dev/stderr"
}
function d(text) {
print AnsiCode["gray"] text AnsiCode[0] > "/dev/stderr"
}
function da(array, formatString, sortedIn,
i, j, saveSortedIn) {
if (!formatString)
formatString = "_[%s]='%s'"
if (!sortedIn)
sortedIn = "@ind_num_asc"
saveSortedIn = PROCINFO["sorted_in"]
PROCINFO["sorted_in"] = sortedIn
for (i in array) {
split(i, j, SUBSEP)
d(sprintf(formatString, join(j, ","), array[i]))
}
PROCINFO["sorted_in"] = saveSortedIn
}
function assert(x, message) {
if (!message)
message = "[ERROR] Assertion failed."
if (x)
return x
else
e(message)
}
function fileExists(file) {
return !system("test -f " file)
}
function initUriSchemes() {
UriSchemes[0] = "file"
UriSchemes[1] = "http"
UriSchemes[2] = "https"
}
BEGIN {
initUrlEncoding()
initAnsiCode()
initUriSchemes()
}
function initLocale() {
Locale["af"]["name"]       = "Afrikaans"
Locale["af"]["endonym"]    = "Afrikaans"
Locale["af"]["message"]    = "Vertalings van %s"
Locale["sq"]["name"]       = "Albanian"
Locale["sq"]["endonym"]    = "Shqip"
Locale["sq"]["message"]    = "Përkthimet e %s"
Locale["ar"]["name"]       = "Arabic"
Locale["ar"]["endonym"]    = "العربية"
Locale["ar"]["message"]    = "ترجمات %s"
Locale["ar"]["rtl"]        = "true"
Locale["hy"]["name"]       = "Armenian"
Locale["hy"]["endonym"]    = "Հայերեն"
Locale["hy"]["message"]    = "%s-ի թարգմանությունները"
Locale["az"]["name"]       = "Azerbaijani"
Locale["az"]["endonym"]    = "Azərbaycanca"
Locale["az"]["message"]    = "%s sözünün tərcüməsi"
Locale["eu"]["name"]       = "Basque"
Locale["eu"]["endonym"]    = "Euskara"
Locale["eu"]["message"]    = "%s esapidearen itzulpena"
Locale["be"]["name"]       = "Belarusian"
Locale["be"]["endonym"]    = "беларуская"
Locale["be"]["message"]    = "Пераклады %s"
Locale["bn"]["name"]       = "Bengali"
Locale["bn"]["endonym"]    = "বাংলা"
Locale["bn"]["message"]    = "%s এর অনুবাদ"
Locale["bs"]["name"]       = "Bosnian"
Locale["bs"]["endonym"]    = "Bosanski"
Locale["bs"]["message"]    = "Prijevod za: %s"
Locale["bg"]["name"]       = "Bulgarian"
Locale["bg"]["endonym"]    = "български"
Locale["bg"]["message"]    = "Преводи на %s"
Locale["ca"]["name"]       = "Catalan"
Locale["ca"]["endonym"]    = "Català"
Locale["ca"]["message"]    = "Traduccions per a %s"
Locale["ceb"]["name"]      = "Cebuano"
Locale["ceb"]["endonym"]   = "Cebuano"
Locale["ceb"]["message"]   = "%s Mga Paghubad sa PULONG_O_HUGPONG SA PAMULONG"
Locale["zh-CN"]["name"]    = "Chinese Simplified"
Locale["zh-CN"]["endonym"] = "简体中文"
Locale["zh-CN"]["message"] = "%s 的翻译"
Locale["zh-TW"]["name"]    = "Chinese Traditional"
Locale["zh-TW"]["endonym"] = "正體中文"
Locale["zh-TW"]["message"] = "「%s」的翻譯"
Locale["hr"]["name"]       = "Croatian"
Locale["hr"]["endonym"]    = "Hrvatski"
Locale["hr"]["message"]    = "Prijevodi riječi ili izraza %s"
Locale["cs"]["name"]       = "Czech"
Locale["cs"]["endonym"]    = "Čeština"
Locale["cs"]["message"]    = "Překlad výrazu %s"
Locale["da"]["name"]       = "Danish"
Locale["da"]["endonym"]    = "Dansk"
Locale["da"]["message"]    = "Oversættelser af %s"
Locale["nl"]["name"]       = "Dutch"
Locale["nl"]["endonym"]    = "Nederlands"
Locale["nl"]["message"]    = "Vertalingen van %s"
Locale["en"]["name"]       = "English"
Locale["en"]["endonym"]    = "English"
Locale["en"]["message"]    = "Translations of %s"
Locale["eo"]["name"]       = "Esperanto"
Locale["eo"]["endonym"]    = "Esperanto"
Locale["eo"]["message"]    = "Tradukoj de %s"
Locale["et"]["name"]       = "Estonian"
Locale["et"]["endonym"]    = "Eesti"
Locale["et"]["message"]    = "Sõna(de) %s tõlked"
Locale["tl"]["name"]       = "Filipino"
Locale["tl"]["endonym"]    = "Tagalog"
Locale["tl"]["message"]    = "Mga pagsasalin ng %s"
Locale["fi"]["name"]       = "Finnish"
Locale["fi"]["endonym"]    = "Suomi"
Locale["fi"]["message"]    = "Käännökset tekstille %s"
Locale["fr"]["name"]       = "French"
Locale["fr"]["endonym"]    = "Français"
Locale["fr"]["message"]    = "Traductions de %s"
Locale["gl"]["name"]       = "Galician"
Locale["gl"]["endonym"]    = "Galego"
Locale["gl"]["message"]    = "Traducións de %s"
Locale["ka"]["name"]       = "Georgian"
Locale["ka"]["endonym"]    = "ქართული"
Locale["ka"]["message"]    = "%s-ის თარგმანები"
Locale["de"]["name"]       = "German"
Locale["de"]["endonym"]    = "Deutsch"
Locale["de"]["message"]    = "Übersetzungen für %s"
Locale["el"]["name"]       = "Greek"
Locale["el"]["endonym"]    = "Ελληνικά"
Locale["el"]["message"]    = "Μεταφράσεις του %s"
Locale["gu"]["name"]       = "Gujarati"
Locale["gu"]["endonym"]    = "ગુજરાતી"
Locale["gu"]["message"]    = "%s ના અનુવાદ"
Locale["ht"]["name"]       = "Haitian Creole"
Locale["ht"]["endonym"]    = "Kreyòl Ayisyen"
Locale["ht"]["message"]    = "Tradiksyon %s"
Locale["ha"]["name"]       = "Hausa"
Locale["ha"]["endonym"]    = "Hausa"
Locale["ha"]["message"]    = "Fassarar %s"
Locale["he"]["name"]       = "Hebrew"
Locale["he"]["endonym"]    = "עִבְרִית"
Locale["he"]["message"]    = "תרגומים של %s"
Locale["he"]["rtl"]        = "true"
Locale["hi"]["name"]       = "Hindi"
Locale["hi"]["endonym"]    = "हिन्दी"
Locale["hi"]["message"]    = "%s के अनुवाद"
Locale["hmn"]["name"]      = "Hmong"
Locale["hmn"]["endonym"]   = "Hmoob"
Locale["hmn"]["message"]   = "Lus txhais: %s"
Locale["hu"]["name"]       = "Hungarian"
Locale["hu"]["endonym"]    = "Magyar"
Locale["hu"]["message"]    = "%s fordításai"
Locale["is"]["name"]       = "Icelandic"
Locale["is"]["endonym"]    = "Íslenska"
Locale["is"]["message"]    = "Þýðingar á %s"
Locale["ig"]["name"]       = "Igbo"
Locale["ig"]["endonym"]    = "Igbo"
Locale["ig"]["message"]    = "Ntụgharị asụsụ nke %s"
Locale["id"]["name"]       = "Indonesian"
Locale["id"]["endonym"]    = "Bahasa Indonesia"
Locale["id"]["message"]    = "Terjemahan dari %s"
Locale["ga"]["name"]       = "Irish"
Locale["ga"]["endonym"]    = "Gaeilge"
Locale["ga"]["message"]    = "Aistriúcháin ar %s"
Locale["it"]["name"]       = "Italian"
Locale["it"]["endonym"]    = "Italiano"
Locale["it"]["message"]    = "Traduzioni di %s"
Locale["ja"]["name"]       = "Japanese"
Locale["ja"]["endonym"]    = "日本語"
Locale["ja"]["message"]    = "「%s」の翻訳"
Locale["jv"]["name"]       = "Javanese"
Locale["jv"]["endonym"]    = "Basa Jawa"
Locale["jv"]["message"]    = "Terjemahan"
Locale["kn"]["name"]       = "Kannada"
Locale["kn"]["endonym"]    = "ಕನ್ನಡ"
Locale["kn"]["message"]    = "%s ನ ಅನುವಾದಗಳು"
Locale["km"]["name"]       = "Khmer"
Locale["km"]["endonym"]    = "ភាសាខ្មែរ"
Locale["km"]["message"]    = "ការ​បក​ប្រែ​នៃ %s"
Locale["ko"]["name"]       = "Korean"
Locale["ko"]["endonym"]    = "한국어"
Locale["ko"]["message"]    = "%s의 번역"
Locale["lo"]["name"]       = "Lao"
Locale["lo"]["endonym"]    = "ລາວ"
Locale["lo"]["message"]    = "ການ​ແປ​ພາ​ສາ​ຂອງ %s"
Locale["la"]["name"]       = "Latin"
Locale["la"]["endonym"]    = "Latina"
Locale["la"]["message"]    = "Versio de %s"
Locale["lv"]["name"]       = "Latvian"
Locale["lv"]["endonym"]    = "Latviešu"
Locale["lv"]["message"]    = "%s tulkojumi"
Locale["lt"]["name"]       = "Lithuanian"
Locale["lt"]["endonym"]    = "Lietuvių"
Locale["lt"]["message"]    = "„%s“ vertimai"
Locale["mk"]["name"]       = "Macedonian"
Locale["mk"]["endonym"]    = "Македонски"
Locale["mk"]["message"]    = "Преводи на %s"
Locale["ms"]["name"]       = "Malay"
Locale["ms"]["endonym"]    = "Bahasa Melayu"
Locale["ms"]["message"]    = "Terjemahan %s"
Locale["mt"]["name"]       = "Maltese"
Locale["mt"]["endonym"]    = "Malti"
Locale["mt"]["message"]    = "Traduzzjonijiet ta' %s"
Locale["mi"]["name"]       = "Maori"
Locale["mi"]["endonym"]    = "Māori"
Locale["mi"]["message"]    = "Ngā whakamāoritanga o %s"
Locale["mr"]["name"]       = "Marathi"
Locale["mr"]["endonym"]    = "मराठी"
Locale["mr"]["message"]    = "%s ची भाषांतरे"
Locale["mn"]["name"]       = "Mongolian"
Locale["mn"]["endonym"]    = "Монгол"
Locale["mn"]["message"]    = "%s-н орчуулга"
Locale["ne"]["name"]       = "Nepali"
Locale["ne"]["endonym"]    = "नेपाली"
Locale["ne"]["message"]    = "%sका अनुवाद"
Locale["no"]["name"]       = "Norwegian"
Locale["no"]["endonym"]    = "Norsk"
Locale["no"]["message"]    = "Oversettelser av %s"
Locale["fa"]["name"]       = "Persian"
Locale["fa"]["endonym"]    = "فارسی"
Locale["fa"]["message"]    = "ترجمه‌های %s"
Locale["fa"]["rtl"]        = "true"
Locale["pa"]["name"]       = "Punjabi"
Locale["pa"]["endonym"]    = "ਪੰਜਾਬੀ"
Locale["pa"]["message"]    = "ਦੇ ਅਨੁਵਾਦ%s"
Locale["pl"]["name"]       = "Polish"
Locale["pl"]["endonym"]    = "Polski"
Locale["pl"]["message"]    = "Tłumaczenia %s"
Locale["pt"]["name"]       = "Portuguese"
Locale["pt"]["endonym"]    = "Português"
Locale["pt"]["message"]    = "Traduções de %s"
Locale["ro"]["name"]       = "Romanian"
Locale["ro"]["endonym"]    = "Română"
Locale["ro"]["message"]    = "Traduceri pentru %s"
Locale["ru"]["name"]       = "Russian"
Locale["ru"]["endonym"]    = "Русский"
Locale["ru"]["message"]    = "%s: варианты перевода"
Locale["sr"]["name"]       = "Serbian"
Locale["sr"]["endonym"]    = "српски"
Locale["sr"]["message"]    = "Преводи за „%s“"
Locale["sk"]["name"]       = "Slovak"
Locale["sk"]["endonym"]    = "Slovenčina"
Locale["sk"]["message"]    = "Preklady výrazu: %s"
Locale["sl"]["name"]       = "Slovenian"
Locale["sl"]["endonym"]    = "Slovenščina"
Locale["sl"]["message"]    = "Prevodi za %s"
Locale["so"]["name"]       = "Somali"
Locale["so"]["endonym"]    = "Soomaali"
Locale["so"]["message"]    = "Turjumaada %s"
Locale["es"]["name"]       = "Spanish"
Locale["es"]["endonym"]    = "Español"
Locale["es"]["message"]    = "Traducciones de %s"
Locale["sw"]["name"]       = "Swahili"
Locale["sw"]["endonym"]    = "Kiswahili"
Locale["sw"]["message"]    = "Tafsiri ya %s"
Locale["sv"]["name"]       = "Swedish"
Locale["sv"]["endonym"]    = "Svenska"
Locale["sv"]["message"]    = "Översättningar av %s"
Locale["ta"]["name"]       = "Tamil"
Locale["ta"]["endonym"]    = "தமிழ்"
Locale["ta"]["message"]    = "%s இன் மொழிபெயர்ப்புகள்"
Locale["te"]["name"]       = "Telugu"
Locale["te"]["endonym"]    = "తెలుగు"
Locale["te"]["message"]    = "%s యొక్క అనువాదాలు"
Locale["th"]["name"]       = "Thai"
Locale["th"]["endonym"]    = "ไทย"
Locale["th"]["message"]    = "คำแปลของ %s"
Locale["tr"]["name"]       = "Turkish"
Locale["tr"]["endonym"]    = "Türkçe"
Locale["tr"]["message"]    = "%s çevirileri"
Locale["uk"]["name"]       = "Ukrainian"
Locale["uk"]["endonym"]    = "Українська"
Locale["uk"]["message"]    = "Переклади слова або виразу \"%s\""
Locale["ur"]["name"]       = "Urdu"
Locale["ur"]["endonym"]    = "اُردُو"
Locale["ur"]["message"]    = "کے ترجمے %s"
Locale["ur"]["rtl"]        = "true"
Locale["vi"]["name"]       = "Vietnamese"
Locale["vi"]["endonym"]    = "Tiếng Việt"
Locale["vi"]["message"]    = "Bản dịch của %s"
Locale["cy"]["name"]       = "Welsh"
Locale["cy"]["endonym"]    = "Cymraeg"
Locale["cy"]["message"]    = "Cyfieithiadau %s"
Locale["yi"]["name"]       = "Yiddish"
Locale["yi"]["endonym"]    = "ייִדיש"
Locale["yi"]["message"]    = "איבערזעצונגען פון %s"
Locale["yi"]["rtl"]        = "true"
Locale["yo"]["name"]       = "Yoruba"
Locale["yo"]["endonym"]    = "Yorùbá"
Locale["yo"]["message"]    = "Awọn itumọ ti %s"
Locale["zu"]["name"]       = "Zulu"
Locale["zu"]["endonym"]    = "isiZulu"
Locale["zu"]["message"]    = "Ukuhumusha i-%s"
LocaleAlias["in"] = "id"
LocaleAlias["iw"] = "he"
LocaleAlias["ji"] = "yi"
LocaleAlias["jw"] = "jv"
LocaleAlias["mo"] = "ro"
LocaleAlias["sh"] = "sr"
LocaleAlias["zh"] = "zh-CN"
LocaleAlias["zh-cn"] = "zh-CN"
LocaleAlias["zh-tw"] = "zh-TW"
}
function getCode(code) {
code = tolower(code)
if (code in Locale || code == "auto")
return code
else if (code in LocaleAlias)
return LocaleAlias[code]
else
return
}
function initBiDi() {
"fribidi --version 2>/dev/null" |& getline FriBidi
BiDiNoPad = FriBidi ? "fribidi --nopad" : "rev"
BiDi = FriBidi ? "fribidi --width %s" : "rev | sed \"s/'/\\\\\\'/\" | xargs printf '%%s '"
}
function show(text, code,    temp) {
if (!code || Locale[getCode(code)]["rtl"]) {
if (Cache[text][0])
return Cache[text][0]
else {
if (FriBidi || (code && Locale[getCode(code)]["rtl"]))
("echo " parameterize(text) " | " BiDiNoPad) | getline temp
else
temp = text
return Cache[text][0] = temp
}
} else
return text
}
function s(text, code, width,    temp) {
if (!code || Locale[getCode(code)]["rtl"]) {
if (!width) width = Option["width"]
if (Cache[text][width])
return Cache[text][width]
else {
if (FriBidi || (code && Locale[getCode(code)]["rtl"]))
("echo " parameterize(text) " | " sprintf(BiDi, width)) | getline temp
else
temp = text
return Cache[text][width] = temp
}
} else
return text
}
function initLocaleDisplay(    i) {
for (i in Locale)
Locale[i]["display"] = show(Locale[i]["endonym"], i)
}
function parseLang(lang,    code, group) {
match(lang, /^([a-z][a-z][a-z]?)(_|$)/, group)
code = getCode(group[1])
if (lang ~ /^zh_(CN|SG)/) code = "zh-CN"
else if (lang ~ /^zh_(TW|HK)/) code = "zh-TW"
if (!code) code = "en"
return code
}
function initUserLang() {
UserLang = ENVIRON["LC_CTYPE"] ?
parseLang(ENVIRON["LC_CTYPE"]) :
(ENVIRON["LANG"] ?
parseLang(ENVIRON["LANG"]) :
"en")
if (ENVIRON["LANG"] !~ /UTF-8$/ && ENVIRON["LC_CTYPE"] !~ /UTF-8$/)
w("[WARNING] Your locale codeset (" ENVIRON["LANG"] ") is not UTF-8. You have been warned.")
}
function getVersion() {
return Name " " Version
}
#     displayName = "endonym" or "name"
function getReference(displayName) {
if (displayName == "name")
return "┌─────────────────────────────┬──────────────────────┬─────────────────┐\n" \
"│ " Locale["af"]["name"] "           - " AnsiCode["bold"] "af" AnsiCode["no bold"] "    │ " Locale["el"]["name"] "          - " AnsiCode["bold"] "el" AnsiCode["no bold"] "  │ " Locale["mn"]["name"] "  - " AnsiCode["bold"] "mn" AnsiCode["no bold"] " │\n" \
"│ " Locale["sq"]["name"] "            - " AnsiCode["bold"] "sq" AnsiCode["no bold"] "    │ " Locale["gu"]["name"] "       - " AnsiCode["bold"] "gu" AnsiCode["no bold"] "  │ " Locale["ne"]["name"] "     - " AnsiCode["bold"] "ne" AnsiCode["no bold"] " │\n" \
"│ " Locale["ar"]["name"] "              - " AnsiCode["bold"] "ar" AnsiCode["no bold"] "    │ " Locale["ht"]["name"] " - " AnsiCode["bold"] "ht" AnsiCode["no bold"] "  │ " Locale["no"]["name"] "  - " AnsiCode["bold"] "no" AnsiCode["no bold"] " │\n" \
"│ " Locale["hy"]["name"] "            - " AnsiCode["bold"] "hy" AnsiCode["no bold"] "    │ " Locale["ha"]["name"] "          - " AnsiCode["bold"] "ha" AnsiCode["no bold"] "  │ " Locale["fa"]["name"] "    - " AnsiCode["bold"] "fa" AnsiCode["no bold"] " │\n" \
"│ " Locale["az"]["name"] "         - " AnsiCode["bold"] "az" AnsiCode["no bold"] "    │ " Locale["he"]["name"] "         - " AnsiCode["bold"] "he" AnsiCode["no bold"] "  │ " Locale["pl"]["name"] "     - " AnsiCode["bold"] "pl" AnsiCode["no bold"] " │\n" \
"│ " Locale["eu"]["name"] "              - " AnsiCode["bold"] "eu" AnsiCode["no bold"] "    │ " Locale["hi"]["name"] "          - " AnsiCode["bold"] "hi" AnsiCode["no bold"] "  │ " Locale["pt"]["name"] " - " AnsiCode["bold"] "pt" AnsiCode["no bold"] " │\n" \
"│ " Locale["be"]["name"] "          - " AnsiCode["bold"] "be" AnsiCode["no bold"] "    │ " Locale["hmn"]["name"] "          - " AnsiCode["bold"] "hmn" AnsiCode["no bold"] " │ " Locale["pa"]["name"] "    - " AnsiCode["bold"] "pa" AnsiCode["no bold"] " │\n" \
"│ " Locale["bn"]["name"] "             - " AnsiCode["bold"] "bn" AnsiCode["no bold"] "    │ " Locale["hu"]["name"] "      - " AnsiCode["bold"] "hu" AnsiCode["no bold"] "  │ " Locale["ro"]["name"] "   - " AnsiCode["bold"] "ro" AnsiCode["no bold"] " │\n" \
"│ " Locale["bs"]["name"] "             - " AnsiCode["bold"] "bs" AnsiCode["no bold"] "    │ " Locale["is"]["name"] "      - " AnsiCode["bold"] "is" AnsiCode["no bold"] "  │ " Locale["ru"]["name"] "    - " AnsiCode["bold"] "ru" AnsiCode["no bold"] " │\n" \
"│ " Locale["bg"]["name"] "           - " AnsiCode["bold"] "bg" AnsiCode["no bold"] "    │ " Locale["ig"]["name"] "           - " AnsiCode["bold"] "ig" AnsiCode["no bold"] "  │ " Locale["sr"]["name"] "    - " AnsiCode["bold"] "sr" AnsiCode["no bold"] " │\n" \
"│ " Locale["ca"]["name"] "             - " AnsiCode["bold"] "ca" AnsiCode["no bold"] "    │ " Locale["id"]["name"] "     - " AnsiCode["bold"] "id" AnsiCode["no bold"] "  │ " Locale["sk"]["name"] "     - " AnsiCode["bold"] "sk" AnsiCode["no bold"] " │\n" \
"│ " Locale["ceb"]["name"] "             - " AnsiCode["bold"] "ceb" AnsiCode["no bold"] "   │ " Locale["ga"]["name"] "          - " AnsiCode["bold"] "ga" AnsiCode["no bold"] "  │ " Locale["sl"]["name"] "  - " AnsiCode["bold"] "sl" AnsiCode["no bold"] " │\n" \
"│ " Locale["zh-CN"]["name"] "  - " AnsiCode["bold"] "zh-CN" AnsiCode["no bold"] " │ " Locale["it"]["name"] "        - " AnsiCode["bold"] "it" AnsiCode["no bold"] "  │ " Locale["so"]["name"] "     - " AnsiCode["bold"] "so" AnsiCode["no bold"] " │\n" \
"│ " Locale["zh-TW"]["name"] " - " AnsiCode["bold"] "zh-TW" AnsiCode["no bold"] " │ " Locale["ja"]["name"] "       - " AnsiCode["bold"] "ja" AnsiCode["no bold"] "  │ " Locale["es"]["name"] "    - " AnsiCode["bold"] "es" AnsiCode["no bold"] " │\n" \
"│ " Locale["hr"]["name"] "            - " AnsiCode["bold"] "hr" AnsiCode["no bold"] "    │ " Locale["jv"]["name"] "       - " AnsiCode["bold"] "jv" AnsiCode["no bold"] "  │ " Locale["sw"]["name"] "    - " AnsiCode["bold"] "sw" AnsiCode["no bold"] " │\n" \
"│ " Locale["cs"]["name"] "               - " AnsiCode["bold"] "cs" AnsiCode["no bold"] "    │ " Locale["kn"]["name"] "        - " AnsiCode["bold"] "kn" AnsiCode["no bold"] "  │ " Locale["sv"]["name"] "    - " AnsiCode["bold"] "sv" AnsiCode["no bold"] " │\n" \
"│ " Locale["da"]["name"] "              - " AnsiCode["bold"] "da" AnsiCode["no bold"] "    │ " Locale["km"]["name"] "          - " AnsiCode["bold"] "km" AnsiCode["no bold"] "  │ " Locale["ta"]["name"] "      - " AnsiCode["bold"] "ta" AnsiCode["no bold"] " │\n" \
"│ " Locale["nl"]["name"] "               - " AnsiCode["bold"] "nl" AnsiCode["no bold"] "    │ " Locale["ko"]["name"] "         - " AnsiCode["bold"] "ko" AnsiCode["no bold"] "  │ " Locale["te"]["name"] "     - " AnsiCode["bold"] "te" AnsiCode["no bold"] " │\n" \
"│ " Locale["en"]["name"] "             - " AnsiCode["bold"] "en" AnsiCode["no bold"] "    │ " Locale["lo"]["name"] "            - " AnsiCode["bold"] "lo" AnsiCode["no bold"] "  │ " Locale["th"]["name"] "       - " AnsiCode["bold"] "th" AnsiCode["no bold"] " │\n" \
"│ " Locale["eo"]["name"] "           - " AnsiCode["bold"] "eo" AnsiCode["no bold"] "    │ " Locale["la"]["name"] "          - " AnsiCode["bold"] "la" AnsiCode["no bold"] "  │ " Locale["tr"]["name"] "    - " AnsiCode["bold"] "tr" AnsiCode["no bold"] " │\n" \
"│ " Locale["et"]["name"] "            - " AnsiCode["bold"] "et" AnsiCode["no bold"] "    │ " Locale["lv"]["name"] "        - " AnsiCode["bold"] "lv" AnsiCode["no bold"] "  │ " Locale["uk"]["name"] "  - " AnsiCode["bold"] "uk" AnsiCode["no bold"] " │\n" \
"│ " Locale["tl"]["name"] "            - " AnsiCode["bold"] "tl" AnsiCode["no bold"] "    │ " Locale["lt"]["name"] "     - " AnsiCode["bold"] "lt" AnsiCode["no bold"] "  │ " Locale["ur"]["name"] "       - " AnsiCode["bold"] "ur" AnsiCode["no bold"] " │\n" \
"│ " Locale["fi"]["name"] "             - " AnsiCode["bold"] "fi" AnsiCode["no bold"] "    │ " Locale["mk"]["name"] "     - " AnsiCode["bold"] "mk" AnsiCode["no bold"] "  │ " Locale["vi"]["name"] " - " AnsiCode["bold"] "vi" AnsiCode["no bold"] " │\n" \
"│ " Locale["fr"]["name"] "              - " AnsiCode["bold"] "fr" AnsiCode["no bold"] "    │ " Locale["ms"]["name"] "          - " AnsiCode["bold"] "ms" AnsiCode["no bold"] "  │ " Locale["cy"]["name"] "      - " AnsiCode["bold"] "cy" AnsiCode["no bold"] " │\n" \
"│ " Locale["gl"]["name"] "            - " AnsiCode["bold"] "gl" AnsiCode["no bold"] "    │ " Locale["mt"]["name"] "        - " AnsiCode["bold"] "mt" AnsiCode["no bold"] "  │ " Locale["yi"]["name"] "    - " AnsiCode["bold"] "yi" AnsiCode["no bold"] " │\n" \
"│ " Locale["ka"]["name"] "            - " AnsiCode["bold"] "ka" AnsiCode["no bold"] "    │ " Locale["mi"]["name"] "          - " AnsiCode["bold"] "mi" AnsiCode["no bold"] "  │ " Locale["yo"]["name"] "     - " AnsiCode["bold"] "yo" AnsiCode["no bold"] " │\n" \
"│ " Locale["de"]["name"] "              - " AnsiCode["bold"] "de" AnsiCode["no bold"] "    │ " Locale["mr"]["name"] "        - " AnsiCode["bold"] "mr" AnsiCode["no bold"] "  │ " Locale["zu"]["name"] "       - " AnsiCode["bold"] "zu" AnsiCode["no bold"] " │\n" \
"└─────────────────────────────┴──────────────────────┴─────────────────┘"
else
return "┌────────────────────┬────────────────────────┬─────────────────────┐\n" \
"│ " Locale["af"]["display"] "    - " AnsiCode["bold"] "af" AnsiCode["no bold"] "  │ " Locale["hi"]["display"] "            - " AnsiCode["bold"] "hi" AnsiCode["no bold"] "  │ " Locale["nl"]["display"] "  - " AnsiCode["bold"] "nl" AnsiCode["no bold"] "    │\n" \
"│ " Locale["ar"]["display"] "      - " AnsiCode["bold"] "ar" AnsiCode["no bold"] "  │ " Locale["hmn"]["display"] "            - " AnsiCode["bold"] "hmn" AnsiCode["no bold"] " │ " Locale["no"]["display"] "       - " AnsiCode["bold"] "no" AnsiCode["no bold"] "    │\n" \
"│ " Locale["az"]["display"] " - " AnsiCode["bold"] "az" AnsiCode["no bold"] "  │ " Locale["hr"]["display"] "         - " AnsiCode["bold"] "hr" AnsiCode["no bold"] "  │ " Locale["pa"]["display"] "       - " AnsiCode["bold"] "pa" AnsiCode["no bold"] "    │\n" \
"│ " Locale["be"]["display"] "   - " AnsiCode["bold"] "be" AnsiCode["no bold"] "  │ " Locale["ht"]["display"] "   - " AnsiCode["bold"] "ht" AnsiCode["no bold"] "  │ " Locale["pl"]["display"] "      - " AnsiCode["bold"] "pl" AnsiCode["no bold"] "    │\n" \
"│ " Locale["bg"]["display"] "    - " AnsiCode["bold"] "bg" AnsiCode["no bold"] "  │ " Locale["hu"]["display"] "           - " AnsiCode["bold"] "hu" AnsiCode["no bold"] "  │ " Locale["pt"]["display"] "   - " AnsiCode["bold"] "pt" AnsiCode["no bold"] "    │\n" \
"│ " Locale["bn"]["display"] "        - " AnsiCode["bold"] "bn" AnsiCode["no bold"] "  │ " Locale["hy"]["display"] "          - " AnsiCode["bold"] "hy" AnsiCode["no bold"] "  │ " Locale["ro"]["display"] "      - " AnsiCode["bold"] "ro" AnsiCode["no bold"] "    │\n" \
"│ " Locale["bs"]["display"] "     - " AnsiCode["bold"] "bs" AnsiCode["no bold"] "  │ " Locale["id"]["display"] " - " AnsiCode["bold"] "id" AnsiCode["no bold"] "  │ " Locale["ru"]["display"] "     - " AnsiCode["bold"] "ru" AnsiCode["no bold"] "    │\n" \
"│ " Locale["ca"]["display"] "       - " AnsiCode["bold"] "ca" AnsiCode["no bold"] "  │ " Locale["ig"]["display"] "             - " AnsiCode["bold"] "ig" AnsiCode["no bold"] "  │ " Locale["sk"]["display"] "  - " AnsiCode["bold"] "sk" AnsiCode["no bold"] "    │\n" \
"│ " Locale["ceb"]["display"] "      - " AnsiCode["bold"] "ceb" AnsiCode["no bold"] " │ " Locale["is"]["display"] "         - " AnsiCode["bold"] "is" AnsiCode["no bold"] "  │ " Locale["sl"]["display"] " - " AnsiCode["bold"] "sl" AnsiCode["no bold"] "    │\n" \
"│ " Locale["cs"]["display"] "      - " AnsiCode["bold"] "cs" AnsiCode["no bold"] "  │ " Locale["it"]["display"] "         - " AnsiCode["bold"] "it" AnsiCode["no bold"] "  │ " Locale["so"]["display"] "    - " AnsiCode["bold"] "so" AnsiCode["no bold"] "    │\n" \
"│ " Locale["cy"]["display"] "      - " AnsiCode["bold"] "cy" AnsiCode["no bold"] "  │ " Locale["ja"]["display"] "           - " AnsiCode["bold"] "ja" AnsiCode["no bold"] "  │ " Locale["sq"]["display"] "       - " AnsiCode["bold"] "sq" AnsiCode["no bold"] "    │\n" \
"│ " Locale["da"]["display"] "        - " AnsiCode["bold"] "da" AnsiCode["no bold"] "  │ " Locale["jv"]["display"] "        - " AnsiCode["bold"] "jv" AnsiCode["no bold"] "  │ " Locale["sr"]["display"] "      - " AnsiCode["bold"] "sr" AnsiCode["no bold"] "    │\n" \
"│ " Locale["de"]["display"] "      - " AnsiCode["bold"] "de" AnsiCode["no bold"] "  │ " Locale["ka"]["display"] "          - " AnsiCode["bold"] "ka" AnsiCode["no bold"] "  │ " Locale["sv"]["display"] "     - " AnsiCode["bold"] "sv" AnsiCode["no bold"] "    │\n" \
"│ " Locale["el"]["display"] "     - " AnsiCode["bold"] "el" AnsiCode["no bold"] "  │ " Locale["km"]["display"] "         - " AnsiCode["bold"] "km" AnsiCode["no bold"] "  │ " Locale["sw"]["display"] "   - " AnsiCode["bold"] "sw" AnsiCode["no bold"] "    │\n" \
"│ " Locale["en"]["display"] "      - " AnsiCode["bold"] "en" AnsiCode["no bold"] "  │ " Locale["kn"]["display"] "             - " AnsiCode["bold"] "kn" AnsiCode["no bold"] "  │ " Locale["ta"]["display"] "        - " AnsiCode["bold"] "ta" AnsiCode["no bold"] "    │\n" \
"│ " Locale["eo"]["display"] "    - " AnsiCode["bold"] "eo" AnsiCode["no bold"] "  │ " Locale["ko"]["display"] "           - " AnsiCode["bold"] "ko" AnsiCode["no bold"] "  │ " Locale["te"]["display"] "       - " AnsiCode["bold"] "te" AnsiCode["no bold"] "    │\n" \
"│ " Locale["es"]["display"] "      - " AnsiCode["bold"] "es" AnsiCode["no bold"] "  │ " Locale["la"]["display"] "           - " AnsiCode["bold"] "la" AnsiCode["no bold"] "  │ " Locale["th"]["display"] "         - " AnsiCode["bold"] "th" AnsiCode["no bold"] "    │\n" \
"│ " Locale["et"]["display"] "        - " AnsiCode["bold"] "et" AnsiCode["no bold"] "  │ " Locale["lo"]["display"] "              - " AnsiCode["bold"] "lo" AnsiCode["no bold"] "  │ " Locale["tl"]["display"] "     - " AnsiCode["bold"] "tl" AnsiCode["no bold"] "    │\n" \
"│ " Locale["eu"]["display"] "      - " AnsiCode["bold"] "eu" AnsiCode["no bold"] "  │ " Locale["lt"]["display"] "         - " AnsiCode["bold"] "lt" AnsiCode["no bold"] "  │ " Locale["tr"]["display"] "      - " AnsiCode["bold"] "tr" AnsiCode["no bold"] "    │\n" \
"│ " Locale["fa"]["display"] "        - " AnsiCode["bold"] "fa" AnsiCode["no bold"] "  │ " Locale["lv"]["display"] "         - " AnsiCode["bold"] "lv" AnsiCode["no bold"] "  │ " Locale["uk"]["display"] "  - " AnsiCode["bold"] "uk" AnsiCode["no bold"] "    │\n" \
"│ " Locale["fi"]["display"] "        - " AnsiCode["bold"] "fi" AnsiCode["no bold"] "  │ " Locale["mi"]["display"] "            - " AnsiCode["bold"] "mi" AnsiCode["no bold"] "  │ " Locale["ur"]["display"] "        - " AnsiCode["bold"] "ur" AnsiCode["no bold"] "    │\n" \
"│ " Locale["fr"]["display"] "     - " AnsiCode["bold"] "fr" AnsiCode["no bold"] "  │ " Locale["mk"]["display"] "       - " AnsiCode["bold"] "mk" AnsiCode["no bold"] "  │ " Locale["vi"]["display"] "  - " AnsiCode["bold"] "vi" AnsiCode["no bold"] "    │\n" \
"│ " Locale["ga"]["display"] "      - " AnsiCode["bold"] "ga" AnsiCode["no bold"] "  │ " Locale["mn"]["display"] "           - " AnsiCode["bold"] "mn" AnsiCode["no bold"] "  │ " Locale["yi"]["display"] "       - " AnsiCode["bold"] "yi" AnsiCode["no bold"] "    │\n" \
"│ " Locale["gl"]["display"] "       - " AnsiCode["bold"] "gl" AnsiCode["no bold"] "  │ " Locale["mr"]["display"] "            - " AnsiCode["bold"] "mr" AnsiCode["no bold"] "  │ " Locale["yo"]["display"] "      - " AnsiCode["bold"] "yo" AnsiCode["no bold"] "    │\n" \
"│ " Locale["gu"]["display"] "       - " AnsiCode["bold"] "gu" AnsiCode["no bold"] "  │ " Locale["ms"]["display"] "    - " AnsiCode["bold"] "ms" AnsiCode["no bold"] "  │ " Locale["zh-CN"]["display"] "    - " AnsiCode["bold"] "zh-CN" AnsiCode["no bold"] " │\n" \
"│ " Locale["ha"]["display"] "        - " AnsiCode["bold"] "ha" AnsiCode["no bold"] "  │ " Locale["mt"]["display"] "            - " AnsiCode["bold"] "mt" AnsiCode["no bold"] "  │ " Locale["zh-TW"]["display"] "    - " AnsiCode["bold"] "zh-TW" AnsiCode["no bold"] " │\n" \
"│ " Locale["he"]["display"] "        - " AnsiCode["bold"] "he" AnsiCode["no bold"] "  │ " Locale["ne"]["display"] "            - " AnsiCode["bold"] "ne" AnsiCode["no bold"] "  │ " Locale["zu"]["display"] "     - " AnsiCode["bold"] "zu" AnsiCode["no bold"] "    │\n" \
"└────────────────────┴────────────────────────┴─────────────────────┘"
}
function getHelp() {
return "Usage: " Command " [options] [source]:[target] [" AnsiCode["underline"] "text" AnsiCode["no underline"] "] ...\n" \
"       " Command " [options] [source]:[target1]+[target2]+... [" AnsiCode["underline"] "text" AnsiCode["no underline"] "] ...\n\n" \
"Options:\n" \
"  " AnsiCode["bold"] "-V, -version" AnsiCode["no bold"] "\n    Print version and exit.\n" \
"  " AnsiCode["bold"] "-H, -h, -help" AnsiCode["no bold"] "\n    Show this manual, or print this help message and exit.\n" \
"  " AnsiCode["bold"] "-r, -reference" AnsiCode["no bold"] "\n    Print a list of languages (displayed in endonyms) and their ISO 639 codes for reference, and exit.\n" \
"  " AnsiCode["bold"] "-R, -reference-english" AnsiCode["no bold"] "\n    Print a list of languages (displayed in English names) and their ISO 639 codes for reference, and exit.\n" \
"  " AnsiCode["bold"] "-v, -verbose" AnsiCode["no bold"] "\n    Verbose mode. (default)\n" \
"  " AnsiCode["bold"] "-b, -brief" AnsiCode["no bold"] "\n    Brief mode.\n" \
"  " AnsiCode["bold"] "-w [num], -width [num]" AnsiCode["no bold"] "\n    Specify the screen width for padding when displaying right-to-left languages.\n" \
"  " AnsiCode["bold"] "-browser [program]" AnsiCode["no bold"] "\n    Specify the web browser to use.\n" \
"  " AnsiCode["bold"] "-p, -play" AnsiCode["no bold"] "\n    Listen to the translation.\n" \
"  " AnsiCode["bold"] "-player [program]" AnsiCode["no bold"] "\n    Specify the command-line audio player to use, and listen to the translation.\n" \
"  " AnsiCode["bold"] "-x [proxy], -proxy [proxy]" AnsiCode["no bold"] "\n    Use proxy on given port.\n" \
"  " AnsiCode["bold"] "-I, -interactive" AnsiCode["no bold"] "\n    Start an interactive shell, invoking `rlwrap` whenever possible (unless `-no-rlwrap` is specified).\n" \
"  " AnsiCode["bold"] "-no-rlwrap" AnsiCode["no bold"] "\n    Don't invoke `rlwrap` when starting an interactive shell with `-I`.\n" \
"  " AnsiCode["bold"] "-E, -emacs" AnsiCode["no bold"] "\n    Start an interactive shell within GNU Emacs, invoking `emacs`.\n" \
"  " AnsiCode["bold"] "-prompt [prompt_string]" AnsiCode["no bold"] "\n    Customize your prompt string in the interactive shell.\n" \
"  " AnsiCode["bold"] "-prompt-color [color_code]" AnsiCode["no bold"] "\n    Customize your prompt color in the interactive shell.\n" \
"  " AnsiCode["bold"] "-i [file], -input [file]" AnsiCode["no bold"] "\n    Specify the input file name.\n" \
"  " AnsiCode["bold"] "-o [file], -output [file]" AnsiCode["no bold"] "\n    Specify the output file name.\n" \
"  " AnsiCode["bold"] "-l [code], -lang [code]" AnsiCode["no bold"] "\n    Specify your own, native language (\"home/host language\").\n" \
"  " AnsiCode["bold"] "-s [code], -source [code]" AnsiCode["no bold"] "\n    Specify the source language (language of the original text).\n" \
"  " AnsiCode["bold"] "-t [codes], -target [codes]" AnsiCode["no bold"] "\n    Specify the target language(s) (language(s) of the translated text).\n" \
"\nSee the man page " Command "(1) for more information."
}
function plTokenize(returnTokens, string,
delimiters,
newlines,
quotes,
escapeChars,
leftBlockComments,
rightBlockComments,
lineComments,
reservedOperators,
reservedPatterns,
blockCommenting,
c,
currentToken,
escaping,
i,
lineCommenting,
p,
quoting,
r,
s,
tempGroup,
tempPattern,
tempString) {
if (!delimiters[0]) {
delimiters[0] = " "
delimiters[1] = "\t"
delimiters[2] = "\v"
}
if (!newlines[0]) {
newlines[0] = "\n"
newlines[1] = "\r"
}
if (!quotes[0]) {
quotes[0] = "\""
}
if (!escapeChars[0]) {
escapeChars[0] = "\\"
}
if (!leftBlockComments[0]) {
leftBlockComments[0] = "#|"
leftBlockComments[1] = "/*"
leftBlockComments[2] = "(*"
}
if (!rightBlockComments[0]) {
rightBlockComments[0] = "|#"
rightBlockComments[1] = "*/"
rightBlockComments[2] = "*)"
}
if (!lineComments[0]) {
lineComments[0] = ";"
lineComments[1] = "//"
lineComments[2] = "#"
}
if (!reservedOperators[0]) {
reservedOperators[0] = "("
reservedOperators[1] = ")"
reservedOperators[2] = "["
reservedOperators[3] = "]"
reservedOperators[4] = "{"
reservedOperators[5] = "}"
reservedOperators[6] = ","
}
if (!reservedPatterns[0]) {
reservedPatterns[0] = "[+-]?((0|[1-9][0-9]*)|[.][0-9]*|(0|[1-9][0-9]*)[.][0-9]*)([Ee][+-]?[0-9]+)?"
reservedPatterns[1] = "[+-]?0[0-7]+([.][0-7]*)?"
reservedPatterns[2] = "[+-]?0[Xx][0-9A-Fa-f]+([.][0-9A-Fa-f]*)?"
}
split(string, s, "")
currentToken = ""
quoting = escaping = blockCommenting = lineCommenting = 0
p = 0
i = 1
while (i <= length(s)) {
c = s[i]
r = substr(string, i)
if (blockCommenting) {
if (tempString = startsWithAny(r, rightBlockComments))
blockCommenting = 0
i++
} else if (lineCommenting) {
if (belongsTo(c, newlines))
lineCommenting = 0
i++
} else if (quoting) {
currentToken = currentToken c
if (escaping) {
escaping = 0
} else {
if (belongsTo(c, quotes)) {
if (currentToken) {
returnTokens[p++] = currentToken
currentToken = ""
}
quoting = 0
} else if (belongsTo(c, escapeChars)) {
escaping = 1
} else {
}
}
i++
} else {
if (belongsTo(c, delimiters) || belongsTo(c, newlines)) {
if (currentToken) {
returnTokens[p++] = currentToken
currentToken = ""
}
i++
} else if (belongsTo(c, quotes)) {
if (currentToken) {
returnTokens[p++] = currentToken
}
currentToken = c
quoting = 1
i++
} else if (tempString = startsWithAny(r, leftBlockComments)) {
if (currentToken) {
returnTokens[p++] = currentToken
currentToken = ""
}
blockCommenting = 1
i += length(tempString)
} else if (tempString = startsWithAny(r, lineComments)) {
if (currentToken) {
returnTokens[p++] = currentToken
currentToken = ""
}
lineCommenting = 1
i += length(tempString)
} else if (tempString = startsWithAny(r, reservedOperators)) {
if (currentToken) {
returnTokens[p++] = currentToken
currentToken = ""
}
returnTokens[p++] = tempString
i += length(tempString)
} else if (tempPattern = matchesAny(r, reservedPatterns)) {
if (currentToken) {
returnTokens[p++] = currentToken
currentToken = ""
}
match(r, "^" tempPattern, tempGroup)
returnTokens[p++] = tempGroup[0]
i += length(tempGroup[0])
} else {
currentToken = currentToken c
i++
}
}
}
if (currentToken)
returnTokens[p++] = currentToken
}
function plParse(returnAST, tokens,
leftBrackets,
rightBrackets,
separators,
i, j, key, p, stack, token) {
if (!leftBrackets[0]) {
leftBrackets[0] = "("
leftBrackets[1] = "["
leftBrackets[2] = "{"
}
if (!rightBrackets[0]) {
rightBrackets[0] = ")"
rightBrackets[1] = "]"
rightBrackets[2] = "}"
}
if (!separators[0]) {
separators[0] = ","
}
stack[p = 0] = 0
for (i = 0; i < length(tokens); i++) {
token = tokens[i]
if (belongsTo(token, leftBrackets))
stack[++p] = 0
else if (belongsTo(token, rightBrackets))
--p
else if (belongsTo(token, separators))
stack[p]++
else {
key = stack[0]
for (j = 1; j <= p; j++)
key = key SUBSEP stack[j]
returnAST[key] = token
}
}
}
function initAudioPlayer() {
AudioPlayer = !system("mplayer >/dev/null 2>/dev/null") ?
"mplayer" :
(!system("mpg123 >/dev/null 2>/dev/null") ?
"mpg123" :
"")
}
function initSpeechSynthesizer() {
SpeechSynthesizer = !system("say '' >/dev/null 2>/dev/null") ?
"say" :
(!system("espeak '' >/dev/null 2>/dev/null") ?
"espeak" :
"")
}
function initHttpService() {
HttpProtocol = "http://"
HttpHost = "translate.google.com"
HttpPort = 80
if (Option["proxy"]) {
match(Option["proxy"], /^(http:\/*)?([^\/]*):([^\/:]*)/, HttpProxySpec)
HttpService = "/inet/tcp/0/" HttpProxySpec[2] "/" HttpProxySpec[3]
HttpPathPrefix = HttpProtocol HttpHost
} else {
HttpService = "/inet/tcp/0/" HttpHost "/" HttpPort
HttpPathPrefix = ""
}
}
function preprocess(text) {
return quote(text)
}
function postprocess(text) {
text = gensub(/ ([.,;:?!"])/, "\\1", "g", text)
text = gensub(/(["]) /, "\\1", "g", text)
return text
}
function getResponse(text, sl, tl, hl,    content, url) {
url = HttpPathPrefix "/translate_a/single?client=t"                 \
"&ie=UTF-8&oe=UTF-8"                                            \
"&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&dt=at"  \
"&q=" preprocess(text) "&sl=" sl "&tl=" tl "&hl=" hl
print "GET " url " HTTP/1.1\n"             \
"Host: " HttpHost "\n"               \
"Connection: close\n" |& HttpService
while ((HttpService |& getline) > 0)
content = $0
close(HttpService)
return assert(content, "[ERROR] Null response.")
}
function play(text, tl,    url) {
url = HttpProtocol HttpHost "/translate_tts?ie=UTF-8"       \
"&tl=" tl "&q=" preprocess(text)
system(Option["player"] " '" url "' >/dev/null 2>/dev/null")
}
function getTranslation(text, sl, tl, hl,
isVerbose, toSpeech, returnPlaylist,
altTranslations, article, ast, content,
explanation, group, i, il, ils,
isPhonetic, j, original, phonetics,
r, rtl, saveSortedIn, segments,
temp, tokens, translation, translations,
word, words, wordClasses) {
isPhonetic = match(tl, /^@/)
tl = substr(tl, 1 + isPhonetic)
if (!getCode(tl)) {
w("[WARNING] Unknown target language code: " tl)
} else if (getCode(tl) != "auto" && rtl = Locale[getCode(tl)]["rtl"]) {
if (!FriBidi)
w("[WARNING] " Locale[getCode(tl)]["name"] " is a right-to-left language, but GNU FriBidi is not found on your system.\nText might be displayed incorrectly.")
}
content = getResponse(text, sl, tl, hl)
plTokenize(tokens, content)
plParse(ast, tokens)
if (!anything(ast)) {
e("[ERROR] Oops! Something went wrong and I can't translate it for you :(")
ExitCode = 1
}
if (Option["debug"]) {
d(content)
da(tokens, "tokens[%s]='%s'")
da(ast, "ast[%s]='%s'")
}
saveSortedIn = PROCINFO["sorted_in"]
PROCINFO["sorted_in"] = "@ind_num_asc"
for (i in ast) {
if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "0$")
append(translations, postprocess(literal(ast[i])))
if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "1$")
append(original, literal(ast[i]))
if (i ~ "^0" SUBSEP "0" SUBSEP "[[:digit:]]+" SUBSEP "2$")
append(phonetics, literal(ast[i]))
if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
wordClasses[group[1]] = literal(ast[i])
if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "([[:digit:]]+)$", group))
words[group[1]][group[2]][group[3]] = literal(ast[i])
if (match(i, "^0" SUBSEP "1" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "1" SUBSEP "([[:digit:]]+)$", group))
words[group[1]][group[2]]["1"][group[3]] = literal(ast[i])
if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
segments[group[1]] = literal(ast[i])
if (match(i, "^0" SUBSEP "5" SUBSEP "([[:digit:]]+)" SUBSEP "2" SUBSEP "([[:digit:]]+)" SUBSEP "0$", group))
altTranslations[group[1]][group[2]] = postprocess(literal(ast[i]))
if (i ~ "^0" SUBSEP "8" SUBSEP "0" SUBSEP "[[:digit:]]+$" ||
i ~ "^0" SUBSEP "2$")
append(ils, literal(ast[i]))
}
PROCINFO["sorted_in"] = saveSortedIn
translation = join(translations)
il = !anything(ils) || belongsTo(sl, ils) ? sl : ils[0]
if (!isVerbose) {
r = isPhonetic && anything(phonetics) ?
join(phonetics) :
s(translation, tl)
if (toSpeech) {
returnPlaylist[0]["text"] = translation
returnPlaylist[0]["tl"] = tl
}
} else {
r = AnsiCode["bold"] s(translation, tl) AnsiCode["no bold"]
if (anything(phonetics))
r = r "\n" AnsiCode["bold"] join(phonetics) AnsiCode["no bold"]
if (isarray(altTranslations[0]) && anything(altTranslations[0])) {
if (Locale[getCode(hl)]["rtl"] || Locale[getCode(il)]["rtl"])
r = r "\n\n" s(sprintf(Locale[getCode(hl)]["message"], join(original)))
else
r = r "\n\n" sprintf(Locale[getCode(hl)]["message"], join(original))
if (Locale[getCode(il)]["rtl"] || Locale[getCode(tl)]["rtl"])
r = r "\n" s("(" Locale[getCode(il)]["endonym"] " ➔ " Locale[getCode(tl)]["endonym"] ")")
else
r = r "\n" "(" Locale[getCode(il)]["endonym"] " ➔ " Locale[getCode(tl)]["endonym"] ")"
temp = segments[0] "(" join(altTranslations[0], "/") ")"
for (i = 1; i < length(altTranslations); i++)
temp = temp " " segments[i] "(" join(altTranslations[i], "/") ")"
if (Locale[getCode(il)]["rtl"] || Locale[getCode(tl)]["rtl"])
r = r "\n" AnsiCode["bold"] s(temp) AnsiCode["no bold"]
else
r = r "\n" AnsiCode["bold"] temp AnsiCode["no bold"]
}
if (isarray(wordClasses) && anything(wordClasses)) {
for (i = 0; i < length(words); i++) {
r = r "\n\n" s("[" wordClasses[i] "]", hl)
for (j = 0; j < length(words[i]); j++) {
word = words[i][j][0]
explanation = join(words[i][j][1], ", ")
article = words[i][j][4]
if (rtl) {
r = r "\n" AnsiCode["bold"] sprintf("%" Option["width"] - 4 "s", s((article ?
"(" article ")" :
"") " " word, tl, Option["width"] - 4)) AnsiCode["no bold"]
r = r "\n" s(explanation, il, Option["width"] - 8)
} else {
r = r "\n" "    " AnsiCode["bold"] show((article ?
"(" article ") " :
"") word, tl) AnsiCode["no bold"]
r = r "\n" "        " s(explanation, il, Option["width"] - 8)
}
}
}
}
if (toSpeech) {
if (index(Locale[getCode(hl)]["message"], "%s") > 2) {
returnPlaylist[0]["text"] = sprintf(Locale[getCode(hl)]["message"], "")
returnPlaylist[0]["tl"] = hl
returnPlaylist[1]["text"] = join(original)
returnPlaylist[1]["tl"] = il
} else {
returnPlaylist[0]["text"] = join(original)
returnPlaylist[0]["tl"] = il
returnPlaylist[1]["text"] = sprintf(Locale[getCode(hl)]["message"], "")
returnPlaylist[1]["tl"] = hl
}
returnPlaylist[2]["text"] = translation
returnPlaylist[2]["tl"] = tl
}
}
return r
}
function fileTranslation(uri,    group, temp1, temp2) {
temp1 = Option["input"]
temp2 = Option["verbose"]
match(uri, /^file:\/\/(.*)/, group)
Option["input"] = group[1]
Option["verbose"] = 0
translateMain()
Option["input"] = temp1
Option["verbose"] = temp2
}
function webTranslation(uri, sl, tl, hl) {
system(Option["browser"] " " parameterize("https://translate.google.com/translate?" \
"hl=" hl "&sl=" sl "&tl=" tl "&u=" uri) "&")
}
function translate(text, inline,
i, j, playlist, saveSortedIn) {
if (!getCode(Option["hl"])) {
w("[WARNING] Unknown language code: " Option["hl"] ", fallback to English: en")
Option["hl"] = "en"
} else if (getCode(Option["hl"]) != "auto" && Locale[getCode(Option["hl"])]["rtl"]) {
if (!FriBidi)
w("[WARNING] " Locale[getCode(Option["hl"])]["name"] " is a right-to-left language, but GNU FriBidi is not found on your system.\nText might be displayed incorrectly.")
}
if (!getCode(Option["sl"])) {
w("[WARNING] Unknown source language code: " Option["sl"])
} else if (getCode(Option["sl"]) != "auto" && Locale[getCode(Option["sl"])]["rtl"]) {
if (!FriBidi)
w("[WARNING] " Locale[getCode(Option["sl"])]["name"] " is a right-to-left language, but GNU FriBidi is not found on your system.\nText might be displayed incorrectly.")
}
saveSortedIn = PROCINFO["sorted_in"]
PROCINFO["sorted_in"] = "@ind_num_asc"
for (i in Option["tl"]) {
if (!Option["interactive"])
if (Option["verbose"] && i > 1)
print replicate("─", Option["width"])
if (inline &&
startsWithAny(text, UriSchemes) == "file") {
fileTranslation(text)
} else if (inline &&
startsWithAny(text, UriSchemes) == "http" ||
startsWithAny(text, UriSchemes) == "https") {
webTranslation(text, Option["sl"], Option["tl"][i], Option["hl"])
} else {
print getTranslation(text, Option["sl"], Option["tl"][i], Option["hl"], Option["verbose"], Option["play"], playlist) > Option["output"]
if (Option["play"])
if (Option["player"])
for (j in playlist)
play(playlist[j]["text"], playlist[j]["tl"])
else if (SpeechSynthesizer)
for (j in playlist)
print playlist[j]["text"] | SpeechSynthesizer
}
}
PROCINFO["sorted_in"] = saveSortedIn
}
function translateMain(    i, line) {
if (Option["interactive"])
prompt()
i = 0
while (getline line < Option["input"]) {
if (!Option["interactive"])
if (Option["verbose"] && i++ > 0)
print replicate("═", Option["width"])
if (Option["interactive"]) {
if (line ~ /:(q|quit)/)
exit
else if (line ~ /:(s|source)/)
print Option["sl"]
else if (line ~ /:(t|target)/) {
printf "(" Option["tl"][1]
for (i = 2; i <= length(Option["tl"]); i++)
printf ", " Option["tl"][i]
print ")"
}
else {
translate(line)
if (Option["verbose"]) printf "\n"
}
prompt()
} else
translate(line)
}
}
function initRlwrap() {
Rlwrap = ("rlwrap --version 2>/dev/null" | getline) ? "rlwrap" : ""
}
function prompt(    i, p, temp) {
p = Option["prompt"]
# Roughly following ISO 8601:1988, with the notable exception of "%S", "%t" and "%T".
# GNU libc extensions like "%l", "%s" and "%_*" are not supported.
if (p ~ /%a/) gsub(/%a/, strftime("%a"), p)
if (p ~ /%A/) gsub(/%A/, strftime("%A"), p)
if (p ~ /%b/) gsub(/%b/, strftime("%b"), p)
if (p ~ /%B/) gsub(/%B/, strftime("%B"), p)
if (p ~ /%c/) gsub(/%c/, strftime("%c"), p)
if (p ~ /%C/) gsub(/%C/, strftime("%C"), p)
if (p ~ /%d/) gsub(/%d/, strftime("%d"), p)
if (p ~ /%D/) gsub(/%D/, strftime("%D"), p)
if (p ~ /%e/) gsub(/%e/, strftime("%e"), p)
if (p ~ /%F/) gsub(/%F/, strftime("%F"), p)
if (p ~ /%g/) gsub(/%g/, strftime("%g"), p)
if (p ~ /%G/) gsub(/%G/, strftime("%G"), p)
if (p ~ /%h/) gsub(/%h/, strftime("%h"), p)
if (p ~ /%H/) gsub(/%H/, strftime("%H"), p)
if (p ~ /%I/) gsub(/%I/, strftime("%I"), p)
if (p ~ /%j/) gsub(/%j/, strftime("%j"), p)
if (p ~ /%m/) gsub(/%m/, strftime("%m"), p)
if (p ~ /%M/) gsub(/%M/, strftime("%M"), p)
if (p ~ /%n/) gsub(/%n/, strftime("%n"), p)
if (p ~ /%p/) gsub(/%p/, strftime("%p"), p)
if (p ~ /%r/) gsub(/%r/, strftime("%r"), p)
if (p ~ /%R/) gsub(/%R/, strftime("%R"), p)
if (p ~ /%u/) gsub(/%u/, strftime("%u"), p)
if (p ~ /%U/) gsub(/%U/, strftime("%U"), p)
if (p ~ /%V/) gsub(/%V/, strftime("%V"), p)
if (p ~ /%w/) gsub(/%w/, strftime("%w"), p)
if (p ~ /%W/) gsub(/%W/, strftime("%W"), p)
if (p ~ /%x/) gsub(/%x/, strftime("%x"), p)
if (p ~ /%X/) gsub(/%X/, strftime("%X"), p)
if (p ~ /%y/) gsub(/%y/, strftime("%y"), p)
if (p ~ /%Y/) gsub(/%Y/, strftime("%Y"), p)
if (p ~ /%z/) gsub(/%z/, strftime("%z"), p)
if (p ~ /%Z/) gsub(/%Z/, strftime("%Z"), p)
if (p ~ /%_/)
gsub(/%_/, sprintf(Locale[getCode(Option["hl"])]["message"], ""), p)
if (p ~ /%l/)
gsub(/%l/, Locale[getCode(Option["hl"])]["display"], p)
if (p ~ /%L/)
gsub(/%L/, Locale[getCode(Option["hl"])]["name"], p)
if (p ~ /%S/)
gsub(/%S/, Locale[getCode(Option["sl"])]["name"], p)
# %t : target languages, separated by "+"
if (p ~ /%t/) {
temp = Locale[getCode(Option["tl"][1])]["display"]
for (i = 2; i <= length(Option["tl"]); i++)
temp = temp "+" Locale[getCode(Option["tl"][i])]["display"]
gsub(/%t/, temp, p)
}
# %T : target languages (English names), separated by "+"
if (p ~ /%T/) {
temp = Locale[getCode(Option["tl"][1])]["name"]
for (i = 2; i <= length(Option["tl"]); i++)
temp = temp "+" Locale[getCode(Option["tl"][i])]["name"]
gsub(/%T/, temp, p)
}
# %, : target languages, separated by ","
if (p ~ /%,/) {
temp = Locale[getCode(Option["tl"][1])]["display"]
for (i = 2; i <= length(Option["tl"]); i++)
temp = temp "," Locale[getCode(Option["tl"][i])]["display"]
gsub(/%,/, temp, p)
}
# %< : target languages (English names), separated by ","
if (p ~ /%</) {
temp = Locale[getCode(Option["tl"][1])]["name"]
for (i = 2; i <= length(Option["tl"]); i++)
temp = temp "," Locale[getCode(Option["tl"][i])]["name"]
gsub(/%</, temp, p)
}
# %/ : target languages, separated by "/"
if (p ~ /%\//) {
temp = Locale[getCode(Option["tl"][1])]["display"]
for (i = 2; i <= length(Option["tl"]); i++)
temp = temp "/" Locale[getCode(Option["tl"][i])]["display"]
gsub(/%\//, temp, p)
}
# %? : target languages (English names), separated by "/"
if (p ~ /%\?/) {
temp = Locale[getCode(Option["tl"][1])]["name"]
for (i = 2; i <= length(Option["tl"]); i++)
temp = temp "/" Locale[getCode(Option["tl"][i])]["name"]
gsub(/%\?/, temp, p)
}
printf(AnsiCode["bold"] AnsiCode[tolower(Option["prompt-color"])] p AnsiCode[0] " ", Locale[getCode(Option["sl"])]["display"]) > "/dev/stderr"
}
function initGawk(    group) {
Gawk = "gawk"
GawkVersion = PROCINFO["version"]
split(PROCINFO["version"], group, ".")
if (group[1] < 4) {
e("[ERROR] Oops! Your gawk (version " GawkVersion ") appears to be too old.\nYou need at least gawk 4.0.0 to run this program.")
exit 1
}
}
function preInit() {
initGawk()
initBiDi()
initLocale()
initLocaleDisplay()
initUserLang()
RS = "\n"
ExitCode = 0
Option["debug"] = 0
Option["verbose"] = 1
if (ENVIRON["COLUMNS"])
Option["width"] = ENVIRON["COLUMNS"]
else {
"tput cols 2>/dev/null" |& getline Option["width"]
if (!Option["width"]) Option["width"] = 64
}
Option["browser"] = ENVIRON["BROWSER"]
Option["play"] = 0
Option["player"] = ENVIRON["PLAYER"]
Option["proxy"] = ENVIRON["HTTP_PROXY"] ? ENVIRON["HTTP_PROXY"] : ENVIRON["http_proxy"]
Option["interactive"] = 0
Option["no-rlwrap"] = 0
Option["emacs"] = 0
Option["prompt"] = ENVIRON["TRANS_PS"] ? ENVIRON["TRANS_PS"] : "%s>"
Option["prompt-color"] = ENVIRON["TRANS_PS_COLOR"] ? ENVIRON["TRANS_PS_COLOR"] : "blue"
Option["input"] = ""
Option["output"] = "/dev/stdout"
Option["hl"] = ENVIRON["HOME_LANG"] ? ENVIRON["HOME_LANG"] : UserLang
Option["sl"] = ENVIRON["SOURCE_LANG"] ? ENVIRON["SOURCE_LANG"] : "auto"
Option["tl"][1] = ENVIRON["TARGET_LANG"] ? ENVIRON["TARGET_LANG"] : UserLang
}
function postInit() {
initHttpService()
}
BEGIN {
preInit()
pos = 0
while (ARGV[++pos]) {
match(ARGV[pos], /^-(-?no-op)?$/)
if (RSTART) continue
match(ARGV[pos], /^--?(vers(i(on?)?)?|V)$/)
if (RSTART) {
print getVersion()
print
printf("%-22s%s\n", "gawk (GNU Awk)", PROCINFO["version"])
printf("%s\n", FriBidi ? FriBidi : "fribidi (GNU FriBidi) [NOT INSTALLED]")
printf("%-22s%s\n", "User Language", Locale[getCode(UserLang)]["name"] " (" show(Locale[getCode(UserLang)]["endonym"]) ")")
exit
}
match(ARGV[pos], /^--?(h(e(lp?)?)?|H)$/)
if (RSTART) {
if (ENVIRON["TRANS_MANPAGE"])
system("echo -E \"${TRANS_MANPAGE}\" | " \
"groff -Wall -mtty-char -mandoc -Tutf8 -Dutf8 -rLL=${COLUMNS}n -rLT=${COLUMNS}n | " \
(system("most 2>/dev/null") ?
"less -s -P\"\\ \\Manual page " Command "(1) line %lt (press h for help or q to quit)\"" :
"most -Cs"))
else
print getHelp()
exit
}
match(ARGV[pos], /^--?r(e(f(e(r(e(n(ce?)?)?)?)?)?)?)?$/)
if (RSTART) {
print getReference("endonym")
exit
}
match(ARGV[pos], /^--?(reference-(e(n(g(l(i(sh?)?)?)?)?)?)?|R)$/)
if (RSTART) {
print getReference("name")
exit
}
match(ARGV[pos], /^--?d(e(b(ug?)?)?)?$/)
if (RSTART) {
Option["debug"] = 1
continue
}
match(ARGV[pos], /^--?v(e(r(b(o(se?)?)?)?)?)?$/)
if (RSTART) {
Option["verbose"] = 1
continue
}
match(ARGV[pos], /^--?b(r(i(ef?)?)?)?$/)
if (RSTART) {
Option["verbose"] = 0
continue
}
match(ARGV[pos], /^--?w(i(d(th?)?)?)?(=(.*)?)?$/, group)
if (RSTART) {
Option["width"] = group[4] ?
(group[5] ? group[5] : Option["width"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?browser(=(.*)?)?$/, group)
if (RSTART) {
Option["browser"] = group[1] ?
(group[2] ? group[2] : Option["browser"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?p(l(ay?)?)?$/)
if (RSTART) {
Option["play"] = 1
continue
}
match(ARGV[pos], /^--?player(=(.*)?)?$/, group)
if (RSTART) {
Option["play"] = 1
Option["player"] = group[1] ?
(group[2] ? group[2] : Option["player"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?(proxy|x)(=(.*)?)?$/, group)
if (RSTART) {
Option["proxy"] = group[2] ?
(group[3] ? group[3] : Option["proxy"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?(int(e(r(a(c(t(i(ve?)?)?)?)?)?)?)?|I)$/)
if (RSTART) {
Option["interactive"] = 1
continue
}
match(ARGV[pos], /^--?no-rlwrap/)
if (RSTART) {
Option["no-rlwrap"] = 1
continue
}
match(ARGV[pos], /^--?(emacs|E)$/)
if (RSTART) {
Option["emacs"] = 1
continue
}
match(ARGV[pos], /^--?prompt(=(.*)?)?$/, group)
if (RSTART) {
Option["prompt"] = group[1] ?
(group[2] ? group[2] : Option["prompt"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?prompt-color(=(.*)?)?$/, group)
if (RSTART) {
Option["prompt-color"] = group[1] ?
(group[2] ? group[2] : Option["prompt-color"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?i(n(p(ut?)?)?)?(=(.*)?)?$/, group)
if (RSTART) {
Option["input"] = group[4] ?
(group[5] ? group[5] : Option["input"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?o(u(t(p(ut?)?)?)?)?(=(.*)?)?$/, group)
if (RSTART) {
Option["output"] = group[5] ?
(group[6] ? group[6] : Option["output"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?l(a(ng?)?)?(=(.*)?)?$/, group)
if (RSTART) {
Option["hl"] = group[3] ?
(group[4] ? group[4] : Option["hl"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?s(o(u(r(ce?)?)?)?)?(=(.*)?)?$/, group)
if (RSTART) {
Option["sl"] = group[5] ?
(group[6] ? group[6] : Option["sl"]) :
ARGV[++pos]
continue
}
match(ARGV[pos], /^--?t(a(r(g(et?)?)?)?)?(=(.*)?)?$/, group)
if (RSTART) {
if (group[5]) {
if (group[6]) split(group[6], Option["tl"], "+")
} else
split(ARGV[++pos], Option["tl"], "+")
continue
}
match(ARGV[pos], /^[{([]?([[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]])?)?(:|=)((@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]])?\+)*(@?[[:alpha:]][[:alpha:]][[:alpha:]]?(-[[:alpha:]][[:alpha:]])?)?)[})\]]?$/, group)
if (RSTART) {
if (group[1]) Option["sl"] = group[1]
if (group[4]) split(group[4], Option["tl"], "+")
continue
}
match(ARGV[pos], /^--$/)
if (RSTART) {
++pos
break
}
break
}
postInit()
if (Option["interactive"] && !Option["no-rlwrap"]) {
initRlwrap()
if (Rlwrap && (ENVIRON["TRANS_PROGRAM"] || fileExists(EntryPoint))) {
command = Rlwrap " " Gawk " " (ENVIRON["TRANS_PROGRAM"] ?
"\"${TRANS_PROGRAM}\"" :
"-f " EntryPoint) " -" \
" -no-rlwrap"
for (i = 1; i < length(ARGV); i++)
if (ARGV[i])
command = command " " parameterize(ARGV[i])
if (!system(command))
exit
else
;
} else
;
} else if (!Option["interactive"] && !Option["no-rlwrap"] && Option["emacs"]) {
Emacs = "emacs"
if (ENVIRON["TRANS_PROGRAM"] || fileExists(EntryPoint)) {
params = ""
for (i = 1; i < length(ARGV); i++)
if (ARGV[i])
params = params " " (parameterize(ARGV[i], "\""))
if (ENVIRON["TRANS_PROGRAM"]) {
el = "(progn (setq trans-program (getenv \"TRANS_PROGRAM\")) " \
"(setq explicit-shell-file-name \"" Gawk "\") " \
"(setq explicit-" Gawk "-args (cons trans-program '(\"-\" \"-I\" \"-no-rlwrap\"" params "))) " \
"(command-execute 'shell) (rename-buffer \"" Name "\"))"
} else {
el = "(progn (setq explicit-shell-file-name \"" Gawk "\") " \
"(setq explicit-" Gawk "-args '(\"-f\" \"" EntryPoint "\" \"--\" \"-I\" \"-no-rlwrap\"" params ")) " \
"(command-execute 'shell) (rename-buffer \"" Name "\"))"
}
command = Emacs " --eval " parameterize(el)
if (!system(command))
exit
else
Option["interactive"] = 1
} else
Option["interactive"] = 1
}
if (Option["play"]) {
if (!Option["player"]) {
initAudioPlayer()
Option["player"] = AudioPlayer ? AudioPlayer : Option["player"]
if (!Option["player"])
initSpeechSynthesizer()
}
if (!Option["player"] && !SpeechSynthesizer) {
w("[WARNING] No available audio player or speech synthesizer is found.")
Option["play"] = 0
}
}
if (Option["interactive"]) {
print AnsiCode["bold"] AnsiCode[tolower(Option["prompt-color"])] getVersion() AnsiCode[0] > "/dev/stderr"
print AnsiCode[tolower(Option["prompt-color"])] "(:q to quit)" AnsiCode[0] > "/dev/stderr"
}
if (!Option["browser"]) {
"xdg-mime query default text/html 2>/dev/null" |& getline Option["browser"]
match(Option["browser"], "(.*).desktop$", group)
Option["browser"] = group[1]
}
if (pos < ARGC) {
for (i = pos; i < ARGC; i++) {
if (Option["verbose"] && i > pos)
print replicate("═", Option["width"])
translate(ARGV[i], 1)
}
} else {
if (!Option["input"]) Option["input"] = "/dev/stdin"
}
if (Option["input"])
translateMain()
exit ExitCode
}
EOF
export TRANS_PROGRAM
read -r -d '' TRANS_MANPAGE << 'EOF'
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "TRANS" "1" "September 2014" "0.8.21" "TRANS MANUAL"
.
.SH "NAME"
\fBtrans\fR \- Google Translate served as a command\-line tool
.
.SH "SYNOPSIS"
\fBtrans\fR [options] [source]:[target] [\fItext\fR] \.\.\.
.
.P
\fBtrans\fR [options] [source]:[target1]+[target2]+\.\.\. [\fItext\fR] \.\.\.
.
.SH "DESCRIPTION"
This tool uses Google Translate to translate input text into any language\.
.
.P
Each command\-line argument which is not an option will be treated as \fItext\fR to be translated\.
.
.P
When any non\-option argument is given, the program will translate it\. Also, if an input file is specified by an option, the program will then translate from that file\.
.
.P
When every argument is an option (i\.e\. no \fItext\fR is passed via arguments), the program will read the text to be translated from standard input (unless an input file is specified explicitly by an option)\.
.
.SH "OPTIONS"
.
.SS "\-, \-no\-op"
This option effectively does nothing at all\.
.
.SS "\-V, \-version"
Print version and exit\.
.
.SS "\-H, \-h, \-help"
Show this manual, or print this help message and exit\.
.
.SS "\-r, \-reference"
Print a list of languages (displayed in endonyms) and their ISO 639 codes for reference, and exit\.
.
.SS "\-R, \-reference\-english"
Print a list of languages (displayed in English names) and their ISO 639 codes for reference, and exit\.
.
.SS "\-v, \-verbose"
Verbose mode\. (default)
.
.P
Show the most relevant translation, then its phonetic notation (if any), then its alternative translations (if any), then its definition in dictionary (if it is a word),
.
.P
This option is unnecessary since verbose mode is enabled by default\.
.
.SS "\-b, \-brief"
Brief mode\.
.
.P
Show the most relevant translation only, or its phonetic notation only\. Nothing more\.
.
.SS "\-w [num], \-width [num]"
Specify the screen width for padding when displaying right\-to\-left languages\.
.
.P
This option overrides the setting of environment variable \fBCOLUMNS\fR\.
.
.SS "\-browser [program]"
Specify the web browser to use\.
.
.P
This option overrides the setting of environment variable \fBBROWSER\fR\.
.
.SS "\-p, \-play"
Listen to the translation\.
.
.P
When used in verbose mode, you will hear a statement like "Translations of text: wénběn"\. When used in brief mode, you will hear only the actual translation: "wénběn" for example\.
.
.P
You must have one of supported audio players (\fBmplayer\fR or \fBmpg123\fR) installed for streaming from the Google Text\-to\-Speech engine\. Otherwise, a local speech synthesizer can be used instead (\fBsay\fR on Mac OS X, \fBespeak\fR on Linux and other platforms)\.
.
.SS "\-player [program]"
Specify the command\-line audio player to use, and listen to the translation\.
.
.P
Option \fB\-play\fR will try to use \fBmplayer\fR or \fBmpg123\fR by default, since these players are known to work for streaming URLs\. Not all command\-line audio players can work this way\. Use this option only when you have your own preference\.
.
.P
This option overrides the setting of environment variable \fBPLAYER\fR\.
.
.SS "\-x [proxy], \-proxy [proxy]"
Use proxy on given port\. String format:
.
.IP "" 4
.
.nf

[PROTOCOL://]HOST[:PORT]
.
.fi
.
.IP "" 0
.
.P
This option overrides the setting of environment variables \fBHTTP_PROXY\fR and \fBhttp_proxy\fR\.
.
.SS "\-I, \-interactive"
Start an interactive shell, invoking \fBrlwrap\fR whenever possible (unless \fB\-no\-rlwrap\fR is specified)\.
.
.SS "\-no\-rlwrap"
Don\'t invoke \fBrlwrap\fR when starting an interactive shell with \fB\-I\fR\.
.
.P
This option is useful when the terminal type is not supported by \fBrlwrap\fR (e\.g\. Emacs)\.
.
.SS "\-E, \-emacs"
Start an interactive shell within GNU Emacs, invoking \fBemacs\fR\.
.
.P
This option does not need to, and cannot be used along with \fB\-I\fR or \fB\-no\-rlwrap\fR\.
.
.SS "\-prompt [prompt_string]"
Customize your prompt string in the interactive shell\.
.
.P
Format specifiers preceded by a "%" character are supported\. When these format specifiers appear in the prompt string, they will be replaced by the following:
.
.IP "" 4
.
.nf

%_ : prompt message (e\.g\. "Translations of ") in your home language
%l : name of your home language
%L : English name of your home language
%s : name of source language
%S : English name of source language
%t : names of target languages, separated by "+"
%T : English names of target languages, separated by "+"
%, : names of target languages, separated by ","
%< : English names of target languages, separated by ","
%/ : names of target languages, separated by "/"
%? : English names of target languages, separated by "/"
%% : a literal "%"
.
.fi
.
.IP "" 0
.
.P
Furthermore, some format specifiers derived from C Library strftime() and supported by gawk are also supported here:
.
.IP "" 4
.
.nf

%a : the locale\'s abbreviated weekday name
%A : the locale\'s full weekday name
%b : the locale\'s abbreviated month name
%B : the locale\'s full month name
%c : the locale\'s appropriate date and time representation
%C : the century number of the current year (00\-99)
%d : the day of the month (01\-31)
%D : same as \'%m/%d/%y\'
%e : the day of the month (1\-31), padded with a space if it is only one digit
%F : same as \'%Y\-%m\-%d\' (the ISO 8601 date format)
%g : the year modulo 100 of the ISO 8601 week number (00–99)
%G : the full year of the ISO week number
%h : same as \'%b\'
%H : the hour (24\-hour clock) (00–23)
%I : the hour (12\-hour clock) (01\-12)
%j : the day of the year (001–366)
%m : the month (01–12)
%M : the minute (00–59)
%n : a newline character (ASCII LF)
%p : the locale\'s equivalent of the AM/PM designations associated with a 12\-hour clock
%r : the locale\'s 12\-hour clock time
%R : same as \'%H:%M\'
%u : the weekday (Monday is day one) (1–7)
%U : the week number of the year (Sunday as the first day of the week) (00–53)
%V : the week number of the year (Monday as the first day of the week) (01–53)
%w : the weekday (Sunday is day zero) (0–6)
%W : the week number of the year (Monday as the first day of the week) (00–53)
%x : the locale\'s appropriate date representation
%X : the locale\'s appropriate time representation
%y : the year modulo 100 (00–99)
%Y : the full year
%z : the timezone offset in a +HHMM format
%Z : the time zone name or abbreviation
.
.fi
.
.IP "" 0
.
.P
This option overrides the setting of environment variable \fBTRANS_PS\fR\.
.
.SS "\-prompt\-color [color_code]"
Customize your prompt color in the interactive shell\.
.
.P
These color codes (case\-insensitive) are available: (remember to quote them when having a space!)
.
.IP "" 4
.
.nf

default
black
white
red
light red
green
light green
yellow
light yellow
blue
light blue
magenta
light magenta
cyan
light cyan
gray
dark gray
.
.fi
.
.IP "" 0
.
.P
This option overrides the setting of environment variable \fBTRANS_PS_COLOR\fR\.
.
.SS "\-i [file], \-input [file]"
Specify the input file name\.
.
.P
Source text to be translated will be read from that file (instead of standard input)\.
.
.SS "\-o [file], \-output [file]"
Specify the output file name\.
.
.P
Translations will be written to that file (instead of standard output)\.
.
.SS "\-l [code], \-lang [code]"
Specify your own, native language ("home/host language")\. The code value must be the ISO 639 code of a supported language\.
.
.P
This option is optional\. When omitted, the relevant setting of environment variables will be used; when no valid setting is found, English will be used\.
.
.P
This option only affects the display in verbose mode (anything other than the source language and the target language will be displayed in your home language)\. This option has no effect in brief mode\.
.
.P
This option overrides the setting of environment variables \fBLC_TYPE\fR, \fBLANG\fR and \fBHOME_LANG\fR\.
.
.SS "\-s [code], \-source [code]"
Specify the source language (language of the original text)\. The code value must be the ISO 639 code of a supported language\.
.
.P
This option is optional\. When omitted, the relevant setting of environment variable will be used; when no valid setting is found, the language of the original text will be identified automatically (with a possibility of misidentification)\.
.
.P
This option overrides the setting of environment variable \fBSOURCE_LANG\fR\.
.
.SS "\-t [codes], \-target [codes]"
Specify the target language(s) (language(s) of the translated text)\. The code value(s) must be the ISO 639 code(s) of supported language(s)\.
.
.P
This option is optional\. When omitted, the relevant setting of environment variables will be used; when no valid setting is found, everything will be translated into English\.
.
.P
More than one target language can be specified at the same time, concatenated by plus sign "+"\.
.
.P
This option overrides the setting of environment variables \fBLC_TYPE\fR, \fBLANG\fR and \fBTARGET_LANG\fR\.
.
.SS "\-\-"
End\-of\-options\.
.
.P
All arguments after this option are treated as \fItext\fR to be translated\.
.
.SH "SHORTCUT"
A simpler alternative way to specify the source language and the target language(s) for translation is to use a shortcut formatted string:
.
.IP "\(bu" 4
[source]:[target]
.
.IP "\(bu" 4
[source]:[target1]+[target2]+\.\.\.
.
.IP "\(bu" 4
[source]=[target]
.
.IP "\(bu" 4
[source]=[target1]+[target2]+\.\.\.
.
.IP "" 0
.
.P
Delimiter ":" and "=" can be used interchangeably\.
.
.P
Both values of source and target must be ISO 639 codes of supported languages\.
.
.P
Either source or target can be omitted, but the delimiter character must be kept\.
.
.SH "CODE LIST"
.
.nf

┌───────────────────────┬──────────────────────┬─────────────────┐
│ Afrikaans     \- af    │ Greek          \- el  │ Mongolian  \- mn │
│ Albanian      \- sq    │ Gujarati       \- gu  │ Nepali     \- ne │
│ Arabic        \- ar    │ Haitian Creole \- ht  │ Norwegian  \- no │
│ Armenian      \- hy    │ Hausa          \- ha  │ Persian    \- fa │
│ Azerbaijani   \- az    │ Hebrew         \- he  │ Polish     \- pl │
│ Basque        \- eu    │ Hindi          \- hi  │ Portuguese \- pt │
│ Belarusian    \- be    │ Hmong          \- hmn │ Punjabi    \- pa │
│ Bengali       \- bn    │ Hungarian      \- hu  │ Romanian   \- ro │
│ Bosnian       \- bs    │ Icelandic      \- is  │ Russian    \- ru │
│ Bulgarian     \- bg    │ Igbo           \- ig  │ Serbian    \- sr │
│ Catalan       \- ca    │ Indonesian     \- id  │ Slovak     \- sk │
│ Cebuano       \- ceb   │ Irish          \- ga  │ Slovenian  \- sl │
│ Chinese Simp\. \- zh\-CN │ Italian        \- it  │ Somali     \- so │
│ Chinese Trad\. \- zh\-TW │ Japanese       \- ja  │ Spanish    \- es │
│ Croatian      \- hr    │ Javanese       \- jv  │ Swahili    \- sw │
│ Czech         \- cs    │ Kannada        \- kn  │ Swedish    \- sv │
│ Danish        \- da    │ Khmer          \- km  │ Tamil      \- ta │
│ Dutch         \- nl    │ Korean         \- ko  │ Telugu     \- te │
│ English       \- en    │ Lao            \- lo  │ Thai       \- th │
│ Esperanto     \- eo    │ Latin          \- la  │ Turkish    \- tr │
│ Estonian      \- et    │ Latvian        \- lv  │ Ukrainian  \- uk │
│ Filipino      \- tl    │ Lithuanian     \- lt  │ Urdu       \- ur │
│ Finnish       \- fi    │ Macedonian     \- mk  │ Vietnamese \- vi │
│ French        \- fr    │ Malay          \- ms  │ Welsh      \- cy │
│ Galician      \- gl    │ Maltese        \- mt  │ Yiddish    \- yi │
│ Georgian      \- ka    │ Maori          \- mi  │ Yoruba     \- yo │
│ German        \- de    │ Marathi        \- mr  │ Zulu       \- zu │
└───────────────────────┴──────────────────────┴─────────────────┘
.
.fi
.
.SH "ERRORS"
\fBtrans\fR returns 0 if the text was translated successfully, otherwise non\-zero\.
.
.SH "AUTHORS"
Mort Yao <\fIsoi@mort\.ninja\fR>
.
.SH "REPORTING BUGS"
\fIhttps://github\.com/soimort/translate\-shell/issues\fR
EOF
export TRANS_MANPAGE
export COLUMNS
gawk "$TRANS_PROGRAM" - "$@"
