1#!/usr/bin/env python3 2""" 3 Convert the X11 locale.alias file into a mapping dictionary suitable 4 for locale.py. 5 6 Written by Marc-Andre Lemburg <mal@genix.com>, 2004-12-10. 7 8""" 9import locale 10import sys 11_locale = locale 12 13# Location of the X11 alias file. 14LOCALE_ALIAS = '/usr/share/X11/locale/locale.alias' 15# Location of the glibc SUPPORTED locales file. 16SUPPORTED = '/usr/share/i18n/SUPPORTED' 17 18def parse(filename): 19 20 with open(filename, encoding='latin1') as f: 21 lines = list(f) 22 # Remove mojibake in /usr/share/X11/locale/locale.alias. 23 # b'\xef\xbf\xbd' == '\ufffd'.encode('utf-8') 24 lines = [line for line in lines if '\xef\xbf\xbd' not in line] 25 data = {} 26 for line in lines: 27 line = line.strip() 28 if not line: 29 continue 30 if line[:1] == '#': 31 continue 32 locale, alias = line.split() 33 # Fix non-standard locale names, e.g. ks_IN@devanagari.UTF-8 34 if '@' in alias: 35 alias_lang, _, alias_mod = alias.partition('@') 36 if '.' in alias_mod: 37 alias_mod, _, alias_enc = alias_mod.partition('.') 38 alias = alias_lang + '.' + alias_enc + '@' + alias_mod 39 # Strip ':' 40 if locale[-1] == ':': 41 locale = locale[:-1] 42 # Lower-case locale 43 locale = locale.lower() 44 # Ignore one letter locale mappings (except for 'c') 45 if len(locale) == 1 and locale != 'c': 46 continue 47 # Normalize encoding, if given 48 if '.' in locale: 49 lang, encoding = locale.split('.')[:2] 50 encoding = encoding.replace('-', '') 51 encoding = encoding.replace('_', '') 52 locale = lang + '.' + encoding 53 data[locale] = alias 54 return data 55 56def parse_glibc_supported(filename): 57 58 with open(filename, encoding='latin1') as f: 59 lines = list(f) 60 data = {} 61 for line in lines: 62 line = line.strip() 63 if not line: 64 continue 65 if line[:1] == '#': 66 continue 67 line = line.replace('/', ' ').strip() 68 line = line.rstrip('\\').rstrip() 69 words = line.split() 70 if len(words) != 2: 71 continue 72 alias, alias_encoding = words 73 # Lower-case locale 74 locale = alias.lower() 75 # Normalize encoding, if given 76 if '.' in locale: 77 lang, encoding = locale.split('.')[:2] 78 encoding = encoding.replace('-', '') 79 encoding = encoding.replace('_', '') 80 locale = lang + '.' + encoding 81 # Add an encoding to alias 82 alias, _, modifier = alias.partition('@') 83 alias = _locale._replace_encoding(alias, alias_encoding) 84 if modifier and not (modifier == 'euro' and alias_encoding == 'ISO-8859-15'): 85 alias += '@' + modifier 86 data[locale] = alias 87 return data 88 89def pprint(data): 90 items = sorted(data.items()) 91 for k, v in items: 92 print(' %-40s%a,' % ('%a:' % k, v)) 93 94def print_differences(data, olddata): 95 items = sorted(olddata.items()) 96 for k, v in items: 97 if k not in data: 98 print('# removed %a' % k) 99 elif olddata[k] != data[k]: 100 print('# updated %a -> %a to %a' % \ 101 (k, olddata[k], data[k])) 102 # Additions are not mentioned 103 104def optimize(data): 105 locale_alias = locale.locale_alias 106 locale.locale_alias = data.copy() 107 for k, v in data.items(): 108 del locale.locale_alias[k] 109 if locale.normalize(k) != v: 110 locale.locale_alias[k] = v 111 newdata = locale.locale_alias 112 errors = check(data) 113 locale.locale_alias = locale_alias 114 if errors: 115 sys.exit(1) 116 return newdata 117 118def check(data): 119 # Check that all alias definitions from the X11 file 120 # are actually mapped to the correct alias locales. 121 errors = 0 122 for k, v in data.items(): 123 if locale.normalize(k) != v: 124 print('ERROR: %a -> %a != %a' % (k, locale.normalize(k), v), 125 file=sys.stderr) 126 errors += 1 127 return errors 128 129if __name__ == '__main__': 130 import argparse 131 parser = argparse.ArgumentParser() 132 parser.add_argument('--locale-alias', default=LOCALE_ALIAS, 133 help='location of the X11 alias file ' 134 '(default: %a)' % LOCALE_ALIAS) 135 parser.add_argument('--glibc-supported', default=SUPPORTED, 136 help='location of the glibc SUPPORTED locales file ' 137 '(default: %a)' % SUPPORTED) 138 args = parser.parse_args() 139 140 data = locale.locale_alias.copy() 141 data.update(parse_glibc_supported(args.glibc_supported)) 142 data.update(parse(args.locale_alias)) 143 while True: 144 # Repeat optimization while the size is decreased. 145 n = len(data) 146 data = optimize(data) 147 if len(data) == n: 148 break 149 print_differences(data, locale.locale_alias) 150 print() 151 print('locale_alias = {') 152 pprint(data) 153 print('}') 154