Localize strings
This commit is contained in:
parent
820d10a44c
commit
c64fc00987
@ -22,6 +22,7 @@ import os.path
|
|||||||
import pickle
|
import pickle
|
||||||
import base64
|
import base64
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
from relational.relation import Relation
|
from relational.relation import Relation
|
||||||
from relational import parser
|
from relational import parser
|
||||||
@ -153,7 +154,7 @@ class UserInterface:
|
|||||||
def set_relation(self, name: str, rel: Relation) -> None:
|
def set_relation(self, name: str, rel: Relation) -> None:
|
||||||
'''Sets the relation corresponding to name.'''
|
'''Sets the relation corresponding to name.'''
|
||||||
if not is_valid_relation_name(name):
|
if not is_valid_relation_name(name):
|
||||||
raise Exception('Invalid name for destination relation')
|
raise Exception(_('Invalid name for destination relation'))
|
||||||
self.relations[name] = rel
|
self.relations[name] = rel
|
||||||
|
|
||||||
def suggest_name(self, filename: str) -> Optional[str]:
|
def suggest_name(self, filename: str) -> Optional[str]:
|
||||||
@ -184,7 +185,7 @@ class UserInterface:
|
|||||||
relname is not None, adds the result to the
|
relname is not None, adds the result to the
|
||||||
dictionary, with the name given in relname.'''
|
dictionary, with the name given in relname.'''
|
||||||
if not is_valid_relation_name(relname):
|
if not is_valid_relation_name(relname):
|
||||||
raise Exception('Invalid name for destination relation')
|
raise Exception(_('Invalid name for destination relation'))
|
||||||
|
|
||||||
expr = parser.parse(query)
|
expr = parser.parse(query)
|
||||||
result = expr(self.relations)
|
result = expr(self.relations)
|
||||||
@ -226,10 +227,10 @@ class UserInterface:
|
|||||||
try:
|
try:
|
||||||
r = self.execute(query, relname)
|
r = self.execute(query, relname)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception('Error in query: %s\n%s' % (
|
raise Exception(_('Error in query: %s\n%s') % (
|
||||||
query,
|
query,
|
||||||
str(e)
|
str(e)
|
||||||
))
|
))
|
||||||
if r is None:
|
if r is None:
|
||||||
raise Exception('No query executed')
|
raise Exception(_('No query executed'))
|
||||||
return r
|
return r
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
# http://ltworf.github.io/relational/grammar.html
|
# http://ltworf.github.io/relational/grammar.html
|
||||||
from typing import Optional, Union, List, Any, Dict, Literal
|
from typing import Optional, Union, List, Any, Dict, Literal
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
from relational import rtypes
|
from relational import rtypes
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ __all__ = [
|
|||||||
'parse',
|
'parse',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
PRODUCT = '*'
|
PRODUCT = '*'
|
||||||
DIFFERENCE = '-'
|
DIFFERENCE = '-'
|
||||||
UNION = '∪'
|
UNION = '∪'
|
||||||
@ -305,7 +307,7 @@ def parse_tokens(expression: List[Union[list, str]]) -> Node:
|
|||||||
expression = expression[0]
|
expression = expression[0]
|
||||||
|
|
||||||
if len(expression) == 0:
|
if len(expression) == 0:
|
||||||
raise ParserException('Failed to parse empty expression')
|
raise ParserException(_('Failed to parse empty expression'))
|
||||||
|
|
||||||
# The list contains only 1 string. Means it is the name of a relation
|
# The list contains only 1 string. Means it is the name of a relation
|
||||||
if len(expression) == 1:
|
if len(expression) == 1:
|
||||||
@ -330,28 +332,28 @@ def parse_tokens(expression: List[Union[list, str]]) -> Node:
|
|||||||
|
|
||||||
if len(expression[:i]) == 0:
|
if len(expression[:i]) == 0:
|
||||||
raise ParserException(
|
raise ParserException(
|
||||||
f'Expected left operand for {expression[i]!r}')
|
_(f'Expected left operand for {expression[i]!r}'))
|
||||||
|
|
||||||
if len(expression[i + 1:]) == 0:
|
if len(expression[i + 1:]) == 0:
|
||||||
raise ParserException(
|
raise ParserException(
|
||||||
f'Expected right operand for {expression[i]!r}')
|
_(f'Expected right operand for {expression[i]!r}'))
|
||||||
return Binary(expression[i], parse_tokens(expression[:i]), parse_tokens(expression[i + 1:])) # type: ignore
|
return Binary(expression[i], parse_tokens(expression[:i]), parse_tokens(expression[i + 1:])) # type: ignore
|
||||||
'''Searches for unary operators, parsing from right to left'''
|
'''Searches for unary operators, parsing from right to left'''
|
||||||
for i in range(len(expression)):
|
for i in range(len(expression)):
|
||||||
if expression[i] in u_operators: # Unary operator
|
if expression[i] in u_operators: # Unary operator
|
||||||
if len(expression) <= i + 2:
|
if len(expression) <= i + 2:
|
||||||
raise ParserException(
|
raise ParserException(
|
||||||
f'Expected more tokens in {expression[i]!r}')
|
_(f'Expected more tokens in {expression[i]!r}'))
|
||||||
elif len(expression) > i + 3:
|
elif len(expression) > i + 3:
|
||||||
raise ParserException(
|
raise ParserException(
|
||||||
f'Too many tokens in {expression[i]!r}')
|
_(f'Too many tokens in {expression[i]!r}'))
|
||||||
|
|
||||||
return Unary(
|
return Unary(
|
||||||
expression[i], # type: ignore
|
expression[i], # type: ignore
|
||||||
prop=expression[1 + i].strip(), # type: ignore
|
prop=expression[1 + i].strip(), # type: ignore
|
||||||
child=parse_tokens(expression[2 + i]) # type: ignore
|
child=parse_tokens(expression[2 + i]) # type: ignore
|
||||||
)
|
)
|
||||||
raise ParserException(f'Parse error on {expression!r}')
|
raise ParserException(_(f'Parse error on {expression!r}'))
|
||||||
|
|
||||||
|
|
||||||
def _find_matching_parenthesis(expression: str, start=0, openpar='(', closepar=')') -> Optional[int]:
|
def _find_matching_parenthesis(expression: str, start=0, openpar='(', closepar=')') -> Optional[int]:
|
||||||
@ -421,7 +423,7 @@ def tokenize(expression: str) -> list:
|
|||||||
end = _find_matching_parenthesis(expression)
|
end = _find_matching_parenthesis(expression)
|
||||||
if end is None:
|
if end is None:
|
||||||
raise TokenizerException(
|
raise TokenizerException(
|
||||||
"Missing matching ')' in '%s'" % expression)
|
_(f'Missing matching \')\' in \'{expression}\''))
|
||||||
# Appends the tokenization of the content of the parenthesis
|
# Appends the tokenization of the content of the parenthesis
|
||||||
items.append(tokenize(expression[1:end]))
|
items.append(tokenize(expression[1:end]))
|
||||||
# Removes the entire parentesis and content from the expression
|
# Removes the entire parentesis and content from the expression
|
||||||
|
@ -24,6 +24,7 @@ from collections import deque
|
|||||||
from typing import FrozenSet, Iterable, List, Dict, Tuple, Optional
|
from typing import FrozenSet, Iterable, List, Dict, Tuple, Optional
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
from relational.rtypes import *
|
from relational.rtypes import *
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ class Relation:
|
|||||||
content = []
|
content = []
|
||||||
for row in loaded['content']:
|
for row in loaded['content']:
|
||||||
if len(row) != len(header):
|
if len(row) != len(header):
|
||||||
raise ValueError(f'Line {row} contains an incorrect amount of values')
|
raise ValueError(_(f'Line {row} contains an incorrect amount of values'))
|
||||||
t_row: Tuple[Optional[Union[int, float, str, Rdate]], ...] = load(
|
t_row: Tuple[Optional[Union[int, float, str, Rdate]], ...] = load(
|
||||||
row,
|
row,
|
||||||
Tuple[Optional[Union[int, float, str, Rdate]], ...], # type: ignore
|
Tuple[Optional[Union[int, float, str, Rdate]], ...], # type: ignore
|
||||||
@ -136,7 +137,7 @@ class Relation:
|
|||||||
|
|
||||||
for row in content:
|
for row in content:
|
||||||
if len(row) != len(header):
|
if len(row) != len(header):
|
||||||
raise ValueError(f'Line {row} contains an incorrect amount of values')
|
raise ValueError(_(f'Line {row} contains an incorrect amount of values'))
|
||||||
r_content.append(row)
|
r_content.append(row)
|
||||||
|
|
||||||
# Guess types
|
# Guess types
|
||||||
@ -169,7 +170,7 @@ class Relation:
|
|||||||
return other
|
return other
|
||||||
elif len(self.header) == len(other.header) and self.header.sharedAttributes(other.header) == len(self.header):
|
elif len(self.header) == len(other.header) and self.header.sharedAttributes(other.header) == len(self.header):
|
||||||
return other.projection(self.header)
|
return other.projection(self.header)
|
||||||
raise TypeError('Relations differ: [%s] [%s]' % (
|
raise TypeError(_('Relations differ: [%s] [%s]') % (
|
||||||
','.join(self.header), ','.join(other.header)
|
','.join(self.header), ','.join(other.header)
|
||||||
))
|
))
|
||||||
|
|
||||||
@ -180,7 +181,7 @@ class Relation:
|
|||||||
try:
|
try:
|
||||||
c_expr = compile(expr, 'selection', 'eval')
|
c_expr = compile(expr, 'selection', 'eval')
|
||||||
except:
|
except:
|
||||||
raise Exception(f'Failed to compile expression: {expr}')
|
raise Exception(_(f'Failed to compile expression: {expr}'))
|
||||||
|
|
||||||
content = []
|
content = []
|
||||||
for i in self.content:
|
for i in self.content:
|
||||||
@ -193,7 +194,7 @@ class Relation:
|
|||||||
if eval(c_expr, attributes):
|
if eval(c_expr, attributes):
|
||||||
content.append(i)
|
content.append(i)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise Exception(f'Failed to evaluate {expr} with {i}\n{e}')
|
raise Exception(_(f'Failed to evaluate {expr} with {i}\n{e}'))
|
||||||
return Relation(self.header, frozenset(content))
|
return Relation(self.header, frozenset(content))
|
||||||
|
|
||||||
def product(self, other: 'Relation') -> 'Relation':
|
def product(self, other: 'Relation') -> 'Relation':
|
||||||
@ -205,7 +206,7 @@ class Relation:
|
|||||||
raise Exception('Operand must be a relation')
|
raise Exception('Operand must be a relation')
|
||||||
if self.header.sharedAttributes(other.header) != 0:
|
if self.header.sharedAttributes(other.header) != 0:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
'Unable to perform product on relations with colliding attributes'
|
_('Unable to perform product on relations with colliding attributes')
|
||||||
)
|
)
|
||||||
header = Header(self.header + other.header)
|
header = Header(self.header + other.header)
|
||||||
|
|
||||||
@ -231,7 +232,7 @@ class Relation:
|
|||||||
ids = self.header.getAttributesId(attributes)
|
ids = self.header.getAttributesId(attributes)
|
||||||
|
|
||||||
if len(ids) == 0:
|
if len(ids) == 0:
|
||||||
raise Exception('Invalid attributes for projection')
|
raise Exception(_('Invalid attributes for projection'))
|
||||||
header = Header((self.header[i] for i in ids))
|
header = Header((self.header[i] for i in ids))
|
||||||
|
|
||||||
content = frozenset(tuple((i[j] for j in ids)) for i in self.content)
|
content = frozenset(tuple((i[j] for j in ids)) for i in self.content)
|
||||||
@ -472,7 +473,7 @@ class Header(tuple):
|
|||||||
|
|
||||||
for i in self:
|
for i in self:
|
||||||
if not is_valid_relation_name(i):
|
if not is_valid_relation_name(i):
|
||||||
raise Exception(f'"{i}" is not a valid attribute name')
|
raise Exception(_(f'"{i}" is not a valid attribute name'))
|
||||||
|
|
||||||
if len(self) != len(set(self)):
|
if len(self) != len(set(self)):
|
||||||
raise Exception('Attribute names must be unique')
|
raise Exception('Attribute names must be unique')
|
||||||
@ -488,12 +489,12 @@ class Header(tuple):
|
|||||||
attrs = list(self)
|
attrs = list(self)
|
||||||
for old, new in params.items():
|
for old, new in params.items():
|
||||||
if not is_valid_relation_name(new):
|
if not is_valid_relation_name(new):
|
||||||
raise Exception(f'{new} is not a valid attribute name')
|
raise Exception(_(f'{new} is not a valid attribute name'))
|
||||||
try:
|
try:
|
||||||
id_ = attrs.index(old)
|
id_ = attrs.index(old)
|
||||||
attrs[id_] = new
|
attrs[id_] = new
|
||||||
except:
|
except:
|
||||||
raise Exception(f'Field not found: {old}')
|
raise Exception(_(f'Field not found: {old}'))
|
||||||
return Header(attrs)
|
return Header(attrs)
|
||||||
|
|
||||||
def sharedAttributes(self, other: 'Header') -> int:
|
def sharedAttributes(self, other: 'Header') -> int:
|
||||||
|
@ -25,6 +25,7 @@ import keyword
|
|||||||
import re
|
import re
|
||||||
from typing import Union, Set, Any, Callable, Type, Optional
|
from typing import Union, Set, Any, Callable, Type, Optional
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
|
||||||
RELATION_NAME_REGEXP = re.compile(r'^[_a-z][_a-z0-9]*$', re.IGNORECASE)
|
RELATION_NAME_REGEXP = re.compile(r'^[_a-z][_a-z0-9]*$', re.IGNORECASE)
|
||||||
@ -83,7 +84,7 @@ class Rdate:
|
|||||||
'''date: A string representing a date YYYY-MM-DD'''
|
'''date: A string representing a date YYYY-MM-DD'''
|
||||||
r = _date_regexp.match(date)
|
r = _date_regexp.match(date)
|
||||||
if not r:
|
if not r:
|
||||||
raise ValueError(f'{date} is not a valid date')
|
raise ValueError(_(f'{date} is not a valid date'))
|
||||||
|
|
||||||
year = int(r.group(1))
|
year = int(r.group(1))
|
||||||
month = int(r.group(3))
|
month = int(r.group(3))
|
||||||
|
Loading…
Reference in New Issue
Block a user