root/coldbox/trunk/src/system/plugins/i18n.cfc @ 634

Revision 634, 50.9 kB (checked in by lmajano, 6 years ago)

code cleanup

Line 
1<!-----------------------------------------------------------------------
2********************************************************************************
3Copyright 2005-2007 ColdBox Framework by Luis Majano and Ortus Solutions, Corp
4www.coldboxframework.com | www.luismajano.com | www.ortussolutions.com
5********************************************************************************
6
7author:         paul hastings <paul@sustainableGIS.com>
8date:           1-April-2004
9revisions:      25-jun-2004 added locale number formating
10                       7-jul-2004      added localized digit parsing
11                       11-jul-2004     added to/from Arabic-Indic digit functions
12                       12-jul-2004 added metadata function, getDecimalSymbols
13                       13-jul-2004 added localized country and language display functions, showLocaleCountry & showLocaleLanguage
14                       16-jul-2004 added method to return namepart for filtering/sorting on per locale basis
15                       16-aug-2004     added method to delete unicode named files/dirs
16                       3-feb-2005 swapped to ulocales
17                       20-feb-2005 added getCurrencySymbol method
18                       9-jul-2005 added i18nBigDecimalFormat
19                       30-may-2006 swapped to using java epoch offsets from datetimes
20                       16-jun-2006 added date math methods
21                       8-jul-2006 version for coldbox
22notes:
23this CFC contains a several util I18N functions. all valid java locales are supported. it requires the use
24of cfobject.
25
26methods in this CFC:
27       - getLocales returns LIST of java style locales (en_US,etc.) available on this server. PUBLIC
28       - getLocaleNames returns LIST of java style locale names available on this server. PUBLIC
29       - isBIDI returns boolean indicating whether given locale uses lrt to rtl writing sysem direction.
30       required argument is thisLocale. PUBLIC
31       - isValidLocale returns BOOLEAN indicating whether a given locale is valid on this server. should
32       be used for locale validation prior to passing to this CFC. takes one required argument, thisLocale,
33       string such as "en_US", "th_TH", etc. PUBLIC
34       - showCountry: returns country display name in english from given locale, takes
35       one required argument, thisLocale. returns string. PUBLIC
36       - showLanguage: returns language display name in english from given locale, takes
37       one required argument, thisLocale. returns string. PUBLIC
38       - showLocaleCountry: returns localized country display name from given locale, takes
39       one required argument, thisLocale. returns string. PUBLIC
40       - showLocaleLanguage: returns localized language display name from given locale, takes
41       one required argument, thisLocale. returns string. PUBLIC
42       - getDecimalSymbols METADATA function, returns structure holding various decimal format symbols for
43       given locale. required argument is thisLocale, valid java style locale. PUBLIC
44       - getCurrencySymbol METADATA function, returns international (USD, THB,
45       etc.) or localized  currency symbol for given locale. required argument is thisLocale,
46       valid java style locale. optional boolean argument is localized to return localized or
47       international currency symbol. defaults to true (localized). PUBLIC
48
49Modifications
50
5108/20/2006 Luis Majano - Modified for ColdBox
52----------------------------------------------------------------------->
53<cfcomponent name="i18n"
54                         hint="This is the i18N plugin based on Paul Hastings cfc. It uses standard Java locale names and has its own storage mechanism via RBundles['Locale'].  In order to use the plugin, you must instantiate it and call its setfwLocale() method with the appropriate locale to initialize with. Then you may use its methods."
55                         extends="coldbox.system.plugin"
56                         output="false"
57                         cache="true"
58                         cachetimeout="0">
59
60<!------------------------------------------- CONSTRUCTOR ------------------------------------------->
61
62        <cffunction name="init" access="public" returntype="i18n" hint="Constructor" output="false">
63                <cfargument name="controller" type="any" required="true">
64                <cfscript>
65                super.Init(arguments.controller);
66                setpluginName("Internationalization (i18N)");
67                setpluginVersion("1.0.0 coldbox core java");
68                setpluginDescription("Internationalization and Bundles plugin based on Paul Hastings Brain.");
69
70                //<!--- This plugin's properties --->
71                variables.instance.aDFSymbol=createObject("java","java.text.DecimalFormatSymbols");
72                variables.instance.aDateFormat=createObject("java","java.text.DateFormat");
73                variables.instance.sDateFormat=createObject("java","java.text.SimpleDateFormat");
74                variables.instance.aLocale=createObject("java","java.util.Locale");
75                variables.instance.timeZone=createObject("java","java.util.TimeZone");
76                variables.instance.thisLocale = ""; //Setup by the loadLocale() method.
77                loadLocale();
78                variables.instance.aCalendar=createObject("java","java.util.GregorianCalendar").init(variables.instance.thisLocale);
79                variables.instance.dateSymbols = createObject("java","java.text.DateFormatSymbols").init(variables.instance.thisLocale);
80                variables.instance.I18NUtilDate="23-aug-2006"; //should be date of latest change
81                return this;
82                </cfscript>
83        </cffunction>
84
85        <!--- ************************************************************* --->
86
87        <cffunction name="init_i18N" access="public" output="No" hint="Reads,parses,saves the locale and resource bundles defined in the config.xml. Called only internally by the framework. Use at your own risk" returntype="void">
88                <!--- ************************************************************* --->
89                <cfargument name="rbFile"   required="Yes" type="string" hint="This must be the path + filename UP to but NOT including the locale. We auto-add .properties to the end.">
90                <cfargument name="rbLocale" required="No"  type="string" default="en_US">
91                <!--- ************************************************************* --->
92                <!--- Set the default Locale --->
93                <cfset setfwLocale(arguments.rbLocale,true)>
94                <!--- Test for rbFile --->
95                <cfif arguments.rbFile neq "">
96                        <!--- Load the default Bundle --->
97                        <cfset getPlugin("resourceBundle").loadBundle(arguments.rbFile, arguments.rbLocale)>
98                </cfif>
99        </cffunction>
100
101
102<!------------------------------------------- PUBLIC ------------------------------------------->
103
104        <!--- ************************************************************* --->
105        <cffunction name="setfwLocale" access="public" output="false" returnType="any" hint="Set the default locale to use in the framework.">
106                <!--- ************************************************************* --->
107                <cfargument name="locale"               type="string"  required="false"  default="#getController().getSetting("DefaultLocale")#"   hint="The locale to change and set. Must be Java Style: en_US">
108                <cfargument name="dontloadRBFlag"       type="boolean" required="false"  default="false" hint="Flag to load the resource bundle for the specified locale (If not already loaded) or just change the framework's locale.">
109                <!--- ************************************************************* --->
110
111                <!--- Resource Bundle Loading Check --->
112                <cfif getController().getSetting("DefaultResourceBundle") neq "">
113                        <cfif not arguments.dontloadRBFlag and not structKeyExists(getController().getSetting("RBundles"),arguments.locale)>
114                                <cfset getPlugin("resourceBundle").loadBundle(getController().getSetting("DefaultResourceBundle"),arguments.locale)>
115                        </cfif>
116                </cfif>
117
118                <!--- Storage of the Locale --->
119                <cfif getController().getSetting("LocaleStorage") eq "session">
120                        <cfset session.DefaultLocale = arguments.locale>
121                <cfelse>
122                        <cfset client.DefaultLocale = arguments.locale>
123                </cfif>
124
125                <!--- Locale Instance Setup --->
126                <cfset loadLocale(arguments.locale)>
127
128                <cfreturn this>
129        </cffunction>
130        <!--- ************************************************************* --->
131
132        <!--- ************************************************************* --->
133        <cffunction name="loadLocale" access="public" returnType="void" output="false"  hint="Loads a locale.">
134                <!--- ************************************************************* --->
135                <cfargument name="locale" type="string" required="false" default="en_US" />
136            <!--- ************************************************************* --->
137                <cfif not isValidLocale(arguments.locale)>
138                        <cfthrow message="Specified locale must be of the form language_COUNTRY_VARIANT where language, country and variant are 2 characters each, ISO 3166 standard." type="Framework.plugins.i18n.InvalidLocaleException" detail="The locale tested is: #arguments.locale#" />
139                </cfif>
140                <cfset instance.thisLocale = buildLocale(arguments.locale) />
141        </cffunction>
142        <!--- ************************************************************* --->
143
144        <!--- ************************************************************* --->
145        <cffunction name="isValidLocale"  access="public" output="false" returntype="boolean" hint="Validate a locale">
146                <!--- ************************************************************* --->
147                <cfargument name="thisLocale" required="yes" type="string" hint="Locale to validate">
148                <!--- ************************************************************* --->
149                <cfif listFind(arrayToList(getLocales()),arguments.thisLocale)>
150                        <cfreturn true>
151                <cfelse>
152                        <cfreturn false>
153                </cfif>
154        </cffunction>
155        <!--- ************************************************************* --->
156
157        <!--- ************************************************************* --->
158        <cffunction name="getLocales" access="public" output="false" returntype="array" hint="returns array of locales">
159        <cfreturn instance.aLocale.getAvailableLocales()>
160        </cffunction>
161        <!--- ************************************************************* --->
162
163        <!--- ************************************************************* --->
164        <cffunction access="public" name="getLocaleNames" output="false" returntype="string" hint="returns list of locale names, UNICODE direction char (LRE/RLE) added as required">
165        <cfscript>
166               var orgLocales=getLocales();
167               var theseLocales="";
168               var thisName="";
169               var i=0;
170               for (i=1; i LTE arrayLen(orgLocales); i=i+1) {
171                       if (listLen(orgLocales[i],"_") EQ 2) {
172                               if (left(orgLocales[i],2) EQ "ar" or left(orgLocales[i],2) EQ "iw")
173                                       thisName=chr(8235)&orgLocales[i].getDisplayName(orgLocales[i])&chr(8234);
174                               else
175                                       thisName=orgLocales[i].getDisplayName(orgLocales[i]);
176                               theseLocales=listAppend(theseLocales,thisName);
177                       } // if locale more than language
178               } //for
179               return theseLocales;
180        </cfscript>
181        </cffunction>
182        <!--- ************************************************************* --->
183
184        <!--- ************************************************************* --->
185        <cffunction name="getISOlanguages"  access="public" output="false" returntype="array" hint="returns array of 2 letter ISO languages">
186        <cfreturn instance.aLocale.getISOLanguages()>
187        </cffunction>
188        <!--- ************************************************************* --->
189
190        <!--- ************************************************************* --->
191        <cffunction name="getISOcountries" access="public"  output="false" returntype="array" hint="returns array of 2 letter ISO countries">
192        <cfreturn instance.aLocale.getISOCountries()>
193        </cffunction>
194        <!--- ************************************************************* --->
195
196        <!--- ************************************************************* --->
197        <cffunction name="showCountry" access="public" output="false" returntype="string" hint="returns display country name for given locale">
198       <cfreturn instance.thisLocale.getDisplayCountry()>
199        </cffunction>
200        <!--- ************************************************************* --->
201
202        <!--- ************************************************************* --->
203        <cffunction name="showISOCountry" access="public" output="false" returntype="string" hint="returns 2-letter ISO country name for given locale">
204                <cfreturn instance.thisLocale.getCountry()>
205        </cffunction>
206        <!--- ************************************************************* --->
207
208        <!--- ************************************************************* --->
209        <cffunction name="showLanguage" access="public" output="false" returntype="string" hint="returns display country name for given locale">
210                <cfreturn instance.thisLocale.getDisplayLanguage()>
211        </cffunction>
212        <!--- ************************************************************* --->
213
214        <!--- ************************************************************* --->
215        <cffunction name="showLocaleCountry" access="public" output="false" returntype="string" hint="returns display country name for given locale">
216                <cfreturn instance.thisLocale.getDisplayCountry(variables.thisLocale)>
217        </cffunction>
218        <!--- ************************************************************* --->
219
220        <!--- ************************************************************* --->
221        <cffunction name="showLocaleLanguage" access="public" output="false" returntype="string" hint="returns display country name for given locale">
222                <cfreturn instance.thisLocale.getDisplayLanguage(variables.thisLocale)>
223        </cffunction>
224        <!--- ************************************************************* --->
225
226        <!--- ************************************************************* --->
227        <!--- core java uses 'iw' for hebrew, leaving 'he' just in case this is a version thing --->
228        <cffunction name="isBidi" access="public" output="No" returntype="boolean" hint="determines if given locale is BIDI">
229                <cfif listFind("ar,iw,fa,ps,he",left(instance.thisLocale.toString(),2))>
230                        <cfreturn true>
231                <cfelse>
232                        <cfreturn false>
233                </cfif>
234        </cffunction>
235        <!--- ************************************************************* --->
236
237        <!--- ************************************************************* --->
238        <cffunction name="getCurrencySymbol" access="public" returntype="string" output="false" hint="returns currency symbol for this locale">
239                <!--- ************************************************************* --->
240                <cfargument name="localized" required="no" type="boolean" default="true" hint="return international (USD, THB, etc.) or localized ($,etc.) symbol">
241                <!--- ************************************************************* --->
242                <cfset var aCurrency=createObject("java","com.ibm.icu.util.Currency")>
243                <cfset var tmp=arrayNew(1)>
244                <cfif arguments.localized>
245                        <cfset arrayAppend(tmp,true)>
246                    <cfreturn aCurrency.getInstance(instance.thisLocale).getName(instance.thisLocale,aCurrency.SYMBOL_NAME,tmp)>
247                <cfelse>
248                    <cfreturn aCurrency.getInstance(instance.thisLocale).getCurrencyCode()>
249                </cfif>
250        </cffunction>
251        <!--- ************************************************************* --->
252
253        <!--- ************************************************************* --->
254        <cffunction name="getDecimalSymbols"  access="public"  output="false" returntype="struct" hint="returns strucure holding decimal format symbols for this locale">
255        <cfscript>
256               var dfSymbols=instance.aDFSymbol.init(instance.thisLocale);
257               var symbols=structNew();
258               symbols.plusSign=dfSymbols.getPlusSign().toString();
259               symbols.Percent=dfSymbols.getPercent().toString();
260               symbols.minusSign=dfSymbols.getMinusSign().toString();
261               symbols.currencySymbol=dfSymbols.getCurrencySymbol().toString();
262               symbols.internationCurrencySymbol=dfSymbols.getInternationalCurrencySymbol().toString();
263               symbols.monetaryDecimalSeparator=dfSymbols.getMonetaryDecimalSeparator().toString();
264               symbols.exponentSeparator=dfSymbols.getExponentSeparator().toString();
265               symbols.perMille=dfSymbols.getPerMill().toString();
266               symbols.decimalSeparator=dfSymbols.getDecimalSeparator().toString();
267               symbols.groupingSeparator=dfSymbols.getGroupingSeparator().toString();
268               symbols.zeroDigit=dfSymbols.getZeroDigit().toString();
269               return symbols;
270        </cfscript>
271        </cffunction>
272        <!--- ************************************************************* --->
273
274        <!--- ************************************************************* --->
275        <cffunction name="i18nDateTimeFormat" access="public" output="No" returntype="string">
276                <!--- ************************************************************* --->
277                <cfargument name="thisOffset" required="yes" type="numeric" hint="java epoch offset">
278                <cfargument name="thisDateFormat" default="1" required="No" type="numeric" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
279                <cfargument name="thisTimeFormat" default="1" required="No" type="numeric" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
280                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
281                <!--- ************************************************************* --->
282               <cfset var tDateFormat=javacast("int",arguments.thisDateFormat)>
283               <cfset var tTimeFormat=javacast("int",arguments.thisTimeFormat)>
284               <cfset var tDateFormatter=instance.aDateFormat.getDateTimeInstance(tDateFormat,tTimeFormat,instance.thisLocale)>
285               <cfset var tTZ=instance.timeZone.getTimezone(arguments.tz)>
286               <cfset tDateFormatter.setTimezone(tTZ)>
287               <cfreturn tDateFormatter.format(arguments.thisOffset)>
288        </cffunction>
289        <!--- ************************************************************* --->
290
291        <!--- ************************************************************* --->
292        <cffunction name="i18nDateFormat" access="public" output="No" returntype="string">
293                <!--- ************************************************************* --->
294                <cfargument name="thisOffset" required="yes" type="numeric" hint="java epoch offset">
295                <cfargument name="thisDateFormat" default="1" required="No" type="numeric" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
296                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
297                <!--- ************************************************************* --->
298                   <cfset var tDateFormat=javacast("int",arguments.thisDateFormat)>
299               <cfset var tDateFormatter=instance.aDateFormat.getDateInstance(tDateFormat,instance.thisLocale)>
300               <cfset var tTZ=instance.timeZone.getTimezone(arguments.tz)>
301               <cfset tDateFormatter.setTimezone(tTZ)>
302               <cfreturn tDateFormatter.format(arguments.thisOffset)>
303        </cffunction>
304        <!--- ************************************************************* --->
305
306        <!--- ************************************************************* --->
307        <cffunction name="i18nTimeFormat" access="public" output="No" returntype="string">
308                <!--- ************************************************************* --->
309                <cfargument name="thisOffset" required="yes" type="numeric" hint="java epoch offset">
310                <cfargument name="thisTimeFormat" default="1" required="No" type="numeric" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
311                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
312            <!--- ************************************************************* --->
313               <cfset var tTimeFormat=javacast("int",arguments.thisTimeFormat)>
314               <cfset var tTimeFormatter=instance.aDateFormat.getTimeInstance(tTimeFormat,instance.thisLocale)>
315               <cfset var tTZ=instance.timeZone.getTimezone(arguments.tz)>
316               <cfset tTimeFormatter.setTimezone(tTZ)>
317               <cfreturn tTimeFormatter.format(arguments.thisOffset)>
318        </cffunction>
319        <!--- ************************************************************* --->
320
321        <!--- ************************************************************* --->
322        <cffunction name="dateLocaleFormat" access="public" returnType="any" output="false"
323                                hint="locale version of dateFormat. Needs object instantiation. That is your job not mine.">
324                <!--- ************************************************************* --->
325                <cfargument name="date" type="date" required="true">
326                <cfargument name="style" type="string" required="false" default="LONG" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
327                <!--- ************************************************************* --->
328                <cfscript>
329                // hack to trap & fix varchar mystery goop coming out of mysql datetimes
330                try {
331                        return instance.aDateFormat.getDateInstance(instance.aDateFormat[arguments.style],instance.thisLocale).format(arguments.date);
332                }
333                catch(Any e) {
334                        instance.aCalendar.setTime(arguments.date);
335                        return instance.aDateFormat.getDateInstance(instance.aDateFormat[arguments.style],instance.thisLocale).format(instance.aCalendar.getTime());
336                }
337                </cfscript>
338        </cffunction>
339        <!--- ************************************************************* --->
340
341        <!--- ************************************************************* --->
342        <cffunction name="timeLocaleFormat" access="public" returnType="any" output="false"
343                                hint="locale version of timeFormat. Needs object instantiation. That is your job not mine.">
344                <!--- ************************************************************* --->
345                <cfargument name="date"  type="date"    required="true">
346                <cfargument name="style" type="string"  required="false" default="SHORT" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
347                <!--- ************************************************************* --->
348                <cfscript>
349                // hack to trap & fix varchar mystery goop coming out of mysql datetimes
350                try {
351                        return instance.aDateFormat.getTimeInstance(instance.aDateFormat[arguments.style],instance.thisLocale).format(arguments.date);
352                }
353                catch (Any e) {
354                        instance.aCalendar.setTime(arguments.date);
355                        return instance.aDateFormat.getTimeInstance(instance.aDateFormat[arguments.style],instance.thisLocale).format(instance.aCalendar.getTime());
356                }
357                </cfscript>
358        </cffunction>
359        <!--- ************************************************************* --->
360
361        <!--- ************************************************************* --->
362        <cffunction name="datetimeLocaleFormat" access="public" returnType="any" output="false"
363                                hint="locale date/time format. Needs object instantiation. That is your job not mine.">
364                <!--- ************************************************************* --->
365                <cfargument name="date"                 type="date" required="true">
366                <cfargument name="dateStyle"    type="string" required="false" default="SHORT" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
367                <cfargument name="timeStyle"    type="string" required="false" default="SHORT" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
368                <!--- ************************************************************* --->
369                <cfscript>
370                // hack to trap & fix varchar mystery goop coming out of mysql datetimes
371                try {
372                        return instance.aDateFormat.getDateTimeInstance(instance.aDateFormat[arguments.dateStyle],instance.aDateFormat[arguments.timeStyle],instance.thisLocale).format(arguments.date);
373                }
374                catch (Any e) {
375                        variables.aCalendar.setTime(arguments.date);
376                        return instance.aDateFormat.getDateTimeInstance(instance.aDateFormat[arguments.dateStyle],instance.aDateFormat[arguments.timeStyle],instance.thisLocale).format(instance.aCalendar.getTime());
377                }
378                </cfscript>
379        </cffunction>
380        <!--- ************************************************************* --->
381
382        <!--- ************************************************************* --->
383        <cffunction name="i18nDateParse" access="public" output="No" returntype="numeric" hint="parses localized date string to datetime object or returns blank if it can't parse">
384                <!--- ************************************************************* --->
385                <cfargument name="thisDate" required="yes" type="string">
386                <!--- ************************************************************* --->
387                        <cfset var isOk=false>
388                        <cfset var i=0>
389                        <cfset var parsedDate="">
390                        <cfset var tDateFormatter="">
391                        <!--- holy cow batman, can't parse dates in an elegant way. bash! pow! socko! --->
392                        <cfloop index="i" from="0" to="3">
393                                <cfset isOK=true>
394                                <cfset tDateFormatter=instance.aDateFormat.getDateInstance(javacast("int",i),instance.thisLocale)>
395                                <cftry>
396                                        <cfset parsedDate=tDateFormatter.parse(arguments.thisDate)>
397                                        <cfcatch type="Any">
398                                                <cfset isOK=false>
399                                        </cfcatch>
400                                </cftry>
401                                <cfif isOK>
402                                        <cfbreak>
403                                </cfif>
404                </cfloop>
405                <cfreturn parsedDate.getTime()>
406        </cffunction>
407        <!--- ************************************************************* --->
408
409        <!--- ************************************************************* --->
410        <cffunction name="i18nDateTimeParse" access="public" output="No" returntype="numeric" hint="parses localized datetime string to datetime object or returns blank if it can't parse">
411                <!--- ************************************************************* --->
412                <cfargument name="thisDate" required="yes" type="string">
413                <!--- ************************************************************* --->
414                        <cfset var isOk=false>
415                        <cfset var i=0>
416                        <cfset var j=0>
417                        <cfset var dStyle=0>
418                        <cfset var tStyle=0>
419                        <cfset var parsedDate="">
420                        <cfset var tDateFormatter="">
421                        <!--- holy cow batman, can't parse dates in an elegant way. bash! pow! socko! --->
422                        <cfloop index="i" from="0" to="3">
423                                <cfset dStyle=javacast("int",i)>
424                                <cfloop index="j" from="0" to="3">
425                                        <cfset tStyle=javacast("int",j)>
426                                        <cfset isOK=true>
427                                        <cfset tDateFormatter=instance.aDateFormat.getDateTimeInstance(dStyle,tStyle,instance.thisLocale)>
428                                        <cftry>
429                                                <cfset parsedDate=tDateFormatter.parse(arguments.thisDate)>
430                                                <cfcatch type="Any">
431                                                        <cfset isOK=false>
432                                                </cfcatch>
433                                        </cftry>
434                                        <cfif isOK>
435                                                <cfbreak>
436                                        </cfif>
437                                </cfloop>
438               </cfloop>
439               <cfreturn parsedDate.getTime()>
440        </cffunction>
441        <!--- ************************************************************* --->
442
443        <!--- ************************************************************* --->
444        <cffunction name="getDateTimePattern" access="public" output="No" returntype="string" hint="returns locale date/time pattern">
445                <!--- ************************************************************* --->
446                <cfargument name="thisDateFormat" required="no" type="numeric" default="1" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
447                <cfargument name="thisTimeFormat" required="no" type="numeric" default="3" hint="FULL=0, LONG=1, MEDIUM=2, SHORT=3">
448                <!--- ************************************************************* --->
449               <cfset var tDateFormat=javacast("int",arguments.thisDateFormat)>
450               <cfset var tTimeFormat=javacast("int",arguments.thisTimeFormat)>
451               <cfset var tDateFormatter=instance.aDateFormat.getDateTimeInstance(tDateFormat,tTimeFormat,instance.thisLocale)>
452               <cfreturn tDateFormatter.toPattern()>
453        </cffunction>
454        <!--- ************************************************************* --->
455
456        <!--- ************************************************************* --->
457        <cffunction name="formatDateTime" access="public" output="No" returntype="string" hint="formats a date/time to given pattern">
458                <!--- ************************************************************* --->
459                <cfargument name="thisOffset" required="yes" type="numeric">
460                <cfargument name="thisPattern" required="yes" type="string">
461                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
462                <!--- ************************************************************* --->
463               <cfset var tDateFormatter=instance.aDateFormat.getDateTimeInstance(instance.aDateFormat.LONG,instance.aDateFormat.LONG,instance.thisLocale)>
464               <cfset tDateFormatter.applyPattern(arguments.thisPattern)>
465               <cfreturn tDateFormatter.format(arguments.thisOffset)>
466        </cffunction>
467        <!--- ************************************************************* --->
468
469        <!--- ************************************************************* --->
470        <cffunction name="weekStarts" access="public" returnType="string" output="false" hint="Determines the first DOW.">
471               <cfreturn instance.aCalendar.getFirstDayOfWeek() />
472        </cffunction>
473        <!--- ************************************************************* --->
474
475        <!--- ************************************************************* --->
476        <cffunction name="getLocalizedYear" access="public" returnType="string" output="false" hint="Returns localized year, probably only useful for BE calendars like in thailand, etc.">
477                <!--- ************************************************************* --->
478                <cfargument name="thisYear"   type="numeric" required="true" />
479                <!--- ************************************************************* --->
480               <cfset var thisDF=instance.sDateFormat.init("yyyy", buildLocale(instance.thisLocale))>
481               <cfreturn thisDF.format(createDate(arguments.thisYear, 1, 1)) />
482        </cffunction>
483        <!--- ************************************************************* --->
484
485        <!--- ************************************************************* --->
486        <cffunction name="getLocalizedMonth" access="public" returnType="string" output="false" hint="Returns localized month.">
487                <!--- ************************************************************* --->
488                <cfargument name="month" type="numeric" required="true">
489            <!--- ************************************************************* --->
490               <cfset var thisDF=instance.sDateFormat.init("MMMM",buildLocale(instance.thisLocale))>
491               <cfreturn thisDF.format(createDate(1999,arguments.month,1))>
492        </cffunction>
493        <!--- ************************************************************* --->
494
495        <!--- ************************************************************* --->
496        <cffunction name="getLocalizedDays" access="public" returnType="any" output="false"
497                                hint="Facade to getShortWeedDays. For compatability">
498                <cfscript>
499                return getShortWeekDays();
500                </cfscript>
501        </cffunction>
502        <!--- ************************************************************* --->
503
504        <!--- ************************************************************* --->
505        <cffunction name="getShortWeekDays" access="public" output="No" returntype="array" hint="returns short day names for this calendar">
506                <!--- ************************************************************* --->
507                <cfargument name="calendarOrder" required="no" type="boolean" default="true">
508                <!--- ************************************************************* --->
509               <cfset var theseDateSymbols= createObject("java","java.text.DateFormatSymbols").init(instance.thisLocale)>
510               <cfset var localeDays="">
511               <cfset var i=0>
512               <cfset var tmp=listToArray(arrayToList(theseDateSymbols.getShortWeekDays()))>
513               <cfif NOT arguments.calendarOrder>
514                       <cfreturn tmp>
515               <cfelse>
516                       <cfswitch expression="#weekStarts(instance.thisLocale)#">
517                               <cfcase value="1"> <!--- "standard" dates --->
518                                       <cfreturn tmp>
519                               </cfcase>
520                               <cfcase value="2"> <!--- euro dates, starts on monday needs kludge --->
521                                       <cfset localeDays=arrayNew(1)>
522                                       <cfset localeDays[7]=tmp[1]>; <!--- move sunday to last --->
523                                       <cfloop index="i" from="1" to="6">
524                                               <cfset localeDays[i]=tmp[i+1]>
525                                       </cfloop>
526                                       <cfreturn localeDays>
527                               </cfcase>
528                               <cfcase value="7"> <!--- starts saturday, usually arabic, needs kludge --->
529                                       <cfset localeDays=arrayNew(1)>
530                                       <cfset localeDays[1]=tmp[7]> <!--- move saturday to first --->
531                                       <cfloop index="i" from="1" to="6">
532                                               <cfset localeDays[i+1]=tmp[i]>
533                                       </cfloop>
534                                       <cfreturn localeDays>
535                               </cfcase>
536                       </cfswitch>
537               </cfif>
538        </cffunction>
539        <!--- ************************************************************* --->
540
541        <!--- ************************************************************* --->
542        <cffunction name="getYear" output="No" access="public" returntype="numeric" hint="returns year from epoch offset">
543                <!--- ************************************************************* --->
544                <cfargument name="thisOffset"   required="Yes" hint="java epoch offset" type="numeric">
545                <cfargument name="tz"                   required="no" default="#instance.timeZone.getDefault().getID()#">
546                <!--- ************************************************************* --->
547               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
548               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
549               <cfset instance.aCalendar.setTimeZone(thisTZ)>
550               <cfreturn instance.aCalendar.get(instance.aCalendar.YEAR)>
551        </cffunction>
552        <!--- ************************************************************* --->
553
554        <!--- ************************************************************* --->
555        <cffunction name="getMonth" output="No" access="public" returntype="numeric" hint="returns month from epoch offset">
556                <!--- ************************************************************* --->
557                <cfargument name="thisOffset" required="Yes" hint="java epoch offset" type="numeric">
558                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
559                <!--- ************************************************************* --->
560               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
561               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
562               <cfset instance.aCalendar.setTimeZone(thisTZ)>
563               <cfreturn instance.aCalendar.get(instance.aCalendar.MONTH)+1> <!--- java months start at 0 --->
564        </cffunction>
565        <!--- ************************************************************* --->
566
567        <!--- ************************************************************* --->
568        <cffunction name="getDay" output="No" access="public" returntype="numeric" hint="returns day from epoch offset">
569                <!--- ************************************************************* --->
570                <cfargument name="thisOffset" required="Yes" hint="java epoch offset" type="numeric">
571                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
572                <!--- ************************************************************* --->
573               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
574               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
575               <cfset instance.aCalendar.setTimeZone(thisTZ)>
576               <cfreturn instance.aCalendar.get(instance.aCalendar.DATE)>
577        </cffunction>
578        <!--- ************************************************************* --->
579
580        <!--- ************************************************************* --->
581        <cffunction name="getHour" output="No" access="public" returntype="numeric" hint="returns hour of day, 24 hr format, from epoch offset">
582                <!--- ************************************************************* --->
583                <cfargument name="thisOffset" required="Yes" hint="java epoch offset" type="numeric">
584                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
585                <!--- ************************************************************* --->
586               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
587               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
588               <cfset instance.aCalendar.setTimeZone(thisTZ)>
589               <cfreturn instance.aCalendar.get(instance.aCalendar.HOUR_OF_DAY)>
590        </cffunction>
591        <!--- ************************************************************* --->
592
593        <!--- ************************************************************* --->
594        <cffunction name="getMinute" output="No" access="public" returntype="numeric" hint="returns minute from epoch offset">
595                <!--- ************************************************************* --->
596                <cfargument name="thisOffset" required="Yes" hint="java epoch offset" type="numeric">
597                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
598                <!--- ************************************************************* --->
599               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
600               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
601               <cfset instance.aCalendar.setTimeZone(thisTZ)>
602               <cfreturn instance.aCalendar.get(instance.aCalendar.MINUTE)>
603        </cffunction>
604        <!--- ************************************************************* --->
605
606        <!--- ************************************************************* --->
607        <cffunction name="getSecond" output="No" access="public" returntype="numeric" hint="returns second from epoch offset">
608                <!--- ************************************************************* --->
609                <cfargument name="thisOffset" required="Yes" hint="java epoch offset" type="numeric">
610                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
611                <!--- ************************************************************* --->
612               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
613               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
614               <cfset instance.aCalendar.setTimeZone(thisTZ)>
615               <cfreturn instance.aCalendar.get(instance.aCalendar.SECOND)>
616        </cffunction>
617        <!--- ************************************************************* --->
618
619        <!--- ************************************************************* --->
620        <cffunction name="toEpoch" access="public" output="no" returnType="numeric" hint="converts datetime to java epoch offset">
621                <cfargument name="thisDate" required="Yes" hint="datetime to convert to java epoch" type="date">
622               <cfreturn arguments.thisDate.getTime()>
623         </cffunction>
624        <!--- ************************************************************* --->
625
626        <!--- ************************************************************* --->
627        <cffunction name="fromEpoch" access="public" output="no" returnType="date" hint="converts java epoch offset to datetime">
628                <cfargument name="thisOffset" required="Yes" hint="java epoch offset to convert to datetime" type="numeric">
629               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
630               <cfreturn instance.aCalendar.getTime()>
631         </cffunction>
632        <!--- ************************************************************* --->
633
634        <!--- ************************************************************* --->
635        <cffunction name="getAvailableTZ" output="yes" returntype="array" access="public" hint="returns an array of timezones available on this server">
636                <cfreturn instance.timeZone.getAvailableIDs()>
637        </cffunction>
638        <!--- ************************************************************* --->
639
640        <!--- ************************************************************* --->
641        <cffunction name="usesDST" output="No" returntype="boolean" access="public" hint="determines if a given timezone uses DST">
642                <cfargument name="tz" required="no" default="#instance.timeZone.getDefault().getID()#">
643               <cfreturn instance.timeZone.getTimeZone(arguments.tz).useDaylightTime()>
644        </cffunction>
645        <!--- ************************************************************* --->
646
647        <!--- ************************************************************* --->
648        <cffunction name="getRawOffset" output="No" access="public" returntype="numeric" hint="returns rawoffset in hours">
649                <cfargument name="tZ" required="no" default="#instance.timeZone.getDefault().getID()#">
650               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tZ)>
651               <cfreturn thisTZ.getRawOffset()/3600000>
652        </cffunction>
653        <!--- ************************************************************* --->
654
655        <!--- ************************************************************* --->
656        <cffunction name="getDST" output="No" access="public" returntype="numeric" hint="returns DST savings in hours">
657                <cfargument name="thisTZ" required="no" default="#instance.timeZone.getDefault().getID()#">
658               <cfset var tZ=instance.timeZone.getTimeZone(arguments.thisTZ)>
659               <cfreturn tZ.getDSTSavings()/3600000>
660        </cffunction>
661        <!--- ************************************************************* --->
662
663        <!--- ************************************************************* --->
664        <cffunction name="getTZByOffset" output="No" returntype="array" access="public" hint="returns a list of timezones available on this server for a given raw offset">
665                <cfargument name="thisOffset" required="Yes" type="numeric">
666               <cfset var rawOffset=javacast("long",arguments.thisOffset * 3600000)>
667               <cfreturn instance.timeZone.getAvailableIDs(rawOffset)>
668        </cffunction>
669        <!--- ************************************************************* --->
670
671        <!--- ************************************************************* --->
672        <cffunction name="getServerTZ" output="No" access="public" returntype="any" hint="returns server TZ">
673               <cfset var serverTZ=instance.timeZone.getDefault()>
674               <cfreturn serverTZ.getDisplayName(true,instance.timeZone.LONG)>
675        </cffunction>
676        <!--- ************************************************************* --->
677
678        <!--- ************************************************************* --->
679        <cffunction name="inDST" output="No" returntype="boolean" access="public" hint="determines if a given date in a given timezone is in DST">
680                <!--- ************************************************************* --->
681                <cfargument name="thisOffset" required="yes" type="numeric">
682                <cfargument name="tzToTest" required="no" default="#instance.timeZone.getDefault().getID()#">
683                <!--- ************************************************************* --->
684               <cfset var thisTZ=instance.timeZone.getTimeZone(arguments.tzToTest)>
685               <cfset instance.aCalendar.setTimeInMillis(arguments.thisOffset)>
686               <cfset instance.aCalendar.setTimezone(thisTZ)>
687               <cfreturn thisTZ.inDaylightTime(instance.aCalendar.getTime())>
688        </cffunction>
689        <!--- ************************************************************* --->
690
691        <!--- ************************************************************* --->
692        <cffunction name="getTZOffset" output="No" access="public" hint="returns offset in hours">
693                <!--- ************************************************************* --->
694                <cfargument name="thisOffset" required="yes" type="numeric">
695                <cfargument name="thisTZ" required="no" default="#instance.timeZone.getDefault().getID()#">
696                <!--- ************************************************************* --->
697               <cfset var tZ=instance.timeZone.getTimeZone(arguments.thisTZ)>
698               <cfreturn tZ.getOffset(arguments.thisOffset)/3600000> <!--- return hours --->
699        </cffunction>
700        <!--- ************************************************************* --->
701
702        <!--- ************************************************************* --->
703        <cffunction name="i18nDateAdd" access="public" output="No" returntype="numeric">
704                <!--- ************************************************************* --->
705                <cfargument name="thisOffset" required="yes" type="numeric">
706                <cfargument name="thisDatePart" required="yes" type="string">
707                <cfargument name="dateUnits" required="yes" type="numeric">
708                <cfargument name="thisTZ" required="no" default="#instance.timeZone.getDefault().getID()#">
709                <!--- ************************************************************* --->
710               <cfscript>
711                       var dPart="";
712                       var tZ=instance.timeZone.getTimeZone(arguments.thisTZ);
713                       switch (arguments.thisDatepart) {
714                               case "y" :
715                               case "yr" :
716                               case "yyyy" :
717                               case "year" :
718                                       dPart=instance.aCalendar.YEAR;
719                               break;
720                               case "m" :
721                               case "month" :
722                                       dPart=instance.aCalendar.MONTH;
723                               break;
724                               case "w" :
725                               case "week" :
726                                       dPart=instance.aCalendar.WEEK_OF_MONTH;
727                               break;
728                               case "d" :
729                               case "day" :
730                                       dPart=instance.aCalendar.DATE;
731                               break;
732                               case "h" :
733                               case "hr":
734                               case "hour" :
735                                       dPart=instance.aCalendar.HOUR;
736                               break;
737                               case "n" :
738                               case "minute" :
739                                       dPart=instance.aCalendar.MINUTE;
740                               break;
741                               case "s" :
742                               case "second" :
743                                       dPart=instance.aCalendar.SECOND;
744                               break;
745                       }
746                       instance.aCalendar.setTimeInMillis(arguments.thisOffset);
747                       instance.aCalendar.setTimezone(tZ);
748                       instance.aCalendar.add(dPart,javacast("int",arguments.dateUnits));
749                       return instance.aCalendar.getTimeInMillis();
750               </cfscript>
751        </cffunction>
752        <!--- ************************************************************* --->
753
754        <!--- ************************************************************* --->
755        <!--- oh my is this nasty in core java --->
756        <cffunction name="i18nDateDiff"  access="public" output="No" returntype="numeric">
757                <!--- ************************************************************* --->
758                <cfargument name="thisOffset" required="yes" type="numeric">
759                <cfargument name="thatOffset" required="yes" type="numeric">
760                <cfargument name="thisDatePart" required="yes" type="string">
761                <cfargument name="thisTZ" required="no" default="#instance.timeZone.getDefault().getID()#">
762                <!--- ************************************************************* --->
763                <cfscript>
764                       var dPart="";
765                       var elapsed=0;
766                       var before=createObject("java","java.util.GregorianCalendar");
767                       var after=createObject("java","java.util.GregorianCalendar");
768                       var tZ=instance.timeZone.getTimeZone(arguments.thisTZ);
769                       var e=0;
770                       var s=0;
771                       var direction=1;
772                       // lets shortcut first
773                       if (arguments.thisOffset EQ arguments.thatOffset)
774                               return 0;
775                       else {  // setup calendars to test
776                               if (arguments.thisOffset LT arguments.thatOffset) {
777                                       before.setTimeInMillis(arguments.thisOffset);
778                                       after.setTimeInMillis(arguments.thatOffset);
779                                       before.setTimezone(tZ);
780                                       after.setTimezone(tZ);
781                               } else {
782                                       before.setTimeInMillis(arguments.thatOffset);
783                                       after.setTimeInMillis(arguments.thisOffset);
784                                       before.setTimezone(tZ);
785                                       after.setTimezone(tZ);
786                                       direction=-1;
787                               } // which offset came first
788                               switch (arguments.thisDatepart) {
789                                       case "y" :
790                                       case "yr" :
791                                       case "yyyy" :
792                                       case "year" :
793                                               dPart=instance.aCalendar.YEAR;
794                                               before.clear(instance.aCalendar.DATE);
795                                               after.clear(instance.aCalendar.DATE);
796                                               before.clear(instance.aCalendar.MONTH);
797                                               after.clear(instance.aCalendar.MONTH);
798                                       break;
799                                       case "m" :
800                                       case "month" :
801                                               dPart=instance.aCalendar.MONTH;
802                                               before.clear(instance.aCalendar.DATE);
803                                               after.clear(instance.aCalendar.DATE);
804                                       break;
805                                       case "w" :
806                                       case "week" :
807                                               dPart=instance.aCalendar.WEEK_OF_YEAR;
808                                               before.clear(instance.aCalendar.DATE);
809                                               after.clear(instance.aCalendar.DATE);
810                                       break;
811                                       case "d" :
812                                       case "day" :
813                                               // very much a special case
814                                               e=after.getTimeInMillis()+after.getTimeZone().getOffset(after.getTimeInMillis());
815                                               s=before.getTimeInMillis()+before.getTimeZone().getOffset(before.getTimeInMillis());
816                                               return int((e-s)/86400000)*direction;
817                                       break;
818                                       case "h" :
819                                       case "hr" :
820                                       case "hour" :
821                                               e=after.getTimeInMillis()+after.getTimeZone().getOffset(after.getTimeInMillis());
822                                               s=before.getTimeInMillis()+before.getTimeZone().getOffset(before.getTimeInMillis());
823                                               return int((e-s)/3600000)*direction;
824                                       break;
825                                       case "n" :
826                                       case "minute" :
827                                               e=after.getTimeInMillis()+after.getTimeZone().getOffset(after.getTimeInMillis());
828                                               s=before.getTimeInMillis()+before.getTimeZone().getOffset(before.getTimeInMillis());
829                                               return int((e-s)/60000)*direction;
830                                       break;
831                                       case "s" :
832                                       case "second" :
833                                               e=after.getTimeInMillis()+after.getTimeZone().getOffset(after.getTimeInMillis());
834                                               s=before.getTimeInMillis()+before.getTimeZone().getOffset(before.getTimeInMillis());
835                                               return int((e-s)/1000)*direction;
836                                       break;
837                               }// datepart switch
838                               while (before.before(after)){
839                                       before.add(dPart,1);
840                                       elapsed=elapsed+1;
841                               } //count dateparts
842                               return elapsed * direction;
843                       } // if start & end times are the same
844                </cfscript>
845        </cffunction>
846        <!--- ************************************************************* --->
847
848        <!--- ************************************************************* --->
849        <cffunction name="getVersion" access="public" output="false" returntype="struct" hint=" returns version of this CFC and icu4j library it uses.">
850                <cfset var version=StructNew()>
851                <cfset var sys=createObject("java","java.lang.System")>
852                <cfset version.I18NUtilVersion=instance.pluginVersion>
853                <cfset version.I18NUtilDate=instance.I18NUtilDate>
854                <cfset version.javaRuntimeVersion=sys.getProperty("java.runtime.version")>
855                <cfset version.javaVersion=sys.getProperty("java.version")>
856                <cfreturn version>
857        </cffunction>
858        <!--- ************************************************************* --->
859<!------------------------------------------- PRIVATE ------------------------------------------->
860
861        <!--- ************************************************************* --->
862        <cffunction name="buildLocale"  access="private" output="false"hint="creates valid core java locale from java style locale ID">
863                <!--- ************************************************************* --->
864                <cfargument name="thisLocale" required="yes" type="string">
865                <!--- ************************************************************* --->
866                <cfscript>
867                       var l=listFirst(arguments.thisLocale,"_");
868                       var c="";
869                       var v="";
870                       var tLocale=instance.aLocale.getDefault(); // if we fail fallback on server default
871                       switch (listLen(arguments.thisLocale,"_")) {
872                       case 1:
873                               tLocale=instance.aLocale.init(l);
874                       break;
875                       case 2:
876                               c=listLast(arguments.thisLocale,"_");
877                               tLocale=instance.aLocale.init(l,c);
878                       break;
879                       case 3:
880                               c=listGetAt(arguments.thisLocale,2,"_");
881                               v=listLast(arguments.thisLocale,"_");
882                               tLocale=instance.aLocale.init(l,c,v);
883                       break;
884                       }
885                       return tLocale;
886                </cfscript>
887        </cffunction>
888        <!--- ************************************************************* --->
889
890
891</cfcomponent>
Note: See TracBrowser for help on using the browser.