diff --git a/CHANGES.rst b/CHANGES.rst index 2d367074..1099ccc2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,13 @@ Breaking Changes - TBD +Bugfixes & Improvements +^^^^^^^^^^^^^^^^^^^^^^^ + +- Make language code handling more robust (`#983`_, ix5) + +.. _#983: https://github.com/posativ/isso/pull/983 + New Features ^^^^^^^^^^^^ diff --git a/isso/js/app/config.js b/isso/js/app/config.js index fef089c0..71d5f569 100644 --- a/isso/js/app/config.js +++ b/isso/js/app/config.js @@ -17,9 +17,21 @@ for (var i = 0; i < js.length; i++) { var attr = js[i].attributes[j]; if (/^data-isso-/.test(attr.name)) { try { - config[attr.name.substring(10)] = JSON.parse(attr.value); + // Normalize underscores to dashes so that language-specific + // strings can be caught better later on, + // e.g. data-isso-postbox-text-text-PT_BR becomes + // postbox-text-text-pt-br. + // Also note that attr.name only gives lowercase strings as per + // HTML spec, e.g. data-isso-FOO-Bar becomes foo-bar, but since + // the test environment's jest-environment-jsdom seemingly does + // not follow that convention, convert to lowercase here anyway. + config[attr.name.substring(10) + .replace(/_/g, '-') + .toLowerCase()] = JSON.parse(attr.value); } catch (ex) { - config[attr.name.substring(10)] = attr.value; + config[attr.name.substring(10) + .replace(/_/g, '-') + .toLowerCase()] = attr.value; } } } diff --git a/isso/js/app/i18n.js b/isso/js/app/i18n.js index 304b9eca..25794080 100644 --- a/isso/js/app/i18n.js +++ b/isso/js/app/i18n.js @@ -133,7 +133,10 @@ if (!plural || !translations) { } var translate = function(msgid) { - return config[msgid + '-text-' + lang] || + // Need to convert the language string to lowercase because data-isso-* + // attributes are automatically cast to lowercase as per HTML spec + // https://stackoverflow.com/questions/36176474/camel-case-in-html-tag-attributes-and-jquery-doesnt-work-why + return config[msgid + '-text-' + lang.toLowerCase()] || translations[msgid] || catalogue.en[msgid] || "[?" + msgid + "]"; diff --git a/isso/js/tests/unit/i18n-overrides.test.js b/isso/js/tests/unit/i18n-overrides.test.js new file mode 100644 index 00000000..1df1e6fd --- /dev/null +++ b/isso/js/tests/unit/i18n-overrides.test.js @@ -0,0 +1,113 @@ +/** + * @jest-environment jsdom + */ + +/* Keep the above exactly as-is! + * https://jestjs.io/docs/configuration#testenvironment-string + * https://jestjs.io/docs/configuration#testenvironmentoptions-object + */ + +"use strict"; + +beforeEach(() => { + jest.resetModules(); + document.body.innerHTML = ''; +}); + +test('data-isso-* attributes should override i18n strings', () => { + // Set up our document body + document.body.innerHTML = + '
' + + // Note: `src` and `data-isso` need to be set, + // else `api` fails to initialize! + ''; + + var script_tag = document.getElementsByTagName('script')[0]; + script_tag.setAttributeNS(null, 'data-isso-lang', 'pt_BR'); + script_tag.setAttributeNS(null, 'data-isso-postbox-text-text-pt-br', 'Digite seu comentário.'); + + expect(script_tag.getAttribute('data-isso-lang')).toBe('pt_BR'); + // expect(script_tag).toBe('') + + const isso = require("app/isso"); + const $ = require("app/dom"); + const config = require("app/config"); + const template = require("app/template"); + const i18n = require("app/i18n"); + const svg = require("app/svg"); + + template.set("conf", config); + template.set("i18n", i18n.translate); + template.set("pluralize", i18n.pluralize); + template.set("svg", svg); + + var isso_thread = $('#isso-thread'); + isso_thread.append(''); + isso_thread.append(new isso.Postbox(null)); + + expect($('.isso-textarea').placeholder).toMatch('Digite seu comentário.'); +}); + +test('data-isso-* i18n strings should be accepted with underscores', () => { + document.body.innerHTML = + '' + + // Note: `src` and `data-isso` need to be set, + // else `api` fails to initialize! + ''; + + var script_tag = document.getElementsByTagName('script')[0]; + script_tag.setAttributeNS(null, 'data-isso-lang', 'pt_br'); + script_tag.setAttributeNS(null, 'data-isso-postbox-text-text-pt_BR', 'Digite seu comentário.'); + + expect(script_tag.getAttribute('data-isso-lang')).toBe('pt_br'); + + const isso = require("app/isso"); + const $ = require("app/dom"); + const config = require("app/config"); + const template = require("app/template"); + const i18n = require("app/i18n"); + const svg = require("app/svg"); + + template.set("conf", config); + template.set("i18n", i18n.translate); + template.set("pluralize", i18n.pluralize); + template.set("svg", svg); + + var isso_thread = $('#isso-thread'); + isso_thread.append(''); + isso_thread.append(new isso.Postbox(null)); + + expect($('.isso-textarea').placeholder).toMatch('Digite seu comentário.'); +});