8 This module translates national characters into similar sounding
9 latin characters (transliteration).
10 At the moment, Greek, Turkish, Russian, Ukrainian, Czech, Polish,
11 Latvian alphabets are supported (it covers 99% of needs).
21 >>> u'Hello World!'.encode('trans')
23 >>> u'Привет, Мир!'.encode('trans')
27 Work only with unicode strings
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 >>> 'Hello World!'.encode('trans')
30 Traceback (most recent call last):
32 TypeError: trans codec support only unicode string, <type 'str'> given.
37 ... -- Раскудрить твою через коромысло в бога душу мать
38 ... триста тысяч раз едрену вошь тебе в крыло
39 ... и кактус в глотку! -- взревел разъяренный Никодим.
40 ... -- Аминь, -- робко добавил из склепа папа Пий.
41 ... (c) Г. Л. Олди, "Сказки дедушки вампира".'''
43 >>> print s.encode('trans')
44 -- Raskudrit tvoyu cherez koromyslo v boga dushu mat
45 trista tysyach raz edrenu vosh tebe v krylo
46 i kaktus v glotku! -- vzrevel razyarennyy Nikodim.
47 -- Amin, -- robko dobavil iz sklepa papa Piy.
48 (c) G. L. Oldi, "Skazki dedushki vampira".
52 Use the table "id", leaving only the Latin characters, digits and underscores:
54 >>> print u'1 2 3 4 5 \n6 7 8 9 0'.encode('trans')
57 >>> print u'1 2 3 4 5 \n6 7 8 9 0'.encode('trans/id')
59 >>> s.encode('trans/id')[-42:-1]
60 u'_c__G__L__Oldi___Skazki_dedushki_vampira_'
67 >>> u'1 2 3 4 5 6 7 8 9 0'.encode('trans/my')
68 Traceback (most recent call last):
70 ValueError: Table "my" not found in tables!
71 >>> trans.tables['my'] = {u'1': u'A', u'2': u'B'};
72 >>> u'1 2 3 4 5 6 7 8 9 0'.encode('trans/my')
73 u'A_B________________'
78 Table can consist of two parts - the map of diphthongs and map of characters.
79 First are processed diphthongs, by simple replacement on the substring.
80 Then according to the map of characters, replacing each character of string
81 by it's mapping. If character is absent in characters map, checked key None,
82 if not, then is used the default character u'_'.
84 >>> diphthongs = {u'11': u'AA', u'22': u'BB'}
85 >>> characters = {u'a': u'z', u'b': u'y', u'c': u'x',
86 ... u'A': u'A', u'B': u'B', None: u'-'}
87 >>> trans.tables['test'] = (diphthongs, characters)
88 >>> u'11abc22cbaCC'.encode('trans/test')
91 **The characters created by processing of diphthongs are also processed
92 by the map of the symbols:**
94 >>> diphthongs = {u'11': u'AA', u'22': u'BB'}
95 >>> characters = {u'a': u'z', u'b': u'y', u'c': u'x', None: u'-'}
96 >>> trans.tables['test'] = (diphthongs, characters)
97 >>> u'11abc22cbaCC'.encode('trans/test')
100 Without the diphthongs
101 ~~~~~~~~~~~~~~~~~~~~~~
102 These two tables are equivalent:
104 >>> characters = {u'a': u'z', u'b': u'y', u'c': u'x', None: u'-'}
105 >>> trans.tables['t1'] = characters
106 >>> trans.tables['t2'] = ({}, characters)
107 >>> u'11abc22cbaCC'.encode('trans/t1') == u'11abc22cbaCC'.encode('trans/t2')
113 + *Special thanks to Yuri Yurevich aka j2a for the kick in the right direction.*
114 - http://www.python.su/forum/viewtopic.php?pid=28965
115 - http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/media/js/urlify.js
116 + *I please forgiveness for my bad English. I promise to be corrected.*
120 __version__ = '1.1a7'
121 __author__ = 'Zelenyak Aleksandr aka ZZZ <zzz.sochi@gmail.com>'
124 u'à': u'a', u'á': u'a', u'â': u'a', u'ã': u'a', u'ä': u'a', u'å': u'a',
125 u'æ': u'ae', u'ç': u'c', u'è': u'e', u'é': u'e', u'ê': u'e', u'ë': u'e',
126 u'ì': u'i', u'í': u'i', u'î': u'i', u'ï': u'i', u'ð': u'd', u'ñ': u'n',
127 u'ò': u'o', u'ó': u'o', u'ô': u'o', u'õ': u'o', u'ö': u'o', u'ő': u'o',
128 u'ø': u'o', u'ù': u'u', u'ú': u'u', u'û': u'u', u'ü': u'u', u'ű': u'u',
129 u'ý': u'y', u'þ': u'th', u'ÿ': u'y',
131 u'À': u'A', u'Á': u'A', u'Â': u'A', u'Ã': u'A', u'Ä': u'A', u'Å': u'A',
132 u'Æ': u'AE', u'Ç': u'C', u'È': u'E', u'É': u'E', u'Ê': u'E', u'Ë': u'E',
133 u'Ì': u'I', u'Í': u'I', u'Î': u'I', u'Ï': u'I', u'Ð': u'D', u'Ñ': u'N',
134 u'Ò': u'O', u'Ó': u'O', u'Ô': u'O', u'Õ': u'O', u'Ö': u'O', u'Ő': u'O',
135 u'Ø': u'O', u'Ù': u'U', u'Ú': u'U', u'Û': u'U', u'Ü': u'U', u'Ű': u'U',
136 u'Ý': u'Y', u'Þ': u'TH', u'ß': u'ss'
140 u'α': u'a', u'β': u'b', u'γ': u'g', u'δ': u'd', u'ε': u'e', u'ζ': u'z',
141 u'η': u'h', u'θ': u'8', u'ι': u'i', u'κ': u'k', u'λ': u'l', u'μ': u'm',
142 u'ν': u'n', u'ξ': u'3', u'ο': u'o', u'π': u'p', u'ρ': u'r', u'σ': u's',
143 u'τ': u't', u'υ': u'y', u'φ': u'f', u'χ': u'x', u'ψ': u'ps', u'ω': u'w',
144 u'ά': u'a', u'έ': u'e', u'ί': u'i', u'ό': u'o', u'ύ': u'y', u'ή': u'h',
145 u'ώ': u'w', u'ς': u's', u'ϊ': u'i', u'ΰ': u'y', u'ϋ': u'y', u'ΐ': u'i',
147 u'Α': u'A', u'Β': u'B', u'Γ': u'G', u'Δ': u'D', u'Ε': u'E', u'Ζ': u'Z',
148 u'Η': u'H', u'Θ': u'8', u'Ι': u'I', u'Κ': u'K', u'Λ': u'L', u'Μ': u'M',
149 u'Ν': u'N', u'Ξ': u'3', u'Ο': u'O', u'Π': u'P', u'Ρ': u'R', u'Σ': u'S',
150 u'Τ': u'T', u'Υ': u'Y', u'Φ': u'F', u'Χ': u'X', u'Ψ': u'PS', u'Ω': u'W',
151 u'Ά': u'A', u'Έ': u'E', u'Ί': u'I', u'Ό': u'O', u'Ύ': u'Y', u'Ή': u'H',
152 u'Ώ': u'W', u'Ϊ': u'I', u'Ϋ': u'Y'
156 u'ş': u's', u'Ş': u'S', u'ı': u'i', u'İ': u'I', u'ç': u'c', u'Ç': u'C',
157 u'ü': u'u', u'Ü': u'U', u'ö': u'o', u'Ö': u'O', u'ğ': u'g', u'Ğ': u'G'
161 {u'юй': u'yuy', u'ей': u'yay',
162 u'Юй': u'Yuy', u'Ей': u'Yay'},
164 u'а': u'a', u'б': u'b', u'в': u'v', u'г': u'g', u'д': u'd', u'е': u'e',
165 u'ё': u'yo', u'ж': u'zh', u'з': u'z', u'и': u'i', u'й': u'y', u'к': u'k',
166 u'л': u'l', u'м': u'm', u'н': u'n', u'о': u'o', u'п': u'p', u'р': u'r',
167 u'с': u's', u'т': u't', u'у': u'u', u'ф': u'f', u'х': u'h', u'ц': u'c',
168 u'ч': u'ch', u'ш': u'sh', u'щ': u'sh', u'ъ': u'', u'ы': u'y', u'ь': u'',
169 u'э': u'e', u'ю': u'yu', u'я': u'ya',
171 u'А': u'A', u'Б': u'B', u'В': u'V', u'Г': u'G', u'Д': u'D', u'Е': u'E',
172 u'Ё': u'Yo', u'Ж': u'Zh', u'З': u'Z', u'И': u'I', u'Й': u'Y', u'К': u'K',
173 u'Л': u'L', u'М': u'M', u'Н': u'N', u'О': u'O', u'П': u'P', u'Р': u'R',
174 u'С': u'S', u'Т': u'T', u'У': u'U', u'Ф': u'F', u'Х': u'H', u'Ц': u'C',
175 u'Ч': u'Ch', u'Ш': u'Sh', u'Щ': u'Sh', u'Ъ': u'', u'Ы': u'Y', u'Ь': u'',
176 u'Э': u'E', u'Ю': u'Yu', u'Я': u'Ya'
179 ukrainian = (russian[0].copy(), {
180 u'Є': u'Ye', u'І': u'I', u'Ї': u'Yi', u'Ґ': u'G',
181 u'є': u'ye', u'і': u'i', u'ї': u'yi', u'ґ': u'g'
183 ukrainian[1].update(russian[1])
186 u'č': u'c', u'ď': u'd', u'ě': u'e', u'ň': u'n', u'ř': u'r', u'š': u's',
187 u'ť': u't', u'ů': u'u', u'ž': u'z',
188 u'Č': u'C', u'Ď': u'D', u'Ě': u'E', u'Ň': u'N', u'Ř': u'R', u'Š': u'S',
189 u'Ť': u'T', u'Ů': u'U', u'Ž': u'Z'
193 u'ą': u'a', u'ć': u'c', u'ę': u'e', u'ł': u'l', u'ń': u'n', u'ó': u'o',
194 u'ś': u's', u'ź': u'z', u'ż': u'z',
195 u'Ą': u'A', u'Ć': u'C', u'Ę': u'e', u'Ł': u'L', u'Ń': u'N', u'Ó': u'o',
196 u'Ś': u'S', u'Ź': u'Z', u'Ż': u'Z'
200 u'ā': u'a', u'č': u'c', u'ē': u'e', u'ģ': u'g', u'ī': u'i', u'ķ': u'k',
201 u'ļ': u'l', u'ņ': u'n', u'š': u's', u'ū': u'u', u'ž': u'z',
202 u'Ā': u'A', u'Č': u'C', u'Ē': u'E', u'Ģ': u'G', u'Ī': u'i', u'Ķ': u'k',
203 u'Ļ': u'L', u'Ņ': u'N', u'Š': u'S', u'Ū': u'u', u'Ž': u'Z'
208 ascii_str = u'''_0123456789
209 abcdefghijklmnopqrstuvwxyz
210 ABCDEFGHIJKLMNOPQRSTUVWXYZ
211 !"#$%&'()*+,_-./:;<=>?@[\\]^`{|}~ \t\n\r\x0b\x0c'''
213 ascii = ({}, dict(zip(ascii_str, ascii_str)))
214 for t in [latin, greek, turkish, russian, ukrainian, czech, polish, latvian]:
215 if isinstance(t, dict):
217 ascii[0].update(t[0])
218 ascii[1].update(t[1])
219 ascii[1][None] = u'_'
223 id = (ascii[0].copy(), ascii[1].copy())
224 for c in '''!"#$%&'()*+,_-./:;<=>?@[\\]^`{|}~ \t\n\r\x0b\x0c''':
228 def trans(input, table=ascii):
229 '''Translate unicode string, using 'table'.
230 Table may be tuple (diphthongs, other) or dict (other).'''
231 if not isinstance(input, unicode):
232 raise TypeError, 'trans codec support only unicode string, %r given.' \
234 if isinstance(table, dict):
238 for diphthong, value in table[0].items():
239 first = first.replace(diphthong, value)
243 second += table[1].get(char, table[1].get(None, u'_'))
245 return second, len(second)
247 tables = {'ascii': ascii, 'text': ascii, 'id': id}
251 def encode(input, errors='strict', table_name='ascii'):
253 table = tables[table_name]
255 raise ValueError, 'Table "%s" not found in tables!' % table_name
257 return trans(input, table)
259 def no_decode(input, errors='strict'):
260 raise TypeError("trans codec does not support decode.")
262 def trans_codec(enc):
264 return codecs.CodecInfo(encode, no_decode)
267 enc_name, table_name = enc.split('/', 1)
270 if enc_name != 'trans':
272 if table_name not in tables:
273 raise ValueError, 'Table "%s" not found in tables!' % table_name
275 return codecs.CodecInfo(lambda i, e='strict': encode(i, e, table_name),
278 codecs.register(trans_codec)