Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ flutter:
- assets/translations/
```



### 🔌 Loading translations from other resources

You can use JSON,CSV,HTTP,XML,Yaml files, etc.
Expand Down Expand Up @@ -407,6 +409,36 @@ Output:
print('example.emptyNameError'.tr()); //Output: Please fill in your full name
```

### 🔥 Linked files:

> ⚠ This is only available for the default asset loader (on Json Files).

You can split translations for a single locale into multiple files by using linked files. This helps keep your JSON clean and maintainable.

To link an external file, set the key’s value to a path prefixed with `:/`, relative to your translations directory. For example, with default path `assets/translations` and locale `en-US`:

```json
{
"errors": ":/errors.json",
"validation": ":/validation.json",
"notifications": ":/notifications.json"
}
```

At runtime, Easy Localization will load:
```
assets
└── translations
└── en-US
├── errors.json
├── validation.json
└── notifications.json
```

Each linked file must contain a valid JSON object of translation keys.

Don't forget to add your linked files (or linked files folder, here assets/translations/en-US/), to your pubspec.yaml : [See installation](#-installation).

### 🔥 Reset locale `resetLocale()`

Reset locale to device locale
Expand Down
37 changes: 36 additions & 1 deletion lib/src/asset_loader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,45 @@ class RootBundleAssetLoader extends AssetLoader {
return '$basePath/${locale.toStringWithSeparator(separator: "-")}.json';
}

String _getLinkedLocalePath(String basePath, String filePath, Locale locale) {
return '$basePath/${locale.toStringWithSeparator(separator: "-")}/$filePath';
}

Future<Map<String, dynamic>> _getLinkedTranslationFileDataFromBaseJson(
String basePath, Locale locale, Map<String, dynamic> baseJson,
{List<String> fileLoaded = const []}) async {
Map<String, dynamic> fullJson = Map<String, dynamic>.from(baseJson);

for (var entry in baseJson.entries) {
var key = entry.key;
var value = entry.value;

if (value is String && value.startsWith(':/')) {
String filePath = value.substring(2);

if (fileLoaded.contains(filePath)) {
throw Exception('Circular reference detected: $filePath is loaded multiple times');
}

fileLoaded.add(filePath);
value = json.decode(await rootBundle.loadString(_getLinkedLocalePath(basePath, filePath, locale)));
}

if (value is Map<String, dynamic>) {
fullJson[key] =
await _getLinkedTranslationFileDataFromBaseJson(basePath, locale, value, fileLoaded: fileLoaded);
}
}

return fullJson;
}

@override
Future<Map<String, dynamic>?> load(String path, Locale locale) async {
var localePath = getLocalePath(path, locale);
EasyLocalization.logger.debug('Load asset from $path');
return json.decode(await rootBundle.loadString(localePath));

Map<String, dynamic> baseJson = json.decode(await rootBundle.loadString(localePath));
return await _getLinkedTranslationFileDataFromBaseJson(path, locale, baseJson);
}
}
38 changes: 9 additions & 29 deletions test/easy_localization_context_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ void main() async {
saveLocale: false,
useOnlyLangCode: true,
// fallbackLocale:Locale('en') ,
supportedLocales: const [
Locale('ar')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('ar')], // Locale('en', 'US'), Locale('ar','DZ')
child: const MyApp(),
));
// await tester.idle();
Expand Down Expand Up @@ -117,10 +115,7 @@ void main() async {
await tester.pumpWidget(EasyLocalization(
path: '../../i18n',
// fallbackLocale:Locale('en') ,
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ')
child: const MyApp(),
));
// await tester.idle();
Expand All @@ -140,13 +135,10 @@ void main() async {
await tester.pumpWidget(EasyLocalization(
path: '../../i18n',
// fallbackLocale:Locale('en') ,
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ')
child: const MyApp(),
));
// await tester.idle();
await tester.idle();
// The async delegator load will require build on the next frame. Thus, pump
await tester.pump();

Expand All @@ -161,13 +153,10 @@ void main() async {
await tester.runAsync(() async {
await tester.pumpWidget(EasyLocalization(
path: '../../i18n',
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ')
child: const MyApp(),
));
// await tester.idle();
await tester.idle();
// The async delegator load will require build on the next frame. Thus, pump
await tester.pump();

Expand All @@ -182,10 +171,7 @@ void main() async {
await tester.runAsync(() async {
await tester.pumpWidget(EasyLocalization(
path: '../../i18n',
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ')
startLocale: const Locale('ar', 'DZ'),
child: const MyApp(),
));
Expand All @@ -208,10 +194,7 @@ void main() async {
await tester.runAsync(() async {
await tester.pumpWidget(EasyLocalization(
path: '../../i18n',
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ')
child: const MyApp(),
));
await tester.idle();
Expand All @@ -229,10 +212,7 @@ void main() async {
await tester.runAsync(() async {
await tester.pumpWidget(EasyLocalization(
path: '../../i18n',
supportedLocales: const [
Locale('en', 'US'),
Locale('ar', 'DZ')
], // Locale('en', 'US'), Locale('ar','DZ')
supportedLocales: const [Locale('en', 'US'), Locale('ar', 'DZ')], // Locale('en', 'US'), Locale('ar','DZ')
startLocale: const Locale('ar', 'DZ'),
child: const MyApp(),
));
Expand Down
Loading