Skip to main content

Multi-language slug generator supporting 23+ languages including CJK, Arabic, Cyrillic, and more. Faithful Python port of the C# Slugify.MultiLang library.

Project description

slugify-multilang (Python)

A faithful, dependency-free Python port of the C# Slugify.MultiLang library — a multi-language, URL-safe slug generator with extended locale support and sensible handling of CJK, Arabic, and other non-Latin scripts.

Targets Python 3.10+. Standard library only (re + unicodedata).

Install

pip install slugify-multilang

Or from this folder:

cd python
pip install .

Usage

from slugify_multilang import slugify, SlugifySlugOptions, extend

slugify("Director Fu: Your alt account got exposed again!")
# -> "director-fu-your-alt-account-got-exposed-again"

slugify("Café au lait & cròissant")
# -> "cafe-au-lait-and-croissant"

slugify("傅总:你的马甲 又又又掉了!")
# -> "傅总-你的马甲-又又又掉了"

Replacement-only overload

Mirrors the C# string Slugify(this string, string replacement = "-") overload — pass a string instead of an options object:

slugify("hello world", "_")          # -> "hello_world"

Options

SlugifySlugOptions maps 1:1 to the C# SlugifySlugOptions (PascalCase → snake_case):

Field Type Default Meaning
replacement str "-" Word-joining character.
remove re.Pattern | None None Per-character strip regex (default built-in when None).
lower bool True Lowercase the result.
strict bool True Strip anything that isn't a letter, number, or whitespace.
trim bool True Trim surrounding whitespace.
locale str | None None Per-language override map.
from slugify_multilang import slugify, SlugifySlugOptions

slugify("Müdür Fu", SlugifySlugOptions(locale="de"))   # -> "mueduer-fu"
slugify("Hello World", SlugifySlugOptions(lower=False)) # -> "Hello-World"

Locale overrides exist for: bg, de, es, fr, pt, uk, vi, da, nb, it, nl, sv.

Extending the character map

Mirrors the C# Extend method — registers custom mappings globally at runtime:

from slugify_multilang import extend, slugify

extend({"☂": "umbrella", "₿": "btc"})
slugify("☂ ₿")   # -> "umbrella-btc"

How it works

Same five-step pipeline as the C# original:

  1. NFC normalize (unicodedata.normalize("NFC", ...)).
  2. Per-character translation — locale override → global charmap → passthrough.
  3. Remove pass — strip non-URL-friendly characters.
  4. Strict pass (optional) — keep only Unicode letters, numbers, whitespace.
  5. Collapse + lowercase — trim, collapse whitespace runs into replacement, lowercase.

Fidelity

This port is verified against the C# implementation:

  • All 583 global charmap entries are byte-for-byte identical.
  • All 12 locale override maps are identical.
  • The 23-language demo (python demo.py) produces output identical to the C# demo.

One documented nuance

.NET's regex \w includes Unicode combining marks (\p{Mn}); Python's re \w does not. This only affects the intermediate remove pass, and only when strict=False. With the default strict=True, combining marks are stripped by the strict pass in both implementations, so output is identical.

Demo

python demo.py

Publishing to PyPI

Automated via publish.sh (bash) or publish.ps1 (PowerShell), both mirroring the NuGet workflow in ../publish.ps1. Requires uv; publish.ps1 additionally needs pwsh (on macOS: brew install powershell).

Credentials come from your ~/.pypirc ([pypi] section) — read automatically by twine, so no token is passed on the command line:

./publish.sh                 # bash — uploads to PyPI using ~/.pypirc
./publish.sh -r testpypi     # dry-run against TestPyPI (needs a [testpypi] section)

pwsh ./publish.ps1                    # PowerShell equivalent
pwsh ./publish.ps1 -Repository testpypi

The script: reads the current version → checks __init__.py is in sync → runs the test suite → uv builduvx twine checkuvx twine upload to pypi.org → auto-increments the patch version for next time.

twine also honours the TWINE_USERNAME / TWINE_PASSWORD env vars if you prefer not to use ~/.pypirc. uv publish is not used because it does not read ~/.pypirc.

Version-number rule

Same convention as the NuGet package: semver MAJOR.MINOR.PATCH, with the version stored in pyproject.toml being the one published now. After a successful publish the patch component is bumped automatically (e.g. 1.0.2 → 1.0.3). pyproject.toml is the single source of truth and the script keeps slugify_multilang/__init__.py's __version__ in lockstep (it refuses to publish if the two disagree). Bump MINOR/MAJOR by hand for feature/breaking releases. The Python and C# packages share the same version line (1.0.2).

Git repository URL rule

The [project.urls] Homepage and Repository point at the same repository as the C# .csproj (RepositoryUrl / PackageProjectUrl):

https://github.com/balck3py/slugify-multilag

Keep these identical to the C# project so both packages resolve to one source repo.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

slugify_multilang-1.0.2.tar.gz (25.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

slugify_multilang-1.0.2-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file slugify_multilang-1.0.2.tar.gz.

File metadata

  • Download URL: slugify_multilang-1.0.2.tar.gz
  • Upload date:
  • Size: 25.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for slugify_multilang-1.0.2.tar.gz
Algorithm Hash digest
SHA256 1cfbc1e44d01a1f9d8fcceb33781bf8fd61a8e383c5fea1e380fac6ac721ac8b
MD5 0f2501541c1f9dc42b1e1571325c55e6
BLAKE2b-256 bde23e10747bc22dffb015ed2f06d1eef6304d424c8bd2758f5969fe3a5e7f59

See more details on using hashes here.

File details

Details for the file slugify_multilang-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for slugify_multilang-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 47f51dd2581391e31e19ecfd4a498a77ca5380b69481224f92b4338f028ad925
MD5 b13dca69cb0332c9476a17ced7bee1ea
BLAKE2b-256 42eb4a33a6bb70d3d67bb8dd95625c9cb706a247bdf72d13876b24472cc9c2a7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page