国际化程序实现原理

笑着哭i 提交于 2020-02-29 12:04:37


所谓的国际化的程序指的是同一个程序代码可以根据不同的国家实现不同的语言描述,但是程序处理的核心业务是相同的

国际化问题简介

现在假设有一款世界都认可的企业管理平台,那么这个企业的老板决定将这个产品呢推广到全世界各个大型的上市公司,于是这些公司可能来自于:中国、美国、德国等等等等,那么在这样的情况下,首先要考虑的问题是什么呢?
在这里插入图片描述
通过分析之后可以发现,如果要想实现国际化的程序开发,那么要解决的问题就在于以下两点:

  • 如何可以定义保存文字的文件信息
  • 如何可以根据不同的区域语言的编码读取指定的资源信息

Locale 类

通过分析可以发现,如果要想实现国际化,那么首先需要解决的就是不同国家用户的区域和语言编码的问题,而在 java.util 包中提供有一个专门描述区域和语言编码的类: Locale,而后可以主要可以使用 Locale 类中的两个构造方法进行实例化

Locale 类的构造方法:

  • 构造方法:public Locale(String language)
  • 构造方法:public Locale(String language, String country)

此时需要的是国家和语言的代码,而中文的代码:zh_CN、美国英语的代码是en_US

举例:(实例化 Locale 类对象)

package com.java.springtest.international;

import java.util.Locale;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        // 中文环境
        Locale locale = new Locale("zh","CN");
        System.out.println(locale);
    }
}

输出:
在这里插入图片描述
但这是手动的选择语言,如果说现在要想自动获得当前的运行环境,那么现在就可以利用 Locale 类本身默认的方式进行实例化

  • 读取本地默认环境:public static Locale getDefault()
package com.java.springtest.international;

import java.util.Locale;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        // 获取默认环境
        Locale locale = Locale.getDefault();
        System.out.println(locale);
    }
}

输出:
在这里插入图片描述
在实际的开发过程之中,很多人可能并不关心国家和语言的编码,所以为了简化开发,Locale 类也将世界上一些比较著名的国家的编码设置为了常量

package com.java.springtest.international;

import java.util.Locale;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        // 使用 Locale 类的常量
        Locale locale = Locale.CHINA;
        System.out.println(locale);
    }
}

在这里插入图片描述
为什么能根据常量够获取呢?打开 Locale 的源码发现,它也是自己定义的

static public final Locale CHINA = SIMPLIFIED_CHINESE;
static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");

使用常量的优势在于可以避免一些区域编码信息的繁琐

读取资源文件:ResourceBundle

要进行资源文件的读取操作主要依靠的是 java.util.ResourceBundle 类完成,此类定义如下:

public abstract class ResourceBundle extends Object

可以发现 ResourceBundle 是一个抽象类,如果现在想要进行此类对象的实例化可以直接利用该类中提供的一个 static 静态方法完成:

  • 获取 ResourceBundle 类对象:public static final ResourceBundle getBundle(String baseName)
    • -baseName:描述的是资源文件的名称,但是没有后缀(com.java.springtest.message.Message
  • 读取资源内容(根据 key 读取):public final String getString(String key)

举例:使用 ResourceBundle 类读取内容

首先先编写一个简单的资源文件,如下(注意,该资源文件需要放到资源路径 classpath 路径下):
在这里插入图片描述
代码实现:

package com.java.springtest.international;

import java.util.ResourceBundle;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
    	// Message 不需要后缀,如果资源没有放在包里面,则直接编写资源名称即可
        ResourceBundle resourceBundle = ResourceBundle.getBundle("Message");
        // 根据 key 获取内容
        String info = resourceBundle.getString("info");
        // 打印输出
        System.out.println(info);
    }
}

在这里插入图片描述
在进行资源读取的时候数据 key 一定要存在,如果不存在,则会出现以下异常信息,如下:

package com.java.springtest.international;

import java.util.ResourceBundle;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        ResourceBundle resourceBundle = ResourceBundle.getBundle("Message");
        String info = resourceBundle.getString("inFo");
        System.out.println(info);
    }
}
Exception in thread "main" java.util.MissingResourceException: 
Can't find resource for bundle java.util.PropertyResourceBundle, key inFo

实现国家化程序

也就是说依靠资源文件、Locale、ResourceBundle 类就可以实现国际化的处理操作,那么下面来进行国际化的程序实现(核心关键:读取资源信息)

举例:(代码实现)

1、在 classpath 下建立一个 com.java.springtest.message.Message_zh_CN.properties(中文资源)

info = 欢迎您的访问!

2、在 classpath 下建立一个 com.java.springtest.message.Message_en_US.properties(英文资源)

info = Welcome!

现在加上没有默认的区域的资源文件,一共定义了三个资源文件
在这里插入图片描述
3、通过程序进行指定区域的资源信息加载

package com.java.springtest.international;

import java.util.ResourceBundle;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        ResourceBundle resourceBundle = ResourceBundle.getBundle("Message");
        String info = resourceBundle.getString("info");
        System.out.println(info);
    }
}

此时再次利用 ResourceBundle 类读取资源的时候并没有设置一个明确的 Locale 对象,但是 发现 Message_zh_CN 的文件起作用了,为什么不是 Message 呢?因为这个方法里面默认加载的就是当前本地的 Locale 的资源:

// Locale 类中的 getBundle() 方法
@CallerSensitive
    public static final ResourceBundle getBundle(String baseName)
    {
    	// 获取当前的资源
        return getBundleImpl(baseName, Locale.getDefault(),
                             getLoader(Reflection.getCallerClass()),
                             getDefaultControl(baseName));
    }

4、如果现在有需要也可以修改当前的 Locale 环境,则可以使用 ResourceBundle 类中的如下方法:

  • 获取 ResourceBundle:public static final ResourceBundle getBundle(String baseName,
    Locale locale)
package com.java.springtest.international;

import java.util.Locale;
import java.util.ResourceBundle;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        Locale locale = new Locale("en","US");
        ResourceBundle resourceBundle = ResourceBundle.getBundle("Message",locale);
        String info = resourceBundle.getString("info");
        System.out.println(info);
    }
}

输出:
在这里插入图片描述
如果现在有指定区域的资源文件存在的时候,那么没有设置区域的资源文件的信息将不会被读取

资源文件的读取顺序:读取指定区域的资源文件 > 默认的本地资源 > 公共的资源(没有设置区域的)

消息格式化

如果说现在某一位用户登录成功了,那么一般都会显示这样的信息 "XXX,欢迎您 ",也就是说这个时候会显示用户名,那么此时如果这些内容保存在了资源文件里面,则就需要通过占位符来进行描述,同时对于读取出来的数据也需要进行消息格式化的处理

举例:(修改资源文件)

资源名称 资源信息
中文资源文件】com.java.springtest.message.Message_zh_CN.properties info = 欢迎{0}的访问,当前日期是{1}
英文资源文件】com.java.springtest.message.Message_en_US.properties info = Welcome{0},date:{1}

如果有需要则可以继续添加 {1}、{2} 之类的内容

此时如果要进行资源的读取则会将占位符的信息一起读取出来,所以此时就需要利用 MessageFormat 类进行格式化处理
在这里插入图片描述
在 MessageFormat 中提供了一个格式化文本的方法:public static String format(String pattern,
Object… arguments)

举例:(格式化文本实现国际化)

package com.java.springtest.international;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;

/**
 * @author Woo_home
 * @create by 2020/1/30
 */
public class JavaAPIDemo {
    public static void main(String[] args) {
        Locale locale = new Locale("en","US");
        ResourceBundle resourceBundle = ResourceBundle.getBundle("Message",locale);
        String info = resourceBundle.getString("info");
        System.out.println(MessageFormat.format(info,"international",new SimpleDateFormat("yyyy-MM-dd").format(new Date())));
    }
}

在这里插入图片描述
如果在开发中遇到资源文件里面有 {0}、{1} 的结构表示的都是占位符,该信息一定都要进行格式化处理

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!