2021SC@SDUSC山东大学软件学院软件工程应用与实践 COCOON 第三篇

这篇博客探讨了i18n(国际化)的实现,重点介绍了I18nUtils类,它提供了查找和解析语言环境的方法。此外,XMLResourceBundle类详细解释了如何存储和读取XML格式的消息包,以及XMLResourceBundleFactory如何根据指定条件获取和创建资源包。内容涵盖了从HTTP请求、会话、cookie和参数中检索语言环境,以及处理XML资源包的加载和更新。
摘要由CSDN通过智能技术生成

2021SC@SDUSC

i18n:

i18n为internationalization的缩写,为国际化的实现。该包中有两个接口文件,分别为Bundle和BundleFactory,另外有一个I18nUtils类提供i18n格式化和解析路由的实用程序类。

I18nUtils:

在I18nUtils类中,提供的方法一共可以看作4个,逐个分析。

首先是findLocate方法,需要提供的参数有objectModel, attribute, parameters, defaultLocale, useLocate, useLocales, useBlankLocale以及test,并且对该方法进行了重载,重载后的方法减少了三个参数,转而使用默认值,默认useLocales和useBlankLocale为false,test为空。

public static Locale findLocale(Map objectModel,
                                    String attribute,
                                    Parameters parameters,
                                    Locale defaultLocale,
                                    boolean useLocale,
                                    boolean useLocales,
                                    boolean useBlankLocale,
                                    LocaleValidator test) {
        String localeStr;
        Locale locale;

        Request request = ObjectModelHelper.getRequest(objectModel);

        localeStr = request.getParameter(attribute);
        if (localeStr != null) {
            locale = parseLocale(localeStr);
            if (test == null || test.test("request", locale)) {
                return locale;
            }
        }

        HttpSession session = request.getSession(false);
        if (session != null &&
                ((localeStr = (String) session.getAttribute(attribute)) != null)) {
            locale = parseLocale(localeStr);
            if (test == null || test.test("session", locale)) {
                return locale;
            }
        }

        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals(attribute)) {
                    localeStr = cookie.getValue();
                    locale = parseLocale(localeStr);
                    if (test == null || test.test("cookie", locale)) {
                        return locale;
                    }
                    break;
                }
            }
        }

        if (parameters != null) {
            localeStr = parameters.getParameter("locale", null);
            if (localeStr != null) {
                locale = parseLocale(localeStr);
                if (test == null || test.test("sitemap", locale)) {
                    return locale;
                }
            }
        }
        if (useLocale && !useLocales) {
            locale = request.getLocale();
            if (test == null || test.test("request", locale)) {
                return locale;
            }
        }

        if (useLocales) {
            Enumeration locales = request.getLocales();
            while (locales.hasMoreElements()) {
                locale = (Locale)locales.nextElement();
                if (test == null || test.test("request", locale)) {
                    return locale;
                }
            }
        }

        if (defaultLocale != null) {
            locale = defaultLocale;
            if (test == null || test.test("default", locale)) {
                return locale;
            }
        }

        if (useBlankLocale) {
            locale = new Locale("", "");
            if (test == null || test.test("blank", locale)) {
                return locale;
            }
        }
 
        return null;
    }

findLocale方法从objectModel中寻找合适的语言环境,在该方法中,分别对request, session, cookie, sitemap,本地设置浏览器和服务器默认值等返回。

parseLocale同样进行了重载,都需要给出语言环境字符,如果给定语言环境则若字符串为空返回给定的语言环境,若不给定,则会返回VM默认环境。

storeLocale方法在请求,会话或cookie中存储Locale,在参数中通过布尔值设置存储在什么位置,根据设置的参数将给定的Locale存储。

该类中提供的最后一个方法为matchesI18nNamespace,通过该方法对i18n的命名空间进行匹配。

XMLResourceBundle:

该方法实现了Bundle接口,用来表示单个的XML消息包,实现了如下的XML格式:

<catalogue xml:lang="en">
   <message key="key1">Message <br/> Value 1</message>
   <message key="key2">Message <br/> Value 1</message>
   ...
 </catalogue>

通过key来指示值,返回的对象为ParamSaxBuffer的实例,如果此包中不存在键的值,则查询父包。

该类提供了reload, getLocale, getSourceURI, getValidity, getObject,getString 方法,其中的get方法都容易理解,都是根据需要返回所需要的值。

reload方法根据 source URI 重新加载XML包,

 protected boolean reload(SourceResolver resolver, long interval) {
        Source newSource = null;
        Map newValues;

        try {
            int valid = this.validity == null ? SourceValidity.INVALID : this.validity.isValid();
            if (valid != SourceValidity.VALID) {
                newSource = resolver.resolveURI(this.sourceURI);
                SourceValidity newValidity = newSource.getValidity();

                if (valid == SourceValidity.INVALID || this.validity.isValid(newValidity) != SourceValidity.VALID) {
                    newValues = new HashMap();
                    SourceUtil.toSAX(newSource, new SAXContentHandler(newValues));
                    synchronized (this) {
                        if (interval > 0 && newValidity != null) {
                            this.validity = new DelayedValidity(interval, newValidity);
                        } else {
                            this.validity = newValidity;
                        }
                        this.values = newValues;
                    }
                }
            }

            return true;

        } catch (MalformedURLException e) {
            getLogger().error("Bundle <" + this.sourceURI + "> not loaded: Invalid URI", e);
            newValues = Collections.EMPTY_MAP;

        } catch (ResourceNotFoundException e) {
            if (getLogger().isDebugEnabled()) {
                getLogger().info("Bundle <" + sourceURI + "> not loaded: Source URI not found", e);
            } else if (getLogger().isInfoEnabled()) {
                getLogger().info("Bundle <" + sourceURI + "> not loaded: Source URI not found");
            }
            newValues = Collections.EMPTY_MAP;

        } catch (SourceNotFoundException e) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("Bundle <" + sourceURI + "> not loaded: Source URI not found");
            }
            newValues = Collections.EMPTY_MAP;

        } catch (CascadingIOException e) {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("Bundle <" + sourceURI + "> not loaded: Source URI not found");
            }
            newValues = Collections.EMPTY_MAP;

        } catch (SAXException e) {
            getLogger().error("Bundle <" + sourceURI + "> not loaded: Invalid XML", e);
            newValues = this.values;

        } catch (Exception e) {
            getLogger().error("Bundle <" + sourceURI + "> not loaded: Exception", e);
            newValues = this.values;

        } finally {
            if (newSource != null) {
                resolver.release(newSource);
            }
        }

        synchronized (this) {
            if (interval > 0) {
                this.validity = new ExpiresValidity(interval);
            } else {
                this.validity = null;
            }
            this.values = newValues;
        }

        return false;
    }

若保存的validity不是有效的则获取新的source和validity,同时施加了同步锁,确保代码就会以原子的方式执行,当多个线程在执行这段代码的时候,它们是互斥的,不会相互干扰,不会同时执行。

后续代码则是对各种异常的捕获。

该类中,还包含一个私有类,SAXContentHandler控制XML bundle和创建映射。

XMLResourceBundleFactory:

该类实现了BundleFactory接口,同时实现了设置,回收,接口可维护以及线程安全。

该类提供了多个get方法,可以获取目录,父级语言环境,缓存键, sourceURI,同时提供了更新缓存方法。

该类对select方法进行了重载,可以通过多种不同参数调用,而最终,select方法调用自身的私有方法_select返回bundle,首先从缓存中查找,若未找到,则会从父bundle中寻找,寻找时会进行对自身的递归调用,逐层遍历,若遍历完本层,则会寻找父Locale,最后将找到的结果返回。

_create方法同样作为私有方法,是供_select使用,创建bundle。

在获取缓存键方法中,同样使用了index记录当前的位置,通过递归来获取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值