Changes
diff --git a/pkgs/messages_builder/lib/arb_parser.dart b/pkgs/messages_builder/lib/arb_parser.dart
index 43904a1..4ed5e9c 100644
--- a/pkgs/messages_builder/lib/arb_parser.dart
+++ b/pkgs/messages_builder/lib/arb_parser.dart
@@ -19,12 +19,14 @@
     final context = arb['@@context'] as String?;
     final messages = arb.keys
         .where((key) => !key.startsWith('@'))
-        .map((key) => parseMessage(
-              arb[key] as String,
-              arb['@$key'] as Map<String, dynamic>?,
-              key,
-              '${context}_$locale',
-            ))
+        .map(
+          (key) => parseMessage(
+            arb[key] as String,
+            arb['@$key'] as Map<String, dynamic>?,
+            key,
+            '${context}_$locale',
+          ),
+        )
         .toList();
     messages.sort((a, b) => a.name.compareTo(b.name));
     return MessageFile(
@@ -47,23 +49,32 @@
     String name,
     String debugString,
   ) {
-    final message = MessageParser.parse(
+    final (message, arguments) = MessageParser.parse(
       debugString,
       messageContent,
       name,
     );
+    final meaning = metadata?['meaning'] as String?;
+    final description = metadata?['description'] as String?;
+
     final placeholdersMap = metadata?['placeholders'] as Map<String, dynamic>?;
-    final placeholdersWithMetadata = placeholdersMap?.map(
-          (name, metadata) {
-            final type = (metadata as Map<String, dynamic>)['type'] as String?;
-            return MapEntry(name, Placeholder(name, type ?? 'String'));
-          },
-        ) ??
+    final placeholdersWithMetadata = placeholdersMap?.map((name, metadata) {
+          final type = (metadata as Map<String, dynamic>)['type'] as String?;
+          final example = metadata['example'] as String?;
+          return MapEntry(name, Placeholder(name, type ?? 'String', example));
+        }) ??
         <String, Placeholder>{};
 
-    final placeholders = message.placeholders
-        .map((p) => placeholdersWithMetadata[p.name] ?? p)
-        .toList();
-    return ParameterizedMessage(message.message, message.name, placeholders);
+    return ParameterizedMessage(
+      message: message,
+      name: name,
+      meaning: meaning,
+      description: description,
+      placeholders: arguments
+          .map(
+            (name) => placeholdersWithMetadata[name] ?? Placeholder(name),
+          )
+          .toList(),
+    );
   }
 }
diff --git a/pkgs/messages_builder/lib/message_parser/message_parser.dart b/pkgs/messages_builder/lib/message_parser/message_parser.dart
index a1162e8..ca40d45 100644
--- a/pkgs/messages_builder/lib/message_parser/message_parser.dart
+++ b/pkgs/messages_builder/lib/message_parser/message_parser.dart
@@ -4,14 +4,12 @@
 
 import 'package:messages/messages.dart';
 
-import '../parameterized_message.dart';
-import '../placeholder.dart';
 import 'icu_message_parser.dart';
 import 'plural_parser.dart';
 import 'select_parser.dart';
 
 class MessageParser {
-  static ParameterizedMessage parse(
+  static (Message, List<String>) parse(
     String debugString,
     String fileContents,
     String name,
@@ -19,17 +17,11 @@
     final node = Parser(name, debugString, fileContents).parse();
     final arguments = <String>[];
     final message = parseNode(node, arguments, name) ?? StringMessage('');
-    final placeholders = arguments.map(Placeholder.new).toList();
-    return ParameterizedMessage(message, name, placeholders);
+    return (message, arguments);
   }
 
-  static Message? parseNode(
-    Node node,
-    List<String> arguments, [
-    String? name,
-  ]) {
+  static Message? parseNode(Node node, List<String> arguments, [String? name]) {
     final submessages = <Message>[];
-    final placeholders = <({int argIndex, int afterStringMessage})>[];
     for (var child in node.children) {
       switch (child.type) {
         case ST.string:
@@ -45,10 +37,14 @@
           if (!arguments.contains(identifier)) {
             arguments.add(identifier);
           }
-          placeholders.add((
-            argIndex: arguments.indexOf(identifier),
-            afterStringMessage: submessages.length,
-          ));
+          submessages.add(
+            StringMessage(
+              '',
+              argPositions: [
+                (argIndex: arguments.indexOf(identifier), stringIndex: 0),
+              ],
+            ),
+          );
           break;
         case ST.selectExpr:
           submessages.add(SelectParser().parse(child, arguments));
@@ -57,37 +53,40 @@
           break;
       }
     }
-    if (submessages.isEmpty && placeholders.isEmpty) {
+    if (submessages.isEmpty) {
       return null;
-    } else if (submessages.length == 1 && placeholders.isEmpty) {
-      return submessages.first;
-    } else if (submessages.every((message) => message is StringMessage)) {
-      return combineStringsAndPlaceholders(
-        submessages.whereType<StringMessage>().toList(),
-        placeholders,
-      );
+    }
+    final fold = submessages.fold(<Message>[], (messages, message) {
+      if (messages.isNotEmpty &&
+          message is StringMessage &&
+          messages.last is StringMessage) {
+        final last = messages.removeLast() as StringMessage;
+        return [...messages, combineStringMessages(last, message)];
+      } else {
+        return [...messages, message];
+      }
+    });
+    if (fold.length == 1) {
+      return fold.first;
     } else {
-      return CombinedMessage(submessages);
+      return CombinedMessage(fold);
     }
   }
 
-  static StringMessage combineStringsAndPlaceholders(
-    List<StringMessage> submessages,
-    List<({int afterStringMessage, int argIndex})> placeholders,
-  ) {
-    final argPositions = <({int argIndex, int stringIndex})>[];
-    final s = StringBuffer();
-    for (var i = 0; i < submessages.length + 1; i++) {
-      placeholders
-          .where((element) => element.afterStringMessage == i)
-          .forEach((element) {
-        argPositions.add((argIndex: element.argIndex, stringIndex: s.length));
-      });
-      if (i < submessages.length) {
-        final submessage = submessages[i];
-        s.write(submessage.value);
-      }
-    }
-    return StringMessage(s.toString(), argPositions: argPositions);
-  }
+  static StringMessage combineStringMessages(
+    StringMessage message1,
+    StringMessage message2,
+  ) =>
+      StringMessage(
+        message1.value + message2.value,
+        argPositions: [
+          ...message1.argPositions,
+          ...message2.argPositions.map(
+            (e) => (
+              argIndex: e.argIndex,
+              stringIndex: e.stringIndex + message1.value.length,
+            ),
+          ),
+        ],
+      );
 }
diff --git a/pkgs/messages_builder/lib/parameterized_message.dart b/pkgs/messages_builder/lib/parameterized_message.dart
index 659aff2..f4b6375 100644
--- a/pkgs/messages_builder/lib/parameterized_message.dart
+++ b/pkgs/messages_builder/lib/parameterized_message.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:messages/messages.dart';
+
 import 'placeholder.dart';
 
 /// A wrapper class around a [Message], adding its [placeholders] and a [name].
@@ -26,11 +27,19 @@
 class ParameterizedMessage {
   final Message message;
   final String name;
+  final String? meaning;
+  final String? description;
   final List<Placeholder> placeholders;
 
   static final RegExp _dartName = RegExp(r'^[a-zA-Z][a-zA-Z_0-9]*$');
 
-  ParameterizedMessage(this.message, this.name, this.placeholders);
+  ParameterizedMessage({
+    required this.message,
+    required this.name,
+    this.meaning,
+    this.description,
+    this.placeholders = const [],
+  });
 
   bool get nameIsDartConform => _dartName.hasMatch(name);
 }
diff --git a/pkgs/messages_builder/lib/placeholder.dart b/pkgs/messages_builder/lib/placeholder.dart
index 0d5d1bb..0ab9326 100644
--- a/pkgs/messages_builder/lib/placeholder.dart
+++ b/pkgs/messages_builder/lib/placeholder.dart
@@ -29,8 +29,9 @@
 class Placeholder {
   final String name;
   final String? type;
+  final String? example;
 
-  Placeholder(this.name, [this.type]);
+  Placeholder(this.name, [this.type, this.example]);
 
   @override
   String toString() {
diff --git a/pkgs/messages_builder/test/web_deserializer_native_test.dart b/pkgs/messages_builder/test/web_deserializer_native_test.dart
index 461f36e..8f51fc0 100644
--- a/pkgs/messages_builder/test/web_deserializer_native_test.dart
+++ b/pkgs/messages_builder/test/web_deserializer_native_test.dart
@@ -37,7 +37,7 @@
 void main() {
   test('generateMessageFile from Object json', () {
     final message = StringMessage('Hello World');
-    final message1 = ParameterizedMessage(message, 'helloWorld', []);
+    final message1 = ParameterizedMessage(message: message, name: 'helloWorld');
     final messageList = <ParameterizedMessage>[message1];
     final buffer = JsonSerializer()
         .serialize('', '', messageList.map((e) => e.message).toList())