當resource bundle 的多語言檔案裡包含引號'時

eaglelihh發表於2022-11-23

背景

專案中使用Spring的ReloadableResourceBundleMessageSource這個類來實現多語言,有一次字串裡包含引號'時,解析時出了問題,一起來看一下吧

例子

resources下包含三個語言檔案

分別是:
bundle_zh_CN.properties
hello=你好嗎?{0}

bundle_zh_TW.properties
hello=你好嗎?{0}

bundle_en.properties
hello=how are you ? {0}
測試類:
public class Main {
    public static void main(String[] args) throws UnsupportedEncodingException {
        System.out.println(getMessage("hello", new Object[] {"輝"}, Locale.CHINA));
        System.out.println(getMessage("hello", new Object[] {"輝"}, Locale.TRADITIONAL_CHINESE));
        System.out.println(getMessage("hello", new Object[] {"hui"}, Locale.ENGLISH));
    }

    public static String getMessage(String code, Object[] args, Locale locale) {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
        messageSource.setBasename("bundle");
        messageSource.setCacheSeconds(1800);
        return messageSource.getMessage(code, args, locale);
    }
}

輸出:
你好嗎?輝
你好嗎?輝
how are you ? hui

可以看出沒什麼問題

如果含有引號'

改成:
bundle_zh_CN.properties
hello=你好'嗎?{0}

bundle_zh_TW.properties
hello=你好'嗎?{0}

bundle_en.properties
hello=how are' you ? {0}
輸出結果:
你好嗎?{0}
你好嗎?{0}
how are you ? {0}

可以看出如果含有引號',引數不起作用,而且引號'也沒顯示出來

原因

MessageFormat messageFormat = resolveCode(code, locale);
if (messageFormat != null) {
	synchronized (messageFormat) {
		return messageFormat.format(argsToUse);
	}
}

追蹤原始碼,底層是由Java底層的MessageFormat來實現的

API中解釋如下:
Within a String, a pair of single quotes can be used to quote any arbitrary characters except single quotes. 
For example, pattern string "'{0}'" represents string "{0}", not a FormatElement. 
A single quote itself must be represented by doubled single quotes '' throughout a String. 
For example, pattern string "'{''}'" is interpreted as a sequence of '{ (start of quoting and a left curly brace), '' (a single quote), and }' (a right curly brace and end of quoting), not '{' and '}' (quoted left and right curly braces): representing string "{'}", not "{}".

Any unmatched quote is treated as closed at the end of the given pattern. For example, pattern string "'{0}" is treated as pattern "'{0}'".

大概意思就是:
- 兩個單引號裡面的值保持不變,不會被格式化
- 如果想輸出單引號,使用兩個單引號'' 來輸出單引號'
- 如果只有一個單引號,那麼單引號後面的值就原封不動的輸出來,即不會被格式化

修改

改成:
bundle_zh_CN.properties
hello=你好''嗎?{0}

bundle_zh_TW.properties
hello=你好''嗎?{0}

bundle_en.properties
hello=how are'' you ? {0}

輸出結果:
你好'嗎?輝
你好'嗎?輝
how are' you ? hui
還有一點需要注意的就是:在沒有引數的情況下,如果想輸出引號,那就用一個引號即可,如下:
bundle_zh_CN.properties
hello=你好'嗎?

bundle_zh_TW.properties
hello=你好'嗎?

bundle_en.properties
hello=how are' you ?
public static void main(String[] args) throws UnsupportedEncodingException {
    System.out.println(getMessage("hello", null, Locale.CHINA));
    System.out.println(getMessage("hello", null, Locale.TRADITIONAL_CHINESE));
    System.out.println(getMessage("hello", null, Locale.ENGLISH));
}

輸出:
你好'嗎?
你好'嗎?
how are' you ?

相關文章