veb: translations via %translation_key

This commit is contained in:
Alexander Medvednikov 2024-10-20 21:35:27 +03:00
parent 1cf38ed501
commit 4ed9d13803
13 changed files with 115 additions and 15 deletions

View File

@ -1028,7 +1028,7 @@ fn (t Tree) comptime_call(node ast.ComptimeCall) &Node {
obj.add_terse('method_name', t.string_node(node.method_name)) obj.add_terse('method_name', t.string_node(node.method_name))
obj.add_terse('left', t.expr(node.left)) obj.add_terse('left', t.expr(node.left))
obj.add_terse('is_vweb', t.bool_node(node.is_vweb)) obj.add_terse('is_vweb', t.bool_node(node.is_vweb))
obj.add_terse('vweb_tmpl', t.string_node(node.vweb_tmpl.path)) obj.add_terse('veb_tmpl', t.string_node(node.vweb_tmpl.path))
obj.add_terse('args_var', t.string_node(node.args_var)) obj.add_terse('args_var', t.string_node(node.args_var))
obj.add_terse('has_parens', t.bool_node(node.has_parens)) obj.add_terse('has_parens', t.bool_node(node.has_parens))
obj.add_terse('is_embed', t.bool_node(node.is_embed)) obj.add_terse('is_embed', t.bool_node(node.is_embed))

View File

@ -442,6 +442,7 @@ fn test_the_result_of_insert_should_be_the_last_insert_id() {
insert address into Address insert address into Address
} or { panic(err) } } or { panic(err) }
dump(aid1) dump(aid1)
assert aid1 == 1
aid2 := sql db { aid2 := sql db {
insert address into Address insert address into Address
} or { panic(err) } } or { panic(err) }

View File

@ -1989,7 +1989,7 @@ pub:
mut: mut:
is_d_resolved bool is_d_resolved bool
pub mut: pub mut:
vweb_tmpl File veb_tmpl File
left Expr left Expr
left_type Type left_type Type
result_type Type result_type Type

View File

@ -100,7 +100,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
} }
mut c2 := new_checker(c.table, pref2) mut c2 := new_checker(c.table, pref2)
c2.comptime_call_pos = node.pos.pos c2.comptime_call_pos = node.pos.pos
c2.check(mut node.vweb_tmpl) c2.check(mut node.veb_tmpl)
c.warnings << c2.warnings c.warnings << c2.warnings
c.errors << c2.errors c.errors << c2.errors
c.notices << c2.notices c.notices << c2.notices

View File

@ -50,7 +50,7 @@ fn (mut c Checker) error(message string, pos token.Pos) {
mut msg := message.replace('`Array_', '`[]') mut msg := message.replace('`Array_', '`[]')
if c.pref.is_vweb { if c.pref.is_vweb {
// Show in which veb action the error occurred (for easier debugging) // Show in which veb action the error occurred (for easier debugging)
veb_action := c.table.cur_fn.name.replace('vweb_tmpl_', '') veb_action := c.table.cur_fn.name.replace('veb_tmpl_', '')
mut j := 0 mut j := 0
for _, ch in veb_action { for _, ch in veb_action {
if ch.is_digit() { if ch.is_digit() {

View File

@ -87,9 +87,9 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
is_x_vweb := ret_sym.cname == 'x__vweb__Result' is_x_vweb := ret_sym.cname == 'x__vweb__Result'
is_veb := ret_sym.cname == 'veb__Result' is_veb := ret_sym.cname == 'veb__Result'
for stmt in node.vweb_tmpl.stmts { for stmt in node.veb_tmpl.stmts {
if stmt is ast.FnDecl { if stmt is ast.FnDecl {
if stmt.name.starts_with('main.vweb_tmpl') { if stmt.name.starts_with('main.veb_tmpl') {
if is_html { if is_html {
g.inside_vweb_tmpl = true g.inside_vweb_tmpl = true
if is_veb { if is_veb {

View File

@ -286,7 +286,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
ast.ComptimeCall { ast.ComptimeCall {
w.expr(node.left) w.expr(node.left)
if node.is_vweb { if node.is_vweb {
w.stmts(node.vweb_tmpl.stmts) w.stmts(node.veb_tmpl.stmts)
} }
} }
ast.DumpExpr { ast.DumpExpr {

View File

@ -324,7 +324,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
scope: unsafe { nil } scope: unsafe { nil }
is_vweb: true is_vweb: true
is_veb: is_veb is_veb: is_veb
vweb_tmpl: file veb_tmpl: file
method_name: method_name method_name: method_name
args_var: literal_string_param args_var: literal_string_param
args: [arg] args: [arg]

View File

@ -176,7 +176,7 @@ fn (mut p Parser) parse_map_type() ast.Type {
return 0 return 0
} }
if value_type.idx() == ast.void_type_idx { if value_type.idx() == ast.void_type_idx {
p.error_with_pos('map value type cannot be void', p.tok.pos()) p.error_with_pos('map value type is missing: use `map[KeyType]ValueType`', p.tok.pos())
return 0 return 0
} }
idx := p.table.find_or_register_map(key_type, value_type) idx := p.table.find_or_register_map(key_type, value_type)

View File

@ -1,4 +1,4 @@
vlib/v/parser/tests/map_init_void.vv:2:18: error: map value type cannot be void vlib/v/parser/tests/map_init_void.vv:2:18: error: map value type is missing: use `map[KeyType]ValueType`
1 | fn main() { 1 | fn main() {
2 | m := map[string]{} 2 | m := map[string]{}
| ^ | ^

View File

@ -75,7 +75,7 @@ fn is_html_open_tag(name string, s string) bool {
fn insert_template_code(fn_name string, tmpl_str_start string, line string) string { fn insert_template_code(fn_name string, tmpl_str_start string, line string) string {
// HTML, may include `@var` // HTML, may include `@var`
// escaped by cgen, unless it's a `vweb.RawHtml` string // escaped by cgen, unless it's a `veb.RawHtml` string
trailing_bs := tmpl_str_end + 'sb_${fn_name}.write_u8(92)\n' + tmpl_str_start trailing_bs := tmpl_str_end + 'sb_${fn_name}.write_u8(92)\n' + tmpl_str_start
replace_pairs := ['\\', '\\\\', r"'", "\\'", r'@@', r'@', r'@', r'$', r'$$', r'\@'] replace_pairs := ['\\', '\\\\', r"'", "\\'", r'@@', r'@', r'@', r'$', r'$$', r'\@']
mut rline := line.replace_each(replace_pairs) mut rline := line.replace_each(replace_pairs)
@ -225,8 +225,9 @@ pub fn (mut p Parser) compile_template_file(template_file string, fn_name string
mut source := strings.new_builder(1000) mut source := strings.new_builder(1000)
source.writeln(' source.writeln('
import strings import strings
// === vweb html template === import veb
fn vweb_tmpl_${fn_name}() string { // === veb html template ===
fn veb_tmpl_${fn_name}() string {
mut sb_${fn_name} := strings.new_builder(${lstartlength})\n mut sb_${fn_name} := strings.new_builder(${lstartlength})\n
') ')
@ -438,7 +439,7 @@ fn vweb_tmpl_${fn_name}() string {
key := line[pos + 1..end] key := line[pos + 1..end]
println('GOT tr key line="${line}" key="${key}"') println('GOT tr key line="${line}" key="${key}"')
// source.writeln('\${tr("${key}")}') // source.writeln('\${tr("${key}")}')
line_ = line.replace('%${key}', '\${tr("${key}")}') line_ = line.replace('%${key}', '\${veb.tr(ctx.lang.str(), "${key}")}')
// i += key.len // i += key.len
} }
// println(source.str()) // println(source.str())
@ -454,7 +455,7 @@ fn vweb_tmpl_${fn_name}() string {
source.writeln('\t_tmpl_res_${fn_name} := sb_${fn_name}.str() ') source.writeln('\t_tmpl_res_${fn_name} := sb_${fn_name}.str() ')
source.writeln('\treturn _tmpl_res_${fn_name}') source.writeln('\treturn _tmpl_res_${fn_name}')
source.writeln('}') source.writeln('}')
source.writeln('// === end of vweb html template_file: ${template_file} ===') source.writeln('// === end of veb html template_file: ${template_file} ===')
result := source.str() result := source.str()
$if trace_tmpl_expansion ? { $if trace_tmpl_expansion ? {

95
vlib/veb/tr.v Normal file
View File

@ -0,0 +1,95 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module veb
import os
const tr_map = load_tr_map()
pub fn raw(s string) RawHtml {
return RawHtml(s)
}
/*
struct TrData {
data
}
m map[string]TrData
*/
// This function is run once, on app startup. Setting the `tr_map` const.
// m['en']['house'] == 'House'
fn load_tr_map() map[string]map[string]string {
// Find all translation files to figure out how many languages we have and to load the translation map
files := os.walk_ext('translations/', '.tr')
mut res := map[string]map[string]string{}
for tr_path in files {
lang := fetch_lang_from_tr_path(tr_path)
text := os.read_file(tr_path) or {
eprintln('translation file "${tr_path}" failed to laod')
return {}
}
x := text.split('-----\n')
for i, s in x {
// println('val="${val}"')
nl_pos := s.index('\n') or { continue }
key := s[..nl_pos]
val := s[nl_pos..]
// v := vals[i + 1]
// println('key="${key}" => val="${v}"')
res[lang][key] = val
// println(val)
}
}
return res
}
fn fetch_lang_from_tr_path(path string) string {
return path.find_between('/', '.')
}
// Used by %key in templates
pub fn tr(lang string, key string) string {
res := tr_map[lang][key]
if res == '' {
eprintln('NO TRANSLATION FOR KEY "${key}"')
return key
}
return RawHtml(res)
}
pub fn tr_plural(lang string, key string, amount int) string {
s := tr_map[lang][key]
if s == '' {
eprintln('NO TRANSLATION FOR KEY "${key}"')
return key
}
if s.contains('|') {
//-----
// goods
// товар|а|ов
vals := s.split('|')
if vals.len != 3 {
return s
}
amount_str := amount.str()
// 1, 21, 121 товар
ending := if amount % 10 == 1 && !amount_str.ends_with('11') { // vals[0]
''
// 2, 3, 4, 22 товара
} else if amount % 10 == 2 && !amount_str.ends_with('12') {
vals[1]
} else if amount % 10 == 3 && !amount_str.ends_with('13') {
vals[1]
} else if amount % 10 == 4 && !amount_str.ends_with('14') {
vals[1]
} else {
// 5 товаров, 11 товаров etc
vals[2]
}
return vals[0] + ending
} else {
return s
}
}

View File

@ -1,3 +1,6 @@
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module veb module veb
import io import io