mirror of
https://github.com/vlang/v.git
synced 2025-08-04 02:07:28 -04:00
veb: translations via %translation_key
This commit is contained in:
parent
1cf38ed501
commit
4ed9d13803
@ -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('left', t.expr(node.left))
|
||||
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('has_parens', t.bool_node(node.has_parens))
|
||||
obj.add_terse('is_embed', t.bool_node(node.is_embed))
|
||||
|
@ -442,6 +442,7 @@ fn test_the_result_of_insert_should_be_the_last_insert_id() {
|
||||
insert address into Address
|
||||
} or { panic(err) }
|
||||
dump(aid1)
|
||||
assert aid1 == 1
|
||||
aid2 := sql db {
|
||||
insert address into Address
|
||||
} or { panic(err) }
|
||||
|
@ -1989,7 +1989,7 @@ pub:
|
||||
mut:
|
||||
is_d_resolved bool
|
||||
pub mut:
|
||||
vweb_tmpl File
|
||||
veb_tmpl File
|
||||
left Expr
|
||||
left_type Type
|
||||
result_type Type
|
||||
|
@ -100,7 +100,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
||||
}
|
||||
mut c2 := new_checker(c.table, pref2)
|
||||
c2.comptime_call_pos = node.pos.pos
|
||||
c2.check(mut node.vweb_tmpl)
|
||||
c2.check(mut node.veb_tmpl)
|
||||
c.warnings << c2.warnings
|
||||
c.errors << c2.errors
|
||||
c.notices << c2.notices
|
||||
|
@ -50,7 +50,7 @@ fn (mut c Checker) error(message string, pos token.Pos) {
|
||||
mut msg := message.replace('`Array_', '`[]')
|
||||
if c.pref.is_vweb {
|
||||
// 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
|
||||
for _, ch in veb_action {
|
||||
if ch.is_digit() {
|
||||
|
@ -87,9 +87,9 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
|
||||
is_x_vweb := ret_sym.cname == 'x__vweb__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.name.starts_with('main.vweb_tmpl') {
|
||||
if stmt.name.starts_with('main.veb_tmpl') {
|
||||
if is_html {
|
||||
g.inside_vweb_tmpl = true
|
||||
if is_veb {
|
||||
|
@ -286,7 +286,7 @@ fn (mut w Walker) expr(node_ ast.Expr) {
|
||||
ast.ComptimeCall {
|
||||
w.expr(node.left)
|
||||
if node.is_vweb {
|
||||
w.stmts(node.vweb_tmpl.stmts)
|
||||
w.stmts(node.veb_tmpl.stmts)
|
||||
}
|
||||
}
|
||||
ast.DumpExpr {
|
||||
|
@ -324,7 +324,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||
scope: unsafe { nil }
|
||||
is_vweb: true
|
||||
is_veb: is_veb
|
||||
vweb_tmpl: file
|
||||
veb_tmpl: file
|
||||
method_name: method_name
|
||||
args_var: literal_string_param
|
||||
args: [arg]
|
||||
|
@ -176,7 +176,7 @@ fn (mut p Parser) parse_map_type() ast.Type {
|
||||
return 0
|
||||
}
|
||||
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
|
||||
}
|
||||
idx := p.table.find_or_register_map(key_type, value_type)
|
||||
|
@ -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() {
|
||||
2 | m := map[string]{}
|
||||
| ^
|
||||
|
@ -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 {
|
||||
// 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
|
||||
replace_pairs := ['\\', '\\\\', r"'", "\\'", r'@@', r'@', r'@', r'$', r'$$', r'\@']
|
||||
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)
|
||||
source.writeln('
|
||||
import strings
|
||||
// === vweb html template ===
|
||||
fn vweb_tmpl_${fn_name}() string {
|
||||
import veb
|
||||
// === veb html template ===
|
||||
fn veb_tmpl_${fn_name}() string {
|
||||
mut sb_${fn_name} := strings.new_builder(${lstartlength})\n
|
||||
|
||||
')
|
||||
@ -438,7 +439,7 @@ fn vweb_tmpl_${fn_name}() string {
|
||||
key := line[pos + 1..end]
|
||||
println('GOT tr key line="${line}" key="${key}"')
|
||||
// source.writeln('\${tr("${key}")}')
|
||||
line_ = line.replace('%${key}', '\${tr("${key}")}')
|
||||
line_ = line.replace('%${key}', '\${veb.tr(ctx.lang.str(), "${key}")}')
|
||||
// i += key.len
|
||||
}
|
||||
// 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('\treturn _tmpl_res_${fn_name}')
|
||||
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()
|
||||
$if trace_tmpl_expansion ? {
|
||||
|
95
vlib/veb/tr.v
Normal file
95
vlib/veb/tr.v
Normal 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
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
import io
|
||||
|
Loading…
x
Reference in New Issue
Block a user