init
This commit is contained in:
commit
d4f5319e02
10 changed files with 293 additions and 0 deletions
2
erl/LINGUAS
Normal file
2
erl/LINGUAS
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
en
|
||||||
|
ru
|
12
erl/en.els
Normal file
12
erl/en.els
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Er2 Locale source file
|
||||||
|
|
||||||
|
TRANSLATORS: Plural forms!
|
||||||
|
TRANSLATORS: $plurals are needed
|
||||||
|
"My string"
|
||||||
|
> "\$hehe $plural form"
|
||||||
|
|
||||||
|
"New string"
|
||||||
|
= "New translate"
|
||||||
|
> "New translates"
|
||||||
|
|
||||||
|
"Basic string"
|
13
erl/ru.els
Normal file
13
erl/ru.els
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Er2 Locale source file
|
||||||
|
|
||||||
|
TRANSLATORS: Plural forms!
|
||||||
|
TRANSLATORS: $plurals are needed
|
||||||
|
"My string"
|
||||||
|
= "Моя строка"
|
||||||
|
> "\$hehe $plural форма"
|
||||||
|
|
||||||
|
"New string"
|
||||||
|
= "Новый перевод"
|
||||||
|
> "Новые переводы"
|
||||||
|
|
||||||
|
"Basic string" specially not translated
|
20
license
Normal file
20
license
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Zlib License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Er2 <er2@dismail.de>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgement in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
38
locale.lua
Normal file
38
locale.lua
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
-- Improved gettext
|
||||||
|
--- Er2 Locale
|
||||||
|
--- (c) Er2 2021 <er2@dismail.de>
|
||||||
|
--- Zlib License
|
||||||
|
local gtext = {
|
||||||
|
dloc = 'en_US', sdloc = 'en',
|
||||||
|
pref = '$'
|
||||||
|
}
|
||||||
|
function gtext:__call(str, t)
|
||||||
|
t = type(t) == 'table' and t or {}
|
||||||
|
t.plural = t.plural or 0
|
||||||
|
local plf = t.plural + 1
|
||||||
|
local tr = self.trans[self.locale or self.floc]
|
||||||
|
if tr and tr[str] and tr[str][plf] then str = tr[str][plf]
|
||||||
|
else
|
||||||
|
tr = self.trans[self.floc]
|
||||||
|
if tr and tr[str] and tr[str][plf] then str = tr[str][plf] end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Interpolation
|
||||||
|
str = str:gsub('(.?)%'..gtext.pref..'([%w_]+)', function(p, v)
|
||||||
|
if p == '\\' then return gtext.pref..v end
|
||||||
|
return p.. tostring(t[v] or '')
|
||||||
|
end)
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(path)
|
||||||
|
local self = setmetatable({
|
||||||
|
floc = gtext.dloc,
|
||||||
|
trans = require(path..'.loc')
|
||||||
|
}, gtext)
|
||||||
|
|
||||||
|
if not self.trans[self.floc] then self.floc = gtext.sdloc end
|
||||||
|
if not self.trans[self.floc] then self.floc = l:match '([^\n]+)' end
|
||||||
|
self.locale = self.floc
|
||||||
|
_, gettext = self, self
|
||||||
|
end
|
36
readme.org
Normal file
36
readme.org
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
* Er2 Locale
|
||||||
|
|
||||||
|
Originally it was a part of ErTK (under development),
|
||||||
|
but I decide to open source to other repository.
|
||||||
|
|
||||||
|
Currently there is only Lua implementation,
|
||||||
|
but you can port to other language.
|
||||||
|
|
||||||
|
* Syntax
|
||||||
|
|
||||||
|
Localization files is using it's own format (see ~syntax/example.els~).
|
||||||
|
Also you can see at the ~erl~ directory.
|
||||||
|
|
||||||
|
** Editor support
|
||||||
|
|
||||||
|
Syntax highlighting available only in ~micro~ editor
|
||||||
|
(~syntax~ directory)
|
||||||
|
|
||||||
|
* Tools
|
||||||
|
|
||||||
|
Except runtime we have 2 tools:
|
||||||
|
|
||||||
|
- ~compile.lua~ - Compiles els to one (prog. language specific!) file
|
||||||
|
|
||||||
|
- ~po2els.lua~ - If you want to migrate from gettext
|
||||||
|
or if translation program/service cannot export to els yet
|
||||||
|
|
||||||
|
* Example
|
||||||
|
|
||||||
|
#+begin_src lua
|
||||||
|
require('locale') 'erl' -- init and load erl folder
|
||||||
|
_.locale = 'ru' -- set locale will be used, maybe create $LANG detect
|
||||||
|
_("My string") -- basic usage
|
||||||
|
_ "My string" -- without (), lua feature
|
||||||
|
_("My string", {plural = 1}) -- print plural form, maybe create other function for this
|
||||||
|
#+end_src
|
13
syntax/els.yaml
Normal file
13
syntax/els.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
filetype: els
|
||||||
|
|
||||||
|
detect:
|
||||||
|
filename: "\\.els$"
|
||||||
|
header: "Er2 Locale"
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- comment: ".+" # Comment by default
|
||||||
|
- constant.string: "\"([^\"]+)\"$" # Non-critical bug
|
||||||
|
- todo: "(TODO|XXX|FIXME|TRANSLATORS):.+$"
|
||||||
|
- statement: "^[[:space:]]*[=>]"
|
||||||
|
- identifier: "[^\\\\]\\$([A-Za-z0-9)]+)"
|
||||||
|
- special: "\\\\.?"
|
20
syntax/example.els
Normal file
20
syntax/example.els
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Er2 Locale source
|
||||||
|
|
||||||
|
Let's create a new string
|
||||||
|
"Just string"
|
||||||
|
Currently it haven't got translation
|
||||||
|
but we can fix it
|
||||||
|
= "No, it's localized string"
|
||||||
|
Spaces is optional
|
||||||
|
Also we can replace this translation
|
||||||
|
= "Power string!"
|
||||||
|
|
||||||
|
This is basic, how about plural forms?
|
||||||
|
> "Power strings!"
|
||||||
|
Spaces is also optional
|
||||||
|
|
||||||
|
Oh, I forgot! We can use interpolation
|
||||||
|
> "\$escaped $plural not escaped variable"
|
||||||
|
To use it, type _("string", {key = value})
|
||||||
|
|
||||||
|
Now you know this localization format!
|
79
tools/compile.lua
Normal file
79
tools/compile.lua
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#!/usr/bin/lua
|
||||||
|
-- els to lua translator
|
||||||
|
--- (c) Er2 2021 <er2@dismail.de>
|
||||||
|
--- Zlib license
|
||||||
|
|
||||||
|
print '[1/4] Enter translation directory (without / at end)'
|
||||||
|
local dir = io.read()
|
||||||
|
|
||||||
|
local loc = {}
|
||||||
|
|
||||||
|
if not io.open(dir..'/LINGUAS') then
|
||||||
|
print '[2/4] Enter languages divided by space'
|
||||||
|
local l = io.read() .. ' '
|
||||||
|
for v in l:gmatch '([%w_]+)%s+' do table.insert(loc, v) end
|
||||||
|
else
|
||||||
|
print '[2/4] Reading LINGUAS'
|
||||||
|
local f = io.open(dir..'/LINGUAS')
|
||||||
|
for v in f:read('*a'):gmatch '([^\n]+)' do table.insert(loc, v) end
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
print '[3/4] Generating locales'
|
||||||
|
local t = os.time()
|
||||||
|
local lf = io.open(dir..'/loc.lua', 'w')
|
||||||
|
local k, v = 1
|
||||||
|
lf:write 'return{'
|
||||||
|
repeat v = loc[k]
|
||||||
|
local f = io.open(dir..'/'..v..'.els')
|
||||||
|
if f then print(' Generating', v)
|
||||||
|
local tr = f:read '*a'
|
||||||
|
f:close()
|
||||||
|
lf:write(('%s={'):format(v))
|
||||||
|
local trl, s = {}
|
||||||
|
tr = tr..'\n\b'
|
||||||
|
for l in tr:gmatch '([^\n]+)' do
|
||||||
|
local str = l:match '^%s*"(.+)"%s*$'
|
||||||
|
if l == '\b' or (str and str ~= s) then
|
||||||
|
for _, v in pairs(trl) do
|
||||||
|
v = v:gsub('\\(%$[%w_]+)', '\\\\%1')
|
||||||
|
lf:write(('"%s",'):format(v))
|
||||||
|
end
|
||||||
|
if s then lf:write '},' end
|
||||||
|
trl, s = {str}, str
|
||||||
|
if s then
|
||||||
|
print(' |> String', s)
|
||||||
|
lf:write(('["%s"]={'):format(s))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
str = l:match '^%s*=%s*"(.+)"%s*$'
|
||||||
|
if str and s then
|
||||||
|
print(' =>', str)
|
||||||
|
trl[1] = str
|
||||||
|
end
|
||||||
|
str = l:match '^%s*>%s*"(.+)"%s*$'
|
||||||
|
if str and s then
|
||||||
|
print(' ||>', str)
|
||||||
|
table.insert(trl, str)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
lf:write '},'
|
||||||
|
else
|
||||||
|
print(' 404 Not found', v)
|
||||||
|
table.remove(loc, k)
|
||||||
|
k = k - 1
|
||||||
|
end
|
||||||
|
k = k + 1
|
||||||
|
v = loc[k]
|
||||||
|
until not v
|
||||||
|
lf:write '}'
|
||||||
|
lf:flush()
|
||||||
|
lf:close()
|
||||||
|
print(('%d seconds'):format(os.time() - t))
|
||||||
|
|
||||||
|
print '[4/4] Locale linting'
|
||||||
|
require(dir..'.loc')
|
||||||
|
|
||||||
|
print 'Done!'
|
60
tools/po2els.lua
Normal file
60
tools/po2els.lua
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/lua
|
||||||
|
-- po to els translator
|
||||||
|
--- (c) Er2 2021 <er2@dismail.de>
|
||||||
|
--- Zlib license
|
||||||
|
|
||||||
|
print '[1/3] Enter translation directory (without / at end)'
|
||||||
|
local dir = io.read()
|
||||||
|
|
||||||
|
local loc = {}
|
||||||
|
|
||||||
|
if not io.open(dir..'/LINGUAS') then
|
||||||
|
print '[2/3] Enter languages divided by space'
|
||||||
|
local l = io.read() .. ' '
|
||||||
|
for v in l:gmatch '([%w_]+)%s+' do table.insert(loc, v) end
|
||||||
|
else
|
||||||
|
print '[2/3] Reading LINGUAS'
|
||||||
|
local f = io.open(dir..'/LINGUAS')
|
||||||
|
for v in f:read('*a'):gmatch '([^\n]+)' do table.insert(loc, v) end
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
print '[3/3] Generating els'
|
||||||
|
local t = os.time()
|
||||||
|
local w = 0
|
||||||
|
local k, v = 1
|
||||||
|
repeat v = loc[k]
|
||||||
|
local f = io.open(dir..'/'..v..'.po')
|
||||||
|
if f then print(' Generating', v)
|
||||||
|
local tr = f:read '*a'
|
||||||
|
f:close()
|
||||||
|
f = io.open(dir..'/'..v..'.els', 'w')
|
||||||
|
f:write 'Er2 Locale source file\n'
|
||||||
|
for l in tr:gmatch '[^\n]+' do
|
||||||
|
if l:match '%%%a' then w = w + 1
|
||||||
|
print(' WARN', 'Found printf string, not will be replaced')
|
||||||
|
print(' INFO', l)
|
||||||
|
end
|
||||||
|
l = l
|
||||||
|
:gsub('^%s*".*"%s*$', '')
|
||||||
|
:gsub('^msgid_plural.+', '')
|
||||||
|
:gsub('^msgid%s+"(.*)"', '"%1"')
|
||||||
|
:gsub('^msgstr%s+"(.*)"', ' = "%1"')
|
||||||
|
:gsub('^msgstr%s*%[%s*(%d+)%s*%]%s+(".*")', function(id, str)
|
||||||
|
return (id == '0' and ' = ' or ' > ') .. str end)
|
||||||
|
:gsub('^%s*[=>]?%s*""', '')
|
||||||
|
if #l > 0 then f:write(l, '\n') end
|
||||||
|
end
|
||||||
|
f:flush()
|
||||||
|
f:close()
|
||||||
|
else
|
||||||
|
print(' 404 Not found', v)
|
||||||
|
table.remove(loc, k)
|
||||||
|
k = k - 1
|
||||||
|
end
|
||||||
|
k = k + 1
|
||||||
|
v = loc[k]
|
||||||
|
until not v
|
||||||
|
print(('%d seconds, %d warnings'):format(os.time() - t, w))
|
||||||
|
|
||||||
|
print 'Done!'
|
Loading…
Reference in a new issue