Skip to content

Commit d161d96

Browse files
authored
Merge pull request #1 from freakboy3742/master
Added Django template tag and filter for emojificate
2 parents c270478 + 01f6984 commit d161d96

File tree

12 files changed

+205
-73
lines changed

12 files changed

+205
-73
lines changed

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
*.pyc
2+
__pycache__
3+
*~
4+
.*.sw[op]
5+
*.egg-info
6+
*.egg
7+
.eggs
8+
.tox
9+
local
10+
dist
11+
build
12+
_build
13+
distribute-*

MANIFEST.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
include *.rst
2+
include LICENSE
3+
recursive-include tests *.py
4+
recursive-include docs Makefile
5+
recursive-include docs *.py
6+
recursive-include docs *.bat
7+
recursive-include docs *.rst

README.md

Lines changed: 0 additions & 36 deletions
This file was deleted.

README.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
emojificate
2+
===========
3+
4+
Emojificate is a Python implementation of a concept of using fallback images, alt text, title text and aria labels to represent emoji in HTML code in a more accessible method.
5+
6+
Usage
7+
-----
8+
9+
To convert a string from the command line::
10+
11+
$ python3 -m emojificate "I 💜 emoji 😊"
12+
I <img src="https://twemoji.maxcdn.com/36x36/1f49c.png" alt="💜" title="Purple Heart" height="16px" aria-label="Emoji: Purple Heart"> emoji <img src="https://twemoji.maxcdn.com/36x36/1f60a.png" alt="😊" title="Smiling Face With Smiling Eyes" height="16px" aria-label="Emoji: Smiling Face With Smiling Eyes">
13+
14+
Or, if you've got a Django project, put ``emojificate`` into your ``INSTALLED_APPS``, and then use the following in a template::
15+
16+
{% load emojificate %}
17+
This is some {{ user_content|emojificate }} that has emoji in it.
18+
19+
{% emojified %}
20+
This is some template content that 💜 emoji as well.
21+
{% endemojified %}
22+
23+
Implementation
24+
--------------
25+
26+
TL;DR: Take a string, split it into token, and if a token is emoji, process it into a nice format.
27+
28+
Splitting the string is a problem, because at the moment it **does not handle Zero Width Joining sequences**. However, native Python string tokenization does work for the most part.
29+
30+
Given a list of tokens, we can leverage the native `unicodedata <https://docs.python.org/3/library/unicodedata.html>`__ to:
31+
32+
* see if a token is a unicode Symbol (an emoji)
33+
* get the codepoint for the emoji, and
34+
* get the name of the emoji
35+
36+
From there, we construct an ``<img>`` replacement for the emoji:
37+
38+
* Use images from `twemoji <https://github.com/twitter/twemoji>`__, Twitter's emoji set
39+
* Have an ``alt`` parameter containing the original emoji. This allows for copying-pasting.
40+
* Use the name of the emoji in the ``title`` parameter. This allows for hover-tooltips.
41+
* Add an ``aria-label`` for screen-reader accessibility.
42+
43+
For more information, see `Solve For Emoji <http://glasnt.com/blog/2016/08/06/solve-for-emoji.html>`__.
44+
45+
Limitations
46+
-----------
47+
48+
* Does not handle Zero Width Join Sequences; for example: 🖐🏽, 👩‍👩‍👧

emojificate.py

Lines changed: 0 additions & 37 deletions
This file was deleted.

emojificate/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Examples of valid version strings
2+
# __version__ = '1.2.3.dev1' # Development release 1
3+
# __version__ = '1.2.3a1' # Alpha Release 1
4+
# __version__ = '1.2.3b1' # Beta Release 1
5+
# __version__ = '1.2.3rc1' # RC Release 1
6+
# __version__ = '1.2.3' # Final Release
7+
# __version__ = '1.2.3.post1' # Post Release 1
8+
9+
__version__ = "0.1.0"

emojificate/__main__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import sys
2+
3+
from .filter import emojificate
4+
5+
6+
def display_help():
7+
print("emojificate.py -- turns text with emoji into text with accessible emoji")
8+
9+
10+
if __name__ == "__main__":
11+
line = " ".join(sys.argv[1:])
12+
if line:
13+
print(emojificate(line))
14+
else:
15+
display_help()
16+
sys.exit(1)

emojificate/filter.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import unicodedata
2+
3+
4+
__all__ = ['emojificate']
5+
6+
7+
cdn = "https://twemoji.maxcdn.com/36x36/"
8+
cdn_ft = ".png"
9+
10+
11+
def tag(a, b):
12+
return "%s=\"%s\"" % (a, b)
13+
14+
15+
def convert(char):
16+
if unicodedata.category(char) == "So":
17+
name = unicodedata.name(char).title()
18+
code = char.encode("unicode_escape").decode("utf-8")[2:].strip("0")
19+
return "".join([
20+
"<img",
21+
tag(" src", cdn + code + cdn_ft),
22+
tag(" alt", char),
23+
tag(" title", name),
24+
tag(" aria-label", "Emoji: %s" % name),
25+
">"
26+
])
27+
else:
28+
return char
29+
30+
31+
def emojificate(line):
32+
return ''.join(convert(ch) for ch in line)

emojificate/templatetags/__init__.py

Whitespace-only changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from django.template import Library, Node
2+
from django.utils.safestring import mark_safe
3+
from django.utils.html import conditional_escape
4+
5+
from ..filter import emojificate
6+
7+
8+
register = Library()
9+
10+
11+
@register.filter('emojificate', needs_autoescape=True)
12+
def emojificate_filter(content, autoescape=True):
13+
"Convert any emoji in a string into accessible content."
14+
# return mark_safe(emojificate(content))
15+
if autoescape:
16+
esc = conditional_escape
17+
else:
18+
esc = lambda x: x
19+
return mark_safe(emojificate(esc(content)))
20+
21+
22+
@register.tag('emojified')
23+
def do_emojified(parser, token):
24+
nodelist = parser.parse(('endemojified',))
25+
parser.delete_first_token()
26+
return EmojifiedNode(nodelist)
27+
28+
29+
class EmojifiedNode(Node):
30+
def __init__(self, nodelist):
31+
self.nodelist = nodelist
32+
33+
def render(self, context):
34+
output = self.nodelist.render(context)
35+
return emojificate(output)

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[bdist_wheel]
2+
universal=1

setup.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import re
2+
from setuptools import setup, find_packages
3+
from codecs import open
4+
from os import path
5+
6+
here = path.abspath(path.dirname(__file__))
7+
8+
# Get the long description from the relevant file
9+
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
10+
long_description = f.read()
11+
12+
with open(path.join(here, 'emojificate', '__init__.py'), encoding='utf8') as version_file:
13+
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file.read(), re.M)
14+
if version_match:
15+
version = version_match.group(1)
16+
else:
17+
raise RuntimeError("Unable to find version string.")
18+
19+
setup(
20+
name='emojificate',
21+
version=version,
22+
description='A Python implementation of a concept of using fallback images, alt text, title text and aria labels to represent emoji in HTML code in a more accessible method.',
23+
long_description=long_description,
24+
url='https://github.com/glasnt/emojificate',
25+
author='Katie McLaughlin',
26+
author_email='[email protected]',
27+
license='New BSD',
28+
classifiers=[
29+
'Development Status :: 3 - Alpha',
30+
'Environment :: Web Environment',
31+
'Intended Audience :: Developers',
32+
'License :: OSI Approved :: BSD License',
33+
'Operating System :: OS Independent',
34+
'Programming Language :: Python :: 3',
35+
'Programming Language :: Python :: 3.2',
36+
'Programming Language :: Python :: 3.3',
37+
'Programming Language :: Python :: 3.4',
38+
'Topic :: Text Processing :: Filters',
39+
'Topic :: Utilities',
40+
],
41+
keywords='emoji accessibility a11y',
42+
packages=find_packages(exclude=['docs', 'test']),
43+
)

0 commit comments

Comments
 (0)