Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
728a1933
Unverified
Commit
728a1933
authored
Apr 20, 2021
by
Jenn Magder
Committed by
GitHub
Apr 20, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate gen_l10n to null safety (#80763)
parent
4cceeaa0
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
140 additions
and
263 deletions
+140
-263
gen_l10n.dart
packages/flutter_tools/lib/src/localizations/gen_l10n.dart
+109
-169
gen_l10n_types.dart
...s/flutter_tools/lib/src/localizations/gen_l10n_types.dart
+28
-28
generate_localizations_test.dart
...tools/test/general.shard/generate_localizations_test.dart
+3
-66
No files found.
packages/flutter_tools/lib/src/localizations/gen_l10n.dart
View file @
728a1933
...
...
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import
'package:meta/meta.dart'
;
import
'../base/common.dart'
;
...
...
@@ -18,20 +16,20 @@ import 'localizations_utils.dart';
/// Run the localizations generation script with the configuration [options].
LocalizationsGenerator
generateLocalizations
(
{
@
required
Directory
projectDir
,
@required
Directory
dependenciesDir
,
@
required
LocalizationOptions
options
,
@
required
Logger
logger
,
@
required
FileSystem
fileSystem
,
required
Directory
projectDir
,
Directory
?
dependenciesDir
,
required
LocalizationOptions
options
,
required
Logger
logger
,
required
FileSystem
fileSystem
,
})
{
// If generating a synthetic package, generate a warning if
// flutter: generate is not set.
final
FlutterManifest
flutterManifest
=
FlutterManifest
.
createFromPath
(
final
FlutterManifest
?
flutterManifest
=
FlutterManifest
.
createFromPath
(
projectDir
.
childFile
(
'pubspec.yaml'
).
path
,
fileSystem:
projectDir
.
fileSystem
,
logger:
logger
,
);
if
(
options
.
useSyntheticPackage
&&
!
flutterManifest
.
generateSyntheticPackage
)
{
if
(
options
.
useSyntheticPackage
&&
(
flutterManifest
==
null
||
!
flutterManifest
.
generateSyntheticPackage
)
)
{
throwToolExit
(
'Attempted to generate localizations code without having '
'the flutter: generate flag turned on.'
...
...
@@ -44,9 +42,9 @@ LocalizationsGenerator generateLocalizations({
precacheLanguageAndRegionTags
();
final
String
inputPathString
=
options
?
.
arbDirectory
?.
path
??
fileSystem
.
path
.
join
(
'lib'
,
'l10n'
);
final
String
templateArbFileName
=
options
?
.
templateArbFile
?.
toFilePath
()
??
'app_en.arb'
;
final
String
outputFileString
=
options
?
.
outputLocalizationsFile
?.
toFilePath
()
??
'app_localizations.dart'
;
final
String
inputPathString
=
options
.
arbDirectory
?.
path
??
fileSystem
.
path
.
join
(
'lib'
,
'l10n'
);
final
String
templateArbFileName
=
options
.
templateArbFile
?.
toFilePath
()
??
'app_en.arb'
;
final
String
outputFileString
=
options
.
outputLocalizationsFile
?.
toFilePath
()
??
'app_localizations.dart'
;
LocalizationsGenerator
generator
;
try
{
generator
=
LocalizationsGenerator
(
...
...
@@ -56,16 +54,16 @@ LocalizationsGenerator generateLocalizations({
inputPathString:
inputPathString
,
templateArbFileName:
templateArbFileName
,
outputFileString:
outputFileString
,
outputPathString:
options
?
.
outputDirectory
?.
path
,
outputPathString:
options
.
outputDirectory
?.
path
,
classNameString:
options
.
outputClass
??
'AppLocalizations'
,
preferredSupportedLocales:
options
.
preferredSupportedLocales
,
headerString:
options
.
header
,
headerFile:
options
?
.
headerFile
?.
toFilePath
(),
headerFile:
options
.
headerFile
?.
toFilePath
(),
useDeferredLoading:
options
.
deferredLoading
??
false
,
useSyntheticPackage:
options
.
useSyntheticPackage
??
true
,
areResourceAttributesRequired:
options
.
areResourceAttributesRequired
??
false
,
untranslatedMessagesFile:
options
?
.
untranslatedMessagesFile
?.
toFilePath
(),
usesNullableGetter:
options
?.
usesNullableGetter
??
true
,
useSyntheticPackage:
options
.
useSyntheticPackage
,
areResourceAttributesRequired:
options
.
areResourceAttributesRequired
,
untranslatedMessagesFile:
options
.
untranslatedMessagesFile
?.
toFilePath
(),
usesNullableGetter:
options
.
usesNullableGetter
,
)
..
loadResources
()
..
writeOutputFiles
(
logger
,
isFromYaml:
true
);
...
...
@@ -87,9 +85,9 @@ String _syntheticL10nPackagePath(FileSystem fileSystem) => fileSystem.path.join(
List
<
String
>
generateMethodParameters
(
Message
message
)
{
assert
(
message
.
placeholders
.
isNotEmpty
);
final
Placeholder
countPlaceholder
=
message
.
isPlural
?
message
.
getCountPlaceholder
()
:
null
;
final
Placeholder
?
countPlaceholder
=
message
.
isPlural
?
message
.
getCountPlaceholder
()
:
null
;
return
message
.
placeholders
.
map
((
Placeholder
placeholder
)
{
final
String
type
=
placeholder
==
countPlaceholder
?
'int'
:
placeholder
.
type
;
final
String
?
type
=
placeholder
==
countPlaceholder
?
'int'
:
placeholder
.
type
;
return
'
$type
${placeholder.name}
'
;
}).
toList
();
}
...
...
@@ -102,7 +100,8 @@ String generateDateFormattingLogic(Message message) {
final
Iterable
<
String
>
formatStatements
=
message
.
placeholders
.
where
((
Placeholder
placeholder
)
=>
placeholder
.
isDate
)
.
map
((
Placeholder
placeholder
)
{
if
(
placeholder
.
format
==
null
)
{
final
String
?
placeholderFormat
=
placeholder
.
format
;
if
(
placeholderFormat
==
null
)
{
throw
L10nException
(
'The placeholder,
${placeholder.name}
, has its "type" resource attribute set to '
'the "
${placeholder.type}
" type. To properly resolve for the right '
...
...
@@ -114,7 +113,7 @@ String generateDateFormattingLogic(Message message) {
}
if
(!
placeholder
.
hasValidDateFormat
)
{
throw
L10nException
(
'Date format "
$
{placeholder.format}
" for placeholder '
'Date format "
$
placeholderFormat
" for placeholder '
'
${placeholder.name}
does not have a corresponding DateFormat '
'constructor
\n
. Check the intl library
\'
s DateFormat class '
'constructors for allowed date formats.'
...
...
@@ -122,7 +121,7 @@ String generateDateFormattingLogic(Message message) {
}
return
dateFormatTemplate
.
replaceAll
(
'@(placeholder)'
,
placeholder
.
name
)
.
replaceAll
(
'@(format)'
,
placeholder
.
f
ormat
);
.
replaceAll
(
'@(format)'
,
placeholder
F
ormat
);
});
return
formatStatements
.
isEmpty
?
'@(none)'
:
formatStatements
.
join
(
''
);
...
...
@@ -136,9 +135,10 @@ String generateNumberFormattingLogic(Message message) {
final
Iterable
<
String
>
formatStatements
=
message
.
placeholders
.
where
((
Placeholder
placeholder
)
=>
placeholder
.
isNumber
)
.
map
((
Placeholder
placeholder
)
{
if
(!
placeholder
.
hasValidNumberFormat
)
{
final
String
?
placeholderFormat
=
placeholder
.
format
;
if
(!
placeholder
.
hasValidNumberFormat
||
placeholderFormat
==
null
)
{
throw
L10nException
(
'Number format
$
{placeholder.format}
for the
${placeholder.name}
'
'Number format
$
placeholderFormat
for the
${placeholder.name}
'
'placeholder does not have a corresponding NumberFormat constructor.
\n
'
'Check the intl library
\'
s NumberFormat class constructors for allowed '
'number formats.'
...
...
@@ -157,19 +157,19 @@ String generateNumberFormattingLogic(Message message) {
if
(
placeholder
.
hasNumberFormatWithParameters
)
{
return
numberFormatNamedTemplate
.
replaceAll
(
'@(placeholder)'
,
placeholder
.
name
)
.
replaceAll
(
'@(format)'
,
placeholder
.
f
ormat
)
.
replaceAll
(
'@(format)'
,
placeholder
F
ormat
)
.
replaceAll
(
'@(parameters)'
,
parameters
.
join
(
',
\n
'
));
}
else
{
return
numberFormatPositionalTemplate
.
replaceAll
(
'@(placeholder)'
,
placeholder
.
name
)
.
replaceAll
(
'@(format)'
,
placeholder
.
f
ormat
);
.
replaceAll
(
'@(format)'
,
placeholder
F
ormat
);
}
});
return
formatStatements
.
isEmpty
?
'@(none)'
:
formatStatements
.
join
(
''
);
}
String
generatePluralMethod
(
Message
message
,
AppResourceBundle
bundl
e
)
{
String
_generatePluralMethod
(
Message
message
,
String
translationForMessag
e
)
{
if
(
message
.
placeholders
.
isEmpty
)
{
throw
L10nException
(
'Unable to find placeholders for the plural message:
${message.resourceId}
.
\n
'
...
...
@@ -180,20 +180,12 @@ String generatePluralMethod(Message message, AppResourceBundle bundle) {
// To make it easier to parse the plurals message, temporarily replace each
// "{placeholder}" parameter with "#placeholder#".
String
easyMessage
=
bundle
.
translationFor
(
message
)
;
String
easyMessage
=
translationForMessage
;
for
(
final
Placeholder
placeholder
in
message
.
placeholders
)
{
easyMessage
=
easyMessage
.
replaceAll
(
'{
${placeholder.name}
}'
,
'#
${placeholder.name}
#'
);
}
final
Placeholder
countPlaceholder
=
message
.
getCountPlaceholder
();
if
(
countPlaceholder
==
null
)
{
throw
L10nException
(
'Unable to find the count placeholder for the plural message:
${message.resourceId}
.
\n
'
'Check to see if the plural message is in the proper ICU syntax format '
'and ensure that placeholders are properly specified.'
);
}
const
Map
<
String
,
String
>
pluralIds
=
<
String
,
String
>{
'=0'
:
'zero'
,
'=1'
:
'one'
,
...
...
@@ -206,9 +198,9 @@ String generatePluralMethod(Message message, AppResourceBundle bundle) {
final
List
<
String
>
pluralLogicArgs
=
<
String
>[];
for
(
final
String
pluralKey
in
pluralIds
.
keys
)
{
final
RegExp
expRE
=
RegExp
(
'(
$pluralKey
)
\\
s*{([^}]+)}'
);
final
RegExpMatch
match
=
expRE
.
firstMatch
(
easyMessage
);
final
RegExpMatch
?
match
=
expRE
.
firstMatch
(
easyMessage
);
if
(
match
!=
null
&&
match
.
groupCount
==
2
)
{
String
argValue
=
generateString
(
match
.
group
(
2
));
String
argValue
=
generateString
(
match
.
group
(
2
)
!
);
for
(
final
Placeholder
placeholder
in
message
.
placeholders
)
{
if
(
placeholder
!=
countPlaceholder
&&
placeholder
.
requiresFormatting
)
{
argValue
=
argValue
.
replaceAll
(
...
...
@@ -231,7 +223,7 @@ String generatePluralMethod(Message message, AppResourceBundle bundle) {
}
final
List
<
String
>
parameters
=
message
.
placeholders
.
map
((
Placeholder
placeholder
)
{
final
String
placeholderType
=
placeholder
==
countPlaceholder
?
'int'
:
placeholder
.
type
;
final
String
?
placeholderType
=
placeholder
==
countPlaceholder
?
'int'
:
placeholder
.
type
;
return
'
$placeholderType
${placeholder.name}
'
;
}).
toList
();
...
...
@@ -285,9 +277,9 @@ bool _needsCurlyBracketStringInterpolation(String messageString, String placehol
}
}
String
generateMethod
(
Message
message
,
AppResourceBundle
bundl
e
)
{
String
_generateMethod
(
Message
message
,
String
translationForMessag
e
)
{
String
generateMessage
()
{
String
messageValue
=
generateString
(
bundle
.
translationFor
(
message
)
);
String
messageValue
=
generateString
(
translationForMessage
);
for
(
final
Placeholder
placeholder
in
message
.
placeholders
)
{
if
(
placeholder
.
requiresFormatting
)
{
messageValue
=
messageValue
.
replaceAll
(
...
...
@@ -310,7 +302,7 @@ String generateMethod(Message message, AppResourceBundle bundle) {
}
if
(
message
.
isPlural
)
{
return
generatePluralMethod
(
message
,
bundl
e
);
return
_generatePluralMethod
(
message
,
translationForMessag
e
);
}
if
(
message
.
placeholdersRequireFormatting
)
{
...
...
@@ -335,7 +327,7 @@ String generateMethod(Message message, AppResourceBundle bundle) {
.
replaceAll
(
'@(message)'
,
generateMessage
());
}
String
generateBaseClassMethod
(
Message
message
,
LocaleInfo
templateArbLocale
)
{
String
generateBaseClassMethod
(
Message
message
,
LocaleInfo
?
templateArbLocale
)
{
final
String
comment
=
message
.
description
??
'No description provided for @
${message.resourceId}
.'
;
final
String
templateLocaleTranslationComment
=
'''
/// In
$templateArbLocale
, this message translates to:
...
...
@@ -396,9 +388,9 @@ String _generateLookupByScriptCode(
.
replaceAll
(
'@(code)'
,
'scriptCode'
)
.
replaceAll
(
'@(switchClauses)'
,
localesWithScriptCodes
.
map
((
LocaleInfo
locale
)
{
return
generateSwitchClauseTemplate
(
locale
)
.
replaceAll
(
'@(case)'
,
locale
.
scriptCode
);
.
replaceAll
(
'@(case)'
,
locale
.
scriptCode
!
);
}).
join
(
'
\n
'
));
}).
where
((
String
switchClause
)
=>
switchClause
!=
null
);
}).
where
Type
<
String
>(
);
if
(
switchClauses
.
isEmpty
)
{
return
''
;
...
...
@@ -429,9 +421,9 @@ String _generateLookupByCountryCode(
.
replaceAll
(
'@(code)'
,
'countryCode'
)
.
replaceAll
(
'@(switchClauses)'
,
localesWithCountryCodes
.
map
((
LocaleInfo
locale
)
{
return
generateSwitchClauseTemplate
(
locale
)
.
replaceAll
(
'@(case)'
,
locale
.
countryCode
);
.
replaceAll
(
'@(case)'
,
locale
.
countryCode
!
);
}).
join
(
'
\n
'
));
}).
where
((
String
switchClause
)
=>
switchClause
!=
null
);
}).
where
Type
<
String
>(
);
if
(
switchClauses
.
isEmpty
)
{
return
''
;
...
...
@@ -460,7 +452,7 @@ String _generateLookupByLanguageCode(
return
generateSwitchClauseTemplate
(
locale
)
.
replaceAll
(
'@(case)'
,
locale
.
languageCode
);
}).
join
(
'
\n
'
);
}).
where
((
String
switchClause
)
=>
switchClause
!=
null
);
}).
where
Type
<
String
>(
);
if
(
switchClauses
.
isEmpty
)
{
return
''
;
...
...
@@ -504,11 +496,11 @@ String _generateLookupBody(
}
String
_generateDelegateClass
(
{
AppResourceBundleCollection
allBundles
,
String
className
,
Set
<
String
>
supportedLanguageCodes
,
bool
useDeferredLoading
,
String
fileName
,
required
AppResourceBundleCollection
allBundles
,
required
String
className
,
required
Set
<
String
>
supportedLanguageCodes
,
required
bool
useDeferredLoading
,
required
String
fileName
,
})
{
final
String
lookupBody
=
_generateLookupBody
(
...
...
@@ -544,24 +536,24 @@ class LocalizationsGenerator {
/// Throws a [FileSystemException] when a file operation necessary for setting
/// up the [LocalizationsGenerator] cannot be completed.
factory
LocalizationsGenerator
({
@
required
FileSystem
fileSystem
,
@
required
String
inputPathString
,
String
outputPathString
,
@
required
String
templateArbFileName
,
String
outputFileString
,
@
required
String
classNameString
,
List
<
String
>
preferredSupportedLocales
,
String
headerString
,
String
headerFile
,
required
FileSystem
fileSystem
,
required
String
inputPathString
,
String
?
outputPathString
,
required
String
templateArbFileName
,
required
String
outputFileString
,
required
String
classNameString
,
List
<
String
>
?
preferredSupportedLocales
,
String
?
headerString
,
String
?
headerFile
,
bool
useDeferredLoading
=
false
,
String
inputsAndOutputsListPath
,
String
?
inputsAndOutputsListPath
,
bool
useSyntheticPackage
=
true
,
String
projectPathString
,
String
?
projectPathString
,
bool
areResourceAttributesRequired
=
false
,
String
untranslatedMessagesFile
,
String
?
untranslatedMessagesFile
,
bool
usesNullableGetter
=
true
,
})
{
final
Directory
projectDirectory
=
projectDirFromPath
(
fileSystem
,
projectPathString
);
final
Directory
?
projectDirectory
=
projectDirFromPath
(
fileSystem
,
projectPathString
);
final
Directory
inputDirectory
=
inputDirectoryFromPath
(
fileSystem
,
inputPathString
,
projectDirectory
);
final
Directory
outputDirectory
=
outputDirectoryFromPath
(
fileSystem
,
outputPathString
??
inputPathString
,
useSyntheticPackage
,
projectDirectory
);
return
LocalizationsGenerator
.
_
(
...
...
@@ -576,7 +568,7 @@ class LocalizationsGenerator {
baseOutputFile:
outputDirectory
.
childFile
(
outputFileString
),
preferredSupportedLocales:
preferredSupportedLocalesFromLocales
(
preferredSupportedLocales
),
header:
headerFromFile
(
headerString
,
headerFile
,
inputDirectory
),
useDeferredLoading:
useDeferredLoading
??
false
,
useDeferredLoading:
useDeferredLoading
,
untranslatedMessagesFile:
_untranslatedMessagesFileFromPath
(
fileSystem
,
untranslatedMessagesFile
),
inputsAndOutputsListFile:
_inputsAndOutputsListFileFromPath
(
fileSystem
,
inputsAndOutputsListPath
),
areResourceAttributesRequired:
areResourceAttributesRequired
,
...
...
@@ -586,17 +578,16 @@ class LocalizationsGenerator {
/// Creates an instance of the localizations generator class.
///
/// It takes in a [FileSystem] representation that the class will act upon.
LocalizationsGenerator
.
_
(
this
.
_fs
,
{
this
.
inputDirectory
,
@required
this
.
outputDirectory
,
@required
this
.
templateArbFile
,
@required
this
.
baseOutputFile
,
@required
this
.
className
,
LocalizationsGenerator
.
_
(
this
.
_fs
,
{
required
this
.
inputDirectory
,
required
this
.
outputDirectory
,
required
this
.
templateArbFile
,
required
this
.
baseOutputFile
,
required
this
.
className
,
this
.
preferredSupportedLocales
=
const
<
LocaleInfo
>[],
this
.
header
=
''
,
this
.
useDeferredLoading
=
false
,
this
.
inputsAndOutputsListFile
,
required
this
.
inputsAndOutputsListFile
,
this
.
useSyntheticPackage
=
true
,
this
.
projectDirectory
,
this
.
areResourceAttributesRequired
=
false
,
...
...
@@ -605,9 +596,11 @@ class LocalizationsGenerator {
});
final
FileSystem
_fs
;
Iterable
<
Message
>
_allMessages
;
AppResourceBundleCollection
_allBundles
;
LocaleInfo
_templateArbLocale
;
Iterable
<
Message
>
_allMessages
=
<
Message
>[];
late
final
AppResourceBundleCollection
_allBundles
=
AppResourceBundleCollection
(
inputDirectory
);
late
final
AppResourceBundle
_templateBundle
=
AppResourceBundle
(
templateArbFile
);
late
final
LocaleInfo
_templateArbLocale
=
_templateBundle
.
locale
;
@visibleForTesting
final
bool
useSyntheticPackage
;
...
...
@@ -623,44 +616,32 @@ class LocalizationsGenerator {
///
/// It is assumed that all input files (e.g. [templateArbFile], arb files
/// for translated messages, header file templates) will reside here.
///
/// This directory is specified with the [initialize] method.
final
Directory
inputDirectory
;
/// The Flutter project's root directory.
///
/// This directory is specified with the [initialize] method.
final
Directory
projectDirectory
;
final
Directory
?
projectDirectory
;
/// The directory to generate the project's localizations files in.
///
/// It is assumed that all output files (e.g. The localizations
/// [outputFile], `messages_<locale>.dart` and `messages_all.dart`)
/// will reside here.
///
/// This directory is specified with the [initialize] method.
final
Directory
outputDirectory
;
/// The input arb file which defines all of the messages that will be
/// exported by the generated class that's written to [outputFile].
///
/// This file is specified with the [initialize] method.
final
File
templateArbFile
;
/// The file to write the generated abstract localizations and
/// localizations delegate classes to. Separate localizations
/// files will also be generated for each language using this
/// filename as a prefix and the locale as the suffix.
///
/// This file is specified with the [initialize] method.
final
File
baseOutputFile
;
/// The class name to be used for the localizations class in [outputFile].
///
/// For example, if 'AppLocalizations' is passed in, a class named
/// AppLocalizations will be used for localized message lookups.
///
/// The class name is specified with the [initialize] method.
final
String
className
;
/// The list of preferred supported locales.
...
...
@@ -673,8 +654,6 @@ class LocalizationsGenerator {
/// The order of locales in this list will also be the order of locale
/// priority. For example, if a device supports 'en' and 'es' and
/// ['es', 'en'] is passed in, the 'es' locale will take priority over 'en'.
///
/// The list of preferred locales is specified with the [initialize] method.
final
List
<
LocaleInfo
>
preferredSupportedLocales
;
/// The list of all arb path strings in [inputDirectory].
...
...
@@ -715,19 +694,15 @@ class LocalizationsGenerator {
/// string format.
final
Map
<
File
,
String
>
_languageFileMap
=
<
File
,
String
>{};
/// Contains the generated application's localizations and localizations delegate
/// classes.
String
_generatedLocalizationsFile
;
/// A generated file that will contain the list of messages for each locale
/// that do not have a translation yet.
@visibleForTesting
final
File
untranslatedMessagesFile
;
final
File
?
untranslatedMessagesFile
;
/// The file that contains the list of inputs and outputs for generating
/// localizations.
@visibleForTesting
final
File
inputsAndOutputsListFile
;
final
File
?
inputsAndOutputsListFile
;
final
List
<
String
>
_inputFileList
=
<
String
>[];
final
List
<
String
>
_outputFileList
=
<
String
>[];
...
...
@@ -753,7 +728,7 @@ class LocalizationsGenerator {
}
@visibleForTesting
static
Directory
projectDirFromPath
(
FileSystem
fileSystem
,
String
projectPathString
)
{
static
Directory
?
projectDirFromPath
(
FileSystem
fileSystem
,
String
?
projectPathString
)
{
if
(
projectPathString
==
null
)
{
return
null
;
}
...
...
@@ -771,10 +746,7 @@ class LocalizationsGenerator {
/// Sets the reference [Directory] for [inputDirectory].
@visibleForTesting
static
Directory
inputDirectoryFromPath
(
FileSystem
fileSystem
,
String
inputPathString
,
Directory
projectDirectory
)
{
if
(
inputPathString
==
null
)
{
throw
L10nException
(
'inputPathString argument cannot be null'
);
}
static
Directory
inputDirectoryFromPath
(
FileSystem
fileSystem
,
String
inputPathString
,
Directory
?
projectDirectory
)
{
final
Directory
inputDirectory
=
fileSystem
.
directory
(
projectDirectory
!=
null
?
_getAbsoluteProjectPath
(
inputPathString
,
projectDirectory
)
...
...
@@ -800,7 +772,7 @@ class LocalizationsGenerator {
/// Sets the reference [Directory] for [outputDirectory].
@visibleForTesting
static
Directory
outputDirectoryFromPath
(
FileSystem
fileSystem
,
String
outputPathString
,
bool
useSyntheticPackage
,
Directory
projectDirectory
)
{
static
Directory
outputDirectoryFromPath
(
FileSystem
fileSystem
,
String
outputPathString
,
bool
useSyntheticPackage
,
Directory
?
projectDirectory
)
{
Directory
outputDirectory
;
if
(
useSyntheticPackage
)
{
outputDirectory
=
fileSystem
.
directory
(
...
...
@@ -809,13 +781,6 @@ class LocalizationsGenerator {
:
_syntheticL10nPackagePath
(
fileSystem
)
);
}
else
{
if
(
outputPathString
==
null
)
{
throw
L10nException
(
'outputPathString argument cannot be null if not using '
'synthetic package option.'
);
}
outputDirectory
=
fileSystem
.
directory
(
projectDirectory
!=
null
?
_getAbsoluteProjectPath
(
outputPathString
,
projectDirectory
)
...
...
@@ -828,13 +793,6 @@ class LocalizationsGenerator {
/// Sets the reference [File] for [templateArbFile].
@visibleForTesting
static
File
templateArbFileFromFileName
(
String
templateArbFileName
,
Directory
inputDirectory
)
{
if
(
templateArbFileName
==
null
)
{
throw
L10nException
(
'templateArbFileName argument cannot be null'
);
}
if
(
inputDirectory
==
null
)
{
throw
L10nException
(
'inputDirectory cannot be null when setting template arb file'
);
}
final
File
templateArbFile
=
inputDirectory
.
childFile
(
templateArbFileName
);
final
String
templateArbFileStatModeString
=
templateArbFile
.
statSync
().
modeString
();
if
(
templateArbFileStatModeString
[
0
]
==
'-'
&&
templateArbFileStatModeString
[
3
]
==
'-'
)
{
...
...
@@ -846,15 +804,6 @@ class LocalizationsGenerator {
return
templateArbFile
;
}
/// Sets the reference [File] for the localizations delegate [outputFile].
@visibleForTesting
static
File
baseOutputFileFromOutputFile
(
FileSystem
fileSystem
,
String
outputFileString
,
Directory
outputDirectory
)
{
if
(
outputDirectory
==
null
)
{
throw
L10nException
(
'outputFileString argument cannot be null'
);
}
return
outputDirectory
.
childFile
(
outputFileString
);
}
static
bool
_isValidClassName
(
String
className
)
{
// Public Dart class name cannot begin with an underscore
if
(
className
[
0
]
==
'_'
)
{
...
...
@@ -879,8 +828,8 @@ class LocalizationsGenerator {
/// classes.
@visibleForTesting
static
String
classNameFromString
(
String
classNameString
)
{
if
(
classNameString
==
null
||
classNameString
.
isEmpty
)
{
throw
L10nException
(
'classNameString argument cannot be
null or
empty'
);
if
(
classNameString
.
isEmpty
)
{
throw
L10nException
(
'classNameString argument cannot be empty'
);
}
if
(!
_isValidClassName
(
classNameString
))
{
throw
L10nException
(
...
...
@@ -893,7 +842,7 @@ class LocalizationsGenerator {
/// Sets [preferredSupportedLocales] so that this particular list of locales
/// will take priority over the other locales.
@visibleForTesting
static
List
<
LocaleInfo
>
preferredSupportedLocalesFromLocales
(
List
<
String
>
inputLocales
)
{
static
List
<
LocaleInfo
>
preferredSupportedLocalesFromLocales
(
List
<
String
>
?
inputLocales
)
{
if
(
inputLocales
==
null
||
inputLocales
.
isEmpty
)
{
return
const
<
LocaleInfo
>[];
}
...
...
@@ -902,7 +851,7 @@ class LocalizationsGenerator {
}).
toList
();
}
static
String
headerFromFile
(
String
headerString
,
String
headerFile
,
Directory
inputDirectory
)
{
static
String
headerFromFile
(
String
?
headerString
,
String
?
headerFile
,
Directory
inputDirectory
)
{
if
(
headerString
!=
null
&&
headerFile
!=
null
)
{
throw
L10nException
(
'Cannot accept both header and header file arguments.
\n
'
...
...
@@ -928,7 +877,7 @@ class LocalizationsGenerator {
static
String
_getAbsoluteProjectPath
(
String
relativePath
,
Directory
projectDirectory
)
=>
projectDirectory
.
fileSystem
.
path
.
join
(
projectDirectory
.
path
,
relativePath
);
static
File
_untranslatedMessagesFileFromPath
(
FileSystem
fileSystem
,
String
untranslatedMessagesFileString
)
{
static
File
?
_untranslatedMessagesFileFromPath
(
FileSystem
fileSystem
,
String
?
untranslatedMessagesFileString
)
{
if
(
untranslatedMessagesFileString
==
null
||
untranslatedMessagesFileString
.
isEmpty
)
{
return
null
;
}
...
...
@@ -936,7 +885,7 @@ class LocalizationsGenerator {
return
fileSystem
.
file
(
untranslatedMessagesFileString
);
}
static
File
_inputsAndOutputsListFileFromPath
(
FileSystem
fileSystem
,
String
inputsAndOutputsListPath
)
{
static
File
?
_inputsAndOutputsListFileFromPath
(
FileSystem
fileSystem
,
String
?
inputsAndOutputsListPath
)
{
if
(
inputsAndOutputsListPath
==
null
)
{
return
null
;
}
...
...
@@ -969,12 +918,10 @@ class LocalizationsGenerator {
// Load _allMessages from templateArbFile and _allBundles from all of the ARB
// files in inputDirectory. Also initialized: supportedLocales.
void
loadResources
()
{
final
AppResourceBundle
templateBundle
=
AppResourceBundle
(
templateArbFile
);
_templateArbLocale
=
templateBundle
.
locale
;
_allMessages
=
templateBundle
.
resourceIds
.
map
((
String
id
)
=>
Message
(
templateBundle
.
resources
,
id
,
areResourceAttributesRequired
,
_allMessages
=
_templateBundle
.
resourceIds
.
map
((
String
id
)
=>
Message
(
_templateBundle
.
resources
,
id
,
areResourceAttributesRequired
,
));
for
(
final
String
resourceId
in
templateBundle
.
resourceIds
)
{
for
(
final
String
resourceId
in
_
templateBundle
.
resourceIds
)
{
if
(!
_isValidGetterAndMethodName
(
resourceId
))
{
throw
L10nException
(
'Invalid ARB resource name "
$resourceId
" in
$templateArbFile
.
\n
'
...
...
@@ -985,7 +932,6 @@ class LocalizationsGenerator {
}
}
_allBundles
=
AppResourceBundleCollection
(
inputDirectory
);
if
(
inputsAndOutputsListFile
!=
null
)
{
_inputFileList
.
addAll
(
_allBundles
.
bundles
.
map
((
AppResourceBundle
bundle
)
{
return
bundle
.
file
.
absolute
.
path
;
...
...
@@ -1011,7 +957,7 @@ class LocalizationsGenerator {
void
_addUnimplementedMessage
(
LocaleInfo
locale
,
String
message
)
{
if
(
_unimplementedMessages
.
containsKey
(
locale
))
{
_unimplementedMessages
[
locale
].
add
(
message
);
_unimplementedMessages
[
locale
]
!
.
add
(
message
);
}
else
{
_unimplementedMessages
.
putIfAbsent
(
locale
,
()
=>
<
String
>[
message
]);
}
...
...
@@ -1032,9 +978,9 @@ class LocalizationsGenerator {
_addUnimplementedMessage
(
locale
,
message
.
resourceId
);
}
return
generateMethod
(
return
_
generateMethod
(
message
,
bundle
.
translationFor
(
message
)
==
null
?
templateBundle
:
bundle
,
bundle
.
translationFor
(
message
)
??
templateBundle
.
translationFor
(
message
)!
,
);
});
...
...
@@ -1065,7 +1011,7 @@ class LocalizationsGenerator {
final
Iterable
<
String
>
methods
=
messages
.
where
((
Message
message
)
=>
bundle
.
translationFor
(
message
)
!=
null
)
.
map
((
Message
message
)
=>
generateMethod
(
message
,
bundle
));
.
map
((
Message
message
)
=>
_generateMethod
(
message
,
bundle
.
translationFor
(
message
)!
));
return
subclassTemplate
.
replaceAll
(
'@(language)'
,
describeLocale
(
locale
.
toString
()))
...
...
@@ -1078,7 +1024,7 @@ class LocalizationsGenerator {
// Generate the AppLocalizations class, its LocalizationsDelegate subclass,
// and all AppLocalizations subclasses for every locale. This method by
// itself does not generate the output files.
void
_generateCode
()
{
String
_generateCode
()
{
bool
isBaseClassLocale
(
LocaleInfo
locale
,
String
language
)
{
return
locale
.
languageCode
==
language
&&
locale
.
countryCode
==
null
...
...
@@ -1100,8 +1046,8 @@ class LocalizationsGenerator {
final
Iterable
<
String
>
supportedLocalesCode
=
supportedLocales
.
map
((
LocaleInfo
locale
)
{
final
String
languageCode
=
locale
.
languageCode
;
final
String
countryCode
=
locale
.
countryCode
;
final
String
scriptCode
=
locale
.
scriptCode
;
final
String
?
countryCode
=
locale
.
countryCode
;
final
String
?
scriptCode
=
locale
.
scriptCode
;
if
(
countryCode
==
null
&&
scriptCode
==
null
)
{
return
'Locale(
\'
$languageCode
\'
)'
;
...
...
@@ -1131,8 +1077,8 @@ class LocalizationsGenerator {
className
,
outputFileName
,
header
,
_allBundles
.
bundleFor
(
locale
),
_allBundles
.
bundleFor
(
_templateArbLocale
),
_allBundles
.
bundleFor
(
locale
)
!
,
_allBundles
.
bundleFor
(
_templateArbLocale
)
!
,
_allMessages
,
);
...
...
@@ -1143,7 +1089,7 @@ class LocalizationsGenerator {
final
Iterable
<
String
>
subclasses
=
localesForLanguage
.
map
<
String
>((
LocaleInfo
locale
)
{
return
_generateSubclass
(
className
,
_allBundles
.
bundleFor
(
locale
),
_allBundles
.
bundleFor
(
locale
)
!
,
_allMessages
,
);
});
...
...
@@ -1175,7 +1121,7 @@ class LocalizationsGenerator {
fileName:
fileName
,
);
_generatedLocalizationsFile
=
fileTemplate
return
fileTemplate
.
replaceAll
(
'@(header)'
,
header
)
.
replaceAll
(
'@(class)'
,
className
)
.
replaceAll
(
'@(methods)'
,
_allMessages
.
map
((
Message
message
)
=>
generateBaseClassMethod
(
message
,
_templateArbLocale
)).
join
(
'
\n
'
))
...
...
@@ -1194,7 +1140,7 @@ class LocalizationsGenerator {
void
writeOutputFiles
(
Logger
logger
,
{
bool
isFromYaml
=
false
})
{
// First, generate the string contents of all necessary files.
_generateCode
();
final
String
generatedLocalizationsFile
=
_generateCode
();
// A pubspec.yaml file is required when using a synthetic package. If it does not
// exist, create a blank one.
...
...
@@ -1228,10 +1174,10 @@ class LocalizationsGenerator {
}
});
baseOutputFile
.
writeAsStringSync
(
_
generatedLocalizationsFile
);
if
(
untranslatedM
essagesFile
!=
null
)
{
_generateUntranslatedMessagesFile
(
logger
);
baseOutputFile
.
writeAsStringSync
(
generatedLocalizationsFile
);
final
File
?
messagesFile
=
untranslatedMessagesFile
;
if
(
m
essagesFile
!=
null
)
{
_generateUntranslatedMessagesFile
(
logger
,
messagesFile
);
}
else
if
(
_unimplementedMessages
.
isNotEmpty
)
{
_unimplementedMessages
.
forEach
((
LocaleInfo
locale
,
List
<
String
>
messages
)
{
logger
.
printStatus
(
'"
$locale
":
${messages.length}
untranslated message(s).'
);
...
...
@@ -1257,16 +1203,16 @@ class LocalizationsGenerator {
'need to be translated.'
);
}
if
(
inputsAndOutputsListFile
!=
null
)
{
final
File
?
inputsAndOutputsListFileLocal
=
inputsAndOutputsListFile
;
if
(
inputsAndOutputsListFile
Local
!=
null
)
{
_outputFileList
.
add
(
baseOutputFile
.
absolute
.
path
);
// Generate a JSON file containing the inputs and outputs of the gen_l10n script.
if
(!
inputsAndOutputsListFile
.
existsSync
())
{
inputsAndOutputsListFile
.
createSync
(
recursive:
true
);
if
(!
inputsAndOutputsListFile
Local
.
existsSync
())
{
inputsAndOutputsListFile
Local
.
createSync
(
recursive:
true
);
}
inputsAndOutputsListFile
.
writeAsStringSync
(
inputsAndOutputsListFile
Local
.
writeAsStringSync
(
json
.
encode
(<
String
,
Object
>
{
'inputs'
:
_inputFileList
,
'outputs'
:
_outputFileList
,
...
...
@@ -1275,13 +1221,7 @@ class LocalizationsGenerator {
}
}
void
_generateUntranslatedMessagesFile
(
Logger
logger
)
{
if
(
logger
==
null
)
{
throw
L10nException
(
'Logger must be defined when generating untranslated messages file.'
);
}
void
_generateUntranslatedMessagesFile
(
Logger
logger
,
File
untranslatedMessagesFile
)
{
if
(
_unimplementedMessages
.
isEmpty
)
{
untranslatedMessagesFile
.
writeAsStringSync
(
'{}'
);
if
(
inputsAndOutputsListFile
!=
null
)
{
...
...
packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart
View file @
728a1933
...
...
@@ -187,7 +187,7 @@ class OptionalParameter {
// }
//
class
Placeholder
{
Placeholder
(
this
.
resourceId
,
this
.
name
,
Map
<
String
,
dynamic
>
attributes
)
Placeholder
(
this
.
resourceId
,
this
.
name
,
Map
<
String
,
Object
?
>
attributes
)
:
assert
(
resourceId
!=
null
),
assert
(
name
!=
null
),
example
=
_stringAttribute
(
resourceId
,
name
,
attributes
,
'example'
),
...
...
@@ -212,10 +212,10 @@ class Placeholder {
static
String
?
_stringAttribute
(
String
resourceId
,
String
name
,
Map
<
String
,
dynamic
>
attributes
,
Map
<
String
,
Object
?
>
attributes
,
String
attributeName
,
)
{
final
dynamic
value
=
attributes
[
attributeName
];
final
Object
?
value
=
attributes
[
attributeName
];
if
(
value
==
null
)
{
return
null
;
}
...
...
@@ -231,9 +231,9 @@ class Placeholder {
static
List
<
OptionalParameter
>
_optionalParameters
(
String
resourceId
,
String
name
,
Map
<
String
,
dynamic
>
attributes
Map
<
String
,
Object
?
>
attributes
)
{
final
dynamic
value
=
attributes
[
'optionalParameters'
];
final
Object
?
value
=
attributes
[
'optionalParameters'
];
if
(
value
==
null
)
{
return
<
OptionalParameter
>[];
}
...
...
@@ -267,7 +267,7 @@ class Placeholder {
// localized string to be shown for the template ARB file's locale.
// The docs for the Placeholder explain how placeholder entries are defined.
class
Message
{
Message
(
Map
<
String
,
dynamic
>
bundle
,
this
.
resourceId
,
bool
isResourceAttributeRequired
)
Message
(
Map
<
String
,
Object
?
>
bundle
,
this
.
resourceId
,
bool
isResourceAttributeRequired
)
:
assert
(
bundle
!=
null
),
assert
(
resourceId
!=
null
&&
resourceId
.
isNotEmpty
),
value
=
_value
(
bundle
,
resourceId
),
...
...
@@ -298,23 +298,23 @@ class Message {
);
}
static
String
_value
(
Map
<
String
,
dynamic
>
bundle
,
String
resourceId
)
{
final
dynamic
value
=
bundle
[
resourceId
];
static
String
_value
(
Map
<
String
,
Object
?
>
bundle
,
String
resourceId
)
{
final
Object
?
value
=
bundle
[
resourceId
];
if
(
value
==
null
)
{
throw
L10nException
(
'A value for resource "
$resourceId
" was not found.'
);
}
if
(
value
is
!
String
)
{
throw
L10nException
(
'The value of "
$resourceId
" is not a string.'
);
}
return
bundle
[
resourceId
]
as
String
;
return
value
;
}
static
Map
<
String
,
dynamic
>
_attributes
(
Map
<
String
,
dynamic
>
bundle
,
static
Map
<
String
,
Object
?>?
_attributes
(
Map
<
String
,
Object
?
>
bundle
,
String
resourceId
,
bool
isResourceAttributeRequired
,
)
{
final
dynamic
attributes
=
bundle
[
'@
$resourceId
'
];
final
Object
?
attributes
=
bundle
[
'@
$resourceId
'
];
if
(
isResourceAttributeRequired
)
{
if
(
attributes
==
null
)
{
throw
L10nException
(
...
...
@@ -324,7 +324,7 @@ class Message {
}
}
if
(
attributes
!=
null
&&
attributes
is
!
Map
<
String
,
dynamic
>)
{
if
(
attributes
!=
null
&&
attributes
is
!
Map
<
String
,
Object
?
>)
{
throw
L10nException
(
'The resource attribute "@
$resourceId
" is not a properly formatted Map. '
'Ensure that it is a map with keys that are strings.'
...
...
@@ -340,20 +340,20 @@ class Message {
);
}
return
attributes
as
Map
<
String
,
dynamic
>
;
return
attributes
as
Map
<
String
,
Object
?>?
;
}
static
String
?
_description
(
Map
<
String
,
dynamic
>
bundle
,
Map
<
String
,
Object
?
>
bundle
,
String
resourceId
,
bool
isResourceAttributeRequired
,
)
{
final
Map
<
String
,
dynamic
>
resourceAttributes
=
_attributes
(
bundle
,
resourceId
,
isResourceAttributeRequired
);
final
Map
<
String
,
Object
?>?
resourceAttributes
=
_attributes
(
bundle
,
resourceId
,
isResourceAttributeRequired
);
if
(
resourceAttributes
==
null
)
{
return
null
;
}
final
dynamic
value
=
resourceAttributes
[
'description'
];
final
Object
?
value
=
resourceAttributes
[
'description'
];
if
(
value
==
null
)
{
return
null
;
}
...
...
@@ -366,27 +366,27 @@ class Message {
}
static
List
<
Placeholder
>
_placeholders
(
Map
<
String
,
dynamic
>
bundle
,
Map
<
String
,
Object
?
>
bundle
,
String
resourceId
,
bool
isResourceAttributeRequired
,
)
{
final
Map
<
String
,
dynamic
>
resourceAttributes
=
_attributes
(
bundle
,
resourceId
,
isResourceAttributeRequired
);
final
Map
<
String
,
Object
?>?
resourceAttributes
=
_attributes
(
bundle
,
resourceId
,
isResourceAttributeRequired
);
if
(
resourceAttributes
==
null
)
{
return
<
Placeholder
>[];
}
final
dynamic
allPlaceholdersMap
=
resourceAttributes
[
'placeholders'
];
final
Object
?
allPlaceholdersMap
=
resourceAttributes
[
'placeholders'
];
if
(
allPlaceholdersMap
==
null
)
{
return
<
Placeholder
>[];
}
if
(
allPlaceholdersMap
is
!
Map
<
String
,
dynamic
>)
{
if
(
allPlaceholdersMap
is
!
Map
<
String
,
Object
?
>)
{
throw
L10nException
(
'The "placeholders" attribute for message
$resourceId
, is not '
'properly formatted. Ensure that it is a map with string valued keys.'
);
}
return
allPlaceholdersMap
.
keys
.
map
<
Placeholder
>((
String
placeholderName
)
{
final
dynamic
value
=
allPlaceholdersMap
[
placeholderName
];
if
(
value
is
!
Map
<
String
,
dynamic
>)
{
final
Object
?
value
=
allPlaceholdersMap
[
placeholderName
];
if
(
value
is
!
Map
<
String
,
Object
?
>)
{
throw
L10nException
(
'The value of the "
$placeholderName
" placeholder attribute for message '
'"
$resourceId
", is not properly formatted. Ensure that it is a map '
...
...
@@ -403,9 +403,9 @@ class AppResourceBundle {
factory
AppResourceBundle
(
File
file
)
{
assert
(
file
!=
null
);
// Assuming that the caller has verified that the file exists and is readable.
Map
<
String
,
dynamic
>
resources
;
Map
<
String
,
Object
?
>
resources
;
try
{
resources
=
json
.
decode
(
file
.
readAsStringSync
())
as
Map
<
String
,
dynamic
>;
resources
=
json
.
decode
(
file
.
readAsStringSync
())
as
Map
<
String
,
Object
?
>;
}
on
FormatException
catch
(
e
)
{
throw
L10nException
(
'The arb file
${file.path}
has the following formatting issue:
\n
'
...
...
@@ -413,7 +413,7 @@ class AppResourceBundle {
);
}
String
localeString
=
resources
[
'@@locale'
]
as
String
;
String
?
localeString
=
resources
[
'@@locale'
]
as
String
?
;
// Look for the first instance of an ISO 639-1 language code, matching exactly.
final
String
fileName
=
file
.
fileSystem
.
path
.
basenameWithoutExtension
(
file
.
path
);
...
...
@@ -470,10 +470,10 @@ class AppResourceBundle {
final
File
file
;
final
LocaleInfo
locale
;
final
Map
<
String
,
dynamic
>
resources
;
final
Map
<
String
,
Object
?
>
resources
;
final
Iterable
<
String
>
resourceIds
;
String
translationFor
(
Message
message
)
=>
resources
[
message
.
resourceId
]
as
String
;
String
?
translationFor
(
Message
message
)
=>
resources
[
message
.
resourceId
]
as
String
?
;
@override
String
toString
()
{
...
...
packages/flutter_tools/test/general.shard/generate_localizations_test.dart
View file @
728a1933
...
...
@@ -98,75 +98,12 @@ void main() {
);
});
testWithoutContext
(
'set
InputDirectory fails if input string is null
'
,
()
{
testWithoutContext
(
'set
ting className fails if input string is empty
'
,
()
{
_standardFlutterDirectoryL10nSetup
(
fs
);
try
{
LocalizationsGenerator
.
inputDirectoryFromPath
(
fs
,
null
,
fs
.
directory
(
'bogus'
)
);
LocalizationsGenerator
.
classNameFromString
(
''
);
}
on
L10nException
catch
(
e
)
{
expect
(
e
.
message
,
contains
(
'cannot be null'
));
return
;
}
fail
(
'LocalizationsGenerator.setInputDirectory should fail if the '
'input string is null.'
);
});
testWithoutContext
(
'setOutputDirectory fails if output string is null while not using the '
'synthetic package option'
,
()
{
_standardFlutterDirectoryL10nSetup
(
fs
);
try
{
LocalizationsGenerator
.
outputDirectoryFromPath
(
fs
,
null
,
false
,
null
);
}
on
L10nException
catch
(
e
)
{
expect
(
e
.
message
,
contains
(
'cannot be null'
));
return
;
}
fail
(
'LocalizationsGenerator.setOutputDirectory should fail if the '
'input string is null.'
);
},
);
testWithoutContext
(
'setTemplateArbFile fails if inputDirectory is null'
,
()
{
try
{
LocalizationsGenerator
.
templateArbFileFromFileName
(
defaultTemplateArbFileName
,
null
);
}
on
L10nException
catch
(
e
)
{
expect
(
e
.
message
,
contains
(
'cannot be null'
));
return
;
}
fail
(
'LocalizationsGenerator.setTemplateArbFile should fail if the '
'inputDirectory is not specified.'
);
});
testWithoutContext
(
'setTemplateArbFile fails if templateArbFileName is null'
,
()
{
_standardFlutterDirectoryL10nSetup
(
fs
);
try
{
LocalizationsGenerator
.
templateArbFileFromFileName
(
null
,
fs
.
directory
(
'bogus'
));
}
on
L10nException
catch
(
e
)
{
expect
(
e
.
message
,
contains
(
'cannot be null'
));
return
;
}
fail
(
'LocalizationsGenerator.setTemplateArbFile should fail if the '
'templateArbFileName passed in is null.'
);
});
testWithoutContext
(
'setting className fails if input string is null'
,
()
{
_standardFlutterDirectoryL10nSetup
(
fs
);
try
{
LocalizationsGenerator
.
classNameFromString
(
null
);
}
on
L10nException
catch
(
e
)
{
expect
(
e
.
message
,
contains
(
'cannot be null'
));
expect
(
e
.
message
,
contains
(
'cannot be empty'
));
return
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment