From 5a437779d9c751feb65b6a65b709291f0f094b4b Mon Sep 17 00:00:00 2001 From: Omar Al-Ithawi Date: Wed, 27 Mar 2024 20:20:12 +0300 Subject: [PATCH] fix: add fallback `gettext` function if translations aren't pulled in dev envs (#34416) --- cms/templates/base.html | 4 + common/static/js/src/gettext_fallback.js | 132 +++++++++++++++++++++++ lms/templates/main.html | 4 + 3 files changed, 140 insertions(+) create mode 100644 common/static/js/src/gettext_fallback.js diff --git a/cms/templates/base.html b/cms/templates/base.html index 6907161fff..68df2d1a0e 100644 --- a/cms/templates/base.html +++ b/cms/templates/base.html @@ -61,6 +61,10 @@ from openedx.core.release import RELEASE_LINE % endif + % if settings.DEBUG: + ## Provides a fallback for gettext functions in development environment + + % endif <%block name="header_meta"> diff --git a/common/static/js/src/gettext_fallback.js b/common/static/js/src/gettext_fallback.js new file mode 100644 index 0000000000..63a72d7536 --- /dev/null +++ b/common/static/js/src/gettext_fallback.js @@ -0,0 +1,132 @@ +'use strict'; + +/** + * This is a fallback file for the Django JavaScript internationalization library if the language gettext catalog + * is not available. + */ + +(function(globals) { + const django = globals.django || (globals.django = {}); + + /* gettext library */ + if (!django.jsi18n_initialized) { + django.catalog = django.catalog || {}; + + django.pluralidx = function(n) { + const v = (n != 1); + if (typeof v === 'boolean') { + return v ? 1 : 0; + } else { + return v; + } + }; + + django.gettext = function(msgid) { + const value = django.catalog[msgid]; + if (typeof value === 'undefined') { + return msgid; + } else { + return (typeof value === 'string') ? value : value[0]; + } + }; + + django.ngettext = function(singular, plural, count) { + const value = django.catalog[singular]; + if (typeof value === 'undefined') { + return (count == 1) ? singular : plural; + } else { + return value.constructor === Array ? value[django.pluralidx(count)] : value; + } + }; + + django.gettext_noop = function(msgid) { + return msgid; + }; + + django.pgettext = function(context, msgid) { + let value = django.gettext(context + '\x04' + msgid); + if (value.includes('\x04')) { + value = msgid; + } + return value; + }; + + django.npgettext = function(context, singular, plural, count) { + let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count); + if (value.includes('\x04')) { + value = django.ngettext(singular, plural, count); + } + return value; + }; + + django.interpolate = function(fmt, obj, named) { + if (named) { + return fmt.replace(/%\(\w+\)s/g, function(match) { + return String(obj[match.slice(2, -2)]) + }); + } else { + return fmt.replace(/%s/g, function(match) { + return String(obj.shift()) + }); + } + }; + + /* formatting library */ + django.formats = { + DATETIME_FORMAT: 'N j, Y, P', + DATETIME_INPUT_FORMATS: [ + '%Y-%m-%d %H:%M:%S', + '%Y-%m-%d %H:%M:%S.%f', + '%Y-%m-%d %H:%M', + '%m/%d/%Y %H:%M:%S', + '%m/%d/%Y %H:%M:%S.%f', + '%m/%d/%Y %H:%M', + '%m/%d/%y %H:%M:%S', + '%m/%d/%y %H:%M:%S.%f', + '%m/%d/%y %H:%M', + '%Y-%m-%d' + ], + DATE_FORMAT: 'N j, Y', + DATE_INPUT_FORMATS: [ + '%Y-%m-%d', + '%m/%d/%Y', + '%m/%d/%y' + ], + DECIMAL_SEPARATOR: '.', + FIRST_DAY_OF_WEEK: 0, + MONTH_DAY_FORMAT: 'F j', + NUMBER_GROUPING: 3, + SHORT_DATETIME_FORMAT: 'm/d/Y P', + SHORT_DATE_FORMAT: 'm/d/Y', + THOUSAND_SEPARATOR: ',', + TIME_FORMAT: 'P', + TIME_INPUT_FORMATS: [ + '%H:%M:%S', + '%H:%M:%S.%f', + '%H:%M' + ], + YEAR_MONTH_FORMAT: 'F Y' + }; + + django.get_format = function(format_type) { + const value = django.formats[format_type]; + if (typeof value === 'undefined') { + return format_type; + } else { + return value; + } + }; + + /* add to global namespace */ + globals.pluralidx = django.pluralidx; + globals.gettext = django.gettext; + globals.ngettext = django.ngettext; + globals.gettext_noop = django.gettext_noop; + globals.pgettext = django.pgettext; + globals.npgettext = django.npgettext; + globals.interpolate = django.interpolate; + globals.get_format = django.get_format; + + django.jsi18n_initialized = true; + } +}(this)); diff --git a/lms/templates/main.html b/lms/templates/main.html index 963e82fb53..1a11900dae 100644 --- a/lms/templates/main.html +++ b/lms/templates/main.html @@ -80,6 +80,10 @@ from common.djangoapps.pipeline_mako import render_require_js_path_overrides % endif + % if settings.DEBUG: + ## Provides a fallback for gettext functions in development environment + + % endif <% favicon_url = branding_api.get_favicon_url() %>