1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include <rpl/producer.h>
11 #include "lang_auto.h"
12 #include "base/weak_ptr.h"
13 
14 namespace Lang {
15 
16 inline constexpr auto kChoosingStickerReplacement = "oo"_cs;
17 
18 struct Language {
19 	QString id;
20 	QString pluralId;
21 	QString baseId;
22 	QString name;
23 	QString nativeName;
24 };
25 
26 inline bool operator==(const Language &a, const Language &b) {
27 	return (a.id == b.id) && (a.name == b.name);
28 }
29 
30 inline bool operator!=(const Language &a, const Language &b) {
31 	return !(a == b);
32 }
33 
34 QString DefaultLanguageId();
35 QString LanguageIdOrDefault(const QString &id);
36 QString CloudLangPackName();
37 QString CustomLanguageId();
38 Language DefaultLanguage();
39 
40 class Instance;
41 Instance &GetInstance();
42 
43 enum class Pack {
44 	None,
45 	Current,
46 	Base,
47 };
48 
49 class Instance {
50 	struct PrivateTag;
51 
52 public:
53 	Instance();
54 	Instance(not_null<Instance*> derived, const PrivateTag &);
55 
56 	void switchToId(const Language &language);
57 	void switchToCustomFile(const QString &filePath);
58 
59 	Instance(const Instance &other) = delete;
60 	Instance &operator=(const Instance &other) = delete;
61 	Instance(Instance &&other) = default;
62 	Instance &operator=(Instance &&other) = default;
63 
64 	QString systemLangCode() const;
65 	QString langPackName() const;
66 	QString cloudLangCode(Pack pack) const;
67 	QString id() const;
68 	rpl::producer<QString> idChanges() const;
69 	QString baseId() const;
70 	QString name() const;
71 	QString nativeName() const;
72 	QString id(Pack pack) const;
73 	bool isCustom() const;
74 	int version(Pack pack) const;
75 
76 	QByteArray serialize() const;
77 	void fillFromSerialized(const QByteArray &data, int dataAppVersion);
78 
79 	bool supportChoosingStickerReplacement() const;
80 	int rightIndexChoosingStickerReplacement(bool named) const;
81 
82 	void applyDifference(
83 		Pack pack,
84 		const MTPDlangPackDifference &difference);
85 	static std::map<ushort, QString> ParseStrings(
86 		const MTPVector<MTPLangPackString> &strings);
87 
updated()88 	[[nodiscard]] rpl::producer<> updated() const {
89 		return _updated.events();
90 	}
91 
getValue(ushort key)92 	QString getValue(ushort key) const {
93 		Expects(key < _values.size());
94 
95 		return _values[key];
96 	}
97 	QString getNonDefaultValue(const QByteArray &key) const;
isNonDefaultPlural(ushort key)98 	bool isNonDefaultPlural(ushort key) const {
99 		Expects(key + 5 < _nonDefaultSet.size());
100 
101 		return _nonDefaultSet[key]
102 			|| _nonDefaultSet[key + 1]
103 			|| _nonDefaultSet[key + 2]
104 			|| _nonDefaultSet[key + 3]
105 			|| _nonDefaultSet[key + 4]
106 			|| _nonDefaultSet[key + 5]
107 			|| (_base && _base->isNonDefaultPlural(key));
108 	}
109 
110 private:
111 	void setBaseId(const QString &baseId, const QString &pluralId);
112 
113 	void applyDifferenceToMe(const MTPDlangPackDifference &difference);
114 	void applyValue(const QByteArray &key, const QByteArray &value);
115 	void resetValue(const QByteArray &key);
116 	void reset(const Language &language);
117 	void fillFromCustomContent(
118 		const QString &absolutePath,
119 		const QString &relativePath,
120 		const QByteArray &content);
121 	bool loadFromCustomFile(const QString &filePath);
122 	void loadFromContent(const QByteArray &content);
123 	void loadFromCustomContent(
124 		const QString &absolutePath,
125 		const QString &relativePath,
126 		const QByteArray &content);
127 	void updatePluralRules();
128 	void updateChoosingStickerReplacement();
129 
130 	Instance *_derived = nullptr;
131 
132 	QString _id, _pluralId;
133 	rpl::event_stream<QString> _idChanges;
134 	QString _name, _nativeName;
135 	QString _customFilePathAbsolute;
136 	QString _customFilePathRelative;
137 	QByteArray _customFileContent;
138 	int _version = 0;
139 	rpl::event_stream<> _updated;
140 
141 	struct {
142 		bool support = false;
143 		int rightIndex = 0;
144 		int rightIndexNamed = 0;
145 	} _choosingStickerReplacement;
146 
147 	mutable QString _systemLanguage;
148 
149 	std::vector<QString> _values;
150 	std::vector<uchar> _nonDefaultSet;
151 	std::map<QByteArray, QByteArray> _nonDefaultValues;
152 
153 	std::unique_ptr<Instance> _base;
154 
155 };
156 
157 namespace details {
158 
159 QString Current(ushort key);
160 rpl::producer<QString> Value(ushort key);
161 
162 } // namespace details
163 } // namespace Lang
164