From 04b9b3a1ab0f9107c049e4ac7fa02f0977b3826b Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 14:14:49 +0200 Subject: [PATCH 01/10] chore: update dependencies --- CHANGELOG.md | 20 ++++++++++++++++++++ README.md | 23 +++++++++-------------- example/lib/main.dart | 4 ++-- example/pubspec.lock | 34 +++++++++++++++++----------------- lib/src/gen/l10n_config.dart | 12 ++++++++++-- pubspec.yaml | 4 ++-- 6 files changed, 60 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39ba272..a7c337c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## 0.8.2 + +### Breaking Changes + +- Default `synthetic-package` changed from `true` to `false` to align with Flutter 3.32+ deprecation +- Import paths changed from `package:flutter_gen/gen_l10n/...` to direct source imports + +### Migration + +1. Add `synthetic-package: false` to your `l10n.yaml` (or rely on new default) +2. Update imports: + ```dart + // Before + import 'package:flutter_gen/gen_l10n/crowdin_localizations.dart'; + + // After + import 'package:your_app/l10n/crowdin_localizations.dart'; + ``` +3. Run `flutter pub run crowdin_sdk:gen` to regenerate + ## 0.8.1 - fix: add undeclared placeholders to the placeholders list diff --git a/README.md b/README.md index 368baf4..b4dbc51 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ To manage distributions, open the Crowdin project and go to the *Translations* > ```yml dependencies: - crowdin_sdk: ^0.8.1 + crowdin_sdk: ^0.8.2 flutter_localizations: sdk: flutter @@ -103,16 +103,16 @@ To manage distributions, open the Crowdin project and go to the *Translations* > flutter pub run crowdin_sdk:gen ``` - This generates `crowdin_localizations.dart` in the `{FLUTTER_PROJECT}/.dart_tool/flutter_gen/gen_l10n` directory. This wrapper class extends Flutter's generated localization classes to integrate Crowdin OTA translations. - + This generates `crowdin_localizations.dart` in the same directory as your `app_localizations.dart` (by default, in your `arb-dir` directory, e.g., `lib/l10n/`). This wrapper class extends Flutter's generated localization classes to integrate Crowdin OTA translations. + > **Important:** Re-run this command whenever you modify the structure of your ARB files (e.g., add/remove keys or change parameters). - Update localizationsDelegates in your project: ```dart - import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + import 'package:your_app/l10n/app_localizations.dart'; import 'package:crowdin_sdk/crowdin_sdk.dart'; - import 'package:flutter_gen/gen_l10n/crowdin_localizations.dart'; + import 'package:your_app/l10n/crowdin_localizations.dart'; ``` ```dart @@ -341,15 +341,10 @@ For more information about OAuth authorization in Crowdin, please check [this ar - Swedish - `sv`: `sv-SE` - Urdu (India) - `ur`: `ur-IN` -- Since flutter tool no longer generate a synthetic package:flutter_gen, please follow 1st way from [Migration Guide](https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source#migration-guide): - - Specify synthetic-package: false in the accompanying [l10n.yaml](https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization#configuring-the-l10n-yaml-file) file: - `synthetic-package: false` - - - The files are generated into the path specified by arb-dir - `arb-dir: lib/i18n` - - - Or, specifically provide an output path: - `output-dir: lib/src/generated/i18n` +- **synthetic-package default**: Starting from v0.8.2, the SDK defaults to `synthetic-package: false` to align with Flutter 3.32+ deprecation of the synthetic `flutter_gen` package. If you're upgrading from an earlier version, see the [Migration Guide](https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source#migration-guide): + - Add `synthetic-package: false` to your `l10n.yaml` (or rely on the new default) + - Update imports from `package:flutter_gen/gen_l10n/...` to your local path (e.g., `package:your_app/l10n/...`) + - Run `flutter pub run crowdin_sdk:gen` to regenerate ## Contributing diff --git a/example/lib/main.dart b/example/lib/main.dart index 51e5d2f..e18b6d5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -2,8 +2,8 @@ import 'dart:convert'; import 'package:crowdin_sdk/crowdin_sdk.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:flutter_gen/gen_l10n/crowdin_localizations.dart'; +import 'l10n/app_localizations.dart'; +import 'l10n/crowdin_localizations.dart'; import 'package:intl/intl.dart'; diff --git a/example/pubspec.lock b/example/pubspec.lock index 269e8d7..a1dc3b4 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -132,10 +132,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -208,34 +208,34 @@ packages: dependency: "direct main" description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.2" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -264,10 +264,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" nm: dependency: transitive description: @@ -445,10 +445,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.7" typed_data: dependency: transitive description: @@ -525,10 +525,10 @@ packages: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: @@ -586,5 +586,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.7.0 <4.0.0" + dart: ">=3.8.0-0 <4.0.0" flutter: ">=3.27.0" diff --git a/lib/src/gen/l10n_config.dart b/lib/src/gen/l10n_config.dart index bae67e8..28721e7 100644 --- a/lib/src/gen/l10n_config.dart +++ b/lib/src/gen/l10n_config.dart @@ -18,7 +18,7 @@ class L10nConfig { required this.outputLocalizationFile, required this.outputDir, required this.outputClass, - this.syntheticPackage = true, + this.syntheticPackage = false, }); String get finalOutputDir => syntheticPackage @@ -41,7 +41,15 @@ class L10nConfig { String outputClass = yamlGenConfig['output-class'] ?? 'AppLocalizations'; - bool syntheticPackage = yamlGenConfig['synthetic-package'] ?? true; + bool syntheticPackage = yamlGenConfig['synthetic-package'] ?? false; + + if (syntheticPackage) { + print( + '⚠️ Warning: synthetic-package: true is deprecated in Flutter 3.32+.'); + print(' Consider setting synthetic-package: false in l10n.yaml'); + print( + ' See: https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source'); + } return L10nConfig( arbDir: arbDir, diff --git a/pubspec.yaml b/pubspec.yaml index bdae595..27d5a17 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,13 +14,13 @@ dependencies: http: '>=0.13.3 <2.0.0' intl: '>=0.17.0 <=0.20.2' shared_preferences: ^2.0.4 - connectivity_plus: '>=2.1.0 <7.0.0' + connectivity_plus: '>=2.1.0 <8.0.0' yaml: ^3.1.1 meta: ^1.7.0 path: ^1.8.1 oauth2: ^2.0.1 url_launcher: ^6.1.0 - app_links: '>=3.4.2 <7.0.0' + app_links: '>=3.4.2 <8.0.0' web_socket_channel: '>=2.2.0 <4.0.0' flutter_localizations: From 3409cff4f626517d12bcff3d1a144515fa4ea3dd Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 14:16:30 +0200 Subject: [PATCH 02/10] chore: static analysis --- lib/src/crowdin_request_limiter.dart | 4 ++-- test/crowdin_api_test.dart | 4 ++-- test/crowdin_request_limiter_test.dart | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/src/crowdin_request_limiter.dart b/lib/src/crowdin_request_limiter.dart index 95959e2..9eb27be 100644 --- a/lib/src/crowdin_request_limiter.dart +++ b/lib/src/crowdin_request_limiter.dart @@ -23,7 +23,7 @@ class CrowdinRequestLimiter { bool get pauseRequests => _stopPermanently || _pauseRequests || _checkIsPausedForToday(); - init(CrowdinStorage storage) { + void init(CrowdinStorage storage) async { _storage = storage; _stopPermanently = _storage.getIsPausedPermanently() ?? false; _errorMap = _storage.getErrorMap() ?? {}; @@ -59,7 +59,7 @@ class CrowdinRequestLimiter { _storage.setErrorMap(_cleanErrorMapFromUnusedDays()); } - reset() { + void reset() { if (!_stopPermanently) { _pauseRequests = false; _errorMap = {}; diff --git a/test/crowdin_api_test.dart b/test/crowdin_api_test.dart index 4c330bb..e2b7b97 100644 --- a/test/crowdin_api_test.dart +++ b/test/crowdin_api_test.dart @@ -101,7 +101,7 @@ void main() { test('getManifest returns null and increment error count on 400 status', () async { - await requestLimiter.init(storage); + requestLimiter.init(storage); final uri = Uri.parse('https://distributions.crowdin.net/hash/manifest.json'); @@ -119,7 +119,7 @@ void main() { 'getManifest returns null and do not call request when requests paused', () async { storage.setIsPausedPermanently(true); - await requestLimiter.init(storage); + requestLimiter.init(storage); final uri = Uri.parse('https://distributions.crowdin.net/hash/manifest.json'); diff --git a/test/crowdin_request_limiter_test.dart b/test/crowdin_request_limiter_test.dart index 8279f89..6f94785 100644 --- a/test/crowdin_request_limiter_test.dart +++ b/test/crowdin_request_limiter_test.dart @@ -34,7 +34,7 @@ void main() { test('should initialize with storage values', () async { storage.setIsPausedPermanently(true); - await requestLimiter.init(storage); + requestLimiter.init(storage); expect(storage.getIsPausedPermanently(), true); expect(requestLimiter.pauseRequests, true); }); @@ -49,13 +49,13 @@ void main() { test('should pause requests after max errors in a day', () async { storage.setErrorMap({getTodayDateString(): 10}); - await requestLimiter.init(storage); + requestLimiter.init(storage); expect(requestLimiter.pauseRequests, true); }); test('should reset error map and pause state', () async { storage.setErrorMap({getTodayDateString(): 10}); - await requestLimiter.init(storage); + requestLimiter.init(storage); expect(requestLimiter.pauseRequests, true); requestLimiter.reset(); expect(requestLimiter.pauseRequests, false); @@ -67,7 +67,7 @@ void main() { _formatter.format(DateTime.now().subtract(const Duration(days: 1))): 10, _formatter.format(DateTime.now().subtract(const Duration(days: 2))): 10, }); - await requestLimiter.init(storage); + requestLimiter.init(storage); requestLimiter.incrementErrorCounter(); expect(requestLimiter.pauseRequests, true); }); From b922f4c558092ebdab80057c6b025f20e0ff355e Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 14:16:59 +0200 Subject: [PATCH 03/10] fix real time preview --- lib/src/real_time_preview/crowdin_preview_manager.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/src/real_time_preview/crowdin_preview_manager.dart b/lib/src/real_time_preview/crowdin_preview_manager.dart index a531361..483ac0c 100644 --- a/lib/src/real_time_preview/crowdin_preview_manager.dart +++ b/lib/src/real_time_preview/crowdin_preview_manager.dart @@ -145,12 +145,11 @@ class CrowdinPreviewManager { 'Something went wrong when subscribing to translations for real-time preview. Metadata is not provided'); } else { _CrowdinMetadata metadata = _metadata!; - final webSocketTicketEvent = - 'update-draft:${metadata.wsHash}:${metadata.projectId}:${metadata.userId}'; - final ticket = await _getWebsocketTicket( - credentials: _credentials, event: webSocketTicketEvent); for (var id in finalMapping.values) { - final String event = '$webSocketTicketEvent:$langCode:$id'; + final String event = + 'update-draft:${metadata.wsHash}:${metadata.projectId}:${metadata.userId}:$langCode:$id'; + final ticket = + await _getWebsocketTicket(credentials: _credentials, event: event); if (ticket != null) { var data = jsonEncode({ 'action': 'subscribe', From 27e464e77fab32ced9261a6ca107f98055f80037 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 14:30:32 +0200 Subject: [PATCH 04/10] remove unnecessary messages --- lib/src/gen/l10n_config.dart | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/src/gen/l10n_config.dart b/lib/src/gen/l10n_config.dart index 28721e7..1c8d36f 100644 --- a/lib/src/gen/l10n_config.dart +++ b/lib/src/gen/l10n_config.dart @@ -43,14 +43,6 @@ class L10nConfig { bool syntheticPackage = yamlGenConfig['synthetic-package'] ?? false; - if (syntheticPackage) { - print( - '⚠️ Warning: synthetic-package: true is deprecated in Flutter 3.32+.'); - print(' Consider setting synthetic-package: false in l10n.yaml'); - print( - ' See: https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source'); - } - return L10nConfig( arbDir: arbDir, templateArbFile: templateArbFile, From 6451e3efa4f3856c27430b57348458741b2ed236 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 14:54:42 +0200 Subject: [PATCH 05/10] chore: update flutter version in build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9709356..c9d89f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: branches: [ main ] env: - FLUTTER_VERSION: '3.29.3' + FLUTTER_VERSION: '3.38.7' jobs: test: From 623c52861057afc1c96cf0a18b1a5f27ac7c247d Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 15:08:50 +0200 Subject: [PATCH 06/10] chore: update sdk version to 1.0.0 --- CHANGELOG.md | 4 +++- README.md | 6 +++--- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7c337c..d2c93f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,9 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## 0.8.2 +## 1.0.0 + +- First stable release ### Breaking Changes diff --git a/README.md b/README.md index b4dbc51..1d8b901 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

-# Crowdin Flutter SDK [](https://github.com/crowdin/flutter-sdk) +# Crowdin Flutter SDK The Crowdin Flutter SDK enables Over-The-Air (OTA) translation updates, delivering new translations from your Crowdin project directly to users without requiring app store updates. The SDK works on top of Flutter's standard localization system (`flutter_localizations`), providing a seamless bridge between your local ARB files and Crowdin's Content Delivery Network. @@ -87,7 +87,7 @@ To manage distributions, open the Crowdin project and go to the *Translations* > ```yml dependencies: - crowdin_sdk: ^0.8.2 + crowdin_sdk: ^1.0.0 flutter_localizations: sdk: flutter @@ -341,7 +341,7 @@ For more information about OAuth authorization in Crowdin, please check [this ar - Swedish - `sv`: `sv-SE` - Urdu (India) - `ur`: `ur-IN` -- **synthetic-package default**: Starting from v0.8.2, the SDK defaults to `synthetic-package: false` to align with Flutter 3.32+ deprecation of the synthetic `flutter_gen` package. If you're upgrading from an earlier version, see the [Migration Guide](https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source#migration-guide): +- **synthetic-package default**: Starting from v1.0.0, the SDK defaults to `synthetic-package: false` to align with Flutter 3.32+ deprecation of the synthetic `flutter_gen` package. If you're upgrading from an earlier version, see the [Migration Guide](https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source#migration-guide): - Add `synthetic-package: false` to your `l10n.yaml` (or rely on the new default) - Update imports from `package:flutter_gen/gen_l10n/...` to your local path (e.g., `package:your_app/l10n/...`) - Run `flutter pub run crowdin_sdk:gen` to regenerate diff --git a/pubspec.yaml b/pubspec.yaml index 27d5a17..72dd1a0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: crowdin_sdk description: Crowdin Flutter SDK for instant translation delivery Over-The-Air directly to your application -version: 0.8.1 +version: 1.0.0 repository: https://github.com/crowdin/flutter-sdk homepage: https://github.com/crowdin/flutter-sdk From 1d69a619ab77e83ab137c47f0e7f827733743446 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 15:35:52 +0200 Subject: [PATCH 07/10] chore: update Requirements --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d8b901..2b042ba 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,8 @@ This architecture ensures your app always has working translations (from local A ## Requirements -* Dart >=2.17.0 +* Flutter >=3.22.0 +* Dart >=3.4.0 ## Setup From cb92b080e731dedbcce23928aac23555ab5a0833 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 15:40:47 +0200 Subject: [PATCH 08/10] chore: update environment --- pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 72dd1a0..7e03f91 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,8 +5,8 @@ repository: https://github.com/crowdin/flutter-sdk homepage: https://github.com/crowdin/flutter-sdk environment: - sdk: '>=2.17.0 <4.0.0' - flutter: ">=1.17.0" + sdk: '>=3.4.0 <4.0.0' + flutter: ">=3.22.0" dependencies: flutter: From 471efa7eb2e23dcb896ccfd589fa3e5a9e9a2585 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 15:50:37 +0200 Subject: [PATCH 09/10] chore: remove bang operator unnecessary --- example/pubspec.lock | 2 +- lib/src/common/gen_l10n_types.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index a1dc3b4..6992b22 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -103,7 +103,7 @@ packages: path: ".." relative: true source: path - version: "0.8.1" + version: "1.0.0" crypto: dependency: transitive description: diff --git a/lib/src/common/gen_l10n_types.dart b/lib/src/common/gen_l10n_types.dart index cbddfe7..34b4b1c 100644 --- a/lib/src/common/gen_l10n_types.dart +++ b/lib/src/common/gen_l10n_types.dart @@ -459,7 +459,7 @@ class Message { static final RegExp _pluralRE = RegExp(r'\s*\{([\w\s,]*),\s*plural\s*,'); - bool get isPlural => _pluralMatch != null && _pluralMatch!.groupCount == 1; + bool get isPlural => _pluralMatch != null && _pluralMatch.groupCount == 1; Placeholder getCountPlaceholder() { assert(isPlural); From 0b925696cc8ca09c40465f72a49138c1fc841959 Mon Sep 17 00:00:00 2001 From: Yurii Date: Wed, 21 Jan 2026 16:10:49 +0200 Subject: [PATCH 10/10] chore: changelog update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c93f3..679dea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline ### Breaking Changes +- **Minimum requirements updated**: Dart SDK `>=3.4.0 <4.0.0`, Flutter `>=3.22.0` - Default `synthetic-package` changed from `true` to `false` to align with Flutter 3.32+ deprecation - Import paths changed from `package:flutter_gen/gen_l10n/...` to direct source imports