Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add catalog url and js namespace for OEP-58 JS translations | FC-0012 #691

Merged
merged 1 commit into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,25 @@ These are notable changes in XBlock.
Unreleased
----------

1.9.0 - 2023-11-20
------------------

* Support for `OEP-58 JavaScript translations <https://docs.openedx.org/en/latest/developers/concepts/oep58.html>`_:

* Introduced abstract JavaScript translations support by adding the ``i18n_js_namespace`` property and
``get_i18n_js_namespace`` method to the ``SharedBlockBase``. This allows XBlocks to define a JavaScript namespace
so the XBlock i18n runtime service can manage and load JavaScript translations for XBlocks.

* Added the stub ``get_javascript_i18n_catalog_url`` method to the ``NullI18nService`` class to be implemented
by runtime services.

* See the `edx-platform atlas translations proposal <https://github.com/openedx/edx-platform/blob/master/docs/decisions/0019-oep-58-atlas-translations-design.rst>`_

1.8.1 - 2023-10-07
------------------

* Python Requirements Update
* Update setup.py, adds required packages

1.8.0 - 2023-09-25
------------------
Expand Down
2 changes: 1 addition & 1 deletion xblock/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ def __init__(self, *args, **kwargs):
# without causing a circular import
xblock.fields.XBlockMixin = XBlockMixin

__version__ = '1.8.1'
__version__ = '1.9.0'
12 changes: 12 additions & 0 deletions xblock/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class SharedBlockBase(Plugin):

resources_dir = ''
public_dir = 'public'
i18n_js_namespace = None

@classmethod
def get_resources_dir(cls):
Expand All @@ -70,6 +71,17 @@ def get_public_dir(cls):
"""
return cls.public_dir

@classmethod
def get_i18n_js_namespace(cls):
"""
Gets the JavaScript translations namespace for this XBlock.

Returns:
str: The JavaScript namespace for this XBlock.
None: If this doesn't have JavaScript translations configured.
"""
return cls.i18n_js_namespace

@classmethod
def open_local_resource(cls, uri):
"""
Expand Down
10 changes: 10 additions & 0 deletions xblock/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,16 @@ def strftime(self, dtime, format): # pylint: disable=redefined-builtin
timestring = dtime.strftime(format)
return timestring

def get_javascript_i18n_catalog_url(self):
"""
Return the URL to the JavaScript i18n catalog file.

This method returns None in NullI18nService. When implemented in
a runtime, it should return the URL to the JavaScript i18n catalog so
it can be loaded in frontends.
"""
return None

@property
def ugettext(self):
"""
Expand Down
33 changes: 33 additions & 0 deletions xblock/test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,39 @@ class FieldTester(XBlock):
assert {1} == field_tester._field_data.get(field_tester, 'field_d')


def test_shared_block_base_defaults():
"""
Test default values and static methods provided by the SharedBlockBase class.
"""
class DefaultsTester(XBlock):
pass

defaults_tester = DefaultsTester(
TestRuntime(services={'field-data': DictFieldData({})}),
scope_ids=Mock(spec=ScopeIds)
)

# Testing the default static method return values of SharedBlockBase
assert defaults_tester.get_resources_dir() == ''
assert defaults_tester.get_public_dir() == 'public'
assert defaults_tester.get_i18n_js_namespace() is None

class CustomizedValuesTester(XBlock):
resources_dir = 'custom_resource_dir'
public_dir = 'another_public_dir'
i18n_js_namespace = 'CustomizedValuesTesterI18N'

customized_values_tester = CustomizedValuesTester(
TestRuntime(services={'field-data': DictFieldData({})}),
scope_ids=Mock(spec=ScopeIds),
)

# Testing the customized static method return values of SharedBlockBase
assert customized_values_tester.get_resources_dir() == 'custom_resource_dir'
assert customized_values_tester.get_public_dir() == 'another_public_dir'
assert customized_values_tester.get_i18n_js_namespace() == 'CustomizedValuesTesterI18N'


def test_mutable_none_values():
# Check that fields with values intentionally set to None
# save properly.
Expand Down
3 changes: 3 additions & 0 deletions xblock/test/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ def assert_equals_unicode(str1, str2):
assert_equals_unicode("Feb 14, 2013 at 22:30", i18n.strftime(when, "DATE_TIME"))
assert_equals_unicode("10:30:17 PM", i18n.strftime(when, "TIME"))

# Runtimes are expected to implement this method though.
assert i18n.get_javascript_i18n_catalog_url() is None, 'NullI18nService does not implement this method.'

# secret_service is available.
assert self.runtime.service(self, "secret_service") == 17

Expand Down