#!/usr/bin/env luajit
--[[
tool to generate localized metadata for application stores.
We currently support F-Droid(fastlane) and Flathub(appstream).
usage: ./tools/update_metadata.lua
]]--
package.path = "frontend/?.lua;base/" .. package.path
local _ = require("gettext")
-- we can't require util here, some C libraries might not be available
local function htmlEscape(text)
return text:gsub("[}{\">/<'&]", {
["&"] = "&",
["<"] = "<",
[">"] = ">",
['"'] = """,
["'"] = "'",
["/"] = "/",
})
end
local metadata = {
summary = _("Ebook reader"),
desc = {
paragraphs = {
_("KOReader is an ebook reader optimized for e-ink screens. It can open many formats and provides advanced text adjustments."),
_("See below for a selection of its many features:"),
},
highlights = {
_("Supports both fixed page formats (PDF, DjVu, CBT, CBZ) and reflowable e-book formats (EPUB, FB2, Mobi, DOC, CHM, TXT, HTML). Scanned PDF/DjVu documents can be reflowed. Special flow directions for reading double column PDFs and manga."),
_("Multi-lingual user interface optimized for e-ink screens. Highly customizable reader view with complete typesetting options. Multi-lingual hyphenation dictionaries are bundled in."),
_("Non-Latin script support for books, including the Hebrew, Arabic, Persian, Russian, Chinese, Japanese and Korean languages."),
_("Unique Book Map and Page Browser features to navigate your book."),
_("Special multi-page highlight mode with many local and online export options."),
_("Can synchronize your reading progress across all your KOReader running devices."),
_("Integrated with Calibre, Wallabag, Wikipedia, Google Translate and other content providers."),
},
},
notes = {
_ ("Release notes available on the link below"),
},
screenshots = {
{ image = "https://github.com/koreader/koreader-artwork/raw/master/koreader-menu-framed.png",
default = true,
},
{ image = "https://github.com/koreader/koreader-artwork/raw/master/koreader-footnotes-framed.png",
},
{ image = "https://github.com/koreader/koreader-artwork/raw/master/koreader-dictionary-framed.png",
}
},
keywords = {
_("reader"),
_("viewer"),
_("dictionary"),
_("wikipedia"),
_("wallabag"),
_("annotations"),
-- don't translate formats
"epub",
"fb2",
"pdf",
"djvu",
},
-- appstream metadata that needs no translation
component = [[
rocks.koreader.KOReader
KOReader
KOReader Community
CC0-1.0
AGPL-3.0-only
https://koreader.rocks/
https://github.com/koreader/koreader/issues
https://koreader.rocks/user_guide
https://hosted.weblate.org/engage/koreader/
https://github.com/koreader/koreader
https://github.com/koreader/koreader
#ffffff
#303030
360
pointing
keyboard
gamepad
1024
600
always
touch
application/epub+zip
application/fb2
application/fb3
application/msword
application/oxps
application/pdf
application/rtf
application/tcr
application/vnd.amazon.mobi8-ebook
application/vnd.comicbook+tar
application/vnd.comicbook+zip
application/vnd.ms-htmlhelp
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/vnd.palm
application/x-cbz
application/x-chm
application/x-fb2
application/x-fb3
application/x-mobipocket-ebook
application/x-tar
application/xhtml+xml
application/xml
application/zip
image/djvu
image/gif
image/jp2
image/jpeg
image/jxr
image/png
image/svg+xml
image/tiff
image/vnd.djvu
image/vnd.ms-photo
image/x-djvu
image/x-portable-arbitrarymap
image/x-portable-bitmap
text/html
text/plain
rocks.koreader.KOReader.desktop
Office
Viewer
Literature
]],
}
local updated_files = {}
local function writeFile(str, path)
local f = io.open(path, "w")
table.insert(updated_files, path)
if f then
f:write(str)
f:write("\n")
f:close()
end
end
local function isLocaleDir(str)
for _, v in ipairs({"templates", "README.md", "LICENSE"}) do
if str == v then return false end
end
return true
end
local function getLocales()
local locales = {}
local output = io.popen('ls l10n')
if not output then return {} end
for dir in output:lines() do
if isLocaleDir(dir) then
locales[#locales + 1] = dir
end
end
output:close()
table.insert(locales, 1, "en")
return locales
end
local locales = getLocales()
local function htmlDescription(lang)
local lang = lang or "en"
local desc = metadata.desc
local t = {}
_.changeLang(lang)
for i, v in ipairs (desc.paragraphs) do
table.insert(t, "
" .. htmlEscape(_(v)) .. "
")
end
table.insert(t, "")
for i, v in ipairs(desc.highlights) do
table.insert(t, " - " .. htmlEscape(_(v)) .. "
")
end
table.insert(t, "
")
return table.concat(t, "\n")
end
local function tag(element, lang, str, pad)
local offset = ""
local pad = pad or 0
if pad >= 1 then
for i = 1, pad do
offset = offset .. " "
end
end
if lang == "en" then
return string.format("%s<%s>%s%s>",
offset, element, str, element)
else
return string.format('%s<%s xml:lang="%s">%s%s>',
offset, element, lang, str, element)
end
end
local function genAppstream()
local metadata_file = "platform/common/koreader.metainfo.xml"
print("Building appstream metadata, this might take a while...")
local t = {}
local desc = metadata.desc
table.insert(t, '')
table.insert(t, '')
table.insert(t, '')
table.insert(t, metadata.component)
local orig, translated
_.changeLang("en")
orig = metadata.summary
for __, lang in ipairs(locales) do
_.changeLang(lang)
translated = _(metadata.summary)
if orig ~= translated or lang == "en" then
table.insert(t, tag("summary", lang, htmlEscape(translated), 2))
end
end
table.insert(t, ' ')
for i, v in ipairs (desc.paragraphs) do
_.changeLang("en")
orig = v
for __, lang in ipairs(locales) do
_.changeLang(lang)
translated = _(v)
if orig ~= translated or lang == "en" then
table.insert(t, tag("p", lang, htmlEscape(translated), 4))
end
end
end
table.insert(t, ' ')
for i, v in ipairs(desc.highlights) do
_.changeLang("en")
orig = v
for __, lang in ipairs(locales) do
_.changeLang(lang)
translated = _(v)
if orig ~= translated or lang == "en" then
table.insert(t, tag("li", lang, htmlEscape(translated), 6))
end
end
end
table.insert(t, '
')
table.insert(t, ' ')
table.insert(t, ' ')
for i, v in ipairs(metadata.screenshots) do
if v.default then
table.insert(t, ' ')
else
table.insert(t, ' ')
end
table.insert(t, tag("image", "en", v.image, 6))
if v.caption then
_.changeLang(en)
orig = v.caption
for __, lang in ipairs(locales) do
_.changeLang(lang)
translated = _(v.caption)
if orig ~= translated or lang == "en" then
table.insert(t, tag("caption", lang, htmlEscape(translated), 6))
end
end
end
table.insert(t, ' ')
end
table.insert(t, ' ')
table.insert(t, ' ')
for i, v in ipairs(metadata.keywords) do
_.changeLang(en)
orig = v
for __, lang in ipairs(locales) do
_.changeLang(lang)
translated = _(v)
if orig ~= translated or lang == "en" then
table.insert(t, tag("keyword", lang, htmlEscape(translated), 4))
end
end
end
table.insert(t, ' ')
table.insert(t, [[
]])
for i, v in ipairs(metadata.notes) do
_.changeLang(en)
orig = v
for __, lang in ipairs(locales) do
_.changeLang(lang)
translated = _(v)
if orig ~= translated or lang == "en" then
table.insert(t, tag("p", lang, htmlEscape(translated), 8))
end
end
end
table.insert(t, [[
https://github.com/koreader/koreader/releases/tag/%%VERSION%%
]])
table.insert(t, '')
writeFile(table.concat(t, "\n"), metadata_file)
end
local function genFastlane()
print("Building fastlane metadata")
local short, full = "short_description.txt", "full_description.txt"
local short_orig = metadata.summary
local full_orig = htmlDescription()
local short_translated, full_translated
for __, lang in ipairs(locales) do
_.changeLang(lang)
if lang == "en" then
metadata_dir = "metadata/en-US/"
metadata_file = metadata_dir .. short
writeFile(short_orig, metadata_file)
metadata_file = metadata_dir .. full
writeFile(full_orig, metadata_file)
else
metadata_dir = "metadata/" .. lang .. "/"
short_translated = _(metadata.summary)
full_translated = htmlDescription(lang)
if short_orig ~= short_translated or full_orig ~= full_translated then
os.execute('mkdir -p ' .. metadata_dir)
end
if short_orig ~= short_translated then
metadata_file = metadata_dir .. short
writeFile(short_translated, metadata_file)
end
if full_orig ~= full_translated then
metadata_file = metadata_dir .. full
writeFile(full_translated, metadata_file)
end
end
end
end
genAppstream()
genFastlane()
print("All done! Updated files:")
print(table.concat(updated_files, "\n"))