Refactor static methods as functions in util module

This commit is contained in:
Guthrie McAfee Armstrong 2022-06-04 20:39:25 -04:00
parent 42a1f01e6f
commit 17ff3a8795
No known key found for this signature in database
GPG key ID: ED4DAE89F08242D2
11 changed files with 311 additions and 341 deletions

View file

@ -1,11 +1,6 @@
import os
import sys
import appdirs
CONTAINER_NAME = "dangerzone.rocks/dangerzone"
APPDATA_PATH = appdirs.user_config_dir("dangerzone")
if "DANGERZONE_MODE" in os.environ:
mode = os.environ["DANGERZONE_MODE"]
else:

View file

@ -7,6 +7,7 @@ from colorama import Fore, Style
from .global_common import GlobalCommon
from .common import Common
from .container import convert
import dangerzone.util as dzutil
def print_header(s):
@ -73,14 +74,14 @@ def cli_main(output_filename, ocr_lang, filename):
# Validate OCR language
if ocr_lang:
valid = False
for lang in global_common.ocr_languages:
if global_common.ocr_languages[lang] == ocr_lang:
for lang in dzutil.OCR_LANGUAGES:
if dzutil.OCR_LANGUAGES[lang] == ocr_lang:
valid = True
break
if not valid:
click.echo("Invalid OCR language code. Valid language codes:")
for lang in global_common.ocr_languages:
click.echo(f"{global_common.ocr_languages[lang]}: {lang}")
for lang in dzutil.OCR_LANGUAGES:
click.echo(f"{dzutil.OCR_LANGUAGES[lang]}: {lang}")
return
# Ensure container is installed

View file

@ -1,10 +1,3 @@
import os
import stat
import platform
import tempfile
import appdirs
class Common(object):
"""
The Common class is a singleton of shared functionality throughout an open dangerzone window

View file

@ -1,4 +1,3 @@
import platform
import subprocess
import pipes
import shutil
@ -6,23 +5,7 @@ import os
import tempfile
import appdirs
# What container tech is used for this platform?
if platform.system() == "Linux":
container_tech = "podman"
else:
# Windows, Darwin, and unknown use docker for now, dangerzone-vm eventually
container_tech = "docker"
# Define startupinfo for subprocesses
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
startupinfo = None
# Name of the dangerzone container
container_name = "dangerzone.rocks/dangerzone"
import dangerzone.util as dzutil
def exec(args, stdout_callback=None):
@ -30,13 +13,13 @@ def exec(args, stdout_callback=None):
print("> " + args_str)
with subprocess.Popen(
args,
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
bufsize=1,
universal_newlines=True,
startupinfo=startupinfo,
args,
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
bufsize=1,
universal_newlines=True,
startupinfo=dzutil.get_subprocess_startupinfo(),
) as p:
if stdout_callback:
for line in p.stdout:
@ -47,12 +30,7 @@ def exec(args, stdout_callback=None):
def exec_container(args, stdout_callback=None):
if container_tech == "podman":
container_runtime = shutil.which("podman")
else:
container_runtime = shutil.which("docker")
args = [container_runtime] + args
args = [dzutil.CONTAINER_RUNTIME] + args
return exec(args, stdout_callback)
@ -80,18 +58,18 @@ def convert(input_filename, output_filename, ocr_lang, stdout_callback):
# Convert document to pixels
args = (
["run", "--network", "none"]
+ platform_args
+ [
"-v",
f"{input_filename}:/tmp/input_file",
"-v",
f"{pixel_dir}:/dangerzone",
container_name,
"/usr/bin/python3",
"/usr/local/bin/dangerzone.py",
"document-to-pixels",
]
["run", "--network", "none"]
+ platform_args
+ [
"-v",
f"{input_filename}:/tmp/input_file",
"-v",
f"{pixel_dir}:/dangerzone",
dzutil.CONTAINER_NAME,
"/usr/bin/python3",
"/usr/local/bin/dangerzone.py",
"document-to-pixels",
]
)
ret = exec_container(args, stdout_callback)
if ret != 0:
@ -101,22 +79,22 @@ def convert(input_filename, output_filename, ocr_lang, stdout_callback):
# Convert pixels to safe PDF
args = (
["run", "--network", "none"]
+ platform_args
+ [
"-v",
f"{pixel_dir}:/dangerzone",
"-v",
f"{safe_dir}:/safezone",
"-e",
f"OCR={ocr}",
"-e",
f"OCR_LANGUAGE={ocr_lang}",
container_name,
"/usr/bin/python3",
"/usr/local/bin/dangerzone.py",
"pixels-to-pdf",
]
["run", "--network", "none"]
+ platform_args
+ [
"-v",
f"{pixel_dir}:/dangerzone",
"-v",
f"{safe_dir}:/safezone",
"-e",
f"OCR={ocr}",
"-e",
f"OCR_LANGUAGE={ocr_lang}",
dzutil.CONTAINER_NAME,
"/usr/bin/python3",
"/usr/local/bin/dangerzone.py",
"pixels-to-pdf",
]
)
ret = exec_container(args, stdout_callback)
if ret != 0:
@ -139,7 +117,6 @@ def convert(input_filename, output_filename, ocr_lang, stdout_callback):
return success
# From global_common:
# def validate_convert_to_pixel_output(self, common, output):

View file

@ -1,15 +1,11 @@
import sys
import os
import inspect
import platform
import subprocess
import shutil
import gzip
import colorama
from colorama import Fore, Back, Style
from . import CONTAINER_NAME
from .settings import Settings
import dangerzone
from dangerzone.settings import Settings
import dangerzone.util as dzutil
class GlobalCommon(object):
@ -18,182 +14,11 @@ class GlobalCommon(object):
"""
def __init__(self):
# Version
try:
with open(self.get_resource_path("version.txt")) as f:
self.version = f.read().strip()
except FileNotFoundError:
# In dev mode, in Windows, get_resource_path doesn't work properly for the container, but luckily
# it doesn't need to know the version
self.version = "unknown"
self.version = dzutil.VERSION
# Initialize terminal colors
colorama.init(autoreset=True)
# Languages supported by tesseract
self.ocr_languages = {
"Afrikaans": "ar",
"Albanian": "sqi",
"Amharic": "amh",
"Arabic": "ara",
"Arabic script": "Arabic",
"Armenian": "hye",
"Armenian script": "Armenian",
"Assamese": "asm",
"Azerbaijani": "aze",
"Azerbaijani (Cyrillic)": "aze_cyrl",
"Basque": "eus",
"Belarusian": "bel",
"Bengali": "ben",
"Bengali script": "Bengali",
"Bosnian": "bos",
"Breton": "bre",
"Bulgarian": "bul",
"Burmese": "mya",
"Canadian Aboriginal script": "Canadian_Aboriginal",
"Catalan": "cat",
"Cebuano": "ceb",
"Cherokee": "chr",
"Cherokee script": "Cherokee",
"Chinese - Simplified": "chi_sim",
"Chinese - Simplified (vertical)": "chi_sim_vert",
"Chinese - Traditional": "chi_tra",
"Chinese - Traditional (vertical)": "chi_tra_vert",
"Corsican": "cos",
"Croatian": "hrv",
"Cyrillic script": "Cyrillic",
"Czech": "ces",
"Danish": "dan",
"Devanagari script": "Devanagari",
"Divehi": "div",
"Dutch": "nld",
"Dzongkha": "dzo",
"English": "eng",
"English, Middle (1100-1500)": "enm",
"Esperanto": "epo",
"Estonian": "est",
"Ethiopic script": "Ethiopic",
"Faroese": "fao",
"Filipino": "fil",
"Finnish": "fin",
"Fraktur script": "Fraktur",
"Frankish": "frk",
"French": "fra",
"French, Middle (ca.1400-1600)": "frm",
"Frisian (Western)": "fry",
"Gaelic (Scots)": "gla",
"Galician": "glg",
"Georgian": "kat",
"Georgian script": "Georgian",
"German": "deu",
"Greek": "ell",
"Greek script": "Greek",
"Gujarati": "guj",
"Gujarati script": "Gujarati",
"Gurmukhi script": "Gurmukhi",
"Hangul script": "Hangul",
"Hangul (vertical) script": "Hangul_vert",
"Han - Simplified script": "HanS",
"Han - Simplified (vertical) script": "HanS_vert",
"Han - Traditional script": "HanT",
"Han - Traditional (vertical) script": "HanT_vert",
"Hatian": "hat",
"Hebrew": "heb",
"Hebrew script": "Hebrew",
"Hindi": "hin",
"Hungarian": "hun",
"Icelandic": "isl",
"Indonesian": "ind",
"Inuktitut": "iku",
"Irish": "gle",
"Italian": "ita",
"Italian - Old": "ita_old",
"Japanese": "jpn",
"Japanese script": "Japanese",
"Japanese (vertical)": "jpn_vert",
"Japanese (vertical) script": "Japanese_vert",
"Javanese": "jav",
"Kannada": "kan",
"Kannada script": "Kannada",
"Kazakh": "kaz",
"Khmer": "khm",
"Khmer script": "Khmer",
"Korean": "kor",
"Korean (vertical)": "kor_vert",
"Kurdish (Arabic)": "kur_ara",
"Kyrgyz": "kir",
"Lao": "lao",
"Lao script": "Lao",
"Latin": "lat",
"Latin script": "Latin",
"Latvian": "lav",
"Lithuanian": "lit",
"Luxembourgish": "ltz",
"Macedonian": "mkd",
"Malayalam": "mal",
"Malayalam script": "Malayalam",
"Malay": "msa",
"Maltese": "mlt",
"Maori": "mri",
"Marathi": "mar",
"Mongolian": "mon",
"Myanmar script": "Myanmar",
"Nepali": "nep",
"Norwegian": "nor",
"Occitan (post 1500)": "oci",
"Old Georgian": "kat_old",
"Oriya (Odia) script": "Oriya",
"Oriya": "ori",
"Pashto": "pus",
"Persian": "fas",
"Polish": "pol",
"Portuguese": "por",
"Punjabi": "pan",
"Quechua": "que",
"Romanian": "ron",
"Russian": "rus",
"Sanskrit": "san",
"script and orientation": "osd",
"Serbian (Latin)": "srp_latn",
"Serbian": "srp",
"Sindhi": "snd",
"Sinhala script": "Sinhala",
"Sinhala": "sin",
"Slovakian": "slk",
"Slovenian": "slv",
"Spanish, Castilian - Old": "spa_old",
"Spanish": "spa",
"Sundanese": "sun",
"Swahili": "swa",
"Swedish": "swe",
"Syriac script": "Syriac",
"Syriac": "syr",
"Tajik": "tgk",
"Tamil script": "Tamil",
"Tamil": "tam",
"Tatar": "tat",
"Telugu script": "Telugu",
"Telugu": "tel",
"Thaana script": "Thaana",
"Thai script": "Thai",
"Thai": "tha",
"Tibetan script": "Tibetan",
"Tibetan Standard": "bod",
"Tigrinya": "tir",
"Tonga": "ton",
"Turkish": "tur",
"Ukrainian": "ukr",
"Urdu": "urd",
"Uyghur": "uig",
"Uzbek (Cyrillic)": "uzb_cyrl",
"Uzbek": "uzb",
"Vietnamese script": "Vietnamese",
"Vietnamese": "vie",
"Welsh": "cym",
"Yiddish": "yid",
"Yoruba": "yor",
}
# Load settings
self.settings = Settings()
@ -339,9 +164,9 @@ class GlobalCommon(object):
+ ""
)
print(Back.BLACK + Fore.YELLOW + Style.DIM + "│ │")
left_spaces = (15 - len(self.version) - 1) // 2
left_spaces = (15 - len(dzutil.VERSION) - 1) // 2
right_spaces = left_spaces
if left_spaces + len(self.version) + 1 + right_spaces < 15:
if left_spaces + len(dzutil.VERSION) + 1 + right_spaces < 15:
right_spaces += 1
print(
Back.BLACK
@ -352,7 +177,7 @@ class GlobalCommon(object):
+ Back.BLACK
+ Fore.LIGHTWHITE_EX
+ Style.BRIGHT
+ f"{' '*left_spaces}Dangerzone v{self.version}{' '*right_spaces}"
+ f"{' '*left_spaces}Dangerzone v{dzutil.VERSION}{' '*right_spaces}"
+ Fore.YELLOW
+ Style.DIM
+ ""
@ -372,48 +197,6 @@ class GlobalCommon(object):
)
print(Back.BLACK + Fore.YELLOW + Style.DIM + "╰──────────────────────────╯")
@staticmethod
def get_container_runtime():
if platform.system() == "Linux":
return shutil.which("podman")
else:
return shutil.which("docker")
@staticmethod
def get_resource_path(filename):
if getattr(sys, "dangerzone_dev", False):
# Look for resources directory relative to python file
prefix = os.path.join(
os.path.dirname(
os.path.dirname(
os.path.abspath(inspect.getfile(inspect.currentframe()))
)
),
"share",
)
else:
if platform.system() == "Darwin":
prefix = os.path.join(
os.path.dirname(os.path.dirname(sys.executable)), "Resources/share"
)
elif platform.system() == "Linux":
prefix = os.path.join(sys.prefix, "share", "dangerzone")
else:
# Windows
prefix = os.path.join(os.path.dirname(sys.executable), "share")
resource_path = os.path.join(prefix, filename)
return resource_path
@staticmethod
def get_subprocess_startupinfo():
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
return startupinfo
else:
return None
@staticmethod
def install_container():
"""
@ -426,13 +209,13 @@ class GlobalCommon(object):
print("Installing Dangerzone container image...")
p = subprocess.Popen(
[GlobalCommon.get_container_runtime(), "load"],
[dzutil.CONTAINER_RUNTIME, "load"],
stdin=subprocess.PIPE,
startupinfo=GlobalCommon.get_subprocess_startupinfo(),
startupinfo=dzutil.get_subprocess_startupinfo(),
)
chunk_size = 10240
compressed_container_path = GlobalCommon.get_resource_path("container.tar.gz")
compressed_container_path = dzutil.get_resource_path("container.tar.gz")
with gzip.open(compressed_container_path) as f:
while True:
chunk = f.read(chunk_size)
@ -455,22 +238,22 @@ class GlobalCommon(object):
See if the podman container is installed. Linux only.
"""
# Get the image id
with open(GlobalCommon.get_resource_path("image-id.txt")) as f:
with open(dzutil.get_resource_path("image-id.txt")) as f:
expected_image_id = f.read().strip()
# See if this image is already installed
installed = False
found_image_id = subprocess.check_output(
[
GlobalCommon.get_container_runtime(),
dzutil.CONTAINER_RUNTIME,
"image",
"list",
"--format",
"{{.ID}}",
CONTAINER_NAME,
dangerzone.util.CONTAINER_NAME,
],
text=True,
startupinfo=GlobalCommon.get_subprocess_startupinfo(),
startupinfo=dzutil.get_subprocess_startupinfo(),
)
found_image_id = found_image_id.strip()
@ -483,8 +266,8 @@ class GlobalCommon(object):
try:
subprocess.check_output(
[GlobalCommon.get_container_runtime(), "rmi", "--force", found_image_id],
startupinfo=GlobalCommon.get_subprocess_startupinfo(),
[dzutil.CONTAINER_RUNTIME, "rmi", "--force", found_image_id],
startupinfo=dzutil.get_subprocess_startupinfo(),
)
except:
print("Couldn't delete old container image, so leaving it there")

View file

@ -53,7 +53,7 @@ def gui_main(filename):
# Create the system tray
# noinspection PyUnusedLocal
systray = SysTray(global_common, gui_common, app)
systray = SysTray(gui_common, app)
closed_windows = {}
windows = {}

View file

@ -4,17 +4,14 @@ import subprocess
import shlex
import pipes
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtGui import QIcon
from colorama import Fore
from . import Application
from ..global_common import GlobalCommon
import dangerzone.util as dzutil
if platform.system() == "Darwin":
import plistlib
elif platform.system() == "Linux":
import grp
import getpass
if platform.system() == "Linux":
from xdg.DesktopEntry import DesktopEntry # type: ignore
@ -39,14 +36,6 @@ class GuiCommon(object):
# Are we done waiting (for Docker Desktop to be installed, or for container to install)
self.is_waiting_finished = False
@staticmethod
def get_window_icon():
if platform.system() == "Windows":
path = GlobalCommon.get_resource_path("dangerzone.ico")
else:
path = GlobalCommon.get_resource_path("icon.png")
return QtGui.QIcon(path)
def open_pdf_viewer(self, filename: str):
if platform.system() == "Darwin":
# Open in Preview
@ -118,7 +107,7 @@ class Alert(QtWidgets.QDialog):
):
super(Alert, self).__init__()
self.setWindowTitle("dangerzone")
self.setWindowIcon(GuiCommon.get_window_icon())
self.setWindowIcon(QIcon(dzutil.WINDOW_ICON_PATH))
self.setModal(True)
flags = ( # TODO Mypy: unsupported left operand type for | ("WindowType")
@ -133,7 +122,7 @@ class Alert(QtWidgets.QDialog):
logo = QtWidgets.QLabel()
logo.setPixmap(
QtGui.QPixmap.fromImage(
QtGui.QImage(GlobalCommon.get_resource_path("icon.png"))
QtGui.QImage(dzutil.get_resource_path("icon.png"))
)
)

View file

@ -5,8 +5,10 @@ import subprocess
import json
import shutil
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtGui import QIcon
from colorama import Style, Fore
import dangerzone.util as dzutil
from . import GuiCommon
from ..common import Common
from ..container import convert
@ -24,7 +26,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.common = Common()
self.setWindowTitle("Dangerzone")
self.setWindowIcon(self.gui_common.get_window_icon())
self.setWindowIcon(QIcon(dzutil.WINDOW_ICON_PATH))
self.setMinimumWidth(600)
self.setMinimumHeight(400)
@ -33,7 +35,7 @@ class MainWindow(QtWidgets.QMainWindow):
logo = QtWidgets.QLabel()
logo.setPixmap(
QtGui.QPixmap.fromImage(
QtGui.QImage(self.global_common.get_resource_path("icon.png"))
QtGui.QImage(dzutil.get_resource_path("icon.png"))
)
)
header_label = QtWidgets.QLabel("dangerzone")
@ -165,7 +167,7 @@ class WaitingWidget(QtWidgets.QWidget):
[container_runtime, "image", "ls"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
startupinfo=self.global_common.get_subprocess_startupinfo(),
startupinfo=dzutil.get_subprocess_startupinfo(),
) as p:
p.communicate()
if p.returncode != 0:
@ -361,8 +363,8 @@ class SettingsWidget(QtWidgets.QWidget):
# OCR document
self.ocr_checkbox = QtWidgets.QCheckBox("OCR document, language")
self.ocr_combobox = QtWidgets.QComboBox()
for k in self.global_common.ocr_languages:
self.ocr_combobox.addItem(k, self.global_common.ocr_languages[k])
for k in dzutil.OCR_LANGUAGES:
self.ocr_combobox.addItem(k, dzutil.OCR_LANGUAGES[k])
ocr_layout = QtWidgets.QHBoxLayout()
ocr_layout.addWidget(self.ocr_checkbox)
ocr_layout.addWidget(self.ocr_combobox)
@ -499,7 +501,7 @@ class ConvertThread(QtCore.QThread):
def run(self):
if self.global_common.settings.get("ocr"):
ocr_lang = self.global_common.ocr_languages[
ocr_lang = dzutil.OCR_LANGUAGES[
self.global_common.settings.get("ocr_language")
]
else:
@ -557,7 +559,7 @@ class ConvertWidget(QtWidgets.QWidget):
self.error_image = QtWidgets.QLabel()
self.error_image.setPixmap(
QtGui.QPixmap.fromImage(
QtGui.QImage(self.global_common.get_resource_path("error.png"))
QtGui.QImage(dzutil.get_resource_path("error.png"))
)
)
self.error_image.hide()
@ -616,7 +618,7 @@ class ConvertWidget(QtWidgets.QWidget):
subprocess.Popen(
f'explorer.exe /select,"{dest_filename_windows}"',
shell=True,
startupinfo=self.global_common.get_subprocess_startupinfo(),
startupinfo=dzutil.get_subprocess_startupinfo(),
)
# Open

View file

@ -1,19 +1,19 @@
from PySide6 import QtWidgets
from PySide6.QtGui import QIcon
from dangerzone.global_common import GlobalCommon
from dangerzone.gui import GuiCommon, Application
import dangerzone.util as dzutil
class SysTray(QtWidgets.QSystemTrayIcon):
def __init__(
self, global_common: GlobalCommon, gui_common: GuiCommon, app: Application
self, gui_common: GuiCommon, app: Application
):
super(SysTray, self).__init__()
self.global_common = global_common
self.gui_common = gui_common
self.app = app
self.setIcon(self.gui_common.get_window_icon())
self.setIcon(QIcon(dzutil.WINDOW_ICON_PATH))
menu = QtWidgets.QMenu()

View file

@ -1,12 +1,12 @@
import os
import json
from dangerzone import APPDATA_PATH
import dangerzone.util as dzutil
class Settings:
def __init__(self):
self.settings_filename = os.path.join(APPDATA_PATH, "settings.json")
self.settings_filename = os.path.join(dzutil.APPDATA_PATH, "settings.json")
self.default_settings = {
"save": True,
"ocr": True,
@ -47,6 +47,6 @@ class Settings:
self.save()
def save(self):
os.makedirs(APPDATA_PATH, exist_ok=True)
os.makedirs(dzutil.APPDATA_PATH, exist_ok=True)
with open(self.settings_filename, "w") as settings_file:
json.dump(self.settings, settings_file, indent=4)

230
dangerzone/util.py Normal file
View file

@ -0,0 +1,230 @@
import inspect
import os
import platform
import shutil
import subprocess
import sys
import appdirs
# If a general-purpose function doesn't depend on anything else in the dangerzone package, then it belongs here.
def get_resource_path(filename):
if getattr(sys, "dangerzone_dev", False):
# Look for resources directory relative to python file
prefix = os.path.join(
os.path.dirname(
os.path.dirname(
os.path.abspath(inspect.getfile(inspect.currentframe()))
)
),
"share",
)
else:
if platform.system() == "Darwin":
prefix = os.path.join(
os.path.dirname(os.path.dirname(sys.executable)), "Resources/share"
)
elif platform.system() == "Linux":
prefix = os.path.join(sys.prefix, "share", "dangerzone")
else:
# Windows
prefix = os.path.join(os.path.dirname(sys.executable), "share")
resource_path = os.path.join(prefix, filename)
return resource_path
def get_subprocess_startupinfo():
if platform.system() == "Windows":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
return startupinfo
else:
return None
def _get_version() -> str:
"""Dangerzone version number. Prefer dangerzone.VERSION to this function."""
try:
with open(get_resource_path("version.txt")) as f:
version = f.read().strip()
except FileNotFoundError:
# In dev mode, in Windows, get_resource_path doesn't work properly for the container, but luckily
# it doesn't need to know the version
version = "unknown"
return version
VERSION = _get_version()
APPDATA_PATH = appdirs.user_config_dir("dangerzone")
SYSTEM = platform.system()
CONTAINER_NAME = "dangerzone.rocks/dangerzone"
CONTAINER_COMMAND = "podman" if SYSTEM == "Linux" else "Docker"
CONTAINER_RUNTIME = shutil.which(CONTAINER_COMMAND)
WINDOW_ICON_FILENAME = "dangerzone.ico" if SYSTEM == "Windows" else "icon.png"
WINDOW_ICON_PATH = get_resource_path(WINDOW_ICON_FILENAME)
# Languages supported by tesseract
OCR_LANGUAGES = {
"Afrikaans": "ar",
"Albanian": "sqi",
"Amharic": "amh",
"Arabic": "ara",
"Arabic script": "Arabic",
"Armenian": "hye",
"Armenian script": "Armenian",
"Assamese": "asm",
"Azerbaijani": "aze",
"Azerbaijani (Cyrillic)": "aze_cyrl",
"Basque": "eus",
"Belarusian": "bel",
"Bengali": "ben",
"Bengali script": "Bengali",
"Bosnian": "bos",
"Breton": "bre",
"Bulgarian": "bul",
"Burmese": "mya",
"Canadian Aboriginal script": "Canadian_Aboriginal",
"Catalan": "cat",
"Cebuano": "ceb",
"Cherokee": "chr",
"Cherokee script": "Cherokee",
"Chinese - Simplified": "chi_sim",
"Chinese - Simplified (vertical)": "chi_sim_vert",
"Chinese - Traditional": "chi_tra",
"Chinese - Traditional (vertical)": "chi_tra_vert",
"Corsican": "cos",
"Croatian": "hrv",
"Cyrillic script": "Cyrillic",
"Czech": "ces",
"Danish": "dan",
"Devanagari script": "Devanagari",
"Divehi": "div",
"Dutch": "nld",
"Dzongkha": "dzo",
"English": "eng",
"English, Middle (1100-1500)": "enm",
"Esperanto": "epo",
"Estonian": "est",
"Ethiopic script": "Ethiopic",
"Faroese": "fao",
"Filipino": "fil",
"Finnish": "fin",
"Fraktur script": "Fraktur",
"Frankish": "frk",
"French": "fra",
"French, Middle (ca.1400-1600)": "frm",
"Frisian (Western)": "fry",
"Gaelic (Scots)": "gla",
"Galician": "glg",
"Georgian": "kat",
"Georgian script": "Georgian",
"German": "deu",
"Greek": "ell",
"Greek script": "Greek",
"Gujarati": "guj",
"Gujarati script": "Gujarati",
"Gurmukhi script": "Gurmukhi",
"Hangul script": "Hangul",
"Hangul (vertical) script": "Hangul_vert",
"Han - Simplified script": "HanS",
"Han - Simplified (vertical) script": "HanS_vert",
"Han - Traditional script": "HanT",
"Han - Traditional (vertical) script": "HanT_vert",
"Hatian": "hat",
"Hebrew": "heb",
"Hebrew script": "Hebrew",
"Hindi": "hin",
"Hungarian": "hun",
"Icelandic": "isl",
"Indonesian": "ind",
"Inuktitut": "iku",
"Irish": "gle",
"Italian": "ita",
"Italian - Old": "ita_old",
"Japanese": "jpn",
"Japanese script": "Japanese",
"Japanese (vertical)": "jpn_vert",
"Japanese (vertical) script": "Japanese_vert",
"Javanese": "jav",
"Kannada": "kan",
"Kannada script": "Kannada",
"Kazakh": "kaz",
"Khmer": "khm",
"Khmer script": "Khmer",
"Korean": "kor",
"Korean (vertical)": "kor_vert",
"Kurdish (Arabic)": "kur_ara",
"Kyrgyz": "kir",
"Lao": "lao",
"Lao script": "Lao",
"Latin": "lat",
"Latin script": "Latin",
"Latvian": "lav",
"Lithuanian": "lit",
"Luxembourgish": "ltz",
"Macedonian": "mkd",
"Malayalam": "mal",
"Malayalam script": "Malayalam",
"Malay": "msa",
"Maltese": "mlt",
"Maori": "mri",
"Marathi": "mar",
"Mongolian": "mon",
"Myanmar script": "Myanmar",
"Nepali": "nep",
"Norwegian": "nor",
"Occitan (post 1500)": "oci",
"Old Georgian": "kat_old",
"Oriya (Odia) script": "Oriya",
"Oriya": "ori",
"Pashto": "pus",
"Persian": "fas",
"Polish": "pol",
"Portuguese": "por",
"Punjabi": "pan",
"Quechua": "que",
"Romanian": "ron",
"Russian": "rus",
"Sanskrit": "san",
"script and orientation": "osd",
"Serbian (Latin)": "srp_latn",
"Serbian": "srp",
"Sindhi": "snd",
"Sinhala script": "Sinhala",
"Sinhala": "sin",
"Slovakian": "slk",
"Slovenian": "slv",
"Spanish, Castilian - Old": "spa_old",
"Spanish": "spa",
"Sundanese": "sun",
"Swahili": "swa",
"Swedish": "swe",
"Syriac script": "Syriac",
"Syriac": "syr",
"Tajik": "tgk",
"Tamil script": "Tamil",
"Tamil": "tam",
"Tatar": "tat",
"Telugu script": "Telugu",
"Telugu": "tel",
"Thaana script": "Thaana",
"Thai script": "Thai",
"Thai": "tha",
"Tibetan script": "Tibetan",
"Tibetan Standard": "bod",
"Tigrinya": "tir",
"Tonga": "ton",
"Turkish": "tur",
"Ukrainian": "ukr",
"Urdu": "urd",
"Uyghur": "uig",
"Uzbek (Cyrillic)": "uzb_cyrl",
"Uzbek": "uzb",
"Vietnamese script": "Vietnamese",
"Vietnamese": "vie",
"Welsh": "cym",
"Yiddish": "yid",
"Yoruba": "yor"
}