posted on 2025-08-17
Периодически я просматриваю новые библиотеки, которые добавляются в репозиторий https://ultralisp.org. Недавно мне попалась Common Lisp библиотека для интернационализации программ на Common Lisp. Она называется Fluent.
Я начал разбираться, как она работает, и оказалось, что Fluent — это стандарт, подход к интернационализации, предложенный несколько лет назад компанией Mozilla. С тех пор для этого формата переводов создали библиотеки для разных языков программирования. Теперь такая библиотека появилась и для Common Lisp.
Чем Fluent отличается от давно известного всем gettext и ему подобных? Формат Fluent предлагает более гибкий подход к формированию переводов. Под каждый язык и его грамматические особенности можно сделать свой шаблон. Fluent чем-то напоминает язык шаблонов Mustache.
Для примера покажу, как это выглядит на Common Lisp. Сначала нужно создать директорию для хранения переводов. Для примера сделаем поддержку английского и русского языков.
Для английского перевода создадим файл /tmp/i18n/en-US/app.ftl
с таким содержимым:
apples-and-leafs = { $apple-count ->
[one] {$apple-count} apple
*[many] {$apple-count} apples
} and { $leaf-count ->
[one] {$leaf-count} leaf.
*[many] {$leaf-count} leafs.
}
Аналогичный файл /tmp/i18n/ru-RU/app.ftl
создадим для русского языка:
apples-and-leafs = { $apple-count ->
[one] {$apple-count} яблоко
[few] {$apple-count} яблока
*[many] {$apple-count} яблок
} и { $leaf-count ->
[one] {$leaf-count} лист.
[few] {$leaf-count} листа.
*[many] {$leaf-count} листов.
}
Обратите внимание, что в русском языке три формы множественного числа, а в английском только две. Благодаря гибкости формата Fluent, можно описать в файле целое предложение, даже если оно зависит от нескольких чисел.
Когда директория с переводами готова, мы можем загрузить эти переводы и получить текст на нужном языке. В Common Lisp это выглядит так:
CL-USER> (let ((ctx (fluent:fluent (fluent:read-all-localisations #P"/tmp/i18n/")
:locale :ru-ru)))
(fluent:resolve ctx "apples-and-leafs" :apple-count 21 :leaf-count 33))
"21 яблоко и 33 листа."
CL-USER> (let ((ctx (fluent:fluent (fluent:read-all-localisations #P"/tmp/i18n/")
:locale :en-us)))
(fluent:resolve ctx "apples-and-leafs" :apple-count 21 :leaf-count 33))
"21 apples and 33 leafs."
По-моему, довольно гибкое решение.
Если мне когда-нибудь понадобится делать приложение с переводами, я обязательно буду использовать Fluent. А был ли у вас опыт создания мультиязычных приложений? Если да, расскажите комментариях, какой подход к хранению переводов использовали?
Обсудить пост в Telegram канале.This blog covers learning, ai, automation, voice, holism, ideas, zerocoder, python, codeassistant, aider, cursor, llm, project, i18n, commonlisp, poftheday, projects, closed, tips, seo, telegram, bot, прототип, smarthome, yandexcloud, logging, software, thoughts, salebot, bots, notes, emacs, lisp, infrastructure, news, lispworks, mcp, hackathon, programming, sql, yandex, cloud