Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format canonical URL structure correctly with URL Processors

EDIT: Could you read my question more carefully? This question is specific and not duplicated as has been said. Obviously I read this question before post.


In this demo code from the docs, the fragment after the lang parameter will be static. So, in English /en/about, and for example, in Portuguese /pt/about. Well, the correct, should be /pt/sobre.

Any idea about the correct way to make that with URL Processors?

from flask import Flask, g

app = Flask(__name__)

@app.url_defaults
def add_language_code(endpoint, values):
    if 'lang_code' in values or not g.lang_code:
        return
    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
        values['lang_code'] = g.lang_code

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    g.lang_code = values.pop('lang_code', None)

@app.route('/<lang_code>/')
def index():
    ...

@app.route('/<lang_code>/about')
def about():
like image 570
user2990084 Avatar asked May 29 '14 08:05

user2990084


People also ask

How do I fix my canonical URL?

There are two main ways to fix canonical issues on a website: by implementing 301 redirects, and/or by adding canonical tags to your site's pages to tell Google which of several similar pages is preferred. The right option depends on the canonical issue you're trying to resolve.

What does a canonical URL look like?

A canonical URL is the URL of the best representative page from a group of duplicate pages, according to Google. For example, if you have two URLs for the same page (such as example.com? dress=1234 and example.com/dresses/1234 ), Google chooses one as canonical.

How do I create a canonical URL?

Navigate to the Settings tab. Then click Advanced Options. In the Canonical URL section, enter a canonical URL for the page or post's content. This is the URL search engines will prioritize when displaying search results relevant to this content.

What is a canonical URL and why should I care?

A canonical URL or “canonical link” is an HTML element that helps search engines avoid the appearance of duplicate content. It does this by identifying a preferred version of a web page. Using canonical URLs improves your site's SEO and makes searching the site easier for your visitors.


1 Answers

Ok, you already have language prefix. So you need have several translations for next part.

The easiest way it use several routes or converters:

@app.route('/<lang_code>/about')
@app.route('/<lang_code>/sobre')
def about():
    pass

or

@app.route('/<lang_code>/<any(about,sobre):about>')
def about(about):
    pass

But it hard to support and add new languages.

Second way is change route method to translate special words or add special translate processor converter, last more interesting and implicit:

from werkzeug.routing import AnyConverter


languages = ['en', 'pt']


def translate_url(word, language):
    if language == 'pt' and word == 'about':
        return 'sobre'
    return word


class TranslateConverter(AnyConverter):

    def __init__(self, map, item):
        AnyConverter.__init__(self, map, *[translate_url(item, language) 
                                           for language in languages])


app.url_map.converters['tr'] = TranslateConverter


@app.route('/<lang_code>/<tr(about):about>')
def about(about):
    pass

But this example have next issue:

/en/about
/en/sorbe
/pt/about
/pt/sorbe

is valid urls, but you can also try use own Rule class (Flask.url_rule_class) where in match method you can process this cases:

from werkzeug.routing import AnyConverter, Rule


class TranslateConverter(AnyConverter):

    def __init__(self, map, item):
        self.language_pairs = {language: translate_url(item, language)
                               for language in languages}
        AnyConverter.__init__(self, map, *tuple(self.language_pairs.values()))


class TranslateCorrelationRule(Rule):

    def match(self, path):
        result = Rule.match(self, path)
        if result is None:
            return result
        lang_code = result.get('lang_code')
        if lang_code is None:
            return result
        for name, value in self._converters.items():
            if not isinstance(value, TranslateConverter):
                continue
            if value.language_pairs[lang_code] != result[name]:
                return
        return result


app.url_map.converters['tr'] = TranslateConverter
app.url_rule_class = TranslateCorrelationRule

If you will simplify url_for usage for this examples you can use next sample:

@app.url_value_preprocessor
def pull_lang_code(endpoint, values):
    if not values:
        return
    g.lang_code = values.pop('lang_code', None)
    for key, value in values.items():
        if key.startswith('_'):
            values.pop(key)


class TranslateCorrelationRule(Rule):

    def _update_translate_values(self, values):
        lang_code = values.get('lang_code', getattr(g, 'lang_code', None))
        if lang_code is None:
            return values
        values = values.copy()
        for argument in self.arguments:
            if argument in values:
                continue
            converter = self._converters[argument]
            if not isinstance(converter, TranslateConverter):
                continue
            values[argument] = converter.language_pairs[lang_code]
        return values

    def suitable_for(self, values, method=None):
        return Rule.suitable_for(self, self._update_translate_values(values),
                                 method)

    def build(self, values, append_unknown=True):
        return Rule.build(self, self._update_translate_values(values),
                          append_unknown)
like image 180
tbicr Avatar answered Oct 11 '22 18:10

tbicr