用于管理Django模型翻译的应用程序
项目描述
django-linguist 是一个 Django 应用程序,用于灵活的模型翻译。
以下是一些定义此应用程序与其他应用程序区别的原则
翻译存储在单个表中,并且您也可以为每个模型使用不同的一个
没有“每个模型一个i18n表”,说“再见”给噩梦:)
不再有痛苦的迁移
不与模型类名绑定,您可以自由使用自己的标识符
没有ORM查询技巧,它不会修补任何东西,这将使您升级Django变得更容易
没有魔法,它使用元类和混入,一切都是明确的
将现有项目接入非常简单
已准备好Django管理界面
如果您正在寻找“每个模型一个国际化表格”的方法,django-parler 是一个不错的选择。
安装
$ pip install django-linguist
在您的 settings.py 中,将 linguist 添加到 INSTALLED_APPS
INSTALLED_APPS = (
# Your other apps here
'linguist',
)
然后同步数据库
# >= Django 1.7
$ python manage.py migrate linguist
# < Django 1.7
$ python manage.py syncdb
这就完了。
配置
模型
三步完成
将 linguist.metaclasses.ModelMeta 添加到您的模型中作为元类
将 linguist.mixins.ManagerMixin 添加到您的模型管理器
在您的模型的 Meta 中添加 linguist 设置
不用担心,这相当简单
from django.db import models
from django.utils.translation import gettext_lazy as _
from linguist.metaclasses import ModelMeta as LinguistMeta
from linguist.mixins import ManagerMixin as LinguistManagerMixin
class PostManager(LinguistManagerMixin, models.Manager):
pass
class Post(models.Model, meta=LinguistMeta):
title = models.CharField(max_length=255)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
objects = PostManager()
class Meta:
verbose_name = _('post')
verbose_name_plural = _('posts')
linguist = {
'identifier': 'can-be-anything-you-want',
'fields': ('title', 'body'),
'default_language': 'fr',
}
linguist 元数据需要以下内容
identifier:您模型的一个唯一标识符(可以是您想要的任何东西)
fields:要翻译的模型字段列表或元组
并且可选地需要以下内容
default_language:要使用的默认语言
default_language_field:包含要使用的默认语言的字段(见下文)
decider:要使用而不是默认的翻译模型(见下文)
这就完了。您准备好了。
每个实例的默认语言
有时,您需要在实例级别定义默认语言。Linguist 通过 default_language_field 选项支持此功能。在您的模型中添加一个用于存储默认语言的字段,然后简单地将该字段名称提供给 Linguist。
让我们举一个例子
from django.db import models
from django.utils.translation import gettext_lazy as _
from linguist.metaclasses import ModelMeta as LinguistMeta
from linguist.mixins import ManagerMixin as LinguistManagerMixin
class PostManager(LinguistManagerMixin, models.Manager):
pass
class Post(models.Model, meta=LinguistMeta):
title = models.CharField(max_length=255)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
lang = models.CharField(max_length=5, default='en')
objects = PostManager()
class Meta:
verbose_name = _('post')
verbose_name_plural = _('posts')
linguist = {
'identifier': 'can-be-anything-you-want',
'fields': ('title', 'body'),
'default_language': 'en',
'default_language_field': 'lang',
}
自定义翻译表
默认情况下,Linguist 将翻译存储到 linguist.models.Translation 表中。因此在一个表中。如果您需要为特定模型使用其他表,Linguist 提供了一种覆盖此行为的方法:使用 deciders。
这实际上非常容易实现。
您可以在三步内完成它
创建一个继承自 linguist.models.base.Translation 的模型
别忘了将其定义为具体模型(在 Meta 中 abstract = False)
将此模型提供给 Linguist 元数据的 decider 选项
这个例子将为您带来光明
from django.db import models
from django.utils.translation import gettext_lazy as _
from linguist.metaclasses import ModelMeta as LinguistMeta
from linguist.mixins import ManagerMixin as LinguistManagerMixin
from linguist.models.base import Translation
# Our Post model decider
class PostTranslation(Translation):
class Meta:
abstract = False
class PostManager(LinguistManagerMixin, models.Manager):
pass
class Post(models.Model, meta=LinguistMeta):
title = models.CharField(max_length=255)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
objects = PostManager()
class Meta:
verbose_name = _('post')
verbose_name_plural = _('posts')
linguist = {
'identifier': 'can-be-anything-you-want',
'fields': ('title', 'body'),
'default_language': 'fr',
'decider': PostTranslation,
}
django.contrib.admin
简单使用 linguist.admin.TranslatableModelAdmin 类
from django.contrib import admin
from linguist.admin import TranslatableModelAdmin
from .models import Post
class PostAdmin(TranslatableModelAdmin):
list_display = ('title', 'body', 'created_at')
admin.site.register(Post, PostAdmin)
额外福利!您可以通过管理员类提供的 languages_column 属性在 list_display 中显示实例的语言
from django.contrib import admin
from linguist.admin import TranslatableModelAdmin
from .models import Post
class PostAdmin(TranslatableModelAdmin):
list_display = ('title', 'body', 'languages_column', 'created_at')
admin.site.register(Post, PostAdmin)
它是如何工作的
Linguist 为您的模型添加了虚拟语言字段。对于上面的例子,如果我们有 en、fr 和 it 在 settings.LANGUAGES 中,它将动态地在 Post 模型中添加以下字段
Post.title_en
Post.title_fr
Post.title_it
Post.body_en
Post.body_fr
Post.body_it
这些字段是虚拟的。它们不在 Post 表中。这些字段围绕 linguist.Translation 模型。所有翻译都将存储在此表中。
当您设置/获取 post.title 时,Linguist 将使用当前活动语言,并将设置/获取正确的字段。例如,如果您的默认语言是英语(en),那么 Post.title 将引用 post.title_en。
ModelMixin 通过以下属性和方法增强您的模型
- instance.linguist_identifier (只读属性)
您在相关翻译类中定义的模型标识符。指向 instance._linguist.identifier 的快捷方式。
- instance.default_language (读写属性)
默认使用的语言。快捷方式指向 instance._linguist.default_language。
- instance.translatable_fields (只读属性)
在相关翻译类中定义的可翻译字段。快捷方式指向 instance._linguist.fields。
- instance.available_languages (只读属性)
此实例可用的语言(包含这些语言的翻译内容)。
- instance.cached_translations_count (只读属性)
返回缓存的翻译数量。每次你设置新的语言并在可翻译字段上设置内容时,将为每种语言和字段创建一个缓存。它在实例保存时用于创建 Translation 对象。
- instance.active_language()
设置实例的当前活动语言。
- instance.clear_translations_cache()
删除所有缓存的翻译。请注意,你设置的所有内容都将被丢弃。因此,保存时不会创建/更新任何翻译。
# Let's create a new Post
>>> post = Post()
# Set English content
>>> post.activate_language('en')
>>> post.title = 'Hello'
# Now set French content
>>> post.activate_language('fr')
>>> post.title = 'Bonjour'
# Be sure everything works as expected for English
>>> post.activate_language('en')
>>> post.title
Hello
# And now for French
>>> post.activate_language('fr')
>>> post.title
Bonjour
# Sweet! Save translations!
>>> post.save()
预加载
为了提高性能,你可以预加载/预取翻译。
对于查询集(你的查询集必须继承自 Linguist 管理器/queryset)
>>> Post.objects.with_translations()
对于对象列表(所有你的对象都必须继承自 Linguist 模型)
>>> from linguist.helpers import prefetch_translations
>>> posts = list(Post.objects.all())
>>> prefetch_translations(posts)
对于实例(它必须继承自 Linguist 模型)
>>> post = Post.objects.first()
>>> post.prefetch_translations()
所有翻译都将缓存在实例中。数据库将不再被查询。
此预加载系统需要三个参数
field_names:要过滤的可翻译字段名称列表
languages:要过滤的语言列表
populate_missing:如果你想要填充缺失的翻译的缓存(默认为 True)
chunks_length:翻译 SELECT IN ids 的块限制
例如,我们只想预取英文的帖子标题,而不用空字符串填充缺失的翻译
>>> Post.objects.with_translations(field_names=['title'], languages=['en'], populate_missing=False)
这对于
QuerySet with_translations()
辅助 prefetch_translations()
实例方法 prefetch_translations()
“填充缺失的翻译”是什么意思?
很简单。默认情况下,当你预取翻译时,实例缓存将用所有支持的语言(见 settings)中的空字符串填充。例如,如果你有 en、fr 和 it 作为支持的语言,并且只有英文翻译,那么如果你尝试访问其他语言,将返回空字符串而不会进行任何数据库查询。
>>> Post.objects.with_translations()
>>> post.title_fr # no database hit here because
''
现在,如果你显式将 populate_missing 设置为 False,如果找不到翻译,它将来自数据库。
>>> Post.objects.with_translations(populate_missing=False)
>>> post.title_fr # database hit here
''
开发
# Don't have pip?
$ sudo easy_install pip
# Don't already have virtualenv?
$ sudo pip install virtualenv
# Clone and install dependencies
$ git clone https://github.com/ulule/django-linguist.git
$ cd django-linguist
$ make devenv
# Enable virtual environment.
$ source .venv/bin/activate
# Launch tests
$ make test
# Launch example project
$ make serve