【问题标题】:How to structure database with localization?如何用本地化构建数据库?
【发布时间】:2018-03-06 22:25:46
【问题描述】:

我正在使用 Flask 框架构建国际网站,该框架可以处理两种语言(目前):英语和法语,使用 Flask-Babel,我将数据存储在使用 SQLAlchemy 作为工具包的 SQL 数据库。

目前,我的模型对于每种语言都有几个重复的属性:

from project import db

class Model(db.Model)

    [...]
    name_en = db.Column(db.String)
    name_fr = db.Column(db.String)
    description_en = db.Column(db.String)
    description_fr = db.Column(db.String)

在我的 .html 模板中,我使用以下内容显示值:

{% if g.locale == 'fr' %}
  {{ model.name_fr }}
{% else %}
  {{ model.name_en }}
{% endif %}

有没有更好的方法来管理这个?如果我想添加一种新语言,修改所有模板会很乏味。 理想情况下,我想在我的模板中添加如下内容:

{{ model.name[g.locale] }}

可以实现吗?

【问题讨论】:

  • 你应该看看flask-babel,但你的问题在这里有点离题,或者可能太宽泛
  • 我尝试搜索关于如何为国际化构建 SQL 数据库的一般指导,这确实是我的问题,但我找不到任何问题。

标签: python flask database-design internationalization


【解决方案1】:

我对 Flask-Babel 一无所知,但我的处理方式是这样的:

我将所有与语言相关的数据移动到具有语言属性的单独表中。例如,如果我的一种语言解决方案是一张桌子,比如:

product (product_id, name, description, price)

对于多种语言,我创建了两个表:

product (product_id, price)
product_language (product_id, language, name, description)

然后当我想检索特定语言的数据时

select pl.name, pl.description, p.price
from product p
join product_language pl on pl.product_id=p.product_id
where p.product_id=@id and pl.language=@language

现在可以轻松添加新语言。代码更改为零:只需在 product_language 表中添加新记录即可。

您必须考虑如果没有特定语言的记录会发生什么。如果您只是像我的示例那样进行内部连接,那么您将得到一个未找到的结果,这可能会也可能不会接受。在某些情况下,这可能是一个错误。在其他情况下,您可能希望回退到默认语言。例如,我正在开发一个程序,其中我们有一个不同语言的消息表。我最近添加了代码来说明如果我们没有具有指定名称国家的消息,则回退到没有国家/地区的语言代码。就像我们没有“fr-ca”一样,试试“fr”。如果我们没有那个,回到英语。 (因为世界上每个人都会说英语,对吧?但说真的,因为我们是一家美国公司,而且我知道我们总是有英语。)

【讨论】:

    【解决方案2】:

    我不知道flask-babel,但只要你坚持使用g.locale 中定义的列上的扩展名相同的语言环境名称,那么你可以这样做

    {{ getattr(model, 'name_{}'.format(g.locale)) }}
    

    {{ getattr(model, 'description_{}'.format(g.locale)) }}
    

    显然,您可以使用其他方式来构建所需列的变量名,但getattr 应该允许您动态获取所需的值。

    或者,这可能是一个更好的解决方案,即更改您返回到页面的内容。与其返回 SQLAlchemy 对象并在模板中包含代码,不如让您的视图处理程序事先进行转换,并且简单总是在对象中返回正确的语言特定值。再说一次,我不知道 Flask,所以这可能是不可能的,但我不明白为什么不可能。

    希望对您有所帮助。

    【讨论】:

    • 感谢您的回答。它使用{{ model['name_{}'.format(g.locale)] }} 工作。 (getattr 无法在 .html 模板中访问,因为它是由 Jinja2 而不是真正的 python 处理的)。
    • 我会打开这个问题,看看我是否能得到更多关于通过国际化组织数据库的好策略的答案。
    • 很高兴有帮助。我很惊讶你可以在 Jinja 中访问 getattr,就像在 Mako 和 Chameleon 中一样,但是 TIL 一些关于 Jinja 的东西。谢谢;)
    【解决方案3】:

    我使用 Jay 的回答来创建我的模型,如下所示:

    from flask import g
    from project import db
    
    
    class Model(db.Model):
    
        __tablename__ = 'models'
    
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        languages = db.relationship('ModelLanguage', backref='model', lazy='dynamic')
        [...]
    
        def __init__(self, url):
            [...]
    
        def __repr__(self):
            return '<Model {}>'.format(self.local_name)
    
        @property
        def local_name(self):
            if hasattr(g, 'locale'):
                if self.languages.filter_by(locale=g.locale).first() is not None:
                    return self.languages.filter_by(locale=g.locale).first().name
            else:
                return self.languages.first().name
    
        @property
        def local_description(self):
            if hasattr(g, 'locale'):
                if self.languages.filter_by(locale=g.locale).first() is not None:
                    return self.languages.filter_by(locale=g.locale).first().description
            else:
                return self.languages.first().description
    
    
    class ModelLanguage(db.Model):
    
        __tablename__ = 'models_languages'
    
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        model_id = db.Column(db.Integer, db.ForeignKey('models.id'))
        locale = db.Column(db.String)
        name = db.Column(db.String)
        description = db.Column(db.String)
    
        def __init__(self, model_id, locale, name, description):
            self.model_id = model_id
            self.locale = locale
            self.name = name
            self.description = description
    
        def __repr__(self):
            return '<Language element for model {0} in {1} >'.format(self.model_id, self.locale)
    

    因此在我的模板中,我可以直接调用{{ model.local_name }} 以正确的语言显示元素。

    【讨论】:

    • 哦,当然是把它放到一个函数中,是的。我并不是要暗示每次都重新编写数据库访问权限。
    • 当然是给一些像我这样的新手争取时间的更具体的例子。 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 2021-05-24
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多