Repository: pypi/warehouse

Issue:
Add Brazilian Portugese to localization footer
https://hosted.weblate.org/projects/pypa/warehouse/#translations says that we're now at 100% translated for Brazilian Portugese. Therefore, let's insert the footer of available locales/translations per #6624, and add Brazilian Portugese.

@yeraydiazdiaz @nlhkabu can either of you do this? Thanks.


Discussion:
I tried editing `warehouse/i18n/__init__.py` and `warehouse/templates/base.html` to include Brazilian Portugese:

~~~
diff --git a/warehouse/i18n/__init__.py b/warehouse/i18n/__init__.py
index 198a33ec..1304ba9f 100644
--- a/warehouse/i18n/__init__.py
+++ b/warehouse/i18n/__init__.py
@@ -14,7 +14,8 @@ from babel.core import Locale
 from pyramid.i18n import TranslationStringFactory, default_locale_negotiator
 from pyramid.threadlocal import get_current_request
 
-KNOWN_LOCALES = {"en": "English"}
+KNOWN_LOCALES = {"en": "English",
+                 "br-pt": "Brazilian Portugese"}
 
 LOCALE_ATTR = "_LOCALE_"
 
diff --git a/warehouse/templates/base.html b/warehouse/templates/base.html
index a46d25c8..80ad7b16 100644
--- a/warehouse/templates/base.html
+++ b/warehouse/templates/base.html
@@ -327,8 +327,7 @@
       </div>
     </footer>
 
-    <!-- TODO: Remove this check once a non-English translation is available. -->
-    {% if KNOWN_LOCALES|length > 1 %}
+
     <div class="language-switcher">
       <form action="{{ request.route_path('locale') }}">
         <ul>
@@ -340,7 +339,7 @@
         </ul>
       </form>
     </div>
-    {% endif %}
+
 
     {% include "warehouse:templates/includes/sponsors.html" %}
~~~

and got this stack trace:

~~~
Traceback (most recent call last):
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid_debugtoolbar/panels/performance.py", line 58, in resource_timer_handler
    result = handler(request)
  File "/opt/warehouse/src/warehouse/raven.py", line 40, in raven_tween
    return handler(request)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid_tm/__init__.py", line 171, in tm_tween
    reraise(*exc_info)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid_tm/compat.py", line 36, in reraise
    raise value
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid_tm/__init__.py", line 136, in tm_tween
    response = handler(request)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/tweens.py", line 43, in excview_tween
    response = _error_handler(request, exc)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/tweens.py", line 17, in _error_handler
    reraise(*exc_info)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/compat.py", line 179, in reraise
    raise value
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/tweens.py", line 41, in excview_tween
    response = handler(request)
  File "/opt/warehouse/src/warehouse/cache/http.py", line 74, in conditional_http_tween
    response = handler(request)
  File "/opt/warehouse/src/warehouse/sanity.py", line 76, in sanity_tween_egress
    return unicode_redirects(handler(request))
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/router.py", line 148, in handle_request
    registry, request, context, context_iface, view_name
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/view.py", line 667, in _call_view
    response = view_callable(context, request)
  File "/opt/warehouse/src/warehouse/sessions.py", line 329, in wrapped
    return view(context, request)
  File "/opt/warehouse/src/warehouse/csrf.py", line 38, in wrapped
    return view(context, request)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/viewderivers.py", line 514, in csrf_view
    return view(context, request)
  File "/opt/warehouse/src/warehouse/cache/origin/__init__.py", line 86, in wrapped
    return view(context, request)
  File "/opt/warehouse/src/warehouse/metrics/views.py", line 34, in wrapper_view
    return view(context, request)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/viewderivers.py", line 460, in rendered_view
    request, result, view_inst, context
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/renderers.py", line 451, in render_view
    return self.render_to_response(response, system, request=request)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/renderers.py", line 474, in render_to_response
    result = self.render(value, system_values, request=request)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/renderers.py", line 470, in render
    result = renderer(value, system_values)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid_jinja2/__init__.py", line 265, in __call__
    return template.render(system)
  File "/opt/warehouse/lib/python3.7/site-packages/jinja2/asyncsupport.py", line 76, in render
    return original_render(self, *args, **kwargs)
  File "/opt/warehouse/lib/python3.7/site-packages/jinja2/environment.py", line 1008, in render
    return self.environment.handle_exception(exc_info, True)
  File "/opt/warehouse/lib/python3.7/site-packages/jinja2/environment.py", line 780, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/opt/warehouse/lib/python3.7/site-packages/jinja2/_compat.py", line 37, in reraise
    raise value.with_traceback(tb)
  File "/opt/warehouse/src/warehouse/templates/index.html", line 25, in top-level template code
    <p class="package-snippet__description">{{ release.summary }}</p>
  File "/opt/warehouse/src/warehouse/templates/base.html", line 144, in top-level template code
    {% block body %}
  File "/opt/warehouse/src/warehouse/templates/base.html", line 246, in block "body"
    {% block content %}
  File "/opt/warehouse/src/warehouse/templates/index.html", line 67, in block "content"
    <p class="statistics-bar__statistic">{% trans num_projects=num_projects|format_number %}{{ num_projects }} projects{% endtrans %}</p>
  File "/opt/warehouse/src/warehouse/i18n/filters.py", line 45, in format_number
    locale = request.locale
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/decorator.py", line 43, in __get__
    val = self.wrapped(inst)
  File "/opt/warehouse/lib/python3.7/site-packages/pyramid/util.py", line 81, in <lambda>
    fn = lambda this: callable(this)
  File "/opt/warehouse/src/warehouse/i18n/__init__.py", line 48, in _locale
    return Locale.parse(request.locale_name, sep="_")
  File "/opt/warehouse/lib/python3.7/site-packages/babel/core.py", line 268, in parse
    parts = parse_locale(identifier, sep=sep)
  File "/opt/warehouse/lib/python3.7/site-packages/babel/core.py", line 1094, in parse_locale
    raise ValueError('expected only letters, got %r' % lang)
ValueError: expected only letters, got 'br-pt'
~~~
I think the right locale is `pt_BR`.
> I think the right locale is `pt_BR`.

Yep, this is correct -- Babel's default locale format is `cc_lc` where `cc` is the country code and `lc` is the language code. 
I tried 

~~~
KNOWN_LOCALES = {"en": "English",
                 "pt_BR": "Brazilian Portugese"}
~~~

and got the same ValueError. @woodruffw diagnosed that I might need to clear my cookies because of a `_LOCALE_` cookie issue. I used a different browser to visit localhost and did not get the error -- now I see the language chooser (INSTEAD of the sponsor footer). There is no Portugese content when I choose Portugese, probably because we haven't merged any of the new translations yet (they are in #6667).

Resolving patch:
diff --git a/warehouse/i18n/__init__.py b/warehouse/i18n/__init__.py
--- a/warehouse/i18n/__init__.py
+++ b/warehouse/i18n/__init__.py
@@ -14,7 +14,7 @@
 from pyramid.i18n import TranslationStringFactory, default_locale_negotiator
 from pyramid.threadlocal import get_current_request
 
-KNOWN_LOCALES = {"en": "English"}
+KNOWN_LOCALES = {"en": "English", "pt_BR": "Portuguese (Brazil)"}
 
 LOCALE_ATTR = "_LOCALE_"
 


Test patch: