国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開發(fā) > Java > 正文

解決Spring國(guó)際化文案占位符失效問題的方法

2024-07-14 08:40:23
字體:
供稿:網(wǎng)友

寫在前面:接下來很長(zhǎng)一段時(shí)間的文章主要會(huì)記錄一些項(xiàng)目中實(shí)際遇到的問題及對(duì)應(yīng)的解決方案,在相應(yīng)代碼分析時(shí)會(huì)直指問題所在,不會(huì)將無關(guān)的流程代碼貼出,感興趣的讀者可以自行跟蹤。同時(shí)希望大家能夠?qū)⑿牡皿w會(huì)在評(píng)論區(qū)分享出來,讓大家共同進(jìn)步!

環(huán)境或版本:Spring 3.2.3

現(xiàn)象:利用Spring自帶的MessageSource來處理國(guó)際化文案,us狀態(tài)下的文案有部分占位符未被替換,cn狀態(tài)下的正常。文案如下:

tms.pallet.order.box.qty=The total palletized boxes quantity {0} doesn't match with the received boxes quantity {1},Please double check!
tms.pallet.order.box.qty=打板總箱數(shù)件{0},與訂單收貨總箱數(shù){1}不一致。請(qǐng)檢查!

直覺:是不是英文文案太長(zhǎng)了,Spring處理時(shí)對(duì)長(zhǎng)度做了限制,仔細(xì)想了想Spring應(yīng)該不會(huì)設(shè)計(jì)的這么坑。

排查:斷點(diǎn)跟蹤Spring源碼(入口:MessageSource的getMessage方法),最后發(fā)現(xiàn)了MessageFormat中這樣的一段處理方法:

 // Indices for segments  private static final int SEG_RAW   = 0;  private static final int SEG_INDEX  = 1;  private static final int SEG_TYPE   = 2;  private static final int SEG_MODIFIER = 3; // modifier or subformat/**   * Sets the pattern used by this message format.   * The method parses the pattern and creates a list of subformats   * for the format elements contained in it.   * Patterns and their interpretation are specified in the   * <a href="#patterns" rel="external nofollow" >class description</a>.   *   * @param pattern the pattern for this message format   * @exception IllegalArgumentException if the pattern is invalid   */  @SuppressWarnings("fallthrough") // fallthrough in switch is expected, suppress it  public void applyPattern(String pattern) {      StringBuilder[] segments = new StringBuilder[4];      // Allocate only segments[SEG_RAW] here. The rest are      // allocated on demand.      segments[SEG_RAW] = new StringBuilder();      int part = SEG_RAW;      int formatNumber = 0;      boolean inQuote = false;      int braceStack = 0;      maxOffset = -1;      for (int i = 0; i < pattern.length(); ++i) {        char ch = pattern.charAt(i);        if (part == SEG_RAW) {          if (ch == '/'') {            if (i + 1 < pattern.length()              && pattern.charAt(i+1) == '/'') {              segments[part].append(ch); // handle doubles              ++i;            } else {              inQuote = !inQuote;            }          } else if (ch == '{' && !inQuote) {            part = SEG_INDEX;            if (segments[SEG_INDEX] == null) {              segments[SEG_INDEX] = new StringBuilder();            }          } else {            segments[part].append(ch);          }        } else {          if (inQuote) {       // just copy quotes in parts            segments[part].append(ch);            if (ch == '/'') {              inQuote = false;            }          } else {            switch (ch) {            case ',':              if (part < SEG_MODIFIER) {                if (segments[++part] == null) {                  segments[part] = new StringBuilder();                }              } else {                segments[part].append(ch);              }              break;            case '{':              ++braceStack;              segments[part].append(ch);              break;            case '}':              if (braceStack == 0) {                part = SEG_RAW;                makeFormat(i, formatNumber, segments);                formatNumber++;                // throw away other segments                segments[SEG_INDEX] = null;                segments[SEG_TYPE] = null;                segments[SEG_MODIFIER] = null;              } else {                --braceStack;                segments[part].append(ch);              }              break;            case ' ':              // Skip any leading space chars for SEG_TYPE.              if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {                segments[part].append(ch);              }              break;            case '/'':              inQuote = true;              // fall through, so we keep quotes in other parts            default:              segments[part].append(ch);              break;            }          }        }      }      if (braceStack == 0 && part != 0) {        maxOffset = -1;        throw new IllegalArgumentException("Unmatched braces in the pattern.");      }      this.pattern = segments[0].toString();  }

上面的這段代碼寫的有點(diǎn)讓人費(fèi)解,略微奇特,我們主要看第一個(gè)邏輯分支:對(duì)每一個(gè)待處理的國(guó)際化文案模板串中的字符進(jìn)行遍歷,當(dāng)字符為"'"時(shí),判斷后一個(gè)字符是否也為“'”,如果是則將“‘”拼接到已處理的StringBuilder中,不是則將inQuote至為True,如果該字符不會(huì)‘{'且inQuote為false則將part重新置為0,并且segments[SEG_INDEX]=null的話重新創(chuàng)建StringBuilder對(duì)象,否則繼續(xù)拼接。

原因分析:

  1. 結(jié)合我們配置的英文文案(其中一共有兩個(gè)占位符,在這這兩占位符之前有一個(gè)單引號(hào)),根據(jù)上面Spring的處理源碼看,實(shí)際處理會(huì)是:對(duì)該字符串進(jìn)行逐個(gè)字符處理,逐個(gè)拼接到已處理的StringBuilder中,當(dāng)處理到‘{'時(shí),此處part將被置為1,同時(shí)segments第1個(gè)存儲(chǔ)位上會(huì)引用StringBuilder類型的對(duì)象,程序繼續(xù)處理下面的待處理的字符,繼續(xù)拼接(請(qǐng)自行看part!= SEG_RAW的邏輯分支),直到處理到‘}'時(shí),part被重新賦值為0,sefgments的其他位被清空,于是繼續(xù)處理下面的字符串繼續(xù)拼接,處理到單引號(hào)時(shí),inQuote被置為True,接下來就一路拼接了,不再對(duì)后面的“{“做占位符處理。
  2. 中文文案中兩個(gè)占位符之間并沒有出現(xiàn)單引號(hào),因此解決了問題現(xiàn)象中的第二點(diǎn),中文文案顯示正常。

解決方案:

從源碼看只有一種解決方式,{}之間的單引號(hào)需要成對(duì)出現(xiàn),我們的處理方式是將文案修改為了:

tms.pallet.order.box.qty=The total palletized boxes quantity {0} doesn''t match with the received boxes quantity {1},Please double check!

直接修改文案其實(shí)并不是一種很好的解決方法,最好是能夠重寫Spring調(diào)用applyPattern方法前的某一方法來將單引號(hào)替換為雙引號(hào)。無奈spring 3.2.3版本中對(duì)應(yīng)國(guó)際化的處理方法一路private,不給你重寫的機(jī)會(huì)。

查閱相關(guān)資料得知,在Spring4.3.2版本中可以通過重寫ResourceBundleMessageSource類中的getStringOrNull方法來實(shí)現(xiàn)。

長(zhǎng)遠(yuǎn)方案:升級(jí)項(xiàng)目中的Spring版本,同時(shí)使用更多的新版特性。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JAVA教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 合肥市| 宽甸| 定远县| 象州县| 信阳市| 湖口县| 新巴尔虎右旗| 万安县| 罗平县| 南澳县| 谢通门县| 砀山县| 静乐县| 平潭县| 木兰县| 深州市| 南城县| 探索| 永城市| 民权县| 南江县| 额敏县| 马鞍山市| 内乡县| 大埔县| 淮北市| 平南县| 鄯善县| 财经| 龙游县| 桂平市| 镇巴县| 会泽县| 乐平市| 和顺县| 武安市| 通榆县| 福建省| 滦平县| 昌黎县| 盐池县|