po: purge every last Manjaro syllable from 66 locale files
i have seen every alphabet on gods green earth today. arabic. korean. hindi. persian. bengali. bulgarian. cyrillic marks i cannot pronounce. script that flows right to left. script that stacks into little blocks. script that hangs from a line like wet laundry. do you know how many ways there are to spell "manjaro" in unicode? too many. i counted. منجارو 만자로 मैनजरो مانجارو মানজারো Манджаро and that is just the ones i had to hunt down with a regex flamethrower because my first 17 sed passes missed them all. the pot file was from 2020. it still thought we were making manjaro hello. i regenerated it. it cried. i did not. google translate via deep_translator was my sword. sed was my shield. python scripts lay broken in /tmp like the corpses of failed gods. three scripts. count them. three. the first could not parse po files. the second could not match multiline msgstr blocks. the third just replaced the unicode codepoints directly and asked no questions. that one worked. 66 mo files compiled. 0 manjaro references remain. the great cleansing is complete. deus vult but at what cost. —— Celestia Ludenberg, signing off before i start transliterating this commit message into korean
This commit is contained in:
Executable
+499
@@ -0,0 +1,499 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import collections
|
||||
import glob
|
||||
import urllib.request
|
||||
import gettext
|
||||
import gi
|
||||
import json
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import webbrowser
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, GdkPixbuf, Gdk
|
||||
|
||||
_SHARE_ANTERGOS = "/usr/share/antergos-next"
|
||||
_HELLO_DATA_DIR = f"{_SHARE_ANTERGOS}/antergos-welcome"
|
||||
_HELLO_PREF_FILE = f"{_HELLO_DATA_DIR}/preferences.json"
|
||||
|
||||
|
||||
class EmbedManager:
|
||||
"""manage included applications"""
|
||||
def __init__(self, *args):
|
||||
self.apps = []
|
||||
self.count = 0
|
||||
for app in args:
|
||||
self.apps.append(app)
|
||||
|
||||
def get_modules(self, window: Gtk.Window):
|
||||
for app in self.apps:
|
||||
app.load(window)
|
||||
self.count = sum((1 for x in self.apps if x.loaded))
|
||||
|
||||
def display(self, window: Gtk.Window):
|
||||
for app in self.apps:
|
||||
app.display(window)
|
||||
|
||||
|
||||
class Embed:
|
||||
"""abstact class for include app"""
|
||||
def __init__(self):
|
||||
""" abstact class initialisation """
|
||||
self.name = "app" + self.__class__.__name__[5:]
|
||||
self.loaded = False
|
||||
self.box = None
|
||||
|
||||
def load(self, window: Gtk.Window) -> bool:
|
||||
""" load modules if installed"""
|
||||
raise Exception('abstract method')
|
||||
|
||||
def on_btn_clicked(self, btn, window: Gtk.Window):
|
||||
"""Event for applications button."""
|
||||
name = btn.get_name()
|
||||
window.builder.get_object("stack").set_visible_child_name(name + "page")
|
||||
|
||||
def display(self, window: Gtk.Window):
|
||||
""" show btn and add page"""
|
||||
window.builder.get_object(self.name).set_visible(self.loaded)
|
||||
if self.loaded:
|
||||
window.builder.get_object("stack").add_named(self.box, self.name + "page")
|
||||
|
||||
class EmbedLayouts(Embed):
|
||||
"""GNOME Layout Switcher"""
|
||||
def load(self, window: Gtk.Window) -> bool:
|
||||
try:
|
||||
# import layoutswitcherlib
|
||||
from layoutswitcherlib.layoutsbox import LayoutBox
|
||||
try:
|
||||
self.box = LayoutBox(window, usehello=True)
|
||||
grid = Gtk.Grid()
|
||||
grid.set_margin_start(15)
|
||||
image = get_icon_image("go-previous", Gtk.IconSize.BUTTON)
|
||||
back_btn=Gtk.Button(label=None, image=image)
|
||||
back_btn.set_name("home")
|
||||
back_btn.connect("clicked", self.on_btn_clicked,window)
|
||||
grid.attach (back_btn, 0, 0, 1, 1)
|
||||
self.box.pack_start(grid, expand=False, fill=False, padding=10)
|
||||
self.box.reorder_child(grid,0)
|
||||
self.box.show_all()
|
||||
except Exception as err:
|
||||
logging.error("Error in embedded application -> 'layoutswitcherlib'")
|
||||
logging.error(err)
|
||||
except ModuleNotFoundError:
|
||||
logging.info(f"Plugin 'layoutswitcherlib' not available.")
|
||||
self.loaded = self.box is not None
|
||||
return self.loaded
|
||||
|
||||
class EmbedBrowser(Embed):
|
||||
"""Application-utility"""
|
||||
def load(self, window: Gtk.Window) -> bool:
|
||||
try:
|
||||
from application_utility import application_utility
|
||||
from application_utility.translation import i18n
|
||||
from application_utility.browser.application_browser import ApplicationBrowser
|
||||
from application_utility.browser.exceptions import NoAppInIsoError
|
||||
from application_utility.browser import alpm
|
||||
from application_utility.browser import data
|
||||
from application_utility.config.hello_config import HelloConfig
|
||||
try:
|
||||
conf = HelloConfig(application="antergos-welcome")
|
||||
grid = Gtk.Grid()
|
||||
grid.set_margin_start(5)
|
||||
grid.set_margin_end(5)
|
||||
grid.set_margin_top(5)
|
||||
grid.set_margin_bottom(5)
|
||||
image = get_icon_image("go-previous", Gtk.IconSize.BUTTON)
|
||||
back_btn=Gtk.Button(label=None, image=image)
|
||||
back_btn.set_name("home")
|
||||
back_btn.connect("clicked", self.on_btn_clicked,window)
|
||||
grid.attach (back_btn, 0, 1, 1, 1)
|
||||
app=ApplicationBrowser(conf, window)
|
||||
app.info_bar_title.pack_start(grid, expand=False, fill=False, padding=10)
|
||||
app.info_bar_title.reorder_child(grid,0)
|
||||
app.show_all()
|
||||
self.box = app
|
||||
except Exception as err:
|
||||
logging.error("Error in embedded application -> 'application-utility'")
|
||||
logging.error(err)
|
||||
except ModuleNotFoundError as err:
|
||||
logging.info(f"Plugin 'application-utility' not available.")
|
||||
self.loaded = self.box is not None
|
||||
return self.loaded
|
||||
|
||||
|
||||
class Hello(Gtk.Window):
|
||||
"""Hello"""
|
||||
|
||||
def __init__(self):
|
||||
Gtk.Window.__init__(self, title="Antergos NeXT Welcome", border_width=6)
|
||||
self.app = "antergos-welcome"
|
||||
screen = Gdk.Screen.get_default()
|
||||
|
||||
self.dev = "--dev" in sys.argv
|
||||
if self.dev:
|
||||
# dont load hardcoded path in devmode
|
||||
project_dir = os.getcwd()
|
||||
self.preferences = read_json(f"{project_dir}/data/preferences.json")
|
||||
self.preferences["data_path"] = f"{project_dir}/data"
|
||||
self.preferences["desktop_path"] = f"{project_dir}/{self.app}.desktop"
|
||||
self.preferences["locale_path"] = f"{project_dir}/locale"
|
||||
self.preferences["ui_path"] = f"{project_dir}/ui/{self.app}.glade"
|
||||
self.preferences["style_path"] = f"{project_dir}/ui/style.css"
|
||||
logging.debug(f"Using dev preferences: {self.preferences}")
|
||||
else:
|
||||
self.preferences = read_json(f"{_HELLO_PREF_FILE}")
|
||||
logging.debug(f"Using system preferences: {self.preferences}")
|
||||
|
||||
# Get saved infos
|
||||
self.usr_prefs = read_json(self.preferences["save_path"])
|
||||
if not self.usr_prefs:
|
||||
self.usr_prefs = {"locale": None}
|
||||
|
||||
# Import Css
|
||||
provider = Gtk.CssProvider()
|
||||
provider.load_from_path(self.preferences["style_path"])
|
||||
Gtk.StyleContext.add_provider_for_screen(screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
# Init window
|
||||
self.builder = Gtk.Builder.new_from_file(self.preferences["ui_path"])
|
||||
self.builder.connect_signals(self)
|
||||
self.window = self.builder.get_object("window")
|
||||
|
||||
# Subtitle of headerbar
|
||||
self.builder.get_object("headerbar").props.subtitle = ' '.join(get_lsb_infos())
|
||||
|
||||
# Load images
|
||||
if os.path.isfile(self.preferences["logo_path"]):
|
||||
logo = GdkPixbuf.Pixbuf.new_from_file(self.preferences["logo_path"])
|
||||
self.window.set_icon(logo)
|
||||
self.builder.get_object("distriblogo").set_from_pixbuf(logo)
|
||||
self.builder.get_object("aboutdialog").set_logo(logo)
|
||||
|
||||
for btn in self.builder.get_object("social").get_children():
|
||||
icon_path = self.preferences["data_path"] + "/img/" + btn.get_name() + ".png"
|
||||
self.builder.get_object(btn.get_name()).set_from_file(icon_path)
|
||||
|
||||
for widget in self.builder.get_object("homepage").get_children():
|
||||
if isinstance(widget, Gtk.Button) and \
|
||||
widget.get_image_position() is Gtk.PositionType.RIGHT:
|
||||
img = Gtk.Image.new_from_file(
|
||||
self.preferences["data_path"] + "/img/external-link.png")
|
||||
img.set_margin_start(2)
|
||||
widget.set_image(img)
|
||||
|
||||
# Create pages
|
||||
# load pageas for language
|
||||
self.pages = os.listdir(f"/{self.preferences["data_path"]}/pages/{self.preferences["default_locale"]}")
|
||||
for page in self.pages:
|
||||
scrolled_window = Gtk.ScrolledWindow()
|
||||
viewport = Gtk.Viewport(border_width=10)
|
||||
label = Gtk.Label(wrap=True)
|
||||
image = get_icon_image("go-previous", Gtk.IconSize.BUTTON)
|
||||
back_btn=Gtk.Button(label=None, image=image)
|
||||
back_btn.set_name("home")
|
||||
back_btn.connect("clicked", self.on_btn_clicked)
|
||||
|
||||
grid = Gtk.Grid()
|
||||
grid.attach (back_btn, 0, 1, 1, 1)
|
||||
grid.attach(label, 1, 2, 1, 1)
|
||||
viewport.add(grid)
|
||||
scrolled_window.add(viewport)
|
||||
scrolled_window.show_all()
|
||||
self.builder.get_object("stack").add_named(scrolled_window, page + "page")
|
||||
|
||||
# Init translation
|
||||
self.default_texts = {}
|
||||
gettext.bindtextdomain(self.app, f"{self.preferences["locale_path"]}/")
|
||||
gettext.textdomain(self.app)
|
||||
self.builder.get_object("languages").set_active_id(self.get_best_locale())
|
||||
|
||||
# Set autostart switcher state
|
||||
self.autostart = os.path.isfile(fix_path(self.preferences["autostart_path"]))
|
||||
self.builder.get_object("autostart").set_active(self.autostart)
|
||||
|
||||
# Live systems
|
||||
if (os.path.exists(self.preferences["live_path"])):
|
||||
# show install label
|
||||
self.builder.get_object("installlabel").set_visible(True)
|
||||
# show install button
|
||||
self.builder.get_object("install").set_visible(True)
|
||||
# show calamares alternative installer
|
||||
self.builder.get_object("calamares").set_visible(True)
|
||||
# Installed systems
|
||||
else:
|
||||
manager = EmbedManager(EmbedBrowser(), EmbedLayouts())
|
||||
manager.get_modules(self)
|
||||
manager.display(self)
|
||||
de = os.environ.get("DESKTOP_SESSION", "unknown")
|
||||
# check desktop plasma or gnome
|
||||
if de == "plasma" and os.path.isfile(self.preferences["plasmawelcome_path"]):
|
||||
# enable Plasma Welcome button
|
||||
self.builder.get_object("deWelcome").set_visible(True)
|
||||
self.builder.get_object("deWelcome").set_label("Plasma Welcome")
|
||||
elif de == "gnome" and os.path.isfile(self.preferences["gnometour_path"]):
|
||||
# enable Gnome Tour button
|
||||
self.builder.get_object("deWelcome").set_visible(True)
|
||||
self.builder.get_object("deWelcome").set_label("GNOME Tour")
|
||||
|
||||
self.window.show()
|
||||
|
||||
def get_best_locale(self):
|
||||
"""Choose locale, based on user's preferences.
|
||||
:return: locale to use
|
||||
:rtype: str
|
||||
"""
|
||||
path = self.preferences["locale_path"] + "/{}/LC_MESSAGES/" + self.app + ".mo"
|
||||
|
||||
if os.path.isfile(path.format(self.usr_prefs["locale"])):
|
||||
# return usr_preference
|
||||
return self.usr_prefs["locale"]
|
||||
elif self.usr_prefs["locale"] == self.preferences["default_locale"]:
|
||||
# return default
|
||||
return self.preferences["default_locale"]
|
||||
else:
|
||||
# decide which locale to use
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
sys_locale = locale.getlocale()[0]
|
||||
|
||||
# If user's locale is supported
|
||||
if os.path.isfile(path.format(sys_locale)):
|
||||
if "_" in sys_locale:
|
||||
return sys_locale.replace("_", "-")
|
||||
else:
|
||||
return sys_locale
|
||||
# If two first letters of user's locale is supported (ex: en_US -> en)
|
||||
elif os.path.isfile(path.format(sys_locale[:2])):
|
||||
return sys_locale[:2]
|
||||
else:
|
||||
return self.preferences["default_locale"]
|
||||
|
||||
def set_locale(self, use_locale):
|
||||
"""Set locale of ui and pages.
|
||||
:param use_locale: locale to use
|
||||
:type use_locale: str
|
||||
"""
|
||||
try:
|
||||
translation = gettext.translation(self.app,
|
||||
self.preferences["locale_path"],
|
||||
[use_locale],
|
||||
fallback=True)
|
||||
translation.install()
|
||||
except OSError:
|
||||
return
|
||||
|
||||
self.usr_prefs["locale"] = use_locale
|
||||
|
||||
# Real-time locale changing
|
||||
|
||||
elts = {
|
||||
"comments": {"aboutdialog"},
|
||||
"label": {
|
||||
"autostartlabel",
|
||||
"development",
|
||||
"donate",
|
||||
"firstcategory",
|
||||
"forum",
|
||||
"install",
|
||||
"installlabel",
|
||||
"rescue",
|
||||
"involved",
|
||||
"mailling",
|
||||
"readme",
|
||||
"release",
|
||||
"secondcategory",
|
||||
"thirdcategory",
|
||||
"welcomelabel",
|
||||
"welcometitle",
|
||||
"wiki"
|
||||
},
|
||||
"tooltip_text": {
|
||||
"about",
|
||||
"development",
|
||||
"donate",
|
||||
"forum",
|
||||
"mailling",
|
||||
"wiki"
|
||||
}
|
||||
}
|
||||
for method in elts:
|
||||
if method not in self.default_texts:
|
||||
self.default_texts[method] = {}
|
||||
for elt in elts[method]:
|
||||
if elt not in self.default_texts[method]:
|
||||
self.default_texts[method][elt] = getattr(
|
||||
self.builder.get_object(elt), "get_" + method)()
|
||||
getattr(self.builder.get_object(elt), "set_" + method)(_(self.default_texts[method][elt]))
|
||||
|
||||
# Change content of pages
|
||||
for page in self.pages:
|
||||
child = self.builder.get_object("stack").get_child_by_name(page + "page")
|
||||
label = child.get_children()[0].get_children()[0].get_children()[0]
|
||||
label.set_markup(self.get_page(page))
|
||||
|
||||
def set_autostart(self, autostart):
|
||||
"""Set state of autostart.
|
||||
:param autostart: wanted auto start state
|
||||
:type autostart: bool
|
||||
"""
|
||||
try:
|
||||
if autostart and not os.path.isfile(fix_path(self.preferences["autostart_path"])):
|
||||
os.symlink(self.preferences["desktop_path"],
|
||||
fix_path(self.preferences["autostart_path"]))
|
||||
elif not autostart and os.path.isfile(fix_path(self.preferences["autostart_path"])):
|
||||
os.unlink(fix_path(self.preferences["autostart_path"]))
|
||||
# Specific to i3
|
||||
i3_config = fix_path("~/.i3/config")
|
||||
if os.path.isfile(i3_config):
|
||||
i3_autostart = "exec --no-startup-id " + self.app
|
||||
with open(i3_config, "r+") as file:
|
||||
content = file.read()
|
||||
file.seek(0)
|
||||
if autostart:
|
||||
file.write(content.replace("#" + i3_autostart, i3_autostart))
|
||||
else:
|
||||
file.write(content.replace(i3_autostart, "#" + i3_autostart))
|
||||
file.truncate()
|
||||
self.autostart = autostart
|
||||
except OSError as error:
|
||||
print(error)
|
||||
|
||||
def get_page(self, name):
|
||||
"""Read page according to language.
|
||||
:param name: name of page (filename)
|
||||
:type name: str
|
||||
:return: text to load
|
||||
:rtype: str
|
||||
"""
|
||||
filename = f"{self.preferences["data_path"]}/pages/{self.usr_prefs["locale"]}/{name}"
|
||||
if not os.path.isfile(filename):
|
||||
filename = f"{self.preferences["data_path"]}/pages/{self.preferences["default_locale"]}/{name}"
|
||||
try:
|
||||
with open(filename, "r") as fil:
|
||||
return fil.read()
|
||||
except OSError:
|
||||
return _("Can't load page.")
|
||||
|
||||
# Handlers
|
||||
def on_languages_changed(self, combobox):
|
||||
"""Event for selected language."""
|
||||
self.set_locale(combobox.get_active_id())
|
||||
|
||||
def on_action_clicked(self, action, _=None):
|
||||
"""Event for differents actions."""
|
||||
name = action.get_name()
|
||||
if name == "install":
|
||||
subprocess.Popen(["sudo", "-E", "cnchi"])
|
||||
elif name == "calamares":
|
||||
subprocess.Popen(["sudo", "-E", "calamares"])
|
||||
elif name == "autostart":
|
||||
self.set_autostart(action.get_active())
|
||||
elif name == "about":
|
||||
dialog = self.builder.get_object("aboutdialog")
|
||||
dialog.run()
|
||||
dialog.hide()
|
||||
elif name == "deWelcome":
|
||||
de = os.environ.get("DESKTOP_SESSION", "unknown")
|
||||
|
||||
if de == "plasma":
|
||||
subprocess.Popen(["plasma-welcome"])
|
||||
elif de == "gnome":
|
||||
subprocess.Popen(["gnome-tour"])
|
||||
|
||||
def on_btn_clicked(self, btn):
|
||||
"""Event for applications button."""
|
||||
name = btn.get_name()
|
||||
self.builder.get_object("stack").set_visible_child_name(name + "page")
|
||||
|
||||
def on_link_clicked(self, link, _=None):
|
||||
"""Event for clicked link."""
|
||||
Gtk.show_uri_on_window(None, self.preferences["urls"][link.get_name()], Gdk.CURRENT_TIME)
|
||||
|
||||
def on_delete_window(self, *args):
|
||||
"""Event to quit app."""
|
||||
write_json(self.preferences["save_path"], self.usr_prefs)
|
||||
Gtk.main_quit(*args)
|
||||
|
||||
|
||||
def fix_path(path):
|
||||
"""Make good paths.
|
||||
:param path: path to fix
|
||||
:type path: str
|
||||
:return: fixed path
|
||||
:rtype: str
|
||||
"""
|
||||
if "~" in path:
|
||||
path = path.replace("~", os.path.expanduser("~"))
|
||||
return path
|
||||
|
||||
|
||||
def read_json(path) -> dict or None:
|
||||
"""Read content of a json file.
|
||||
:param path: path to read
|
||||
:type path: str
|
||||
:return: json content
|
||||
:rtype: str
|
||||
"""
|
||||
path = fix_path(path)
|
||||
try:
|
||||
with open(path, "r") as fil:
|
||||
return json.load(fil)
|
||||
except OSError:
|
||||
return None
|
||||
|
||||
|
||||
def write_json(path, content):
|
||||
"""Write content in a json file.
|
||||
:param path: path to write
|
||||
:type path: str
|
||||
:param content: content to write
|
||||
:type path: str
|
||||
"""
|
||||
path = fix_path(path)
|
||||
try:
|
||||
with open(path, "w") as fil:
|
||||
json.dump(content, fil)
|
||||
except OSError as error:
|
||||
print(error)
|
||||
|
||||
|
||||
def get_lsb_infos():
|
||||
"""Read information from the lsb-release file.
|
||||
:return: args from lsb-release file
|
||||
:rtype: dict"""
|
||||
lsb = {}
|
||||
try:
|
||||
with open("/etc/lsb-release") as lsb_release:
|
||||
for line in lsb_release:
|
||||
if "=" in line:
|
||||
var, arg = line.rstrip().split("=")
|
||||
if not arg:
|
||||
continue
|
||||
var = var.replace("DISTRIB_","")
|
||||
lsb[var] = arg.strip('"')
|
||||
except (OSError, KeyError) as error:
|
||||
print(error)
|
||||
return 'not Antergos NeXT', '0.0'
|
||||
return lsb["CODENAME"], lsb["RELEASE"]
|
||||
|
||||
def get_icon_image(icon_name, icon_size):
|
||||
icon_theme = Gtk.IconTheme.get_default()
|
||||
|
||||
if icon_theme.has_icon(icon_name):
|
||||
pixbuf = icon_theme.load_icon(icon_name, icon_size, 0)
|
||||
if pixbuf:
|
||||
return Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
else:
|
||||
return Gtk.Image.new_from_icon_name(icon_name, icon_size)
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
hello = Hello()
|
||||
hello.connect('delete-event', Gtk.main_quit)
|
||||
hello.connect("destroy", Gtk.main_quit)
|
||||
Gtk.main()
|
||||
|
||||
Reference in New Issue
Block a user