2017-01-08 10 views
1

Я хочу реализовать поддержку i18n для приложения калитки 7.Wicket7: интернационализация и доступ к базе данных

Требования:

  • Переводы должны быть легко доступны для редактирования администратора пользователем
  • Переводы должны проходить без передислокации

Мой фактический apporach является проведение переводов внутри БД. Все переводы будут кэшироваться. Если перевод изменен с помощью Frontend-задачи, кэш и db будут обновляться. До сих пор так легко.

Фактически я застрял в замене переводов внутри страницы. Рабочее решение будет загружать каждый перевод во время реализации. Эти переводы будут установлены во многих элементах калитки. Мне не нравится этот подход, потому что он сильно испортит код (html + java).

Я попытаюсь реализовать механизм замены в моем действительном подходе. После того, как страница отображается, механизм проходит через всю страницу и делает эти работы:

  1. поиск всех заполнителей
  2. нагрузочных перевод для заполнителей-ключей (кэш)
  3. заменить заполнители с переводами

Это должно работать для тела и заголовка (название сайта)

Вот пример калитки-шаблон

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<title>${landingpage.site.title}</title> 
</head> 
<body> 
    <header wicket:id="headerPanel">header</header> 
    ${welcome.message} 
    <footer wicket:id="footerPanel">footer</footer> 
</body> 
</html> 

В этом случае следует признать и заменить $ {landingpage.site.title} и $ {welcome.message}. Как видите, он напрямую определяется внутри шаблона, а не в java-коде. И этого я хочу достичь.

Надеюсь, я сформулировал требования достаточно четко. Если нет, не против комментировать. Я уточню вопрос, чтобы сделать его более понятным.

Мой подход заключается в реализации BasePage (расширяет страницу) и перезаписать onAfterRender-метод

@Override 
protected void onAfterRender() { 
    super.onAfterRender(); 
    Response originalResponse = RequestCycle.get().getResponse(); 
    String updatedResponse = replaceWithTranslations(originalResponse); 
    originalResponse.reset(); 
    originalResponse.write(updatedResponse); 
} 

метод replaceWithTranslations еще не реализованы и возвращает простой строки на самом деле. Этот метод должен преобразовывать выходной поток исходного Repsonse в String, ищет заполнители и заменяет их значениями db.

Этот подход, кажется, есть 2 проблемы:

  • Я не получаю ответ в виде строки
  • Я получаю WicketRuntimeException (Page.checkRendering в Page.java:666)

Любые советы были бы замечательными!

+0

Почему вы не используете подход Wicket i18n? С '' и т. Д.? (См .: https://ci.apache.org/projects/wicket/guide/7.x/guide/i18n.html) – RobAu

+0

Первое чтение этой статьи заставило меня почувствовать себя сумасшедшим. Все шаблоны испорчены с помощью . И описаны только локализованные файлы свойств. На другом веб-сайте я читал: калитка не может обрабатывать другие входы. К настоящему времени я знаю, что эта информация - мусор. Спасибо за ваше внимание! Можете ли вы посмотреть на решение ниже, если это так? – Mike

ответ

1

Вдохновленный @RobAu Я дал возможность калиткой i18n шанс. Вот с чем я придумал:

шаблон:

<html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title><wicket:message key="landingpage.site.title">Site-Title</wicket:message></title> 
    </head> 
    <body> 
    <header wicket:id="headerPanel">header</header> 
    <wicket:message key="welcome.message">Welcome</wicket:message> 
    <footer wicket:id="footerPanel">footer</footer> 
    </body> 
</html> 

калитка: сообщение для атрибутов:

<input type="text" placeholder="username" wicket:message="placeholder:login.username"/> 

IStringResourceLoader:

@org.springframework.stereotype.Component 
public class I18NResourceLoader implements IStringResourceLoader { 

    @Autowired 
    private I18NCache i18nCache; 

    @Override 
    public String loadStringResource(final Class<?> clazz, final String key, final Locale locale, final String style, final String variation) { 
    return loadTranslation(key, locale); 
    } 

    @Override 
    public String loadStringResource(final Component component, final String key, final Locale locale, final String style, final String variation) { 
    return loadTranslation(key, locale); 
    } 

    private String loadTranslation(final String key, final Locale locale) { 
    final Optional<Translation> optional = i18nCache.get(key, locale); 
    if (!optional.isPresent()) { 
     return key; 
    } 
    return optional.get().getText(); 
    } 
} 

Перевода и I18NCache является самозанятых классов.

И, наконец, регистрация:

public abstract class BasePage extends WebPage { 

    @SpringBean 
    private I18NResourceLoader i18NResourceLoader; 

    public BasePage(){ 
    addI18NResourceLoader(); 

     ... 

    } 

    private void addI18NResourceLoader() { 
    final List<IStringResourceLoader> resourceLoaders = Application.get().getResourceSettings().getStringResourceLoaders(); 
    final boolean existsResourceLoader = resourceLoaders.stream() 
      .filter(p -> p instanceof I18NResourceLoader) 
      .collect(Collectors.counting()) > 0L; 
    if (!existsResourceLoader) { 
     resourceLoaders.add(i18NResourceLoader); 
    } 
    } 

    ... 

} 

Pro-х: подход

  • калитку в
  • Нет связывайтесь с RegEx-замена-Handling
  • SPR

Con-х

  • Шаблон чувствует себя немного более грязный

На самом деле, у меня нет информации о выполнении этого подхода.

Я решил сохранить логику добавления ResourceLoader в BasePage по двум причинам.

  1. BasePage отвечает за все concering страницы-представление (слабая причина :-))
  2. Я использую DI. Если бы я добавил логику в WebApplication, мне пришлось бы вручную вводить I18NResourceLoader или его зависимости.
+0

Молодец, Майк, ты понял. Я согласен, что '' немного неуклюже. Чтобы определить, улучшена или хуже производительность, вы должны ее профилировать. Это также зависит от реализации 'replaceWithTranslations'. – RobAu

+1

Btw Я думаю, вы теперь добавляете 'i18NResourceLoader' каждый раз, когда страница построена. Вы можете/должны переместить эту логику в 'Application.init()' – RobAu

+0

О да, вы абсолютно правы! Я пропустил этот момент :-) Это реальная утечка памяти и производительности. Каждый запрос добавит ResourceLoader в массив. Я обновлю ответ. Большое спасибо! – Mike

1

ОК, проблемы кажутся очень простыми.

Уловка или удача, здесь у нас есть BufferedWebResponse. Простой бросок будет делать трюк:

@Override 
protected void onAfterRender() { 
    super.onAfterRender(); 
    BufferedWebResponse originalResponse = (BufferedWebResponse) RequestCycle.get().getResponse(); 
    String translatedResponse = replaceWithTranslations(originalResponse); 
    originalResponse.reset(); 
    originalResponse.write(translatedResponse); 
} 

private String replaceWithTranslations(BufferedWebResponse originalResponse) { 
    String untranslatedText = originalResponse.getText().toString(); 
    String translatedText = doTheTranslation(untranslatedText); 
    return translatedText; 
} 
+0

Также вы можете использовать 'org.apache.wicket.response.filter.IResponseFilter' для этого. Его цель заключается именно в такой пост-обработке окончательной разметки перед отправкой в ​​браузер. –

0

Я думаю, что вы можете расширить IComponentResolver заменить заполнители как WicketMessageResolver.

+0

Не могли бы вы подробнее разобраться, пожалуйста? Мои исследования вызвали довольно полезную связь.Особенно комментарии. http://sanityresort.blogspot.de/2011/08/creating-custom-wicket-tag-resolver.html Я сделаю это. Это калитка для решения таких проблем? – Mike