Можно сконвертировать нативные Java-классы в XML/JSON/YAML?

Если бы я назвал этот вопрос "Идеальное решение задачи интернационализации Java-приложения", то его бы заминусовали и дали бы ссылку на какую-нибудь библиотеку. Но именно эта задача породила данный вопрос.

Я не знаю все готовых решений, но у многих есть есть один существенный недостаток - они статически невалидируемы. Это значит, что ассоциативные массивы с переводами на нужный язык пишутся в таких форматах, как XML или JSON, при этом до компиляции программы нельзя проверить, забыл ли программист что-то указать или не перепутал ли он ключ - это всплывёт только при компиляции, или, что ещё хуже, при запуске программы.

Итак, субъективно, но на концептуальном уровне идеальное решение интернационализации Java-приложения должно обладать такими свойствами:

  1. Статическая валидируемость. Это значит, что если программист забыл добавить какой-то перевод, или добавил лишний, или какой-то перепутал, то об этом будет известно ещё до того, как программу будут компилировать (грубо говоря, IDE должна распознать и подсветить ошибку).
  2. Динамическая подгружаемость файлов. Это особенность нужна, когда и статических строк, и языков очень много (то есть в общем случае). Включать в сборку все языки - незачем, ибо большинству пользователей нужен лишь один язык. Достаточно в сборку включить один язык по умолчанию, а остальные - подгрузить из интернета по необходимости (то есть в тот момент, как пользователь пожелает переключить язык интерфейса).

Пример решения на другом языке

Пока не знаю, позволяет ли это сделать Java, но на моём основном языке - TypeScript, такое возможно (в совокупности с Webpack).

  1. Создаём тип, в которым должны быть указаны все ключи:
type Translations {
  applicationTitle: string;
  dayOfWeek: {
   sunday: string;
   monday: string;
   // ...
  },
  greet: (userName: string)=> string;
}
  1. Создаём TypeScript-файл под каждый язык. Явное указание типа не даст чего-то перепутать или забыть:
const russian: Translations = {
  applicationTitle: "Приложение",
  dayOfWeek: {
   sunday: "воскресенье";
   monday: "понедельник";
   // ...
  },
  greet: (userName: string)=> `${userName}, доброго времени суток!`
}

Требование статической валидируемости соблюдено.

  1. Если речь идёт о веб-приложениях, то там разумно язык по умолчанию подшить в общую сборку, а остальные - динамически подгружать. Webpack позволяет это легко (если знать как) сделать. Да, подгружаться будут откомпилированные JavaScript-файлы, а не TypeScript, но в JavaScript-файлах ошибки быть не может, потому что иначе компилятор TypeScript-а их бы не скомпилировал (при определённых настройках). С десктопными Node.js приложениями, думаю, возможно нечто подобное - загрузить нужный JavaScript-файл, отсутствие ошибок в котором гарантированно предварительной компиляцией из TypeScript-а, и прочитать его.

Что насчет Java?

Я знаю в Java два инструмента обязывания: final (обязывает инициализировать поля в конструкторе) и abstract (обязывает реализовать методы. interface по концепции близок, по тому его сюда же). Объявить тип можно примерно так:

abstract class Translation  {
  final String applicationTitle;
  final DaysOfWeek DaysOfWeek;  
  abstract greet(String userName);
}

Все переводы должны быть унаследованы от этого класса. Осталось их только сконвертировать в нужный формат. О том, как это сделать, и есть мой вопрос.

Проблематичный являются функции шаблонизации, например greet(String userName). Пока для меня аннотации - это магия, но возможно, они помогут решить эту проблему.


Ответы (0 шт):