言語機能

説明

Plone のプログラムによって言語の状態を参照、変更します。

はじめに

それぞれのセッションでは言語に関連する情報を記載しています。

有効な言語は plone.i18n.negotiator モジュールによって 決定 されます。 以下のいくつかの要因によってどの言語を使用するかを決定します。

  • クッキー(言語選択の設定に使用)
  • ドメイン名(日本語は .ja、英語は .en のような)
  • コンテクスト(現在のコンテンツの)言語
  • ブラウザの言語ヘッダー

言語の決定についてはページを表示するときの最初にネゴシエーションを行います。

現在の言語を取得する

view/viewlet で現在の言語を取得する例です。

from Acquisition import aq_inner
from zope.component import getMultiAdapter

class MyView(BrowserView):

    ...

        def language(self):
            """
            @return: Two letter string, the active language code
            """
            context = aq_inner(self.context)
            portal_state = getMultiAdapter((context, self.request), name=u'plone_portal_state')
            current_language = portal_state.language()
            return current_language

コンテントアイテムの言語を取得する

全てのコンテンツトオブジェクトは IDublinCore インターフェースで定義されている Language() での検索をサポートしているわけではありません。 以下は、コンテンツが提供された言語を安全に取得する方法です。

BrowserView メソッドの例:

from Acquisition import aq_inner

def language(self):
    """ Get the language of the context.

    Useful in producing <html> tag.
    You need to output language for every HTML page, see http://www.w3.org/TR/xhtml1/#strict


    @return: The two letter language code of the current content.
    """
    portal_state = self.context.unrestrictedTraverse("@@plone_portal_state")

    return aq_inner(self.context).Language() or portal_state.default_language()

サイトの言語設定を行う

Manually:

# Setup site langauge settings
portal = context.getSite()
ltool = portal.portal_languages
defaultLanguage = 'en'
supportedLanguages = ['en','es']
ltool.manage_setLanguageSettings(defaultLanguage, supportedLanguages,
                                      setUseCombinedLanguageCodes=False)

手動で行います。:

# サイトの言語設定を行います
portal = context.getSite()
ltool = portal.portal_languages
defaultLanguage = 'en'
supportedLanguages = ['en','ja']
ltool.manage_setLanguageSettings(defaultLanguage, supportedLanguages,
                                      setUseCombinedLanguageCodes=False)

ユニットテストのために、言語の設定を変更したあとの afterSetUp() の中で以下のコードを実行する必要があります。:

# THIS IS FOR UNIT TESTING ONLY
# Normally called by pretraverse hook,
# but must be called manually for the unit tests
# Goes only for the current request
ltool.setLanguageBindings()

GenericSetup と propertiestool.xml を使用します。

Linguaplone が有効になっているサイトでは、 GenericSetup の portal_languages.xml を使用します。

言語セレクターのカスタマイズ

多言語の plone サイトでは2種類の言語セレクター用の viewlet が存在します。

  • Plone vanilla
  • LinguaPlone - LinguaPlone アドオンプロダクトをインストールすると、 Plone デフォルトの言語セレクターを LinguaPlone が提供するものに置き換えます。

さらに情報を得るためには、以下を参照してください。

言語の旗でトップレベルドメインを切り替える

異なる言語のために複数ドメインを使用しているサイトでは、言語セレクターでそれぞれのドメインを遷移する方がよりよい場合があります。 検索エンジンは動的な言語の変更はうまく処理できず言語切り替えのリンクをインデックス化し、その結果あなたのサイトの検索結果として適切でないものを出力する場合があります。

言語ネゴシエーションのカスタマイズ

以下のサンプルコードを参照してください。

languages.py:

"""

    Custom language negotiator based on hostname.

"""

from Products.PloneLanguageTool import LanguageTool

# These are default languages available when hostname cannot be solved
all_languages = [ "fi", "en" ]

def get_host_name(request):
    """ Extract host name in virtual host safe manner

    @param request: HTTPRequest object, assumed contains environ dictionary

    @return: Host DNS name, as requested by client. Lowercased, no port part.
    """

    if "HTTP_X_FORWARDED_HOST" in request.environ:
        # Virtual host
        host = request.environ["HTTP_X_FORWARDED_HOST"]
    elif "HTTP_HOST" in request.environ:
        # Direct client request
        host = request.environ["HTTP_HOST"]
    else:
        host = None
        return host

    # separate to domain name and port sections
    host=host.split(":")[0].lower()

    return host


def get_language(domain_name):
    """
    @param domain_name: Full qualified domain name of HTTP request
    """

    if domain_name.endswith(".mobi") or domain_name.endswith(".com"):
        return "en"
    elif domain_name.endswith(".fi"):
        return "fi"
    else:
        return "en"

def getCcTLDLanguages(self):
    """
    Monkey-patched top level domain language negotiator.

    This will be installed by collective.monkeypatcher.
    """

    if not hasattr(self, 'REQUEST'):
        return None

    request = self.REQUEST

    # Could not extract hostname
    hostname = get_host_name(request)

    if not hostname:
        return all_languages

    # Limit available languages based on hostname
    langs = [ get_language(hostname) ]

    return langs

# Also we need to fix a bug present in Plone 3.3.5
#
#    @memoize
#    def language(self):
#        # TODO Looking for lower-case language is wrong, the negotiator
#        # machinery uses uppercase LANGUAGE. We cannot change this as long
#        # as we don't ship with a newer PloneLanguageTool which respects
#        # the content language, though.
#        return self.request.get('language', None) or \
#                aq_inner(self.context).Language() or self.default_language()

from plone.memoize.view import memoize, memoize_contextless

def working_portal_state_language(self):
        return self.request.get('LANGUAGE', None) or \
                self.request.get('language', None) or \
                aq_inner(self.context).Language() or \
                self.default_language()

working_portal_state_language = memoize(working_portal_state_language)

configure.zcml:

<!-- Use collective.monkeypatcher to introduce our custom language negotiation phase -->
<monkey:patch
      description="Add custom TLD language resolution"
      class="Products.PloneLanguageTool.LanguageTool"
      original="getCcTLDLanguages"
      replacement=".languages.getCcTLDLanguages"
      />

<monkey:patch
      description="Fix Plone 3.3.5 bug"
      class="plone.app.layout.globals.portal.PortalState"
      original="language"
      replacement=".languages.working_portal_state_language"
      />