django 权限和内容类型翻译

Posted

技术标签:

【中文标题】django 权限和内容类型翻译【英文标题】:django permissions and contenttypes translations 【发布时间】:2015-06-06 13:53:18 【问题描述】:

我一直在使用django-modeltranslation 在 django 中翻译模型。这真的很简单,并且在我一直在开发的应用程序上运行得非常好,其中所有模型翻译的内容都由最终用户插入表单

例如:输入:content, content_en, content_pt, ...

我必须构建一个应用程序,我需要翻译 django 生成的“内置”模型字符串,例如“auth.permission.name”或“contenttypes.contenttype.name” 并将它们添加到翻译 django.po 文件中

我想出了一个很好的解决方案,

它使用 post_migration 信号创建带有 ugettext_lazy 元素列表的文件,因此新的字符串,例如新的 contenttype.name,被动态添加到“django.po”并加载到数据库中。

然而,使用 ugettext 调用创建文件有点奇怪

为了注册字符串,但我没有找到另一种注册方法并将它们动态添加到 django.po 文件中,所以我需要你的帮助

这是我所做的:

1. 我创建了一个名为“工具”的应用程序,它是 INSTALLED_APPS 上的最后一个应用程序,因此它的迁移自然是最后一个被调用的。这个应用程序没有任何模型,它只是运行迁移,有 django-modeltranslation translation.py 文件和一个带有 post_migration 信号调用的应用程序配置。

# translations.py

from modeltranslation.translator import translator, TranslationOptions
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

class PermissionTranslationOptions(TranslationOptions):
    fields = ('name',)

class ContentTypeTranslationOptions(TranslationOptions):
    fields = ('name',)

translator.register(Permission, PermissionTranslationOptions)
translator.register(ContentType, ContentTypeTranslationOptions)

2. 运行“ma​​nage.py makemigrations”会在“auth”和“contenttypes”应用程序上创建带有额外“name_*”字段的迁移。 p>

3.该应用的应用配置具有 post_migrate 信号

# __init__.py

default_app_config = 'apps.tools.config.SystemConfig'

# config.py

from django.apps import AppConfig
from django.db.models.signals import post_migrate
from apps.tools.translations.exporter import make_translations
from apps.tools.translations.importer import load_translations


def run_translations(sender, **kwargs):

    # This creates the translations
    make_translations()

    # This loads the the translations to the db
    load_translations()


class SystemConfig(AppConfig):

    name = 'apps.tools'
    verbose_name = 'Tools'

    def ready(self):
        # Call post migration operations
        post_migrate.connect(run_translations, sender=self)

4. 迁移后调用 make_translations() 并生成包含 uggettext_lazy 调用列表的文件。

这是我想改变的一点。我真的需要创建文件吗?

# exporter

import os
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.utils import translation
from django.contrib.contenttypes.management import update_all_contenttypes


# TODO 
# It has got to be another way

def make_translations():
    # lets go default
    translation.activate("en")
    update_all_contenttypes()

    try:
        f = open(os.path.join(os.path.realpath(os.path.dirname(__file__)), 'translations.py'), 'w')

        # Write file
        f.write("from django.utils.translation import ugettext_lazy as _\n\n")

        # All Permissions to lazy text
        f.write('permissions = \n')
        for perm in Permission.objects.all().order_by('id'):
            f.write('    "'+str(perm.id)+'": _("'+perm.name+'"),\n')
        f.write('\n\n')

        # All Content types to lazy text
        f.write('content_types = \n')
        for content in ContentType.objects.all().order_by('id'):
            f.write('    "'+str(content.id)+'": _("'+content.name+'"),\n')
        f.write('\n\n')

        # Closing file
        f.close()

        # Importing file to get it registered with ugettext_lazy
        try:
            from apps.tools.translations import translations
        except:
            print('Could not import file')
            pass
    except:
        print('Could not create file')
        pass

上面的结果是这样的文件:

from django.utils.translation import ugettext_lazy as _

permissions = 
    "1": _("Can add permission"),
    "2": _("Can change permission"),
    "3": _("Can delete permission"),
    "4": _("Can add group"),
  ...


content_types = 
    "1": _("group"),
    "2": _("user"),
    "3": _("permission"),
    "4": _("content type"),
    "5": _("session"),
  ...

5. 运行“makemessages”会将此字符串添加到“django.po”文件中,但是,post_migration 信号不会在此停止,而是将现有的已编译字符串加载到数据库中

# importer

from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from django.utils import translation


def load_translations():
    try:
        from apps.tools.translations.translations import permissions, content_types
    except:
        # File does not exists
        print('Translations could not be loaded')
        return

    # For each language
    for lang in settings.LANGUAGES:

        # Activate language
        translation.activate(lang[0])

        # Loading translated permissions
        all_permissions = Permission.objects.all()
        for permission in all_permissions:
            permission.name = unicode(permissions[str(permission.id)])
            permission.save()

        # Loading translated content_types
        all_contenttypes = ContentType.objects.all()
        for contenttype in all_contenttypes:
            contenttype.name = unicode(content_types[str(contenttype.id)])
            contenttype.save()

如何在不创建文件的情况下替换“make_translations()”并将这些字符串注册到 ugettext_lazy?

感谢您的帮助

【问题讨论】:

您能否在第一部分详细说明您的解决方案。这可能有助于了解您在做什么。 【参考方案1】:

我已经阅读了您的帖子,并且不知何故我在翻译权限时遇到了同样的问题,我找到了一个非常简单的方法来解决这个问题:

我不建议这样做,也不会后悔。

但解决方案是: 编辑这个路径的app_labeled_name函数修饰为propertyContentType类的.pyenv/Lib/site-packages/django/contrib/contenttypes/models.py,变成这样:

@property
def app_labeled_name(self):
    model = self.model_class()
    if not model:
        return self.model
    return '%s | %s' % (apps.get_app_config(model._meta.app_label).verbose_name,
                        model._meta.verbose_name)

诀窍是使用apps.get_app_config(model._meta.app_label).verbose_name 而不是model._meta.app_label,因此它会使用与在您的应用程序的AppConfig 子类中为您的应用程序设置的任何用途相同的verbose_name

【讨论】:

以上是关于django 权限和内容类型翻译的主要内容,如果未能解决你的问题,请参考以下文章

Django中不同的用户级别

[django]错误:无法重置内容类型

Django - 在管理面板中显示具有内容类型的模型

Django 内容类型究竟是如何工作的?

django rest 框架:内容类型 unique_together 和序列化

django 重置内容类型不匹配