<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>F monologue &#187; I18N</title>
	<atom:link href="http://blog.fguy.com/tag/i18n/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.fguy.com</link>
	<description>Taehoon Kang</description>
	<lastBuildDate>Fri, 10 Feb 2012 00:53:34 +0000</lastBuildDate>
	<language>ko</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.fguy.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/302d17afa2133e49879c9121b033814d?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>F monologue &#187; I18N</title>
		<link>http://blog.fguy.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.fguy.com/osd.xml" title="F monologue" />
	<atom:link rel='hub' href='http://blog.fguy.com/?pushpress=hub'/>
		<item>
		<title>Struts2 에서의 국제화</title>
		<link>http://blog.fguy.com/2008/07/23/struts2-%ec%97%90%ec%84%9c%ec%9d%98-%ea%b5%ad%ec%a0%9c%ed%99%94/</link>
		<comments>http://blog.fguy.com/2008/07/23/struts2-%ec%97%90%ec%84%9c%ec%9d%98-%ea%b5%ad%ec%a0%9c%ed%99%94/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 07:37:11 +0000</pubDate>
		<dc:creator>fguy</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[I18N]]></category>
		<category><![CDATA[Struts2 internationalization]]></category>

		<guid isPermaLink="false">http://fguy.krac.kr/2008/07/23/struts2-%ec%97%90%ec%84%9c%ec%9d%98-%ea%b5%ad%ec%a0%9c%ed%99%94/</guid>
		<description><![CDATA[Struts2 의 국제화는 Struts2의 TextProvider에 의해 이루어진다. 내부적으로는 PropertyResourceBundle&#160;을 사용하고 있어서 기본적으로는 한글을 사용할 수가 없다. Java의 properties 파일은 ISO-8859-1 인코딩을 사용하고 있기 때문이다. properties 파일의 인코딩을 UTF-8로 바꾼다 해도 내부적으로 ISO-8859-1로 취급해버린다. Struts의 소스 코드를 건드리지 않고 한글을 제대로 &#8230; <a href="http://blog.fguy.com/2008/07/23/struts2-%ec%97%90%ec%84%9c%ec%9d%98-%ea%b5%ad%ec%a0%9c%ed%99%94/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.fguy.com&amp;blog=13748523&amp;post=29&amp;subd=fguyblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://cwiki.apache.org/WW/internationalization.html" target="_blank">Struts2 의 국제화</a>는 Struts2의 <a href="http://struts.apache.org/2.1.2/struts2-core/apidocs/com/opensymphony/xwork2/TextProvider.html" target="_blank">TextProvider</a>에 의해 이루어진다. 내부적으로는 <a href="http://java.sun.com/javase/6/docs/api/java/util/PropertyResourceBundle.html" target="_blank">PropertyResourceBundle</a>&nbsp;을 사용하고 있어서 기본적으로는 한글을 사용할 수가 없다.</p>
<p>Java의 properties 파일은 ISO-8859-1 인코딩을 사용하고 있기 때문이다. properties 파일의 인코딩을 UTF-8로 바꾼다 해도 내부적으로 ISO-8859-1로 취급해버린다.</p>
<p>Struts의 소스 코드를 건드리지 않고 한글을 제대로 출력할 수 없을까 하고 생각해보았다.</p>
<p>또한 Struts2 i18n layout에 익숙한 사용자도 있을 것이기 때문에 xml 로 resource bundle을 바꾸기도 좀 그렇기 때문에 기존의 properties 파일을 사용하는 방법으로 고민해보았다.</p>
<p>&lt;s:text&gt;태그에서는 Action Class 의 getText() method를 호출하기 때문에 getText() method를 바꾸기로 하였다. </p>
<p>각 Action 에서는 다음 class 를 상속하여 구현하고, properties 파일의 인코딩을 UTF-8로 바꾸면 국제화에 문제가 없을 것이다.</p>
<p><strong>AbstractAction.java</strong></p>
<pre>package com.fguy.action;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import com.fguy.util.UTF8ResourceBundle;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.ValueStack;

@SuppressWarnings("unchecked")
public abstract class AbstractAction extends ActionSupport {
	private static final long serialVersionUID = 5107762886506915539L;

	@Override
	public String getText(String textName) {
		return convertResource(super.getText(textName));
	}

	@Override
	public String getText(String textName, List args) {
		return convertResource(super.getText(textName, args));
	}

	@Override
	public String getText(String key, String defaultValue, List args,
			ValueStack stack) {
		return convertResource(super.getText(key, defaultValue, args, stack));
	}

	@Override
	public String getText(String textName, String defaultValue, List args) {
		return convertResource(super.getText(textName, defaultValue, args));
	}

	@Override
	public String getText(String textName, String defaultValue, String obj) {
		return convertResource(super.getText(textName, defaultValue, obj));
	}

	@Override
	public String getText(String key, String defaultValue, String[] args,
			ValueStack stack) {
		return convertResource(super.getText(key, defaultValue, args, stack));
	}

	@Override
	public String getText(String key, String defaultValue, String[] args) {
		return convertResource(super.getText(key, defaultValue, args));
	}

	@Override
	public String getText(String textName, String defaultValue) {
		return convertResource(super.getText(textName, defaultValue));
	}

	@Override
	public String getText(String key, String[] args) {
		return convertResource(super.getText(key, args));
	}

	@Override
	public ResourceBundle getTexts() {
		return new UTF8ResourceBundle((PropertyResourceBundle) super.getTexts());
	}

	@Override
	public ResourceBundle getTexts(String bundleName) {
		return new UTF8ResourceBundle((PropertyResourceBundle) super
				.getTexts(bundleName));
	}

	/**
	 * Convert localized string from properties file
	 *
	 * @param text
	 * @return
	 */
	private static final String convertResource(String text) {
		String result = text;
		try {
			result = new String(result.getBytes("ISO-8859-1"), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
		return result;
	}
}
</pre>
<p><strong>UTF8ResourceBundle.java</strong></p>
<pre>package com.fguy.util;

import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

@SuppressWarnings("unchecked")
public class UTF8ResourceBundle extends ResourceBundle {
	PropertyResourceBundle bundle;

	public UTF8ResourceBundle(PropertyResourceBundle bundle) {
		this.bundle = bundle;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.util.ResourceBundle#getKeys()
	 */
	public Enumeration getKeys() {
		return bundle.getKeys();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see java.util.ResourceBundle#handleGetObject(java.lang.String)
	 */
	protected Object handleGetObject(String key) {
		String value = (String) bundle.handleGetObject(key);
		try {
			return new String(value.getBytes("ISO-8859-1"), "UTF-8");
		} catch (UnsupportedEncodingException e) {
			// Shouldn't fail - but should we still add logging message?
			throw new RuntimeException(e);
		}
	}
}
</pre>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/fguyblog.wordpress.com/29/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/fguyblog.wordpress.com/29/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fguyblog.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fguyblog.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fguyblog.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fguyblog.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fguyblog.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fguyblog.wordpress.com/29/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fguyblog.wordpress.com/29/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fguyblog.wordpress.com/29/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.fguy.com&amp;blog=13748523&amp;post=29&amp;subd=fguyblog&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.fguy.com/2008/07/23/struts2-%ec%97%90%ec%84%9c%ec%9d%98-%ea%b5%ad%ec%a0%9c%ed%99%94/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d10c905edc572a61b5206377c1a36c98?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">fguy79</media:title>
		</media:content>
	</item>
	</channel>
</rss>
