source: calamares/trunk/fuentes/src/modules/locale/LocaleConfiguration.cpp @ 7538

Last change on this file since 7538 was 7538, checked in by kbut, 13 months ago

sync with github

File size: 12.2 KB
Line 
1/* === This file is part of Calamares - <https://github.com/calamares> ===
2 *
3 *   Copyright 2016, Teo Mrnjavac <teo@kde.org>
4 *   Copyright 2017, Adriaan de Groot <groot@kde.org>
5 *
6 *   Calamares is free software: you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation, either version 3 of the License, or
9 *   (at your option) any later version.
10 *
11 *   Calamares is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with Calamares. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "LocaleConfiguration.h"
21#include <QLocale>
22
23LocaleConfiguration::LocaleConfiguration()
24    : explicit_lang( false )
25    , explicit_lc( false )
26{
27}
28
29
30LocaleConfiguration
31LocaleConfiguration::createDefault()
32{
33    LocaleConfiguration lc = LocaleConfiguration();
34    lc.lang = lc.lc_numeric = lc.lc_time = lc.lc_monetary = lc.lc_paper = lc.lc_name
35            = lc.lc_address = lc.lc_telephone = lc.lc_measurement
36            = lc.lc_identification = "en_US.UTF-8";
37    return lc;
38}
39
40
41LocaleConfiguration
42LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
43                                              const QStringList& availableLocales,
44                                              const QString& countryCode )
45{
46    LocaleConfiguration lc;
47
48    // Note that the documentation how this works is in packages.conf
49    QString language = languageLocale.split( '_' ).first();
50    lc.myLanguageLocaleBcp47 = QLocale(language).bcp47Name().toLower();
51
52    QStringList linesForLanguage;
53    for ( const QString &line : availableLocales )
54    {
55        if ( line.startsWith( language ) )
56            linesForLanguage.append( line );
57    }
58
59    QString lang;
60    if ( linesForLanguage.length() == 0 || languageLocale.isEmpty() )
61        lang = "en_US.UTF-8";
62    else if ( linesForLanguage.length() == 1 )
63        lang = linesForLanguage.first();
64    else
65    {
66        QStringList linesForLanguageUtf;
67        // FIXME: this might be useless if we already filter out non-UTF8 locales
68        foreach ( QString line, linesForLanguage )
69        {
70            if ( line.contains( "UTF-8", Qt::CaseInsensitive ) ||
71                 line.contains( "utf8", Qt::CaseInsensitive ) )
72                linesForLanguageUtf.append( line );
73        }
74
75        if ( linesForLanguageUtf.length() == 1 )
76            lang = linesForLanguageUtf.first();
77    }
78
79    // lang could still be empty if we found multiple locales that satisfy myLanguage
80
81    // The following block was inspired by Ubiquity, scripts/localechooser-apply.
82    // No copyright statement found in file, assuming GPL v2 or later.
83    /*  # In the special cases of Portuguese and Chinese, selecting a
84        # different location may imply a different dialect of the language.
85        # In such cases, make LANG reflect the selected language (for
86        # messages, character types, and collation) and make the other
87        # locale categories reflect the selected location. */
88    if ( language == "pt" || language == "zh" )
89    {
90        QString proposedLocale = QString( "%1_%2" ).arg( language )
91                                                   .arg( countryCode );
92        foreach ( QString line, linesForLanguage )
93        {
94            if ( line.contains( proposedLocale ) )
95            {
96                lang = line;
97                break;
98            }
99        }
100    }
101
102    // If we found no good way to set a default lang, do a search with the whole
103    // language locale and pick the first result, if any.
104    if ( lang.isEmpty() )
105    {
106        for ( const QString &line : availableLocales )
107        {
108            if ( line.startsWith( languageLocale ) )
109            {
110                lang = line;
111                break;
112            }
113        }
114
115    }
116
117    // Else we have an unrecognized or unsupported locale, all we can do is go with
118    // en_US.UTF-8 UTF-8. This completes all default language setting guesswork.
119    if ( lang.isEmpty() )
120        lang = "en_US.UTF-8";
121
122
123    // The following block was inspired by Ubiquity, scripts/localechooser-apply.
124    // No copyright statement found in file, assuming GPL v2 or later.
125    /*  # It is relatively common for the combination of language and location (as
126        # selected on the timezone page) not to identify a supported combined
127        # locale.  For example, this happens when the user is a migrant, or when
128        # they prefer to use a different language to interact with their computer
129        # because that language is better-supported.
130        #
131        # In such cases, we would like to be able to use a locale reflecting the
132        # selected language in LANG for messages, character types, and collation,
133        # and to make the other locale categories reflect the selected location.
134        # This means that we have to guess at a suitable locale for the selected
135        # location, and we do not want to ask yet another locale-related question.
136        # Nevertheless, some cases are ambiguous: a user who has asked for the
137        # English language and identifies their location as Switzerland will get
138        # different numeric representation depending on which Swiss locale we pick.
139        #
140        # The goal of identifying a reasonable default for migrants makes things
141        # easier: it is reasonable to default to French for France despite the
142        # existence of several minority languages there, because anyone who prefers
143        # those languages will probably already have selected them and won't arrive
144        # here.  However, in some cases we're unsure, and in some cases we actively
145        # don't want to pick a "preferred" language: selecting either Greek or
146        # Turkish as the default language for migrants to Cyprus would probably
147        # offend somebody!  In such cases we simply punt to the old behaviour of not
148        # setting up a locale reflecting the location, which is suboptimal but is at
149        # least unlikely to give offence.
150        #
151        # Our best shot at general criteria for selecting a default language in
152        # these circumstances are as follows:
153        #
154        #  * Exclude special-purpose (e.g. en_DK) and artificial (e.g. la_AU,
155        #    tlh_GB) locales.
156        #  * If there is a language specific to or very strongly associated with the
157        #    country in question, prefer it unless it has rather few native
158        #    speakers.
159        #  * Exclude minority languages that are relatively unlikely to be spoken by
160        #    migrants who have not already selected them as their preferred language
161        #    earlier in the installer.
162        #  * If there is an official national language likely to be seen in print
163        #    media, road signs, etc., then prefer that.
164        #  * In cases of doubt, selecting no default language is safe. */
165
166    // We make a proposed locale based on the UI language and the timezone's country. There is no
167    // guarantee that this will be a valid, supported locale (often it won't).
168    QString lc_formats;
169    QString combined = QString( "%1_%2" ).arg( language )
170                                         .arg( countryCode );
171    // We look up if it's a supported locale.
172    for ( const QString &line : availableLocales )
173    {
174        if ( line.startsWith( combined ) )
175        {
176            lang = line;
177            lc_formats = line;
178            break;
179        }
180    }
181
182    if ( lc_formats.isEmpty() )
183    {
184        QStringList available;
185        for ( const QString &line : availableLocales )
186        {
187            if ( line.contains( QString( "_%1" ).arg( countryCode ) ) )
188            {
189                available.append( line );
190            }
191        }
192        available.sort();
193        if ( available.count() == 1 )
194        {
195            lc_formats = available.first();
196        }
197        else
198        {
199            QMap< QString, QString > countryToDefaultLanguage {
200                { "AU", "en" },
201                { "CN", "zh" },
202                { "DE", "de" },
203                { "DK", "da" },
204                { "DZ", "ar" },
205                { "ES", "es" },
206                // Somewhat unclear: Oromo has the greatest number of
207                // native speakers; English is the most widely spoken
208                // language and taught in secondary schools; Amharic is
209                // the official language and was taught in primary
210                // schools.
211                { "ET", "am" },
212                { "FI", "fi" },
213                { "FR", "fr" },
214                { "GB", "en" },
215                // Irish (Gaelic) is strongly associated with Ireland,
216                // but nearly all its native speakers also speak English,
217                // and migrants are likely to use English.
218                { "IE", "en" },
219                { "IT", "it" },
220                { "MA", "ar" },
221                { "MK", "mk" },
222                { "NG", "en" },
223                { "NL", "nl" },
224                { "NZ", "en" },
225                { "IL", "he" },
226                // Filipino is a de facto version of Tagalog, which is
227                // also spoken; English is also an official language.
228                { "PH", "fil" },
229                { "PK", "ur" },
230                { "PL", "pl" },
231                { "RU", "ru" },
232                // Chinese has more speakers, but English is the "common
233                // language of the nation" (Wikipedia) and official
234                // documents must be translated into English to be
235                // accepted.
236                { "SG", "en" },
237                { "SN", "wo" },
238                { "TR", "tr" },
239                { "TW", "zh" },
240                { "UA", "uk" },
241                { "US", "en" },
242                { "ZM", "en" }
243            };
244            if ( countryToDefaultLanguage.contains( countryCode ) )
245            {
246                QString combinedLocale =
247                        QString( "%1_%2" ).arg( countryToDefaultLanguage.value( countryCode ) )
248                                          .arg( countryCode );
249
250                for ( const QString &line : availableLocales )
251                {
252                    if ( line.startsWith( combinedLocale ) )
253                    {
254                        lc_formats = line;
255                        break;
256                    }
257                }
258            }
259        }
260    }
261
262    // If we cannot make a good choice for a given country we go with the LANG
263    // setting, which defaults to en_US.UTF-8 UTF-8 if all else fails.
264    if ( lc_formats.isEmpty() )
265        lc_formats = lang;
266
267    lc.lang = lang;
268    lc.lc_address = lc.lc_identification = lc.lc_measurement = lc.lc_monetary
269                  = lc.lc_name = lc.lc_numeric = lc.lc_paper = lc.lc_telephone
270                  = lc.lc_time = lc_formats;
271
272    return lc;
273}
274
275
276bool
277LocaleConfiguration::isEmpty() const
278{
279    return lang.isEmpty() &&
280         lc_numeric.isEmpty() &&
281         lc_time.isEmpty() &&
282         lc_monetary.isEmpty() &&
283         lc_paper.isEmpty() &&
284         lc_name.isEmpty() &&
285         lc_address.isEmpty() &&
286         lc_telephone.isEmpty() &&
287         lc_measurement.isEmpty() &&
288         lc_identification.isEmpty();
289}
290
291
292QMap< QString, QString >
293LocaleConfiguration::toMap() const
294{
295    QMap< QString, QString > map;
296
297    if ( !lang.isEmpty() )
298        map.insert( "LANG", lang );
299
300    if ( !lc_numeric.isEmpty() )
301        map.insert( "LC_NUMERIC", lc_numeric );
302
303    if ( !lc_time.isEmpty() )
304        map.insert( "LC_TIME", lc_time );
305
306    if ( !lc_monetary.isEmpty() )
307        map.insert( "LC_MONETARY", lc_monetary );
308
309    if ( !lc_paper.isEmpty() )
310        map.insert( "LC_PAPER", lc_paper );
311
312    if ( !lc_name.isEmpty() )
313        map.insert( "LC_NAME", lc_name );
314
315    if ( !lc_address.isEmpty() )
316        map.insert( "LC_ADDRESS", lc_address );
317
318    if ( !lc_telephone.isEmpty() )
319        map.insert( "LC_TELEPHONE", lc_telephone );
320
321    if ( !lc_measurement.isEmpty() )
322        map.insert( "LC_MEASUREMENT", lc_measurement );
323
324    if ( !lc_identification.isEmpty() )
325        map.insert( "LC_IDENTIFICATION", lc_identification );
326
327    return map;
328}
329
330QString
331LocaleConfiguration::toBcp47() const
332{
333    return myLanguageLocaleBcp47;
334}
Note: See TracBrowser for help on using the repository browser.