summaryrefslogtreecommitdiffstats
path: root/extensions/common/message_bundle.h
blob: 9c0bde79a303447185c1b7a33eff3922945f5368 (plain)
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
175
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_COMMON_MESSAGE_BUNDLE_H_
#define EXTENSIONS_COMMON_MESSAGE_BUNDLE_H_

#include <stddef.h>

#include <map>
#include <string>
#include <vector>

#include "base/memory/linked_ptr.h"

namespace base {
class DictionaryValue;
class Value;
}

namespace extensions {

// Contains localized extension messages for one locale. Any messages that the
// locale does not provide are pulled from the default locale.
class MessageBundle {
 public:
  typedef std::map<std::string, std::string> SubstitutionMap;
  typedef std::vector<linked_ptr<base::DictionaryValue> > CatalogVector;

  // JSON keys of interest for messages file.
  static const char kContentKey[];
  static const char kMessageKey[];
  static const char kPlaceholdersKey[];

  // Begin/end markers for placeholders and messages
  static const char kPlaceholderBegin[];
  static const char kPlaceholderEnd[];
  static const char kMessageBegin[];
  static const char kMessageEnd[];

  // Reserved message names in the dictionary.
  // Update i18n documentation when adding new reserved value.
  static const char kUILocaleKey[];
  // See http://code.google.com/apis/gadgets/docs/i18n.html#BIDI for
  // description.
  // TODO(cira): point to chrome docs once they are out.
  static const char kBidiDirectionKey[];
  static const char kBidiReversedDirectionKey[];
  static const char kBidiStartEdgeKey[];
  static const char kBidiEndEdgeKey[];
  // Extension id gets added in the
  // browser/renderer_host/resource_message_filter.cc to enable message
  // replacement for non-localized extensions.
  static const char kExtensionIdKey[];

  // Values for some of the reserved messages.
  static const char kBidiLeftEdgeValue[];
  static const char kBidiRightEdgeValue[];

  // Creates MessageBundle or returns NULL if there was an error. Expects
  // locale_catalogs to be sorted from more specific to less specific, with
  // default catalog at the end.
  static MessageBundle* Create(const CatalogVector& locale_catalogs,
                               std::string* error);

  // Get message from the catalog with given key.
  // Returned message has all of the internal placeholders resolved to their
  // value (content).
  // Returns empty string if it can't find a message.
  // We don't use simple GetMessage name, since there is a global
  // #define GetMessage GetMessageW override in Chrome code.
  std::string GetL10nMessage(const std::string& name) const;

  // Get message from the given catalog with given key.
  static std::string GetL10nMessage(const std::string& name,
                                    const SubstitutionMap& dictionary);

  // Number of messages in the catalog.
  // Used for unittesting only.
  size_t size() const { return dictionary_.size(); }

  // Replaces all __MSG_message__ with values from the catalog.
  // Returns false if there is a message in text that's not defined in the
  // dictionary.
  bool ReplaceMessages(std::string* text, std::string* error) const;
  // Static version that accepts dictionary.
  static bool ReplaceMessagesWithExternalDictionary(
      const SubstitutionMap& dictionary, std::string* text, std::string* error);

  // Replaces each occurance of variable placeholder with its value.
  // I.e. replaces __MSG_name__ with value from the catalog with the key "name".
  // Returns false if for a valid message/placeholder name there is no matching
  // replacement.
  // Public for easier unittesting.
  static bool ReplaceVariables(const SubstitutionMap& variables,
                               const std::string& var_begin,
                               const std::string& var_end,
                               std::string* message,
                               std::string* error);

  // Allow only ascii 0-9, a-z, A-Z, and _ in the variable name.
  // Returns false if the input is empty or if it has illegal characters.
  static bool IsValidName(const std::string& name);

  // Getter for dictionary_.
  const SubstitutionMap* dictionary() const { return &dictionary_; }

  ~MessageBundle();

 private:
  // Testing friend.
  friend class MessageBundleTest;

  // Use Create to create MessageBundle instance.
  MessageBundle();

  // Initializes the instance from the contents of vector of catalogs.
  // If the key is not present in more specific catalog we fall back to next one
  // (less specific).
  // Returns false on error.
  bool Init(const CatalogVector& locale_catalogs, std::string* error);

  // Appends locale specific reserved messages to the dictionary.
  // Returns false if there was a conflict with user defined messages.
  bool AppendReservedMessagesForLocale(const std::string& application_locale,
                                       std::string* error);

  // Helper methods that navigate JSON tree and return simplified message.
  // They replace all $PLACEHOLDERS$ with their value, and return just key/value
  // of the message.
  bool GetMessageValue(const std::string& key,
                       const base::Value& name_value,
                       std::string* value,
                       std::string* error) const;

  // Get all placeholders for a given message from JSON subtree.
  bool GetPlaceholders(const base::DictionaryValue& name_tree,
                       const std::string& name_key,
                       SubstitutionMap* placeholders,
                       std::string* error) const;

  // For a given message, replaces all placeholders with their actual value.
  // Returns false if replacement failed (see ReplaceVariables).
  bool ReplacePlaceholders(const SubstitutionMap& placeholders,
                           std::string* message,
                           std::string* error) const;

  // Holds all messages for application locale.
  SubstitutionMap dictionary_;
};

///////////////////////////////////////////////////////////////////////////////
//
// Renderer helper typedefs and functions.
//
///////////////////////////////////////////////////////////////////////////////

// A map of message name to message.
typedef std::map<std::string, std::string> L10nMessagesMap;

// A map of extension ID to l10n message map.
typedef std::map<std::string, L10nMessagesMap > ExtensionToL10nMessagesMap;

// Returns the extension_id to messages map.
ExtensionToL10nMessagesMap* GetExtensionToL10nMessagesMap();

// Returns message map that matches given extension_id, or NULL.
L10nMessagesMap* GetL10nMessagesMap(const std::string& extension_id);

// Erases the L10nMessagesMap for the given |extension_id|.
void EraseL10nMessagesMap(const std::string& extension_id);

}  // namespace extensions

#endif  // EXTENSIONS_COMMON_MESSAGE_BUNDLE_H_