Add locale-sensitive casing (#880)

* Add locale-sensitive casing

* Add changelog

* Add default_components to built libs

* Use casemap key instead

* Trigger on labeling
diff --git a/.github/workflows/intl4x.yml b/.github/workflows/intl4x.yml
index d8c34d4..e29594d 100644
--- a/.github/workflows/intl4x.yml
+++ b/.github/workflows/intl4x.yml
@@ -6,6 +6,7 @@
 on:
   pull_request:
     branches: [main]
+    types: [opened, synchronize, reopened, labeled, unlabeled]
     paths:
       - ".github/workflows/intl4x.yml"
       - "pkgs/intl4x/**"
@@ -293,21 +294,21 @@
         run: |
           rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
 
-          dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_x64 --os linux --architecture x64 --compile_type dynamic --cargo_features collator,datetime,list,decimal,plurals,experimental,compiled_data
+          dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_x64 --os linux --architecture x64 --compile_type dynamic --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental,compiled_data
 
       - name: Build Mac
         if: matrix.os == 'macos-latest'
         run: |
           rustup component add rust-src --toolchain nightly-aarch64-apple-darwin
 
-          dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/macos_arm64 --os macos --architecture arm64 --compile_type dynamic --cargo_features collator,datetime,list,decimal,plurals,experimental,compiled_data
+          dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/macos_arm64 --os macos --architecture arm64 --compile_type dynamic --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental,compiled_data
 
       - name: Build Windows
         if: matrix.os == 'windows-latest'
         run: |
           rustup component add rust-src --toolchain nightly-x86_64-pc-windows-msvc
 
-          dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_x64 --os windows --architecture x64 --compile_type dynamic --cargo_features collator,datetime,list,decimal,plurals,experimental,compiled_data
+          dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_x64 --os windows --architecture x64 --compile_type dynamic --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental,compiled_data
 
       - name: Run `dart pub get`
         run: |
diff --git a/.github/workflows/intl4x_artifacts.yml b/.github/workflows/intl4x_artifacts.yml
index 8e7d610..9947c7e 100644
--- a/.github/workflows/intl4x_artifacts.yml
+++ b/.github/workflows/intl4x_artifacts.yml
@@ -73,14 +73,14 @@
         
         mkdir submodules/icu4x/bin
         
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_arm_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture arm --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_ia32_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture ia32 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_arm_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture arm --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_riscv64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture riscv64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_arm_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture arm --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_ia32_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture ia32 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/android_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os android --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_arm_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture arm --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_riscv64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture riscv64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/linux_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os linux --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
 
     - name: Build Linux data
       if: matrix.os == 'ubuntu-latest' && matrix.compiletype == 'static' && matrix.include_data == false
@@ -111,10 +111,10 @@
 
         mkdir submodules/icu4x/bin
         
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/ios_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os ios --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/ios_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os ios --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/macos_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os macos --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/macos_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os macos --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/ios_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os ios --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/ios_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os ios --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/macos_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os macos --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/macos_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os macos --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
 
     - name: Build Mac data
       if: matrix.os == 'macos-latest' && matrix.compiletype == 'static' && matrix.include_data == false
@@ -140,9 +140,9 @@
         
         mkdir submodules/icu4x/bin
         
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os windows --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_ia32_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os windows --architecture ia32 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
-        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os windows --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_arm64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os windows --architecture arm64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_ia32_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os windows --architecture ia32 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
+        dart pkgs/intl4x/lib/src/hook_helpers/build_libs.g.dart --working_directory submodules/icu4x --file submodules/icu4x/bin/windows_x64_${{ matrix.compiletype }}${{ env.FILENAME_SUFFIX }} --os windows --architecture x64 --compile_type ${{ matrix.compiletype }} --cargo_features collator,datetime,list,decimal,plurals,casemap,experimental${{ env.DATA }}
 
     - name: Build Windows data
       if: matrix.os == 'windows-latest' && matrix.compiletype == 'static' && matrix.include_data == false
diff --git a/pkgs/intl4x/CHANGELOG.md b/pkgs/intl4x/CHANGELOG.md
index 6ab96d2..6065f6b 100644
--- a/pkgs/intl4x/CHANGELOG.md
+++ b/pkgs/intl4x/CHANGELOG.md
@@ -1,7 +1,11 @@
+## 0.12.2-wip
+
+- Add lower- and uppercasing.
+
 ## 0.12.1
 
 - Use new artifacts from `intl4x-icu-v.0.12.0-artifacts`.
- 
+
 ## 0.12.0
 
 - Update to ICU4X 2.0.
diff --git a/pkgs/intl4x/hook/build.dart b/pkgs/intl4x/hook/build.dart
index 08b1a41..b137cad 100644
--- a/pkgs/intl4x/hook/build.dart
+++ b/pkgs/intl4x/hook/build.dart
@@ -215,7 +215,7 @@
         'plurals',
         'buffer_provider',
         'experimental',
-        'default_components',
+        'casemap',
         'compiled_data',
       ],
     );
diff --git a/pkgs/intl4x/lib/case_mapping.dart b/pkgs/intl4x/lib/case_mapping.dart
new file mode 100644
index 0000000..9853c6b
--- /dev/null
+++ b/pkgs/intl4x/lib/case_mapping.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'intl4x.dart';
+
+export 'src/case_mapping/case_mapping.dart';
+export 'src/locale/locale.dart';
+
+extension CaseMappingWithIntl4X on String {
+  String toLocaleLowerCase(Locale locale) =>
+      Intl(locale: locale).caseMapping.toLowerCase(this);
+  String toLocaleUpperCase(Locale locale) =>
+      Intl(locale: locale).caseMapping.toUpperCase(this);
+}
diff --git a/pkgs/intl4x/lib/intl4x.dart b/pkgs/intl4x/lib/intl4x.dart
index 106c83d..c3e9058 100644
--- a/pkgs/intl4x/lib/intl4x.dart
+++ b/pkgs/intl4x/lib/intl4x.dart
@@ -2,9 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'case_mapping.dart';
 import 'collation.dart';
 import 'display_names.dart';
 import 'number_format.dart';
+import 'src/case_mapping/case_mapping_impl.dart';
 import 'src/collation/collation.dart';
 import 'src/collation/collation_impl.dart';
 import 'src/datetime_format/datetime_format.dart';
@@ -18,7 +20,6 @@
 import 'src/list_format/list_format.dart';
 import 'src/list_format/list_format_impl.dart';
 import 'src/list_format/list_format_options.dart';
-import 'src/locale/locale.dart';
 import 'src/number_format/number_format.dart';
 import 'src/number_format/number_format_impl.dart';
 import 'src/plural_rules/plural_rules.dart';
@@ -88,6 +89,9 @@
     ),
   );
 
+  CaseMapping get caseMapping =>
+      CaseMapping(CaseMappingImpl.build(locale, localeMatcher, ecmaPolicy));
+
   /// Construct an [Intl] instance providing the current [locale] and the
   /// [ecmaPolicy] defining which locales should fall back to the browser
   /// provided functions.
diff --git a/pkgs/intl4x/lib/src/case_mapping/case_mapping.dart b/pkgs/intl4x/lib/src/case_mapping/case_mapping.dart
new file mode 100644
index 0000000..3f818fc
--- /dev/null
+++ b/pkgs/intl4x/lib/src/case_mapping/case_mapping.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../test_checker.dart';
+import 'case_mapping_impl.dart';
+
+/// A locale-sensitive case mapper for transforming strings.
+///
+/// This class provides methods to convert strings to lowercase or uppercase
+/// based on the current locale. During testing, the input is returned
+/// unchanged.
+class CaseMapping {
+  final CaseMappingImpl _caseMappingImpl;
+
+  const CaseMapping(this._caseMappingImpl);
+
+  String toLowerCase(String input) {
+    if (isInTest) {
+      return input;
+    } else {
+      return _caseMappingImpl.toLowerCase(input);
+    }
+  }
+
+  String toUpperCase(String input) {
+    if (isInTest) {
+      return input;
+    } else {
+      return _caseMappingImpl.toUpperCase(input);
+    }
+  }
+}
diff --git a/pkgs/intl4x/lib/src/case_mapping/case_mapping_4x.dart b/pkgs/intl4x/lib/src/case_mapping/case_mapping_4x.dart
new file mode 100644
index 0000000..fc17a56
--- /dev/null
+++ b/pkgs/intl4x/lib/src/case_mapping/case_mapping_4x.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../bindings/lib.g.dart' as icu;
+import '../locale/locale.dart';
+import '../locale/locale_4x.dart';
+import 'case_mapping_impl.dart';
+
+CaseMappingImpl getCaseMapping4X(Locale locale, Null _) =>
+    CaseMapping4X(locale as Locale4x);
+
+class CaseMapping4X extends CaseMappingImpl {
+  final icu.CaseMapper _caseMapper;
+  final Locale4x _locale;
+
+  CaseMapping4X(this._locale) : _caseMapper = icu.CaseMapper(), super(_locale);
+
+  @override
+  String toLowerCase(String input) =>
+      _caseMapper.lowercase(input, _locale.get4X);
+
+  @override
+  String toUpperCase(String input) =>
+      _caseMapper.uppercase(input, _locale.get4X);
+}
diff --git a/pkgs/intl4x/lib/src/case_mapping/case_mapping_ecma.dart b/pkgs/intl4x/lib/src/case_mapping/case_mapping_ecma.dart
new file mode 100644
index 0000000..75c1516
--- /dev/null
+++ b/pkgs/intl4x/lib/src/case_mapping/case_mapping_ecma.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:js_interop';
+
+import '../locale/locale.dart';
+import '../options.dart';
+import 'case_mapping_impl.dart';
+
+CaseMappingImpl? getCaseMappingECMA(Locale locale, Null _, LocaleMatcher _) =>
+    _CaseMappingECMA.tryToBuild(locale);
+
+extension on JSString {
+  @JS('String.toLocaleUpperCase')
+  external String toLocaleUpperCase(String locale);
+  @JS('String.toLocaleLowerCase')
+  external String toLocaleLowerCase(String locale);
+}
+
+class _CaseMappingECMA extends CaseMappingImpl {
+  _CaseMappingECMA(super.locale);
+
+  static CaseMappingImpl? tryToBuild(Locale locale) => _CaseMappingECMA(locale);
+  @override
+  String toUpperCase(String input) =>
+      input.toJS.toLocaleUpperCase(locale.toLanguageTag());
+
+  @override
+  String toLowerCase(String input) =>
+      input.toJS.toLocaleLowerCase(locale.toLanguageTag());
+}
diff --git a/pkgs/intl4x/lib/src/case_mapping/case_mapping_impl.dart b/pkgs/intl4x/lib/src/case_mapping/case_mapping_impl.dart
new file mode 100644
index 0000000..e62ea81
--- /dev/null
+++ b/pkgs/intl4x/lib/src/case_mapping/case_mapping_impl.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../ecma_policy.dart';
+import '../ecma/ecma_policy.dart';
+import '../locale/locale.dart';
+import '../options.dart';
+import '../utils.dart';
+import 'case_mapping_stub.dart' if (dart.library.js) 'case_mapping_ecma.dart';
+import 'case_mapping_stub_4x.dart' if (dart.library.io) 'case_mapping_4x.dart';
+
+abstract class CaseMappingImpl {
+  final Locale locale;
+
+  CaseMappingImpl(this.locale);
+
+  String toLowerCase(String input);
+  String toUpperCase(String input);
+
+  static CaseMappingImpl build(
+    Locale locales,
+    LocaleMatcher localeMatcher,
+    EcmaPolicy ecmaPolicy,
+  ) => buildFormatter(
+    locales,
+    null,
+    localeMatcher,
+    ecmaPolicy,
+    getCaseMappingECMA,
+    getCaseMapping4X,
+  );
+}
diff --git a/pkgs/intl4x/lib/src/case_mapping/case_mapping_stub.dart b/pkgs/intl4x/lib/src/case_mapping/case_mapping_stub.dart
new file mode 100644
index 0000000..ac7a883
--- /dev/null
+++ b/pkgs/intl4x/lib/src/case_mapping/case_mapping_stub.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../locale/locale.dart';
+import '../options.dart';
+import 'case_mapping_impl.dart';
+
+CaseMappingImpl? getCaseMappingECMA(Locale locale, Null _, LocaleMatcher _) =>
+    throw UnimplementedError('Cannot use ECMA outside of web environments.');
diff --git a/pkgs/intl4x/lib/src/case_mapping/case_mapping_stub_4x.dart b/pkgs/intl4x/lib/src/case_mapping/case_mapping_stub_4x.dart
new file mode 100644
index 0000000..38d5f42
--- /dev/null
+++ b/pkgs/intl4x/lib/src/case_mapping/case_mapping_stub_4x.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2023, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../locale/locale.dart';
+import 'case_mapping_impl.dart';
+
+CaseMappingImpl getCaseMapping4X(Locale locale, Null _) =>
+    throw UnimplementedError('Cannot use ICU4X in web environments.');
diff --git a/pkgs/intl4x/pubspec.yaml b/pkgs/intl4x/pubspec.yaml
index 7f314c1..aa2c39f 100644
--- a/pkgs/intl4x/pubspec.yaml
+++ b/pkgs/intl4x/pubspec.yaml
@@ -1,7 +1,7 @@
 name: intl4x
 description: >-
   A lightweight modular library for internationalization (i18n) functionality.
-version: 0.12.1
+version: 0.12.2-wip
 repository: https://github.com/dart-lang/i18n/tree/main/pkgs/intl4x
 issue_tracker: https://github.com/dart-lang/i18n/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aintl4x
 
diff --git a/pkgs/intl4x/test/case_mapping_test.dart b/pkgs/intl4x/test/case_mapping_test.dart
new file mode 100644
index 0000000..1dc6c41
--- /dev/null
+++ b/pkgs/intl4x/test/case_mapping_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:intl4x/case_mapping.dart';
+import 'package:test/test.dart';
+
+import 'utils.dart';
+
+void main() {
+  testWithFormatting('test name', () {
+    final enUS = Locale.parse('en-US');
+    final trTR = Locale.parse('tr-TR');
+    final ltLT = Locale.parse('lt-LT');
+
+    expect('İstanbul'.toLocaleLowerCase(enUS), 'i̇stanbul');
+    expect('İstanbul'.toLocaleLowerCase(trTR), 'istanbul');
+    expect('ALPHABET'.toLocaleLowerCase(enUS), 'alphabet');
+
+    expect('\u0130'.toLocaleLowerCase(Locale.parse('tr')), 'i');
+    expect('\u0130'.toLocaleLowerCase(enUS), isNot('i'));
+
+    final locales = [
+      'tr',
+      'TR',
+      'tr-TR',
+      'tr-u-co-search',
+      'tr-x-turkish',
+    ].map(Locale.parse);
+    for (final locale in locales) {
+      expect('\u0130'.toLocaleLowerCase(locale), 'i');
+    }
+
+    // --- Lithuanian Testing ---
+    // Here, 'I' should lowercase to 'i' and 'i' should uppercase to 'I'.
+    // The dotless 'i' (U+0131) and dotted 'I' (U+0130) are not typically used
+    // in standard Lithuanian orthography in the same way as Turkish.
+    // So, we expect standard Unicode casing behavior.
+
+    expect('Lietuva'.toLocaleLowerCase(ltLT), 'lietuva');
+    expect('lietuva'.toLocaleUpperCase(ltLT), 'LIETUVA');
+
+    // Test a common character that might have locale-specific casing rules
+    // in other languages but should be standard in Lithuanian.
+    expect('Ė'.toLocaleLowerCase(ltLT), 'ė'); // Ė (U+0116) to ė (U+0117)
+    expect('ė'.toLocaleUpperCase(ltLT), 'Ė');
+
+    // Ensure that Turkish-specific behavior does NOT apply to Lithuanian
+    expect(
+      '\u0130'.toLocaleLowerCase(ltLT),
+      '\u0130'.toLocaleLowerCase(enUS),
+    ); // Dotted I should behave like in English
+    expect('I'.toLocaleLowerCase(ltLT), 'i'); // Regular I to i
+    expect('i'.toLocaleUpperCase(ltLT), 'I'); // Regular i to I
+  });
+}