一、特殊名词介绍

二、背景、场景介绍

帆软决策平台和报表中产品可以通过浏览器自身的语言配置或在URL中指定对应的国际化标志参数来实现一套系统面对不同的使用者,提供不同语言显示的国际化服务。

但也存在两种场景,无法覆盖:

1.浏览器本身的语言包设置不规范,导致后台无法识别出当前的浏览器语言

2.用户本身不希望国际化。

WebLocaleProvider主要用于解决这两个问题。

三、接口介绍

package com.fr.stable.fun;

import com.fr.stable.fun.mark.Mutable;

import java.util.Locale;

/**
 * 处理一些自定义的locale字符串;
 * 比如常规的应该是ko_KR, ja_JP, 但是有的浏览器语言包不规范,
 * 会返回成ko, ja这种.
 *
 * Created by Administrator on 2016/8/17/0017.
 */
public interface WebLocaleProvider extends Mutable{

    String XML_TAG = "WebLocaleProvider";

    int CURRENT_LEVEL = 1;

    Locale dispatchLocale(String localeStr);

}


四、支持版本

产品线

版本

支持情况

备注

FR8.0支持
FR9.0支持
FR10.0支持
BI3.6支持
BI4.0支持
BI5.1支持
BI5.1.2支持
BI5.1.3支持

五、插件注册

<extra-core>
        <WebLocaleProvider class="your class name"/>
</extra-core>


六、原理说明

package com.fr.general;

...
public class GeneralUtils {
    ...

    /**
     * 根据字符串生成指定的语言对象
     * 如果字符串为空, 则返回英文
     *
     * @param localeStr 用于表示语言和国家的字符串
     * @return 语言对象
     */
    public static Locale createLocale(String localeStr) {
        return createLocale(localeStr, Locale.US);
    }

    /**
     * 根据字符串生成指定的语言对象
     *
     * @param localeStr 用于表示语言和国家的字符串
     * @param defaulVal 如果字符串为空, 则返回默认值
     * @return 语言对象
     */
    public static Locale createLocale(String localeStr, Locale defaulVal) {
        ExtraClassManagerProvider provider = StableFactory.getMarkedObject(ExtraClassManagerProvider.XML_TAG, ExtraClassManagerProvider.class);
        if (provider != null) {
            Set<WebLocaleProvider> set = provider.getArray(WebLocaleProvider.XML_TAG);
            Locale locale;
            for (WebLocaleProvider localeProvider : set) {
                locale = localeProvider.dispatchLocale(localeStr);
                if (locale != null) {
                    return locale;
                }
            }
        }

        return LocaleType.parse(localeStr, defaulVal);
    }
   ...
}


package com.fr.general;

import com.fr.stable.StringUtils;

import java.util.Locale;

/**
 * 自定义locale类
 * 浏览器有时返回的locale并不是标准的zh_CN, ja_JP这种格式, 可能只有zh, ja.
 *
 * Win8 IE10后的语言包, 中文不再返回zh_CN, 而是根据不同的语言包返回的不一样的,
 * 有zh_HANS, zh_HANS_CN, zh_HANS-CN, zh_HANS-HK等等.S代表Simplified
 * 2016-7-26 新增zh_CN_#Hans tomcat8 + ie11
 *
 * Created by Administrator on 2016/8/17/0017.
 */
public enum LocaleType {

    JA {
        @Override
        public String localeDescription() {
            return "JA";
        }

        @Override
        public Locale getLocale() {
            return Locale.JAPAN;
        }
    },
    KO {
        @Override
        public String localeDescription() {
            return "KO";
        }

        @Override
        public Locale getLocale() {
            return Locale.KOREA;
        }
    },
    HANS {
        @Override
        public String localeDescription() {
            return "HANS";
        }

        @Override
        public Locale getLocale() {
            return Locale.CHINA;
        }
    },
    HANT {
        @Override
        public String localeDescription() {
            return "HANT";
        }

        @Override
        public Locale getLocale() {
            return Locale.TAIWAN;
        }
    },
    RU {
        @Override
        public String localeDescription() {
            return "RU";
        }

        @Override
        public Locale getLocale() {
            return new Locale("ru", "RU");
        }

    },
    UZ {
        @Override
        public String localeDescription() {
            return "UZ";
        }

        @Override
        public Locale getLocale() {
            return new Locale("uz", "UZ");
        }
    };

    /**
     * 获取指定字符串对应的国际化语言
     *
     * @param localeStr 国际化字符串
     *
     * @return parse后的国际化
     */
    public static Locale parse(String localeStr) {
        return parse(localeStr, Locale.US);
    }

    /**
     * 获取指定字符串对应的国际化语言
     *
     * @param localeStr 国际化字符串
     * @param defaultVal 如果parse失败, 返回默认locale
     *
     * @return parse后的国际化
     */
    public static Locale parse(String localeStr, Locale defaultVal) {
        if (StringUtils.isEmpty(localeStr)) {
            if (defaultVal == null) {
                return null;
            }
            // 兼容之前没有参数, 直接从req转的locale
            localeStr = String.valueOf(defaultVal);
        }

        for (LocaleType type : values()) {
            if (localeStr.toUpperCase().indexOf(type.localeDescription()) != -1){
                return type.getLocale();
            }
        }

        String[] arr = localeStr.split("_");
        if (arr.length > 1) {
            return new Locale(arr[0], arr[1]);
        } else {
            return new Locale(arr[0], StringUtils.EMPTY);
        }
    }

    /**
     * 获取当前字符串对应的locale
     *
     * @return 国际化语言
     */
    public Locale getLocale() {
        return Locale.US;
    }

    /**
     * 获取当前国际化的字符描述
     *
     * @return 国际化的字符描述
     */
    public String localeDescription() {
        return StringUtils.EMPTY;
    }

}


package com.fr.web.utils;
...
public class WebUtils {
	...
	/**
     * 获取req中的国际化信息
     *
     * @param req HTTP请求
     * @return 国际化语言
     * @date 2014-12-1-下午4:39:44
     */
    public static Locale getLocale(HttpServletRequest req) {
        if (req == null) {
            return GeneralContext.getLocale();
        }

        //开放给客户的是fr_locale, 我们内部代码里js还有__fr__locale__
        String localeStr = WebUtils.getHTTPRequestParameter(req, Constants.__FR_LOCALE__);
        localeStr = localeStr == null ? WebUtils.getHTTPRequestParameter(req, "__fr_locale__") : localeStr;

        //性能, 优先处理并发最常规的.
        if (StringUtils.isEmpty(localeStr) && "zh_CN".equals(String.valueOf(req.getLocale()))) {
            return Locale.CHINA;
        }

        return GeneralUtils.createLocale(replaceScript4Xss(localeStr), req.getLocale());
    }
	...
}


七、特殊限制说明

WebLocaleProvider#dispatchLocale 接口主要用于把语言标志参数转换成实际的国际化对象。

从WebUtils.getLocale 方法中可以看出,如果浏览器自身的语言设置是zh_CN,而又没有传递__fr_locale__或fr_locale参数指定国际化标志,那么WebLocaleProvider接口将不会生效!

也就是对于浏览器配置的语言是zh_CN的,必须通过__fr_locale__或fr_locale参数才能使WebLocaleProvider接口生效!(对于国内大陆地区绝大部分用户来说,这个接口的作用就微乎其微了!)

八、常用链接

demo地址:demo-web-locale-provider

九、开源案例

免责声明:所有文档中的开源示例,均为开发者自行开发并提供。仅用于参考和学习使用,开发者和官方均无义务对开源案例所涉及的所有成果进行教学和指导。禁止用于任何商业用途,若作为商用一切后果责任由使用者自行承担。