メッセージリソースとしてExcelファイルを利用する(ResourceBundle)

国際化プログラミングをする時にXXXX.propertiesファイルを作成するけれども、
設計書(Excel)から設定ファイルにいちいち直すのではなくExcelから直接読み取れないかなということで調べてみました。

国際化対応をする場合はResourceBundleクラスを使用するのだけれども、
このクラスとResourceBundle.Controlクラスを継承することで、Excelファイルを読み込めるようになります。

概要はJavaDocに書いてあるとおりなので幾つかピンポイントで。
http://java.sun.com/javase/ja/6/docs/ja/api/java/util/ResourceBundle.Control.html

ResourceBundle.Control#getFormats(String baseName)ではxlsを返すようにします。

	@Override
	public List<String> getFormats(String baseName) {
		if (baseName == null)
			throw new NullPointerException();
		return Arrays.asList("xls");
	}

ResourceBundle.Control#newBundle()内ではJavaDocのサンプル通りに実装したあとに、
XmlResourceBundleの代わりに以下のExcelResourceBundleを返すようにします。

	private static class ExcelResourceBundle extends ResourceBundle {
		private Properties props;

		ExcelResourceBundle(InputStream stream) throws IOException {
			props = new Properties();

			Workbook book = new HSSFWorkbook(new POIFSFileSystem(stream));
			Sheet sheet = book.getSheet("messages");
			for (Row row : sheet) {
				Cell keyCell = row.getCell(0);
				Cell valueCell = row.getCell(1);
				if (keyCell == null) {
					continue;
				}
				String key = keyCell.getStringCellValue();
				String value = (valueCell == null) ? "" : valueCell
						.getStringCellValue();
				if (isTitleOrEmpty(key)) {
					continue;
				}
				props.setProperty(key, value);
			}
		}

		private boolean isTitleOrEmpty(String key) {
			return "Key".equals(key) || key == null || key.length() == 0;
		}

		protected Object handleGetObject(String key) {
			return props.getProperty(key);
		}

		public Enumeration<String> getKeys() {
			return (Enumeration<String>) props.propertyNames();
		}
	}

Excelファイルのサンプルも含めてソースは下からDLしてください。
http://www1.axfc.net/uploader/Sc/so/276281.zip (eclipse+maven)

これだけで、XXXX.xls、XXXXX_ja_JP.xls、XXXXX_en.xls等をさがしに行ってくれるようです。

今回はファイル名で分けていますが、Excelファイルをひとつにして、シート名で国際化対応ということもできそうです。
Excelから直接読み込めればいいなとだけ考えてたけれども、思ったよりも便利かもしれません。