public static String i18n(ITemplate template, Object key, Object... args) {
        String k = string(key);
        if (null != template) {
            II18nMessageResolver resolver = template.__engine().conf().i18nMessageResolver();
            if (null != resolver && II18nMessageResolver.DefaultImpl.INSTANCE != resolver) {
                return resolver.getMessage(template, k, args);
            }
        }
        boolean useFormat = args.length > 0;
        Locale locale = null;
        if (useFormat) {
            // check if the first arg is locale
            Object arg0 = args[0];
            if (arg0 instanceof Locale) {
                locale = (Locale)arg0;
                Object[] args0 = new Object[args.length - 1];
                System.arraycopy(args, 1, args0, 0, args.length - 1);
                args = args0;
                useFormat = args.length > 0;
            }
        }
        if (null == locale) locale = I18N.locale(template);
        RythmEngine engine = null == template ? RythmEngine.get() : template.__engine();
        String cacheKey = null;
        if (null != template && null != locale) {
            cacheKey = CacheKey.i18nMsg(template, k, useFormat, locale);
            Object cached = engine.cached(cacheKey);
            if (S.notEmpty(cached)) return S.str(cached);
        }
        ResourceBundle bundle;
        for (String msgSrc: RythmConfiguration.get().messageSources()) {
            bundle = I18N.bundle(template, msgSrc, locale);
            if (null != bundle) {
                String data = getMessage(template, bundle, k, locale, args);
                if (null != data) {
                    if (null != engine) {
                        engine.cache(cacheKey, data, -1);
                    }
                    return data;
                }
            }
        }
        return k;
    }
public static String i18n ( ITemplate template , Object key , Object ... args ) { String k = string ( key ) ; if ( null != template ) { II18nMessageResolver resolver = template . __engine ( ) . conf ( ) . i18nMessageResolver ( ) ; if ( null != resolver && II18nMessageResolver . DefaultImpl . INSTANCE != resolver ) { return resolver . getMessage ( template , k , args ) ; } } boolean useFormat = args . length > 0 ; Locale locale = null ; if ( useFormat ) { Object arg0 = args [ 0 ] ; if ( arg0 instanceof Locale ) { locale = ( Locale ) arg0 ; Object [ ] args0 = new Object [ args . length - 1 ] ; System . arraycopy ( args , 1 , args0 , 0 , args . length - 1 ) ; args = args0 ; useFormat = args . length > 0 ; } } if ( null == locale ) locale = I18N . locale ( template ) ; RythmEngine engine = null == template ? RythmEngine . get ( ) : template . __engine ( ) ; String cacheKey = null ; if ( null != template && null != locale ) { cacheKey = CacheKey . i18nMsg ( template , k , useFormat , locale ) ; Object cached = engine . cached ( cacheKey ) ; if ( S . notEmpty ( cached ) ) return S . str ( cached ) ; } ResourceBundle bundle ; for ( String msgSrc : RythmConfiguration . get ( ) . messageSources ( ) ) { bundle = I18N . bundle ( template , msgSrc , locale ) ; if ( null != bundle ) { String data = getMessage ( template , bundle , k , locale , args ) ; if ( null != data ) { if ( null != engine ) { engine . cache ( cacheKey , data , - 1 ) ; } return data ; } } } return k ; }
<p>Return i18n message of a given key and args, use the locale info from the template specified.
if <tt>null</tt> template instance passed in then it will try to guess from the current engine via
{@link org.rythmengine.RythmEngine#get()}</p>

@param template
@param key
@param args the format arguments. If the first argument is of type Locale then it will be used to specify
the locale of the processing, and the rest elements are used as format arguments
@return the i18n message