Fcitx
i18nstring.cpp
1 /*
2  * SPDX-FileCopyrightText: 2015-2015 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "i18nstring.h"
9 #include <clocale>
10 #include <cstddef>
11 #include <string>
12 #include "charutils.h"
13 #include "environ.h"
14 #include "misc.h"
15 
16 namespace fcitx {
17 const std::string &I18NString::match(const std::string &locale_) const {
18  std::string locale = locale_;
19  if (locale == "system") {
20  std::optional<std::string> lc;
21  if constexpr (isAndroid() || isApple() || isWindows()) {
22  // bionic doesn't recognize locale other than C or C.UTF-8
23  // https://android.googlesource.com/platform/bionic/+/refs/tags/android-11.0.0_r48/libc/bionic/locale.cpp#175
24  // macOS returns C for setlocale(LC_MESSAGES, nullptr)
25  // Windows's locale value doesn't like the one on linux,
26  // While it is also Lang_Country.Encoding, it's based on windows own
27  // naming. E.g. Chinese (Simplified)_China.936 so assume
28  // FCITX_LOCALE for now, until we have code to convert it to the
29  // unix standard.
30  lc = getEnvironment("FCITX_LOCALE");
31  } else {
32 #ifndef LC_MESSAGES
33  auto *lcMessages = setlocale(LC_ALL, nullptr);
34 #else
35  auto *lcMessages = setlocale(LC_MESSAGES, nullptr);
36 #endif
37  if (lcMessages) {
38  lc = lcMessages;
39  }
40  }
41  if (lc) {
42  locale = std::move(*lc);
43  } else {
44  locale = "";
45  }
46  }
47  // regex
48  // ^(?P<language>[^_.@[:space:]]+)
49  // (_(?P<territory>[[:upper:]]+))?
50  // (\\.(?P<codeset>[-_0-9a-zA-Z]+))?
51  // (@(?P<modifier>[[:ascii:]]+))?$
52  //
53  // check locale format.
54  // [language]_[country].[encoding]@modifier
55  // we don't want too large locale to match.
56  std::string normalizedLocale;
57  size_t languageLength = 0;
58  size_t territoryLength = 0;
59  bool failed = false;
60  auto i = locale.begin();
61  auto e = locale.end();
62  do {
63  while (i != e && !charutils::isspace(*i) && *i != '_' && *i != '.' &&
64  *i != '@') {
65  normalizedLocale.push_back(*i++);
66  }
67 
68  if (i == locale.begin()) {
69  failed = true;
70  break;
71  }
72  languageLength = normalizedLocale.size();
73 
74  if (i != e && *i == '_') {
75  normalizedLocale.push_back('_');
76  i++;
77  while (i != e && charutils::isupper(*i)) {
78  normalizedLocale.push_back(*i);
79  i++;
80  }
81 
82  territoryLength = normalizedLocale.size();
83  }
84 
85  if (i != e && *i == '.') {
86  // encoding is useless for us
87  i++;
88  while (i != e &&
89  (charutils::isupper(*i) || charutils::islower(*i) ||
90  charutils::isdigit(*i) || *i == '_' || *i == '-')) {
91  i++;
92  }
93  }
94 
95  if (i != e && *i == '@') {
96  normalizedLocale.push_back('@');
97  i++;
98  while (i != e) {
99  normalizedLocale.push_back(*i);
100  i++;
101  }
102  }
103  } while (false);
104 
105  if (failed) {
106  normalizedLocale.clear();
107  territoryLength = languageLength = 0;
108  }
109 
110  if (normalizedLocale.empty()) {
111  return default_;
112  }
113  auto iter = map_.find(normalizedLocale);
114  if (territoryLength && iter == map_.end()) {
115  iter = map_.find(normalizedLocale.substr(0, territoryLength));
116  }
117  if (languageLength && iter == map_.end()) {
118  iter = map_.find(normalizedLocale.substr(0, languageLength));
119  }
120  if (iter != map_.end()) {
121  return iter->second;
122  }
123  return default_;
124 }
125 } // namespace fcitx
Definition: action.cpp:17
Local independent API to detect character type.