wasm.locale.objects.pas 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2025 by the Free Pascal development team.
  4. WASM API object for internationalization/localization.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit wasm.locale.objects;
  12. {$mode objfpc}
  13. interface
  14. uses
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. System.SysUtils,
  17. {$ELSE}
  18. sysutils,
  19. {$ENDIF}
  20. wasm.locale.shared, wasm.locale.api;
  21. Type
  22. EWasmLocale = class(Exception);
  23. { TWasmHostLocale }
  24. TWasmHostLocale = class(TObject)
  25. private
  26. FCurrencySymbol: String;
  27. FDateSeparator: String;
  28. FDecimalSeparator: String;
  29. FLongDayNames: TWeekNameArray;
  30. FLongMonthNames: TMonthNameArray;
  31. FShortDayNames: TWeekNameArray;
  32. FShortMonthNames: TMonthNameArray;
  33. FThousandSeparator: String;
  34. FTimeSeparator: string;
  35. FTimeZoneOffset: Integer;
  36. Protected
  37. function ConvertBuf(var Buf : RawByteString; aLen : integer) : string;
  38. procedure InitMonths; virtual;
  39. procedure InitDays; virtual;
  40. procedure InitSeparators; virtual;
  41. procedure InitTimeZone; virtual;
  42. public
  43. constructor create(aLocale : string = '');
  44. procedure TransferToFormatSettings;
  45. property LongMonthNames : TMonthNameArray Read FLongMonthNames;
  46. property ShortMonthNames : TMonthNameArray Read FShortMonthNames;
  47. property LongDayNames : TWeekNameArray Read FLongDayNames;
  48. property ShortDayNames : TWeekNameArray Read FShortDayNames;
  49. Property DecimalSeparator : String Read FDecimalSeparator;
  50. Property ThousandSeparator : String Read FThousandSeparator;
  51. Property CurrencySymbol: String Read FCurrencySymbol;
  52. Property TimeZoneOffset: Integer Read FTimeZoneOffset;
  53. Property DateSeparator: string Read FDateSeparator;
  54. Property TimeSeparator: string Read FTimeSeparator;
  55. end;
  56. implementation
  57. function TWasmHostLocale.ConvertBuf(var Buf: RawByteString; aLen: integer): string;
  58. begin
  59. SetLength(Buf,aLen);
  60. {$IF SIZEOF(char)=1}
  61. Result:=Buf;
  62. {$ELSE}
  63. Result:=UTF8Decode(Buf);
  64. {$ENDIF}
  65. end;
  66. procedure TWasmHostLocale.InitMonths;
  67. var
  68. buf : RawByteString;
  69. S : String;
  70. i,res,len : longint;
  71. long : boolean;
  72. procedure initbuffer; inline;
  73. begin
  74. len:=512;
  75. SetLength(buf,len);
  76. end;
  77. begin
  78. Buf:='';
  79. InitBuffer;
  80. for long in Boolean do
  81. begin
  82. I:=1;
  83. While I<=12 do
  84. begin
  85. res:=__locale_GetNameOfMonth(i,ord(long),@buf[1],@len);
  86. case res of
  87. ELocale_SUCCESS:
  88. begin
  89. S:=ConvertBuf(Buf,Len);
  90. if Long then
  91. FLongMonthNames[i]:=S
  92. else
  93. FShortMonthNames[i]:=S;
  94. inc(i);
  95. InitBuffer;
  96. end;
  97. ELocale_SIZETOOSMALL:
  98. SetLength(Buf,Len); // Redo the loop
  99. else
  100. Raise EWasmLocale.CreateFmt('Failed to get month %d name. Error code: %d',[i,res]);
  101. end;
  102. end;
  103. end;
  104. end;
  105. procedure TWasmHostLocale.InitDays;
  106. var
  107. buf : RawByteString;
  108. S : String;
  109. i,res,len : longint;
  110. long : boolean;
  111. procedure initbuffer; inline;
  112. begin
  113. len:=512;
  114. SetLength(buf,len);
  115. end;
  116. begin
  117. Buf:='';
  118. InitBuffer;
  119. for long in Boolean do
  120. begin
  121. I:=1;
  122. While (I<=7) do
  123. begin
  124. res:=__locale_GetNameOfDay(i,ord(long),@buf[1],@len);
  125. case res of
  126. ELocale_SUCCESS:
  127. begin
  128. S:=ConvertBuf(Buf,Len);
  129. if Long then
  130. FLongDayNames[i]:=S
  131. else
  132. FShortDayNames[i]:=S;
  133. inc(i);
  134. InitBuffer;
  135. end;
  136. ELocale_SIZETOOSMALL:
  137. SetLength(Buf,Len); // Redo the loop
  138. else
  139. Raise EWasmLocale.CreateFmt('Failed to get day %d name. Error code: %d',[i,res]);
  140. end;
  141. end;
  142. end;
  143. end;
  144. procedure TWasmHostLocale.InitSeparators;
  145. var
  146. buf : RawByteString;
  147. res, len : longint;
  148. S : string;
  149. procedure InitBuffer; inline;
  150. begin
  151. len:=24;
  152. setlength(buf,len);
  153. end;
  154. begin
  155. // buf:='';
  156. // Currrency
  157. InitBuffer;
  158. res:=__locale_GetCurrencySymbol(@Buf[1],@len);
  159. if res=ELocale_SUCCESS then
  160. FCurrencySymbol:=ConvertBuf(Buf,Len)
  161. else
  162. Raise EWasmLocale.CreateFmt('Failed to get currency symbol. Error code: %d',[res]);
  163. // Browser has actually no way to determine this.
  164. if FCurrencySymbol='' then
  165. FCurrencySymbol:='$';
  166. // Decimal separator
  167. InitBuffer;
  168. res:=__locale_GetDecimalSeparator(@Buf[1],@len);
  169. if res=ELocale_SUCCESS then
  170. FDecimalSeparator:=ConvertBuf(Buf,Len)
  171. else
  172. Raise EWasmLocale.CreateFmt('Failed to get decimal separator. Error code: %d',[res]);
  173. // Thousands separator
  174. InitBuffer;
  175. res:=__locale_GetThousandSeparator(@Buf[1],@len);
  176. if res=ELocale_SUCCESS then
  177. FThousandSeparator:=ConvertBuf(Buf,Len)
  178. else
  179. Raise EWasmLocale.CreateFmt('Failed to thousands separator. Error code: %d',[res]);
  180. // Date separator
  181. InitBuffer;
  182. res:=__locale_GetDateSeparator(@Buf[1],@len);
  183. if res=ELocale_SUCCESS then
  184. FDateSeparator:=ConvertBuf(Buf,Len)
  185. else
  186. Raise EWasmLocale.CreateFmt('Failed to get date separator. Error code: %d',[res]);
  187. // Time separator
  188. InitBuffer;
  189. res:=__locale_GetTimeSeparator(@Buf[1],@len);
  190. if res=ELocale_SUCCESS then
  191. FTimeSeparator:=ConvertBuf(Buf,Len)
  192. else
  193. Raise EWasmLocale.CreateFmt('Failed to get time separator. Error code: %d',[res]);
  194. end;
  195. procedure TWasmHostLocale.InitTimeZone;
  196. begin
  197. FTimeZoneOffset:=__locale_GetTimeZoneOffset;
  198. end;
  199. constructor TWasmHostLocale.create(aLocale: string);
  200. var
  201. lLocale : AnsiString;
  202. begin
  203. {$IF SIZEOF(CHAR)=1}
  204. lLocale:=aLocale;
  205. {$ELSE}
  206. lLocale:=UTF8Encode(aLocale);
  207. {$ENDIF}
  208. if lLocale<>'' then
  209. __locale_SetWasmLocale(PAnsiChar(lLocale),Length(lLocale));
  210. InitMonths;
  211. InitDays;
  212. InitSeparators;
  213. InitTimeZone;
  214. end;
  215. procedure TWasmHostLocale.TransferToFormatSettings;
  216. function First(aString : String; aDefault : char) : char;
  217. begin
  218. if aString='' then
  219. Result:=aDefault
  220. else
  221. Result:=aString[1];
  222. end;
  223. var
  224. I : Integer;
  225. begin
  226. DefaultFormatSettings.DateSeparator:=First(FDateSeparator,'/');
  227. DefaultFormatSettings.TimeSeparator:=First(FTimeSeparator,':');
  228. DefaultFormatSettings.DecimalSeparator:=First(FDecimalSeparator,'.');
  229. DefaultFormatSettings.CurrencyString:=FCurrencySymbol;
  230. DefaultFormatSettings.ThousandSeparator:=First(FThousandSeparator,',');
  231. for I:=1 to 12 do
  232. begin
  233. DefaultFormatSettings.LongMonthNames[i]:=LongMonthNames[i];
  234. DefaultFormatSettings.ShortMonthNames[i]:=ShortMonthNames[i];
  235. end;
  236. for I:=1 to 7 do
  237. begin
  238. DefaultFormatSettings.LongDayNames[i]:=LongDayNames[i];
  239. DefaultFormatSettings.ShortDayNames[i]:=ShortDayNames[i];
  240. end;
  241. // Sysutils.
  242. end;
  243. end.