Unverified Commit 19e7db58 authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

[gen_l10n] Escape special JSON characters in generateString utility function (#53605)

parent a94e647d
......@@ -373,36 +373,36 @@ class $classNamePrefix$camelCaseName extends $superClass {''';
/// foo "bar" => 'foo "bar"'
/// foo 'bar' => "foo 'bar'"
/// foo 'bar' "baz" => '''foo 'bar' "baz"'''
/// foo\bar => 'foo\\bar'
/// foo\nbar => 'foo\\\\nbar'
/// ```
///
/// When [shouldEscapeDollar] is set to true, the
/// result avoids character escaping, with the
/// exception of the dollar sign:
/// This function is used by tools that take in a JSON-formatted file to
/// generate Dart code. For this reason, characters with special meaning
/// in JSON files. For example, the backspace character (\b) have to be
/// properly escaped by this function so that the generated Dart code
/// correctly represents this character:
/// ```
/// foo\bar => 'foo\\bar'
/// foo\nbar => 'foo\\nbar'
/// foo\\nbar => 'foo\\\\nbar'
/// foo\\bar => 'foo\\\\bar'
/// foo\ bar => 'foo\\ bar'
/// ```
///
/// When [shouldEscapeDollar] is set to true, the '$' characters in the
/// input will be replaced by '$' in the returned string:
/// ```
/// foo$bar = 'foo\$bar'
/// ```
///
/// When [shouldEscapeDollar] is set to false, the
/// result tries to avoid character escaping:
///
/// When [shouldEscapeDollar] is set to false, '$' will be replaced
/// by '\$' in the returned string:
/// ```
/// foo$bar => 'foo\\\$bar'
/// ```
///
/// [shouldEscapeDollar] is true by default.
///
/// Strings with newlines are not supported.
String generateString(String value, { bool escapeDollar = true }) {
assert(escapeDollar != null);
assert(
!value.contains('\n'),
'Since it is assumed that the input string comes '
'from a json/arb file source, messages cannot '
'contain newlines.'
);
const String backslash = '__BACKSLASH__';
assert(
......@@ -419,6 +419,11 @@ String generateString(String value, { bool escapeDollar = true }) {
value = value
.replaceAll("'", "\\'")
.replaceAll('"', '\\"')
.replaceAll('\n', '\\n')
.replaceAll('\f', '\\f')
.replaceAll('\t', '\\t')
.replaceAll('\r', '\\r')
.replaceAll('\b', '\\b')
.replaceAll(backslash, '\\\\');
return "'$value'";
......
......@@ -45,15 +45,31 @@ void main() {
});
test('handles backslash', () {
expect(generateString(r'ab\c'), "'ab\\\\c'");
expect(generateString(r'ab\c'), r"'ab\\c'");
});
test('handles backslash followed by "n" character', () {
expect(generateString(r'ab\nc'), "'ab\\\\nc'");
expect(generateString(r'ab\nc'), r"'ab\\nc'");
});
test('does not support multiline strings', () {
expect(() => generateString('ab\nc'), throwsA(isA<AssertionError>()));
test('supports newline escaping', () {
expect(generateString('ab\nc'), "'ab\\nc'");
});
test('supports form feed escaping', () {
expect(generateString('ab\fc'), "'ab\\fc'");
});
test('supports tab escaping', () {
expect(generateString('ab\tc'), "'ab\\tc'");
});
test('supports carriage return escaping', () {
expect(generateString('ab\rc'), "'ab\\rc'");
});
test('supports backspace escaping', () {
expect(generateString('ab\bc'), "'ab\\bc'");
});
});
}
......@@ -88,28 +88,29 @@ void main() {
'#l10n 9 (Hello GB fallback World)\n'
'#l10n 10 (--- General formatting tests ---)\n'
'#l10n 11 (Hello World)\n'
'#l10n 12 (Hello World)\n'
'#l10n 12 (Hello _NEWLINE_ World)\n'
'#l10n 13 (Hello World)\n'
'#l10n 14 (Hello World on Friday, January 1, 1960)\n'
'#l10n 15 (Hello world argument on 1/1/1960 at 00:00)\n'
'#l10n 16 (Hello World from 1960 to 2020)\n'
'#l10n 17 (Hello for 123)\n'
'#l10n 18 (Hello for price USD123.00)\n'
'#l10n 19 (Hello)\n'
'#l10n 20 (Hello World)\n'
'#l10n 21 (Hello two worlds)\n'
'#l10n 22 (Hello)\n'
'#l10n 23 (Hello new World)\n'
'#l10n 24 (Hello two new worlds)\n'
'#l10n 25 (Hello on Friday, January 1, 1960)\n'
'#l10n 26 (Hello World, on Friday, January 1, 1960)\n'
'#l10n 27 (Hello two worlds, on Friday, January 1, 1960)\n'
'#l10n 28 (Hello other 0 worlds, with a total of 100 citizens)\n'
'#l10n 29 (Hello World of 101 citizens)\n'
'#l10n 30 (Hello two worlds with 102 total citizens)\n'
'#l10n 31 ([Hello] -World- #123#)\n'
'#l10n 32 (Flutter\'s amazing!)\n'
'#l10n 33 (Flutter is "amazing"!)\n'
'#l10n 14 (Hello World)\n'
'#l10n 15 (Hello World on Friday, January 1, 1960)\n'
'#l10n 16 (Hello world argument on 1/1/1960 at 00:00)\n'
'#l10n 17 (Hello World from 1960 to 2020)\n'
'#l10n 18 (Hello for 123)\n'
'#l10n 19 (Hello for price USD123.00)\n'
'#l10n 20 (Hello)\n'
'#l10n 21 (Hello World)\n'
'#l10n 22 (Hello two worlds)\n'
'#l10n 23 (Hello)\n'
'#l10n 24 (Hello new World)\n'
'#l10n 25 (Hello two new worlds)\n'
'#l10n 26 (Hello on Friday, January 1, 1960)\n'
'#l10n 27 (Hello World, on Friday, January 1, 1960)\n'
'#l10n 28 (Hello two worlds, on Friday, January 1, 1960)\n'
'#l10n 29 (Hello other 0 worlds, with a total of 100 citizens)\n'
'#l10n 30 (Hello World of 101 citizens)\n'
'#l10n 31 (Hello two worlds with 102 total citizens)\n'
'#l10n 32 ([Hello] -World- #123#)\n'
'#l10n 33 (Flutter\'s amazing!)\n'
'#l10n 34 (Flutter is "amazing"!)\n'
'#l10n END\n'
);
});
......
......@@ -124,6 +124,7 @@ class Home extends StatelessWidget {
final AppLocalizations localizations = AppLocalizations.of(context);
results.addAll(<String>[
'${localizations.helloWorld}',
'${localizations.helloNewlineWorld}',
'${localizations.hello("World")}',
'${localizations.greeting("Hello", "World")}',
'${localizations.helloWorldOn(DateTime(1960))}',
......@@ -154,7 +155,9 @@ class Home extends StatelessWidget {
try {
int n = 0;
for (final String result in results) {
print('#l10n $n ($result)');
// Newline character replacement is necessary because
// the stream breaks up stdout by new lines.
print('#l10n $n (${result.replaceAll('\n', '_NEWLINE_')})');
n += 1;
}
}
......@@ -188,6 +191,11 @@ void main() {
"description": "The conventional newborn programmer greeting"
},
"helloNewlineWorld": "Hello \n World",
"@helloNewlineWorld": {
"description": "The JSON decoder should convert backslash-n to a newline character in the generated Dart string."
},
"hello": "Hello {world}",
"@hello": {
"description": "A message with a single parameter",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment