summaryrefslogtreecommitdiff
path: root/script/src/language.lua
blob: 3294c5b2c11557d405e5d97be481df9ba84a55c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
local fs = require 'bee.filesystem'
local lni = require 'lni'

local function supportLanguage()
    local list = {}
    for path in (ROOT / 'locale'):list_directory() do
        if fs.is_directory(path) then
            list[#list+1] = path:filename():string():lower()
        end
    end
    return list
end

local function osLanguage()
    return LANG:lower()
end

local function getLanguage(id)
    local support = supportLanguage()
    -- 检查是否支持语言
    if support[id] then
        return id
    end
    -- 根据语言的前2个字母来找近似语言
    for _, lang in ipairs(support) do
        if lang:sub(1, 2) == id:sub(1, 2) then
            return lang
        end
    end
    -- 使用英文
    return 'enUS'
end

local function loadFileByLanguage(name, language)
    local path = ROOT / 'locale' / language / (name .. '.lni')
    local buf = io.load(path)
    if not buf then
        return {}
    end
    local suc, tbl = xpcall(lni, log.error, buf, path:string())
    if not suc then
        return {}
    end
    return tbl
end

local function formatAsArray(str, ...)
    local index = 0
    local args = {...}
    return str:gsub('%{(.-)%}', function (pat)
        local id, fmt
        local pos = pat:find(':', 1, true)
        if pos then
            id = pat:sub(1, pos-1)
            fmt = pat:sub(pos+1)
        else
            id = pat
            fmt = 's'
        end
        id = tonumber(id)
        if not id then
            index = index + 1
            id = index
        end
        return ('%'..fmt):format(args[id])
    end)
end

local function formatAsTable(str, ...)
    local args = ...
    return str:gsub('%{(.-)%}', function (pat)
        local id, fmt
        local pos = pat:find(':', 1, true)
        if pos then
            id = pat:sub(1, pos-1)
            fmt = pat:sub(pos+1)
        else
            id = pat
            fmt = 's'
        end
        if not id then
            return
        end
        return ('%'..fmt):format(args[id])
    end)
end

local function loadLang(name, language)
    local tbl = loadFileByLanguage(name, 'en-US')
    if language ~= 'en-US' then
        local other = loadFileByLanguage(name, language)
        for k, v in pairs(other) do
            tbl[k] = v
        end
    end
    return setmetatable(tbl, {
        __index = function (self, key)
            self[key] = key
            return key
        end,
        __call = function (self, key, ...)
            local str = self[key]
            local suc, res
            if type(...) == 'table' then
                suc, res = pcall(formatAsTable, str, ...)
            else
                suc, res = pcall(formatAsArray, str, ...)
            end
            if suc then
                return res
            else
                -- 这里不能使用翻译,以免死循环
                log.warn(('[%s][%s-%s] formated error: %s'):format(
                    language, name, key, str
                ))
                return str
            end
        end,
    })
end

local function init()
    local id = osLanguage()
    local language = getLanguage(id)
    log.info(('VSC language: %s'):format(id))
    log.info(('LS  language: %s'):format(language))
    return setmetatable({ id = language }, {
        __index = function (self, name)
            local tbl = loadLang(name, language)
            self[name] = tbl
            return tbl
        end,
    })
end

return init()