dz-arabic-slug 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dz_arabic_slug-0.1.0/LICENSE +21 -0
- dz_arabic_slug-0.1.0/PKG-INFO +141 -0
- dz_arabic_slug-0.1.0/README.md +121 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug/__init__.py +12 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug/cli.py +26 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug/core.py +60 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug/mapping.py +27 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug.egg-info/PKG-INFO +141 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug.egg-info/SOURCES.txt +13 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug.egg-info/dependency_links.txt +1 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug.egg-info/entry_points.txt +2 -0
- dz_arabic_slug-0.1.0/dz_arabic_slug.egg-info/top_level.txt +1 -0
- dz_arabic_slug-0.1.0/pyproject.toml +33 -0
- dz_arabic_slug-0.1.0/setup.cfg +4 -0
- dz_arabic_slug-0.1.0/tests/test_core.py +63 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oussama Boudinar <lionweb01@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dz-arabic-slug
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert Arabic text into URL-friendly slugs with proper transliteration.
|
|
5
|
+
Author-email: Oussama Boudinar <lionweb01@gmail.com>
|
|
6
|
+
Maintainer-email: Oussama Boudinar <lionweb01@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/dzopensource-lab/dz-arabic-slug
|
|
9
|
+
Project-URL: Repository, https://github.com/dzopensource-lab/dz-arabic-slug
|
|
10
|
+
Project-URL: Issues, https://github.com/dzopensource-lab/dz-arabic-slug/issues
|
|
11
|
+
Keywords: slug,arabic,slugify,url,transliteration,django,flask,fastapi
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Natural Language :: Arabic
|
|
15
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# dz-arabic-slug
|
|
22
|
+
|
|
23
|
+
Convert Arabic text into clean, URL-friendly slugs with proper transliteration.
|
|
24
|
+
|
|
25
|
+
[](https://github.com/dzopensource-lab/dz-arabic-slug/actions/workflows/test.yml)
|
|
26
|
+
[](https://pypi.org/project/dz-arabic-slug/)
|
|
27
|
+
[](LICENSE)
|
|
28
|
+
|
|
29
|
+
Fix the broken Arabic URLs problem in your Django, Flask, or FastAPI project - in one line of code.
|
|
30
|
+
|
|
31
|
+
## The Problem
|
|
32
|
+
|
|
33
|
+
Standard slug libraries fail with Arabic:
|
|
34
|
+
|
|
35
|
+
slugify("كيف تتعلم البرمجة") # returns "" (empty!)
|
|
36
|
+
|
|
37
|
+
This breaks SEO, user experience, and social sharing.
|
|
38
|
+
|
|
39
|
+
## The Solution
|
|
40
|
+
|
|
41
|
+
from dz_arabic_slug import slugify
|
|
42
|
+
slugify("كيف تتعلم البرمجة")
|
|
43
|
+
# returns "kayf-tataealam-albarmaja"
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
pip install dz-arabic-slug
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### Django
|
|
52
|
+
|
|
53
|
+
from django.db import models
|
|
54
|
+
from dz_arabic_slug import slugify
|
|
55
|
+
|
|
56
|
+
class Article(models.Model):
|
|
57
|
+
title = models.CharField(max_length=200)
|
|
58
|
+
slug = models.SlugField(unique=True, blank=True)
|
|
59
|
+
|
|
60
|
+
def save(self, *args, **kwargs):
|
|
61
|
+
if not self.slug:
|
|
62
|
+
self.slug = slugify(self.title)
|
|
63
|
+
super().save(*args, **kwargs)
|
|
64
|
+
|
|
65
|
+
### Flask
|
|
66
|
+
|
|
67
|
+
from dz_arabic_slug import slugify
|
|
68
|
+
new_article.slug = slugify(new_article.title)
|
|
69
|
+
|
|
70
|
+
### FastAPI
|
|
71
|
+
|
|
72
|
+
from fastapi import FastAPI
|
|
73
|
+
from dz_arabic_slug import slugify
|
|
74
|
+
|
|
75
|
+
app = FastAPI()
|
|
76
|
+
|
|
77
|
+
@app.post("/articles")
|
|
78
|
+
def create_article(title: str):
|
|
79
|
+
return {"slug": slugify(title)}
|
|
80
|
+
|
|
81
|
+
### Command-line
|
|
82
|
+
|
|
83
|
+
arabic-slug "كيف تتعلم البرمجة"
|
|
84
|
+
# output: kayf-tataealam-albarmaja
|
|
85
|
+
|
|
86
|
+
## API Reference
|
|
87
|
+
|
|
88
|
+
### slugify(text, separator="-", max_length=None, allow_arabic=False)
|
|
89
|
+
|
|
90
|
+
| Parameter | Type | Default | Description |
|
|
91
|
+
| :--- | :--- | :--- | :--- |
|
|
92
|
+
| text | str | required | Input text |
|
|
93
|
+
| separator | str | "-" | Character between words |
|
|
94
|
+
| max_length | int | None | Max slug length |
|
|
95
|
+
| allow_arabic | bool | False | Keep Arabic chars |
|
|
96
|
+
|
|
97
|
+
### Examples
|
|
98
|
+
|
|
99
|
+
slugify("مرحبا") # "marhaba"
|
|
100
|
+
slugify("Hello مرحبا 2024") # "hello-marhaba-2024"
|
|
101
|
+
slugify("مرحبا بك", separator="_") # "marhaba_bik"
|
|
102
|
+
slugify("مقال طويل", max_length=10) # "maqal-tawl"
|
|
103
|
+
slugify("مرحبا", allow_arabic=True) # "مرحبا"
|
|
104
|
+
|
|
105
|
+
## Transliteration Table
|
|
106
|
+
|
|
107
|
+
| Arabic | Latin | Arabic | Latin |
|
|
108
|
+
| :---: | :---: | :---: | :---: |
|
|
109
|
+
| ا | a | ف | f |
|
|
110
|
+
| ب | b | ق | q |
|
|
111
|
+
| ت | t | ك | k |
|
|
112
|
+
| ث | th | ل | l |
|
|
113
|
+
| ج | j | م | m |
|
|
114
|
+
| ح | h | ن | n |
|
|
115
|
+
| خ | kh | ه | h |
|
|
116
|
+
| د | d | و | w |
|
|
117
|
+
| ذ | dh | ي | y |
|
|
118
|
+
| ر | r | ة | a |
|
|
119
|
+
| ز | z | ال | al |
|
|
120
|
+
| س | s | لا | la |
|
|
121
|
+
| ش | sh | | |
|
|
122
|
+
| ص | s | | |
|
|
123
|
+
| ض | d | | |
|
|
124
|
+
| ط | t | | |
|
|
125
|
+
| ظ | z | | |
|
|
126
|
+
| ع | a | | |
|
|
127
|
+
| غ | gh | | |
|
|
128
|
+
|
|
129
|
+
Diacritics (tashkeel) are automatically removed.
|
|
130
|
+
|
|
131
|
+
## Testing
|
|
132
|
+
|
|
133
|
+
pytest -v
|
|
134
|
+
|
|
135
|
+
## Contributing
|
|
136
|
+
|
|
137
|
+
Contributions are welcome! Please fork, create a branch, add tests, and submit a Pull Request.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT (c) 2026 Oussama Boudinar <lionweb01@gmail.com> - dzopensource-lab
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# dz-arabic-slug
|
|
2
|
+
|
|
3
|
+
Convert Arabic text into clean, URL-friendly slugs with proper transliteration.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/dzopensource-lab/dz-arabic-slug/actions/workflows/test.yml)
|
|
6
|
+
[](https://pypi.org/project/dz-arabic-slug/)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
Fix the broken Arabic URLs problem in your Django, Flask, or FastAPI project - in one line of code.
|
|
10
|
+
|
|
11
|
+
## The Problem
|
|
12
|
+
|
|
13
|
+
Standard slug libraries fail with Arabic:
|
|
14
|
+
|
|
15
|
+
slugify("كيف تتعلم البرمجة") # returns "" (empty!)
|
|
16
|
+
|
|
17
|
+
This breaks SEO, user experience, and social sharing.
|
|
18
|
+
|
|
19
|
+
## The Solution
|
|
20
|
+
|
|
21
|
+
from dz_arabic_slug import slugify
|
|
22
|
+
slugify("كيف تتعلم البرمجة")
|
|
23
|
+
# returns "kayf-tataealam-albarmaja"
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
pip install dz-arabic-slug
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Django
|
|
32
|
+
|
|
33
|
+
from django.db import models
|
|
34
|
+
from dz_arabic_slug import slugify
|
|
35
|
+
|
|
36
|
+
class Article(models.Model):
|
|
37
|
+
title = models.CharField(max_length=200)
|
|
38
|
+
slug = models.SlugField(unique=True, blank=True)
|
|
39
|
+
|
|
40
|
+
def save(self, *args, **kwargs):
|
|
41
|
+
if not self.slug:
|
|
42
|
+
self.slug = slugify(self.title)
|
|
43
|
+
super().save(*args, **kwargs)
|
|
44
|
+
|
|
45
|
+
### Flask
|
|
46
|
+
|
|
47
|
+
from dz_arabic_slug import slugify
|
|
48
|
+
new_article.slug = slugify(new_article.title)
|
|
49
|
+
|
|
50
|
+
### FastAPI
|
|
51
|
+
|
|
52
|
+
from fastapi import FastAPI
|
|
53
|
+
from dz_arabic_slug import slugify
|
|
54
|
+
|
|
55
|
+
app = FastAPI()
|
|
56
|
+
|
|
57
|
+
@app.post("/articles")
|
|
58
|
+
def create_article(title: str):
|
|
59
|
+
return {"slug": slugify(title)}
|
|
60
|
+
|
|
61
|
+
### Command-line
|
|
62
|
+
|
|
63
|
+
arabic-slug "كيف تتعلم البرمجة"
|
|
64
|
+
# output: kayf-tataealam-albarmaja
|
|
65
|
+
|
|
66
|
+
## API Reference
|
|
67
|
+
|
|
68
|
+
### slugify(text, separator="-", max_length=None, allow_arabic=False)
|
|
69
|
+
|
|
70
|
+
| Parameter | Type | Default | Description |
|
|
71
|
+
| :--- | :--- | :--- | :--- |
|
|
72
|
+
| text | str | required | Input text |
|
|
73
|
+
| separator | str | "-" | Character between words |
|
|
74
|
+
| max_length | int | None | Max slug length |
|
|
75
|
+
| allow_arabic | bool | False | Keep Arabic chars |
|
|
76
|
+
|
|
77
|
+
### Examples
|
|
78
|
+
|
|
79
|
+
slugify("مرحبا") # "marhaba"
|
|
80
|
+
slugify("Hello مرحبا 2024") # "hello-marhaba-2024"
|
|
81
|
+
slugify("مرحبا بك", separator="_") # "marhaba_bik"
|
|
82
|
+
slugify("مقال طويل", max_length=10) # "maqal-tawl"
|
|
83
|
+
slugify("مرحبا", allow_arabic=True) # "مرحبا"
|
|
84
|
+
|
|
85
|
+
## Transliteration Table
|
|
86
|
+
|
|
87
|
+
| Arabic | Latin | Arabic | Latin |
|
|
88
|
+
| :---: | :---: | :---: | :---: |
|
|
89
|
+
| ا | a | ف | f |
|
|
90
|
+
| ب | b | ق | q |
|
|
91
|
+
| ت | t | ك | k |
|
|
92
|
+
| ث | th | ل | l |
|
|
93
|
+
| ج | j | م | m |
|
|
94
|
+
| ح | h | ن | n |
|
|
95
|
+
| خ | kh | ه | h |
|
|
96
|
+
| د | d | و | w |
|
|
97
|
+
| ذ | dh | ي | y |
|
|
98
|
+
| ر | r | ة | a |
|
|
99
|
+
| ز | z | ال | al |
|
|
100
|
+
| س | s | لا | la |
|
|
101
|
+
| ش | sh | | |
|
|
102
|
+
| ص | s | | |
|
|
103
|
+
| ض | d | | |
|
|
104
|
+
| ط | t | | |
|
|
105
|
+
| ظ | z | | |
|
|
106
|
+
| ع | a | | |
|
|
107
|
+
| غ | gh | | |
|
|
108
|
+
|
|
109
|
+
Diacritics (tashkeel) are automatically removed.
|
|
110
|
+
|
|
111
|
+
## Testing
|
|
112
|
+
|
|
113
|
+
pytest -v
|
|
114
|
+
|
|
115
|
+
## Contributing
|
|
116
|
+
|
|
117
|
+
Contributions are welcome! Please fork, create a branch, add tests, and submit a Pull Request.
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT (c) 2026 Oussama Boudinar <lionweb01@gmail.com> - dzopensource-lab
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Copyright (c) 2026 Oussama Boudinar <lionweb01@gmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""dz-arabic-slug - Convert Arabic text into URL-friendly slugs."""
|
|
4
|
+
|
|
5
|
+
from dz_arabic_slug.core import slugify
|
|
6
|
+
|
|
7
|
+
__version__ = "0.1.0"
|
|
8
|
+
__author__ = "Oussama Boudinar"
|
|
9
|
+
__email__ = "lionweb01@gmail.com"
|
|
10
|
+
__license__ = "MIT"
|
|
11
|
+
|
|
12
|
+
__all__ = ["slugify"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright (c) 2026 Oussama Boudinar <lionweb01@gmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""Command-line interface for dz-arabic-slug."""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from dz_arabic_slug import __author__, __email__, __version__
|
|
8
|
+
from dz_arabic_slug.core import slugify
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main():
|
|
12
|
+
"""Convert Arabic text from command line to slug."""
|
|
13
|
+
if len(sys.argv) < 2:
|
|
14
|
+
print(f"dz-arabic-slug v{__version__}")
|
|
15
|
+
print(f"Author: {__author__} <{__email__}>")
|
|
16
|
+
print("License: MIT")
|
|
17
|
+
print()
|
|
18
|
+
print('Usage: arabic-slug "text"')
|
|
19
|
+
sys.exit(1)
|
|
20
|
+
|
|
21
|
+
text = " ".join(sys.argv[1:])
|
|
22
|
+
print(slugify(text))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
main()
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright (c) 2026 Oussama Boudinar <lionweb01@gmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""Core slugify function."""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
import unicodedata
|
|
7
|
+
|
|
8
|
+
from dz_arabic_slug.mapping import ARABIC_TO_LATIN, COMBINATIONS
|
|
9
|
+
|
|
10
|
+
_ARABIC_RANGE = re.compile(r"[\u0600-\u06FF]+")
|
|
11
|
+
_NON_WORD = re.compile(r"[^\w\s-]")
|
|
12
|
+
_MULTI_DASH = re.compile(r"[-\s]+")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _is_arabic(char):
|
|
16
|
+
return bool(_ARABIC_RANGE.match(char))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _transliterate(text):
|
|
20
|
+
for arabic, latin in COMBINATIONS.items():
|
|
21
|
+
text = text.replace(arabic, latin)
|
|
22
|
+
|
|
23
|
+
result = []
|
|
24
|
+
for char in text:
|
|
25
|
+
if _is_arabic(char):
|
|
26
|
+
result.append(ARABIC_TO_LATIN.get(char, ""))
|
|
27
|
+
else:
|
|
28
|
+
result.append(char)
|
|
29
|
+
|
|
30
|
+
return "".join(result)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def slugify(text, separator="-", max_length=None, allow_arabic=False):
|
|
34
|
+
"""Convert text into a URL-friendly slug.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
text: Input text (Arabic, Latin, or mixed).
|
|
38
|
+
separator: Character to separate words (default: "-").
|
|
39
|
+
max_length: Maximum slug length (default: None = unlimited).
|
|
40
|
+
allow_arabic: Keep Arabic characters instead of transliterating.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
A URL-safe slug.
|
|
44
|
+
"""
|
|
45
|
+
if not text:
|
|
46
|
+
return ""
|
|
47
|
+
|
|
48
|
+
text = unicodedata.normalize("NFKD", text)
|
|
49
|
+
|
|
50
|
+
if not allow_arabic:
|
|
51
|
+
text = _transliterate(text)
|
|
52
|
+
|
|
53
|
+
text = _NON_WORD.sub("", text)
|
|
54
|
+
text = _MULTI_DASH.sub(separator, text).strip(separator)
|
|
55
|
+
text = text.lower()
|
|
56
|
+
|
|
57
|
+
if max_length and len(text) > max_length:
|
|
58
|
+
text = text[:max_length].rstrip(separator)
|
|
59
|
+
|
|
60
|
+
return text
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright (c) 2026 Oussama Boudinar <lionweb01@gmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""Arabic to Latin transliteration mapping."""
|
|
4
|
+
|
|
5
|
+
ARABIC_TO_LATIN = {
|
|
6
|
+
"ا": "a", "أ": "a", "إ": "i", "آ": "aa",
|
|
7
|
+
"ب": "b", "ت": "t", "ث": "th",
|
|
8
|
+
"ج": "j", "ح": "h", "خ": "kh",
|
|
9
|
+
"د": "d", "ذ": "dh",
|
|
10
|
+
"ر": "r", "ز": "z",
|
|
11
|
+
"س": "s", "ش": "sh",
|
|
12
|
+
"ص": "s", "ض": "d",
|
|
13
|
+
"ط": "t", "ظ": "z",
|
|
14
|
+
"ع": "a", "غ": "gh",
|
|
15
|
+
"ف": "f", "ق": "q",
|
|
16
|
+
"ك": "k", "ل": "l",
|
|
17
|
+
"م": "m", "ن": "n",
|
|
18
|
+
"ه": "h", "و": "w", "ي": "y",
|
|
19
|
+
"ى": "a", "ة": "a", "ء": "", "ؤ": "w", "ئ": "y",
|
|
20
|
+
"َ": "", "ُ": "", "ِ": "", "ْ": "", "ّ": "", "ً": "", "ٌ": "", "ٍ": "",
|
|
21
|
+
"ـ": "",
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
COMBINATIONS = {
|
|
25
|
+
"لا": "la", "لأ": "la", "لإ": "li", "لآ": "laa",
|
|
26
|
+
"ال": "al",
|
|
27
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dz-arabic-slug
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert Arabic text into URL-friendly slugs with proper transliteration.
|
|
5
|
+
Author-email: Oussama Boudinar <lionweb01@gmail.com>
|
|
6
|
+
Maintainer-email: Oussama Boudinar <lionweb01@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/dzopensource-lab/dz-arabic-slug
|
|
9
|
+
Project-URL: Repository, https://github.com/dzopensource-lab/dz-arabic-slug
|
|
10
|
+
Project-URL: Issues, https://github.com/dzopensource-lab/dz-arabic-slug/issues
|
|
11
|
+
Keywords: slug,arabic,slugify,url,transliteration,django,flask,fastapi
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Natural Language :: Arabic
|
|
15
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# dz-arabic-slug
|
|
22
|
+
|
|
23
|
+
Convert Arabic text into clean, URL-friendly slugs with proper transliteration.
|
|
24
|
+
|
|
25
|
+
[](https://github.com/dzopensource-lab/dz-arabic-slug/actions/workflows/test.yml)
|
|
26
|
+
[](https://pypi.org/project/dz-arabic-slug/)
|
|
27
|
+
[](LICENSE)
|
|
28
|
+
|
|
29
|
+
Fix the broken Arabic URLs problem in your Django, Flask, or FastAPI project - in one line of code.
|
|
30
|
+
|
|
31
|
+
## The Problem
|
|
32
|
+
|
|
33
|
+
Standard slug libraries fail with Arabic:
|
|
34
|
+
|
|
35
|
+
slugify("كيف تتعلم البرمجة") # returns "" (empty!)
|
|
36
|
+
|
|
37
|
+
This breaks SEO, user experience, and social sharing.
|
|
38
|
+
|
|
39
|
+
## The Solution
|
|
40
|
+
|
|
41
|
+
from dz_arabic_slug import slugify
|
|
42
|
+
slugify("كيف تتعلم البرمجة")
|
|
43
|
+
# returns "kayf-tataealam-albarmaja"
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
pip install dz-arabic-slug
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### Django
|
|
52
|
+
|
|
53
|
+
from django.db import models
|
|
54
|
+
from dz_arabic_slug import slugify
|
|
55
|
+
|
|
56
|
+
class Article(models.Model):
|
|
57
|
+
title = models.CharField(max_length=200)
|
|
58
|
+
slug = models.SlugField(unique=True, blank=True)
|
|
59
|
+
|
|
60
|
+
def save(self, *args, **kwargs):
|
|
61
|
+
if not self.slug:
|
|
62
|
+
self.slug = slugify(self.title)
|
|
63
|
+
super().save(*args, **kwargs)
|
|
64
|
+
|
|
65
|
+
### Flask
|
|
66
|
+
|
|
67
|
+
from dz_arabic_slug import slugify
|
|
68
|
+
new_article.slug = slugify(new_article.title)
|
|
69
|
+
|
|
70
|
+
### FastAPI
|
|
71
|
+
|
|
72
|
+
from fastapi import FastAPI
|
|
73
|
+
from dz_arabic_slug import slugify
|
|
74
|
+
|
|
75
|
+
app = FastAPI()
|
|
76
|
+
|
|
77
|
+
@app.post("/articles")
|
|
78
|
+
def create_article(title: str):
|
|
79
|
+
return {"slug": slugify(title)}
|
|
80
|
+
|
|
81
|
+
### Command-line
|
|
82
|
+
|
|
83
|
+
arabic-slug "كيف تتعلم البرمجة"
|
|
84
|
+
# output: kayf-tataealam-albarmaja
|
|
85
|
+
|
|
86
|
+
## API Reference
|
|
87
|
+
|
|
88
|
+
### slugify(text, separator="-", max_length=None, allow_arabic=False)
|
|
89
|
+
|
|
90
|
+
| Parameter | Type | Default | Description |
|
|
91
|
+
| :--- | :--- | :--- | :--- |
|
|
92
|
+
| text | str | required | Input text |
|
|
93
|
+
| separator | str | "-" | Character between words |
|
|
94
|
+
| max_length | int | None | Max slug length |
|
|
95
|
+
| allow_arabic | bool | False | Keep Arabic chars |
|
|
96
|
+
|
|
97
|
+
### Examples
|
|
98
|
+
|
|
99
|
+
slugify("مرحبا") # "marhaba"
|
|
100
|
+
slugify("Hello مرحبا 2024") # "hello-marhaba-2024"
|
|
101
|
+
slugify("مرحبا بك", separator="_") # "marhaba_bik"
|
|
102
|
+
slugify("مقال طويل", max_length=10) # "maqal-tawl"
|
|
103
|
+
slugify("مرحبا", allow_arabic=True) # "مرحبا"
|
|
104
|
+
|
|
105
|
+
## Transliteration Table
|
|
106
|
+
|
|
107
|
+
| Arabic | Latin | Arabic | Latin |
|
|
108
|
+
| :---: | :---: | :---: | :---: |
|
|
109
|
+
| ا | a | ف | f |
|
|
110
|
+
| ب | b | ق | q |
|
|
111
|
+
| ت | t | ك | k |
|
|
112
|
+
| ث | th | ل | l |
|
|
113
|
+
| ج | j | م | m |
|
|
114
|
+
| ح | h | ن | n |
|
|
115
|
+
| خ | kh | ه | h |
|
|
116
|
+
| د | d | و | w |
|
|
117
|
+
| ذ | dh | ي | y |
|
|
118
|
+
| ر | r | ة | a |
|
|
119
|
+
| ز | z | ال | al |
|
|
120
|
+
| س | s | لا | la |
|
|
121
|
+
| ش | sh | | |
|
|
122
|
+
| ص | s | | |
|
|
123
|
+
| ض | d | | |
|
|
124
|
+
| ط | t | | |
|
|
125
|
+
| ظ | z | | |
|
|
126
|
+
| ع | a | | |
|
|
127
|
+
| غ | gh | | |
|
|
128
|
+
|
|
129
|
+
Diacritics (tashkeel) are automatically removed.
|
|
130
|
+
|
|
131
|
+
## Testing
|
|
132
|
+
|
|
133
|
+
pytest -v
|
|
134
|
+
|
|
135
|
+
## Contributing
|
|
136
|
+
|
|
137
|
+
Contributions are welcome! Please fork, create a branch, add tests, and submit a Pull Request.
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
MIT (c) 2026 Oussama Boudinar <lionweb01@gmail.com> - dzopensource-lab
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
dz_arabic_slug/__init__.py
|
|
5
|
+
dz_arabic_slug/cli.py
|
|
6
|
+
dz_arabic_slug/core.py
|
|
7
|
+
dz_arabic_slug/mapping.py
|
|
8
|
+
dz_arabic_slug.egg-info/PKG-INFO
|
|
9
|
+
dz_arabic_slug.egg-info/SOURCES.txt
|
|
10
|
+
dz_arabic_slug.egg-info/dependency_links.txt
|
|
11
|
+
dz_arabic_slug.egg-info/entry_points.txt
|
|
12
|
+
dz_arabic_slug.egg-info/top_level.txt
|
|
13
|
+
tests/test_core.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dz_arabic_slug
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77.0.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dz-arabic-slug"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Convert Arabic text into URL-friendly slugs with proper transliteration."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Oussama Boudinar", email = "lionweb01@gmail.com" }]
|
|
14
|
+
maintainers = [{ name = "Oussama Boudinar", email = "lionweb01@gmail.com" }]
|
|
15
|
+
keywords = ["slug", "arabic", "slugify", "url", "transliteration", "django", "flask", "fastapi"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Natural Language :: Arabic",
|
|
20
|
+
"Topic :: Text Processing :: Linguistic",
|
|
21
|
+
]
|
|
22
|
+
dependencies = []
|
|
23
|
+
|
|
24
|
+
[project.scripts]
|
|
25
|
+
arabic-slug = "dz_arabic_slug.cli:main"
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://github.com/dzopensource-lab/dz-arabic-slug"
|
|
29
|
+
Repository = "https://github.com/dzopensource-lab/dz-arabic-slug"
|
|
30
|
+
Issues = "https://github.com/dzopensource-lab/dz-arabic-slug/issues"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
include = ["dz_arabic_slug*"]
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright (c) 2026 Oussama Boudinar <lionweb01@gmail.com>
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
"""Tests for dz_arabic_slug."""
|
|
4
|
+
|
|
5
|
+
from dz_arabic_slug import slugify
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_simple_arabic():
|
|
9
|
+
assert slugify("مرحبا") == "mrhba"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_arabic_sentence():
|
|
13
|
+
assert slugify("كيف تتعلم البرمجة") == "kyf-ttalm-albrmja"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_mixed_text():
|
|
17
|
+
assert slugify("Hello مرحبا") == "hello-mrhba"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_with_numbers():
|
|
21
|
+
assert slugify("مقال 2024") == "mqal-2024"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_empty_string():
|
|
25
|
+
assert slugify("") == ""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_only_spaces():
|
|
29
|
+
assert slugify(" ") == ""
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_custom_separator():
|
|
33
|
+
assert slugify("مرحبا بك", separator="_") == "mrhba_bk"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_max_length():
|
|
37
|
+
result = slugify("مقال طويل جدا عن البرمجة", max_length=10)
|
|
38
|
+
assert len(result) <= 10
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_allow_arabic():
|
|
42
|
+
assert slugify("مرحبا", allow_arabic=True) == "مرحبا"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_special_characters():
|
|
46
|
+
assert slugify("مرحبا!@#") == "mrhba"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_english_only():
|
|
50
|
+
assert slugify("Hello World") == "hello-world"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_al_definite_article():
|
|
54
|
+
assert slugify("البرمجة") == "albrmja"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_tashkeel_removed():
|
|
58
|
+
assert slugify("مَرْحَبًا") == "mrhba"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_tashkeel_same_as_plain():
|
|
62
|
+
# With or without diacritics, same result
|
|
63
|
+
assert slugify("مَرْحَبًا") == slugify("مرحبا")
|