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