Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions Jint/Native/Global/GlobalObject.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public partial class GlobalObject
private static readonly Key propertyInt16Array = "Int16Array";
private static readonly Key propertyInt32Array = "Int32Array";
private static readonly Key propertyInt8Array = "Int8Array";
//private static readonly Key propertyIntl = "Intl";
private static readonly Key propertyIntl = "Intl";
private static readonly Key propertyJSON = "JSON";
private static readonly Key propertyMap = "Map";
private static readonly Key propertyMath = "Math";
Expand Down Expand Up @@ -109,7 +109,7 @@ protected override void Initialize()
properties.AddDangerous(propertyInt16Array, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Int16Array, PropertyFlags));
properties.AddDangerous(propertyInt32Array, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Int32Array, PropertyFlags));
properties.AddDangerous(propertyInt8Array, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Int8Array, PropertyFlags));
// TODO properties.AddDapropertygerous(propertyIntl, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Intl, propertyFlags));
properties.AddDangerous(propertyIntl, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Intl, PropertyFlags));
properties.AddDangerous(propertyJSON, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Json, PropertyFlags));
properties.AddDangerous(propertyMap, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Map, PropertyFlags));
properties.AddDangerous(propertyMath, new LazyPropertyDescriptor<GlobalObject>(this, static global => global._realm.Intrinsics.Math, PropertyFlags));
Expand Down
103 changes: 103 additions & 0 deletions Jint/Native/Intl/Icu.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
namespace Jint.Native.Intl;

// ICU (International Components for Unicode) is a native C/C++ library provided by the OS
// that implements BCP-47 locale canonicalization, alias resolution, and other i18n data.
// https://github.com/unicode-org/icu
// We use DllImport to bind directly to its functions (e.g. uloc_toLanguageTag) so we can
// reuse the OS-provided ICU implementation instead of reimplementing the spec in C#.
internal static class ICU
{
private const string MacLib = "/usr/lib/libicucore.dylib";
private const string LinuxUc = "icuuc"; // resolves to libicuuc.so[.N]
private const string LinuxI18n = "icui18n"; // resolves to libicui18n.so[.N]

#if OSX || MACCATALYST || IOS || TVOS
private const string UcLib = MacLib;
private const string I18nLib = MacLib;
#elif LINUX
private const string UcLib = LinuxUc;
private const string I18nLib = LinuxI18n;
#else
// Windows: prefer bundling (put icuucNN.dll/icuinNN.dll next to your .exe)
private const string UcLib = "icuuc"; // icuucNN.dll via loader search path
private const string I18nLib = "icuin"; // icuinNN.dll
#endif

// ICU error code enum (partial)
public enum UErrorCode : int
{
U_ZERO_ERROR = 0,
U_ILLEGAL_ARGUMENT_ERROR = 1,
// ... add more as needed
}

[DllImport(UcLib, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int uloc_countAvailable();

[DllImport(UcLib, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr uloc_getAvailable(int n);

// Example for something in i18n (collation)
[DllImport(I18nLib, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int ucol_countAvailable();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string PtrToAnsiString(IntPtr p) => Marshal.PtrToStringAnsi(p)!;

[DllImport(UcLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "uloc_toLanguageTag")]
private static extern unsafe int uloc_toLanguageTag_ptr(
byte* localeIdUtf8, // const char* (UTF-8)
byte[] langtag, // UTF-8 out
int langtagCapacity,
[MarshalAs(UnmanagedType.I1)] bool strict,
ref UErrorCode err);

public static unsafe int uloc_toLanguageTag(
string localeId, byte[] langtag, int langtagCapacity, bool strict, ref UErrorCode err)
{
// NUL-terminate for C
byte[] inBytes = Encoding.UTF8.GetBytes(localeId + "\0");
fixed (byte* p = inBytes)
{
return uloc_toLanguageTag_ptr(p, langtag, langtagCapacity, strict, ref err);
}
}

[DllImport(UcLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "uloc_forLanguageTag")]
private static extern unsafe int uloc_forLanguageTag_ptr(
byte* langtagUtf8, // const char* (UTF-8)
byte[] localeId, // UTF-8 out
int localeIdCapacity,
out int parsedLength,
ref UErrorCode err);

public static unsafe int uloc_forLanguageTag(string langtag, byte[] localeId, int localeIdCapacity, out int parsedLength, ref UErrorCode err)
{
var inBytes = System.Text.Encoding.UTF8.GetBytes(langtag + "\0");
fixed (byte* p = inBytes)
{
return uloc_forLanguageTag_ptr(p, localeId, localeIdCapacity, out parsedLength, ref err);
}
}

[DllImport(UcLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "uloc_canonicalize")]
private static extern unsafe int uloc_canonicalize_ptr(
byte* localeIdUtf8, // const char* (UTF-8, NUL-terminated)
byte[] name, // out buffer (UTF-8, no trailing NUL guaranteed)
int nameCapacity,
ref UErrorCode err);

public static unsafe int uloc_canonicalize(string localeId, byte[] name, int nameCapacity, ref UErrorCode err)
{
// NUL-terminate input for C
var inBytes = Encoding.UTF8.GetBytes(localeId + "\0");
fixed (byte* p = inBytes)
{
return uloc_canonicalize_ptr(p, name, nameCapacity, ref err);
}
}
}

Loading
Loading