Skip to content

Instantly share code, notes, and snippets.

@s3rgeym
Created August 22, 2025 18:24
Show Gist options
  • Save s3rgeym/4fe5af48f2a76d7503517e023ea19592 to your computer and use it in GitHub Desktop.
Save s3rgeym/4fe5af48f2a76d7503517e023ea19592 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import argparse
import pathlib
import re
import sys
from collections import defaultdict
from functools import partial
print_err = partial(print, file=sys.stderr)
TRANS_TABLE = defaultdict(
str,
{
"а": "a",
"б": "b",
"в": "v",
"г": "g",
"д": "d",
"е": "e",
"ё": "yo",
"ж": "zh",
"з": "z",
"и": "i",
"й": "y",
"к": "k",
"л": "l",
"м": "m",
"н": "n",
"о": "o",
"п": "p",
"р": "r",
"с": "s",
"т": "t",
"у": "u",
"ф": "f",
"х": "h",
"ц": "ts",
"ч": "ch",
"ш": "sh",
"щ": "shch",
"ъ": "",
"ы": "y",
"ь": "",
"э": "e",
"ю": "yu",
"я": "ya",
"А": "A",
"Б": "B",
"В": "V",
"Г": "G",
"Д": "D",
"Е": "E",
"Ё": "Yo",
"Ж": "Zh",
"З": "Z",
"И": "I",
"Й": "Y",
"К": "K",
"Л": "L",
"М": "M",
"Н": "N",
"О": "O",
"П": "P",
"Р": "R",
"С": "S",
"Т": "T",
"У": "U",
"Ф": "F",
"Х": "H",
"Ц": "Ts",
"Ч": "Ch",
"Ш": "Sh",
"Щ": "Shch",
"Ъ": "",
"Ы": "Y",
"Ь": "",
"Э": "E",
"Ю": "Yu",
"Я": "Ya",
},
)
def translit(text):
return "".join(TRANS_TABLE.get(char, char) for char in text)
def translit_filenames(directory_path: pathlib.Path, to_lower: bool = False) -> None:
for item in sorted(directory_path.rglob("*"), reverse=True):
if item.name.startswith("."):
continue
new_name = translit(item.name)
new_name = re.sub(r"\s+", "-", new_name).strip("-")
if to_lower:
new_name = new_name.lower()
if item.name != new_name:
new_path = item.parent / new_name
if new_path.exists() and new_path != item:
continue
print_err(f"{item} -> {new_path}")
item.rename(new_path)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Renames files and directories recursively using transliteration."
)
parser.add_argument(
"directory", type=pathlib.Path, help="Path to the directory to process."
)
parser.add_argument(
"-lc",
"--lower-case",
"--lower",
help="To lower case",
action=argparse.BooleanOptionalAction,
default=False,
)
args = parser.parse_args()
if args.directory.is_dir():
translit_filenames(args.directory, args.lower_case)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment