-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathLanguageHandler.h
174 lines (137 loc) · 5.81 KB
/
LanguageHandler.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#pragma once
/** A basic representation of a standardised IETF language tags.
Use one of these to indicate the language of text or
other items in HTML documents, XML documents.
Use the lang attribute to specify language tags in HTML,
and the xml:lang attribute for XML.
More importantly, this serves as a basis for managing languages,
ie: translation files, in your application. You can do so via
the combination of a IETFLanguageFile and a single instance of
a LanguageHandler.
@see IETFLanguageFile, LanguageHandler
*/
struct IETFLanguageTag final
{
/** Constructs a default language tag of the Canadian English variety,
represented as "eng-ca".
*/
IETFLanguageTag() noexcept = default;
/** */
IETFLanguageTag (LanguageCode languageCode, CountryCode countryCode) noexcept :
code (languageCode),
country (countryCode)
{
}
/** @returns true if this language tag matches the given other one. */
bool operator== (const IETFLanguageTag& other) const noexcept
{
return code == other.code
&& country == other.country;
}
/** @returns true if this language tag does not match the given other one. */
bool operator!= (const IETFLanguageTag& other) const noexcept { return ! operator== (other); }
/** @returns a valid language tag if the string was understandible.
Otherwise, the tag will be made up of an unknown language code
and unknown contry code.
*/
static IETFLanguageTag fromString (const String& s)
{
const auto toks = StringArray::fromTokens (s, "-", "");
if (toks.size() != 2)
return { LanguageCode::unknown, CountryCode::unknown };
return { getLanguageCode (toks[0]), getCountryCode (toks[1]) };
}
/** @returns a printable string of the format "language code-country code";
more specifically, this will look like "eng-ca".
*/
String getDescription() const { return toString (code) + "-" + toString (country); }
/** @returns true if language tag*/
bool isValid() const noexcept
{
return code != LanguageCode::unknown
&& country != CountryCode::unknown;
}
LanguageCode code = LanguageCode::eng;
CountryCode country = CountryCode::ca;
};
//==============================================================================
/** A representation of an IETF-compatible file for an app's
set of translations in a particular language.
Simply put, this maps a IETFLanguageTag to a file on disk.
@see IETFLanguageFile, LanguageHandler
*/
struct IETFLanguageFile final
{
/** Default constructor. */
IETFLanguageFile() = default;
/** Constructs a language file representation with a particular tag and file in mind. */
IETFLanguageFile (const IETFLanguageTag& t, const File& source) :
tag (t),
file (source)
{
}
/** @returns true if this and the other language file match. */
bool operator== (const IETFLanguageFile& other) const noexcept { return tag == other.tag && file == other.file; }
/** @returns true if this and the other language file do not match. */
bool operator!= (const IETFLanguageFile& other) const noexcept { return ! operator== (other); }
/** @returns true if this file's tag and the provided tag match. */
bool operator== (const IETFLanguageTag& other) const noexcept { return tag == other; }
/** @returns true if this file's tag and the provided tag do not match. */
bool operator!= (const IETFLanguageTag& other) const noexcept { return ! operator== (other); }
// @TODO Create a conversion system from the JUCE stuff to this stuff...
// if (auto* const ls = LocalisedStrings::getCurrentMappings())
// return ls->getLanguageName();
// return SystemStats::getUserLanguage();
/** @returns true if the language file presently exists. */
bool exists() const noexcept { return file.existsAsFile(); }
/** @returns true if the tag is valid. */
bool isValid() const noexcept { return tag.isValid(); }
IETFLanguageTag tag;
File file;
};
//==============================================================================
/** */
class LanguageHandler final
{
public:
/** Constructor. */
LanguageHandler (const File& languageDirectory);
//==============================================================================
/** @returns */
const File& getLanguageDirectory() const noexcept { return languageDirectory; }
/** */
void addLanguageFile (const IETFLanguageFile&, bool makeActive);
/** Changes the current language. */
void setCurrentLanguage (const IETFLanguageTag&);
/** Changes the current language. */
void setCurrentLanguage (const IETFLanguageFile&);
/** @returns */
const IETFLanguageFile& getCurrentLanguage() const;
/** @returns */
const OwnedArray<IETFLanguageFile>& getAvailableLanguages() const noexcept { return languages; }
//==============================================================================
/** */
class Listener
{
public:
virtual ~Listener() = default;
/** */
virtual void languageChanged (const IETFLanguageFile&) = 0;
};
/** */
void addListener (Listener*);
/** */
void removeListener (Listener*);
/** */
void refresh();
private:
//==============================================================================
const File languageDirectory;
OwnedArray<IETFLanguageFile> languages;
int activeLanguageIndex = -1;
ListenerList<Listener> listeners;
//==============================================================================
static bool isValid (const IETFLanguageFile& lf);
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LanguageHandler)
};