• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 15507594683

07 Jun 2025 11:54AM UTC coverage: 30.951% (-30.4%) from 61.309%
15507594683

push

github

alerque
chore(tooling): Add post-checkout hook to clear makedeps on branch switch

6363 of 20558 relevant lines covered (30.95%)

3445.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.47
/languages/base.lua
1
--- SILE language class.
2
-- @interfaces languages
3

4
local module = require("types.module")
48✔
5
local language = pl.class(module)
48✔
6
language.type = "language"
48✔
7

8
local loadkit = require("loadkit")
48✔
9
local setenv = require("rusile").setenv
48✔
10

11
-- Allows loading FTL resources directly with require(). Guesses the locale based on SILE's default resource paths,
12
-- otherwise if it can't guess it Loads assets directly into the *current* fluent bundle.
13
local require_ftl = loadkit.make_loader("ftl", function (file)
96✔
14
   local contents = assert(file:read("*a"))
151✔
15
   file:close()
151✔
16
   return assert(fluent:add_messages(contents))
302✔
17
end)
18

19
function language:_init (typesetter)
48✔
20
   self.typesetter = typesetter
151✔
21
   module._init(self)
151✔
22
   self:loadMessages()
151✔
23
   self:setupNodeMaker()
151✔
24
   self:setupHyphenator()
151✔
25
end
26

27
function language:_post_init ()
48✔
28
   module._post_init(self)
151✔
29
   self.settings:registerHook("document.language", function (lang)
453✔
30
      self.typesetter:switchLanguage(lang)
2,368✔
31
   end)
32
end
33

34
-- TODO: reconsider naming of 'setup' and 'nodemaker'
35
function language:setupNodeMaker ()
48✔
36
   -- TODO should this be an instance of a constructor? inconsistent with typesetter/language/class/etc.
37
   self.nodemaker = require("languages.base-nodemaker")
×
38
end
39

40
function language:setupHyphenator ()
48✔
41
   -- TODO should this be an constructor instead of an instance? inconsistent with typesetter/language/class/etc.
42
   self.hyphenator = require("languages.base-hyphenator")(self)
300✔
43
end
44

45
function language:activate ()
48✔
46
   local lang = self:_getLegacyCode()
129✔
47
   fluent:set_locale(lang)
129✔
48
   os.setlocale(lang)
129✔
49
   setenv("LANG", lang)
129✔
50
end
51

52
function language:_getLegacyCode ()
48✔
53
   return self._name
2,891✔
54
end
55

56
function language:loadMessages ()
48✔
57
   local lang = self:_getLegacyCode()
151✔
58
   local ftlresource = string.format("languages.%s.messages", lang)
151✔
59
   SU.debug("fluent", "Loading FTL resource", ftlresource, "into locale", lang)
151✔
60
   -- This needs to be set so that we load localizations into the right bundle,
61
   -- but this breaks the sync enabled by the hook in the document.language
62
   -- setting, so we want to set it back when we're done.
63
   local original_lang = fluent:get_locale()
151✔
64
   fluent:set_locale(lang)
151✔
65
   local gotftl, ftl = pcall(require_ftl, ftlresource)
151✔
66
   if not gotftl then
151✔
67
      SU.warn(
×
68
         ("Unable to load localized strings (e.g. table of contents header text) for %s: %s"):format(
×
69
            lang,
70
            ftl:gsub(":.*", "")
×
71
         )
72
      )
73
   end
74
   fluent:set_locale(original_lang)
151✔
75
end
76

77
function language:_declareSettings ()
48✔
78
   self.settings:declare({
96✔
79
      parameter = "document.language",
80
      type = "string",
81
      default = "en",
82
      help = "Locale for localized language support",
83
   })
84
   self.settings:declare({
96✔
85
      parameter = "languages.fixedNbsp",
86
      type = "boolean",
87
      default = false,
88
      help = "Whether to treat U+00A0 (NO-BREAK SPACE) as a fixed-width space",
89
   })
90
end
91

92
function language:_registerCommands ()
48✔
93
   self:registerCommand("language", function (options, content)
96✔
94
      local main = SU.required(options, "main", "language setting")
3✔
95
      if content[1] then
3✔
96
         self.settings:temporarily(function ()
×
97
            self.settings:set("document.language", main)
×
98
            SILE.process(content)
×
99
         end)
100
      else
101
         self.settings:set("document.language", main)
6✔
102
      end
103
   end, "Set the typesetters current language")
51✔
104

105
   self:registerCommand("fluent", function (options, content)
96✔
106
      local key = content[1]
×
107
      local locale = options.locale or self.settings:get("document.language")
×
108
      local original_locale = fluent:get_locale()
×
109
      fluent:set_locale(locale)
×
110
      SU.debug("fluent", "Looking for", key, "in", locale)
×
111
      local entry
112
      if key then
×
113
         entry = fluent:get_message(key)
×
114
      else
115
         SU.warn("Fluent localization function called without passing a valid message id")
×
116
      end
117
      local message
118
      if entry then
×
119
         message = entry:format(options)
×
120
      else
121
         SU.warn(string.format("No localized message for %s found in locale %s", key, locale))
×
122
         fluent:set_locale("und")
×
123
         entry = fluent:get_message(key)
×
124
         if entry then
×
125
            message = entry:format(options)
×
126
         end
127
      end
128
      fluent:set_locale(original_locale)
×
129
      SILE.processString(("<sile>%s</sile>"):format(message), "xml")
×
130
   end, "Localize a given message id")
48✔
131

132
   self:registerCommand("ftl", function (options, content)
96✔
133
      local original_locale = fluent:get_locale()
×
134
      local locale = options.locale or self.settings:get("document.language")
×
135
      SU.debug("fluent", "Loading message(s) into locale", locale)
×
136
      fluent:set_locale(locale)
×
137
      if options.src then
×
138
         fluent:load_file(options.src, locale)
×
139
      elseif SU.ast.hasContent(content) then
×
140
         local input = content[1]
×
141
         fluent:add_messages(input, locale)
×
142
      end
143
      fluent:set_locale(original_locale)
×
144
   end, "Load messages from a Fluent FTL file into the given locale")
48✔
145
end
146

147
return language
48✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc