From 2c5e021f6d33bb5d3c091a4abf61ab5ccf15f93b Mon Sep 17 00:00:00 2001 From: Elango Cheran Date: Wed, 15 Jan 2025 20:40:57 +0000 Subject: [PATCH] ICU-22921 Add howto guide to try MF 2.0 final candidate draft impls See #3334 --- .../format_parse/messages/HelloMF2.zip | Bin 0 -> 4499 bytes .../format_parse/messages/hello_mf2.cpp | 37 ++ .../format_parse/messages/try-mf2.md | 366 ++++++++++++++++++ 3 files changed, 403 insertions(+) create mode 100644 docs/userguide/format_parse/messages/HelloMF2.zip create mode 100644 docs/userguide/format_parse/messages/hello_mf2.cpp create mode 100644 docs/userguide/format_parse/messages/try-mf2.md diff --git a/docs/userguide/format_parse/messages/HelloMF2.zip b/docs/userguide/format_parse/messages/HelloMF2.zip new file mode 100644 index 0000000000000000000000000000000000000000..999a9eed0b27e822abe2a3419430a5c11eb02c75 GIT binary patch literal 4499 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 + +#include "unicode/utypes.h" +#include "unicode/calendar.h" +#include "unicode/errorcode.h" +#include "unicode/locid.h" +#include "unicode/messageformat2.h" + +using namespace icu; + +int main() { + ErrorCode errorCode; + UParseError parseError; + + icu::Calendar* cal(Calendar::createInstance(errorCode)); + cal->set(2025, Calendar::JANUARY, 28); + UDate date = cal->getTime(errorCode); + + message2::MessageFormatter::Builder builder(errorCode); + message2::MessageFormatter mf = builder + .setPattern("Hello {$user}, today is {$now :date style=long}!", parseError, errorCode) + .setLocale(Locale("en_US")) + .build(errorCode); + + std::map argsBuilder; + argsBuilder["user"] = message2::Formattable("John"); + argsBuilder["now"] = message2::Formattable::forDate(date); + message2::MessageArguments arguments(argsBuilder, errorCode); + + icu::UnicodeString result = mf.formatToString(arguments, errorCode); + std::string strResult; + result.toUTF8String(strResult); + std::cout << strResult << std::endl; +} \ No newline at end of file diff --git a/docs/userguide/format_parse/messages/try-mf2.md b/docs/userguide/format_parse/messages/try-mf2.md new file mode 100644 index 00000000000..df99173c9f6 --- /dev/null +++ b/docs/userguide/format_parse/messages/try-mf2.md @@ -0,0 +1,366 @@ +--- +layout: default +title: Trying MF 2.0 Final Candidate +nav_order: 3 +parent: Formatting Messages +grand_parent: Formatting +--- + + +# Trying MF 2.0 Final Candidate +{: .no_toc } + +## Contents +{: .no_toc .text-delta } + +1. TOC +{:toc} + +--- + + + + + +## C++ Linux & macOS + + +1. Prepare a sandbox folder + + ```sh + export ICU_SANDBOX=~/hello_icu_mf2 + mkdir $ICU_SANDBOX + cd $ICU_SANDBOX + ``` + +1. Build ICU4C (you only need to do this once) + + ```sh + git clone https://github.com/unicode-org/icu.git + pushd icu/icu4c/source + + # Run this and choose the platform and toolchain you prefer + ./runConfigureICU --help + + # if macOS + ./runConfigureICU macOS/gcc + # else if Linux (gcc is just an example, there are 5 Linux options) + ./runConfigureICU Linux/gcc + # end + + export DESTDIR=$ICU_SANDBOX/icu_release + make -j8 releaseDist + popd + ``` + +1. Create a minimal C++ file here (we are in the `$ICU_SANDBOX` folder) called [`hello_mf2.cpp`](hello_mf2.cpp) (click to view and/or download). The contents are reproduced below. + + ```cpp + // hello_mf2.cpp + #include + + #include "unicode/utypes.h" + #include "unicode/calendar.h" + #include "unicode/errorcode.h" + #include "unicode/locid.h" + #include "unicode/messageformat2.h" + + using namespace icu; + + int main() { + ErrorCode errorCode; + UParseError parseError; + + icu::Calendar* cal(Calendar::createInstance(errorCode)); + cal->set(2025, Calendar::JANUARY, 28); + UDate date = cal->getTime(errorCode); + + message2::MessageFormatter::Builder builder(errorCode); + message2::MessageFormatter mf = builder + .setPattern("Hello {$user}, today is {$now :date style=long}!", parseError, errorCode) + .setLocale(Locale("en_US")) + .build(errorCode); + + std::map argsBuilder; + argsBuilder["user"] = message2::Formattable("John"); + argsBuilder["now"] = message2::Formattable::forDate(date); + message2::MessageArguments arguments(argsBuilder, errorCode); + + icu::UnicodeString result = mf.formatToString(arguments, errorCode); + std::string strResult; + result.toUTF8String(strResult); + std::cout << strResult << std::endl; + } + ``` + +1. Build your application and run it + + ```sh + g++ hello_mf2.cpp -I$DESTDIR/usr/local/include -std=c++17 -L$DESTDIR/usr/local/lib -licuuc -licudata -licui18n + + # if macOS + DYLD_LIBRARY_PATH=$DESTDIR/usr/local/lib ./a.out + # else if Linux + LD_LIBRARY_PATH=$DESTDIR/usr/local/lib ./a.out + # end + ``` + + This will output + ``` + Hello John, today is January 28, 2025! + ``` + +## C++ Windows with Visual Studio + +### From Visual Studio with minimal work + +These instructions will use a release version of ICU4C (tested with 76.1) and +a "Hello ICU world" project already created. +They provide minimal effort that only requires downloading and opening in Visual Studio +before using. + +> :point_right: **Note**: the MessageFormat 2 implementation in a previously release version may be behind the spec in the first few releases of ICU after the MF2.0 spec was declared 1.0 in CLDR 46.1, +which occurred between ICU 76 and ICU 77. The difference between latest MF2.0 and the spec version supported in ICU may be minimal. + + +1. Download the Visual Studio artifacts from the +[official release of ICU 76.1](https://github.com/unicode-org/icu/releases/tag/release-76-1): + * [icu4c-76_1-Win32-MSVC2022.zip](https://github.com/unicode-org/icu/releases/download/release-76-1/icu4c-76_1-Win32-MSVC2022.zip) + * [icu4c-76_1-Win64-MSVC2022.zip](https://github.com/unicode-org/icu/releases/download/release-76-1/icu4c-76_1-Win64-MSVC2022.zip) + +1. Download the "Hello ICU / MF2 World" project [HelloMF2.zip](HelloMF2.zip). + +1. Unzip the files you just downloaded and merge the content of the two ICU folders. +The "hello world" project to be a sibling to the icu folder. + +1. The folder tree structure should look like this + + ``` + someFolderOfYourChoice\ + +- HelloMF2\ + | \- HelloMF2\ + \- icu\ + \- icu4c\ + +- bin\ + +- bin64\ + +- include\ + | \- unicode\ + +- lib\ + \- lib64\ + ``` + +1. Open the `HelloMF2.sln` solution in Visual Studio and you are ready to go. + +### From command line + +Start the Visual Studio "x64 Native Tools Command Prompt for VS 20xx" + +1. Prepare a sandbox folder + + ```cmd + set ICU_SANDBOX=%USERPROFILE%\hello_icu_mf2 + md %ICU_SANDBOX% + cd %ICU_SANDBOX% + ``` + +1. Build ICU4C (you only need to do this once): + + ```cmd + git clone https://github.com/unicode-org/icu.git + + cd icu\icu4c + msbuild source/allinone/allinone.sln /p:Configuration=Release /p:Platform=x64 /p:SkipUWP=true + cd ..\.. + + set DESTDIR=%ICU_SANDBOX%\icu_release + rd /q/s %DESTDIR% + md %DESTDIR% + xcopy icu\icu4c\include %DESTDIR%\include /E /V /I /Q /Y + xcopy icu\icu4c\bin64 %DESTDIR%\bin64 /E /V /I /Q /Y + xcopy icu\icu4c\lib64 %DESTDIR%\lib64 /E /V /I /Q /Y + ``` + +1. Create a minimal C++ file here (we are in the `$ICU_SANDBOX` folder). Call it `hello_mf2.cpp`. +The link to download and the contents are listed above (see the Linux section). + +1. Build your application and run it + + ```cmd + set DESTDIR=%ICU_SANDBOX%\icu_release + cl /std:c++17 /EHsc /I %DESTDIR%\include %DESTDIR%/lib64/*.lib hello_mf2.cpp + + rem set PATH only once, not every time + set PATH=%DESTDIR%\bin64;%PATH% + + .\hello_mf2.exe + ``` + + This will output + ``` + Hello John, today is January 28, 2025! + ``` + +### From Visual Studio (UI) + +1. Prepare a sandbox folder. Call it `hello_icu_mf2`. + +1. Build ICU4C (you only need to do this once) + + * Clone the ICU repository from + to the `hello_icu_mf2` folder. + We will end up with the folder `hello_icu_mf2\icu`. + + * Start Visual Studio. + * Select _"Open a project or solution"_ + * Open the `allinone.sln` solution from the `hello_icu_mf2\icu\icu4c\source\allinone` folder. + * Select the "Build" -- "Configuration Manager" menu + * Change the active solution to "Release" and "x64" (or another architecture, but you will have to be consistent everywhere after this) + * Select the "Build" -- "Build solution" menu + * Select the "File" -- "Close solution" menu + +1. Create a minimal C++ project in the `hello_icu_mf2` folder. Call it `hello_mf2`. + + * You are still in Visual Studio. Select "Create a new project" + * Choose the project template "Console App" (tagged `C++`, `Windows`, `Console`) + * Click the "Next" button + * Set the "Project name" to "HelloMF2" and set the "Location" to the `hello_icu_mf2` folder. \ + * Click "Create" + * A project will be created in the `hello_icu_mf2\HelloMF2` folder. + +1. Create a macro pointing to the ICU folder with the files we built. + + * Select the "View" -- "Property Manager" menu + * In the new dialog select the root of the tree ("HelloMF2", not the Debug / Release leafs) + * Right click and select "Add New Project Property Sheet..." + * Call it `IcuPropertySheet.props` and click "Add" + * Open (double-click) `IcuPropertySheet` in any of the "leafs" of the tree on the left. + For example in `HelloMF2 / Release | 64 / IcuPropertySheet` + * Select "User Macros" under "Common Properties" (left tree) + * Click the "Add Macro" button + * Name it `IcuDistro` and set the "Value" to the `..\icu\icu4c` folder. + If the test project we created is not in `hello_icu_mf2`, next to `icu`, then you can use a full path to the ICU folder where you just did a built. + You can also point it to one you downloaded (from the GitHub releases, see above). + * Click the "OK" button + +1. Configure the project + + * Select `HelloMF2` in the left-side tree + * Select the "Project" -- "Properties" menu + * For "Configuration" (top-left) select "All Configurations" + * For "Platform" (top-right) select "All Platforms" + * In the left side tree: + * "C/C++" / "General" set "Additional Include Directories" to + `$(IcuDistro)\include;%(AdditionalIncludeDirectories)` + * "C/C++" / "Language" set "C++ Language Standard" to + `ISO C++17 Standard (/std:c++17)` + * "Linker" / "General" set "Additional Dependencies" to \ + `icudt.lib;icuin.lib;icuuc.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)` + * "Linker" / "General" set "Additional Library Directories" to \ + `$(IcuDistro)/lib64;%(AdditionalLibraryDirectories)` + * "Debugging" set "Environment" to \ + `PATH=$(IcuDistro)/bin64;%PATH%` + * For "Platform" (top-right) select "Win32" + * In the left side tree remove the `64` in two of the settings: + * "Linker" / "General" set "Additional Library Directories" to \ + `$(IcuDistro)/lib;%(AdditionalLibraryDirectories)` + * "Debugging" set "Environment" to \ + `PATH=$(IcuDistro)/bin;%PATH%` + +1. Update the default source file to use some ICU functionality + + * Select the "View" -- "Solution Explorer" menu + * In the left-side tree "HelloMF2" / "Source Files" open `HelloMF2.cpp` + * Download the `hello_mf2.cpp` file (see earlier in this page for download link) and save it as + `HelloMF2.cpp`, thereby replacing it. + +1. At this point you should be able to build and run the application, debug it, etc. + +1. When run, it will output + ``` + Hello John, today is January 28, 2025! + ``` + + +## Java + +We will assume that if you are interested in testing a pre-release Java library +you already have (or know how to install) a JDK, Apache Maven, git, +know how to create a project in your favorite IDE, and so on. + +### What you need + +* JDK, any version between 8 and 23 +* Apache Maven + +### Instructions + +1. Create a new Maven project + + ```sh + mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=hello_icu_mf2 -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false + + cd hello_icu_mf2 + ``` + +1. Modify the `pom.xml` file + + 1. The project created as above uses the Java 17 version. + If you are using a lower version then change `` property to whatever Java version you are using. + ```sh + # Example on how to set the Java version to 11 + mvn versions:set-property -Dproperty=maven.compiler.release -DnewVersion=11 + ``` + + 1. Edit the file and add this to `` + ```xml + + com.ibm.icu + icu4j + 77.0.1-SNAPSHOT + + ``` + **Warning:** make sure it is done in `dependencies`, not in `dependencyManagement / dependencies` + +1. Edit the `src/test/java/com/mycompany/app/AppTest.java` file + + 1. Add a new test method + ```java + @Test + public void testMessageFormat2() { + MessageFormatter mf2 = MessageFormatter.builder() + .setLocale(Locale.US) + .setPattern("Hello {$user}, today is {$now :date style=long}!") + .build(); + Calendar cal = Calendar.getInstance(); + cal.set(2025, 0, 28); + + Map arguments = new HashMap<>(); + arguments.put("user", "John"); + arguments.put("now", cal); + System.out.println(mf2.formatToString(arguments)); + } + ``` + + 1. Add imports + + ```java + import java.util.HashMap; + import java.util.Locale; + import java.util.Map; + import com.ibm.icu.util.Calendar; + import com.ibm.icu.message2.MessageFormatter; + ``` + +1. Now run the tests + + ```sh + mvn package -q + ``` + + This will output the following in the the tests' console output + ``` + Hello John, today is January 28, 2025! + ```