### 1、添加国际化配置

resources/i18n/messages.properties

```properties
login.title=登录
login.name=世界
```

resources/i18n/messages_en_US.properties

```properties
login.title=Login
login.name=world
```



### 2、 使用 [solon-i18n](/article/126) 插件


* 使用国际化工具类，获取默认消息

```java
@Controller
public class DemoController {
    // 搭配请求头Content-Language=xx
    @Mapping("/demo/")
    public String demo(Locale locale) {
        //I18nUtil.getMessage("login.title");
        //I18nUtil.getMessage(ctx, "login.title");
        //I18nUtil.getMessage(Context.current(), "login.title");
        
        return I18nUtil.getMessage(locale, "login.title");
    }
}
```

* 使用国际化服务类，获取特定语言包

```java
@Controller
public class LoginController {
    I18nService i18nService = new I18nService("i18n.login");

    // 搭配请求头Content-Language=xx
    @Mapping("/demo/")
    public String demo(Locale locale) {
        return i18nService.get(locale, "login.title");
    }
}
```


* 使用国际化注解，为视图模板提供支持

```java
@I18n("i18n.login") //可以指定语言包
//@I18n //或不指定（默认消息）
@Controller
public class LoginController {
    @Mapping("/login/")
    public ModelAndView login() {
        return new ModelAndView("login.ftl");
    }
}
```

在各种模板里的使用方式：


beetl::
```html
i18n::${i18n["login.title"]}
i18n::${@i18n.get("login.title")}
i18n::${@i18n.getAndFormat("login.title",12,"a")}
```

enjoy::
```html
i18n::#(i18n.get("login.title"))
i18n::#(i18n.getAndFormat("login.title",12,"a"))
```

freemarker::
```html
i18n::${i18n["login.title"]}
i18n::${i18n.get("login.title")}
i18n::${i18n.getAndFormat("login.title",12,"a")}
```

thymeleaf::
```html
i18n::<span th:text='${i18n.get("login.title")}'></span>
i18n::<span th:text='${i18n.getAndFormat("login.title",12,"a")}'></span>
```

velocity::
```html
i18n::${i18n["login.title"]}
i18n::${i18n.get("login.title")}
i18n::${i18n.getAndFormat("login.title",12,"a")}
```


### 3、 也支持分布式国际化本置

这个方式，适合对接企业内部的国际化配置中台。

```java
//实现一个国际化内容块的工帮
public class I18nBundleFactoryImpl implements I18nBundleFactory {
    @Override
    public I18nBundle create(String bundleName, Locale locale) {
        if (I18nUtil.getMessageBundleName().equals(bundleName)) {
            bundleName = Solon.cfg().appName();
        }

        return new I18nBundleImpl(I18nContextManager.getMessageContext(bundleName), locale);
    }
}

//然后注册到Bean容器
Solon.context().wrapAndPut(I18nBundleFactory.class, new I18nBundleFactoryImpl());
```

### 4、三个语种分析器



| 分析器 | 说明 | 
| -------- | -------- | 
| LocaleResolverHeader     | 默认会从 Content-Language 或  Accept-Language 获取语言信息（或者通过 setHeaderName(name) 自定义 ）    |
| LocaleResolverCookie | 默认从 SOLON.LOCALE 获取语言信息（或者通过 setCookieName(name) 自定义） | 
| LocaleResolverSession | 默认从 SOLON.LOCALE 获取语言信息（或者通过 setAttrName(name) 自定义） | 


### 5、 如何切换语言？

框架默认使用 LocaleResolverHeader 分析器，即默认会通过 header[Content-Language]  或 header[Accept-Language] 自动切换。

需要换个分析器？

```java
@Configuration
public class DemoConfig{
    @Bean
    public LocaleResolver localInit(){
        return new LocaleResolverCookie();
    }
    
// 或者，换个 header    
//    @Bean
//    public LocaleResolver localInit(){
//        LocaleResolverHeader localeResolverHeader = new LocaleResolverHeader();
//        localeResolverHeader.setHeaderName("lang");
//        return localeResolverHeader;
//    }
}
```

如果需要完全自定义？

```java
@Component
public class LocaleResolverImpl implements LocaleResolver{
    //....
}
```
