~hkdb/geary/disco

« back to all changes in this revision

Viewing changes to src/client/util/util-international.vala

  • Committer: hkdb
  • Date: 2019-09-26 19:40:48 UTC
  • Revision ID: hkdb@3df.io-20190926194048-n0vggm3yfo8p1ubr
Tags: upstream-3.32.2-disco
ImportĀ upstreamĀ versionĀ 3.32.2-disco

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2016 Software Freedom Conservancy Inc.
 
2
 *
 
3
 * This software is licensed under the GNU Lesser General Public License
 
4
 * (version 2.1 or later).  See the COPYING file in this distribution.
 
5
 */
 
6
 
 
7
extern const string LANGUAGE_SUPPORT_DIRECTORY;
 
8
extern const string ISO_CODE_639_XML;
 
9
extern const string ISO_CODE_3166_XML;
 
10
public const string TRANSLATABLE = "translatable";
 
11
 
 
12
namespace International {
 
13
 
 
14
    private GLib.HashTable<string, string> language_names = null;
 
15
    private GLib.HashTable<string, string> country_names = null;
 
16
 
 
17
    public const string SYSTEM_LOCALE = "";
 
18
 
 
19
    void init(string package_name, string program_path, string locale = SYSTEM_LOCALE) {
 
20
        Intl.setlocale(LocaleCategory.ALL, locale);
 
21
        Intl.bindtextdomain(package_name, get_langpack_dir_path(program_path));
 
22
        Intl.bind_textdomain_codeset(package_name, "UTF-8");
 
23
        Intl.textdomain(package_name);
 
24
    }
 
25
 
 
26
    // TODO: Geary should be able to use langpacks from the build directory
 
27
    private string get_langpack_dir_path(string program_path) {
 
28
        return LANGUAGE_SUPPORT_DIRECTORY;
 
29
    }
 
30
 
 
31
    public string[] get_available_dictionaries() {
 
32
        string[] dictionaries = {};
 
33
 
 
34
        Enchant.Broker broker = new Enchant.Broker();
 
35
        broker.list_dicts((lang_tag, provider_name, provider_desc, provider_file) => {
 
36
                dictionaries += lang_tag;
 
37
            });
 
38
 
 
39
        // Whenever regional variants of the dictionaries are available use them
 
40
        // in place of the generic ones, e.g., discard en if en_US, en_GB, ...
 
41
        // are installed on the system.
 
42
        GLib.GenericSet<string> regional_dictionaries =
 
43
        new GLib.GenericSet<string>(GLib.str_hash, GLib.str_equal);
 
44
        foreach (string dic in dictionaries) {
 
45
            if ("_" in dic) {
 
46
                int underscore = dic.index_of_char('_');
 
47
                regional_dictionaries.add(dic.substring(0, underscore));
 
48
            }
 
49
        }
 
50
 
 
51
        GLib.List<string> filtered_dictionaries = new GLib.List<string>();
 
52
        foreach (string dic in dictionaries) {
 
53
            if ("_" in dic || ! regional_dictionaries.contains(dic))
 
54
                filtered_dictionaries.append(dic);
 
55
        }
 
56
 
 
57
        filtered_dictionaries.sort((dic_a, dic_b) => (dic_a < dic_b) ? -1 : 1);
 
58
 
 
59
        dictionaries = {};
 
60
        foreach (string dic in filtered_dictionaries) {
 
61
            dictionaries += dic;
 
62
        }
 
63
 
 
64
        return dictionaries;
 
65
    }
 
66
 
 
67
    public string[] get_available_locales() {
 
68
        string[] locales = {};
 
69
 
 
70
        try {
 
71
            string? output = null;
 
72
            GLib.Subprocess p = new GLib.Subprocess.newv({ "locale", "-a" },
 
73
                                                         GLib.SubprocessFlags.STDOUT_PIPE);
 
74
            p.communicate_utf8(null, null, out output, null);
 
75
 
 
76
            foreach (string l in output.split("\n")) {
 
77
                locales += l;
 
78
            }
 
79
        } catch (GLib.Error e) {
 
80
            return locales;
 
81
        }
 
82
 
 
83
        return locales;
 
84
    }
 
85
 
 
86
    /*
 
87
     * Strip the information about the encoding from the locale.
 
88
     *
 
89
     * That is, en_US.UTF-8 is mapped to en_US, while en_GB remains
 
90
     * unchanged.
 
91
     */
 
92
    public string strip_encoding(string locale) {
 
93
        int dot = locale.index_of_char('.');
 
94
        return locale.substring(0, dot);
 
95
    }
 
96
 
 
97
    public string[] get_user_preferred_languages() {
 
98
        GLib.GenericSet<string> dicts = new GLib.GenericSet<string>(GLib.str_hash, GLib.str_equal);
 
99
        foreach (string dict in get_available_dictionaries()) {
 
100
            dicts.add(dict);
 
101
        }
 
102
 
 
103
        GLib.GenericSet<string> locales = new GLib.GenericSet<string>(GLib.str_hash, GLib.str_equal);
 
104
        foreach (string locale in get_available_locales()) {
 
105
            locales.add(strip_encoding(locale));
 
106
        }
 
107
 
 
108
        string[] output = {};
 
109
        unowned string[] language_names = GLib.Intl.get_language_names();
 
110
        foreach (string lang in language_names) {
 
111
            // Check if we have the associated locale and the dictionary installed before actually
 
112
            //  considering this language.
 
113
            if (lang != "C" && dicts.contains(lang) && locales.contains(lang)) {
 
114
                output += lang;
 
115
            }
 
116
        }
 
117
        return output;
 
118
    }
 
119
 
 
120
    public string? language_name_from_locale (string locale) {
 
121
        if (language_names == null) {
 
122
            language_names = new HashTable<string, string>(GLib.str_hash, GLib.str_equal);
 
123
 
 
124
            unowned Xml.Doc doc = Xml.Parser.parse_file(ISO_CODE_639_XML);
 
125
            if (doc == null) {
 
126
                return null;
 
127
            }
 
128
            else {
 
129
                unowned Xml.Node root = doc.get_root_element();
 
130
                for (unowned Xml.Node entry = root.children; entry != null; entry = entry.next) {
 
131
                    if (entry.type == Xml.ElementType.ELEMENT_NODE) {
 
132
                        string? iso_639_1 = null;
 
133
                        string? language_name = null;
 
134
 
 
135
                        for (unowned Xml.Attr a = entry.properties; a != null; a = a.next) {
 
136
                            switch (a.name) {
 
137
                            case "iso_639_1_code":
 
138
                                iso_639_1 = a.children->content;
 
139
                                break;
 
140
                            case "name":
 
141
                                language_name = a.children->content;
 
142
                                break;
 
143
                            default:
 
144
                                break;
 
145
                            }
 
146
 
 
147
                            if (language_name != null) {
 
148
                                if (iso_639_1 != null) {
 
149
                                    language_names.insert(iso_639_1, language_name);
 
150
                                }
 
151
                            }
 
152
                        }
 
153
                    }
 
154
                }
 
155
            }
 
156
        }
 
157
 
 
158
        // Look for the name of language matching only the part before the _
 
159
        int pos = -1;
 
160
        if ("_" in locale) {
 
161
            pos = locale.index_of_char('_');
 
162
        }
 
163
 
 
164
        // Return a translated version of the language.
 
165
        string language_name = GLib.dgettext("iso_639", language_names.get(locale.substring(0, pos)));
 
166
 
 
167
        return language_name;
 
168
    }
 
169
 
 
170
    public string? country_name_from_locale(string locale) {
 
171
        if (country_names == null) {
 
172
            country_names = new HashTable<string, string>(GLib.str_hash, GLib.str_equal);
 
173
 
 
174
            unowned Xml.Doc doc = Xml.Parser.parse_file(ISO_CODE_3166_XML);
 
175
 
 
176
            if (doc == null) {
 
177
                return null;
 
178
            }
 
179
            else {
 
180
                unowned Xml.Node root = doc.get_root_element();
 
181
                for (unowned Xml.Node entry = root.children; entry != null; entry = entry.next) {
 
182
                    if (entry.type == Xml.ElementType.ELEMENT_NODE) {
 
183
                        string? iso_3166 = null;
 
184
                        string? country_name = null;
 
185
 
 
186
                        for (unowned Xml.Attr a = entry.properties; a != null; a = a.next) {
 
187
                            switch (a.name) {
 
188
                            case "alpha_2_code":
 
189
                                iso_3166 = a.children->content;
 
190
                                break;
 
191
                            case "name":
 
192
                                country_name = a.children->content;
 
193
                                break;
 
194
                            default:
 
195
                                break;
 
196
                            }
 
197
 
 
198
                            if (country_name != null) {
 
199
                                if (iso_3166 != null) {
 
200
                                    country_names.insert(iso_3166, country_name);
 
201
                                }
 
202
                            }
 
203
                        }
 
204
                    }
 
205
                }
 
206
            }
 
207
        }
 
208
 
 
209
        // Look for the name of language matching only the part before the _
 
210
        int pos = -1;
 
211
        if ("_" in locale) {
 
212
            pos = locale.index_of_char('_');
 
213
        }
 
214
 
 
215
        string country_name  = GLib.dgettext("iso_3166", country_names.get(locale.substring(pos+1)));
 
216
 
 
217
        return country_name;
 
218
    }
 
219
 
 
220
}