diff --git a/common/translations/index.js b/common/translations/index.js
index 1ff99c42..50533981 100644
--- a/common/translations/index.js
+++ b/common/translations/index.js
@@ -1,5 +1,5 @@
// @flow
-
+import { markupToReact } from './markup';
let activeLanguage = 'en';
let fallbackLanguage = 'en';
let repository = {};
@@ -36,5 +36,7 @@ export function setLanguage(code: string) {
}
export default function translate(key: string) {
- return repository[activeLanguage][key] || repository[fallbackLanguage][key] || key;
+ return markupToReact(
+ repository[activeLanguage][key] || repository[fallbackLanguage][key] || key
+ );
}
diff --git a/common/translations/markup.js b/common/translations/markup.js
new file mode 100644
index 00000000..f48ca4d6
--- /dev/null
+++ b/common/translations/markup.js
@@ -0,0 +1,37 @@
+// ad-hoc parser for translation strings
+import React from 'react';
+
+const BOLD_REGEXP = /(\*\*)(.*?)\1/;
+const LINK_REGEXP = /\[([^\[]+)\]\(([^\)]+)\)/;
+
+function linkify(mdString: string) {
+ const parts = mdString.split(LINK_REGEXP);
+ if (parts.length === 1) {
+ return parts[0];
+ }
+ const result = [];
+ let i = 0;
+ while (i + 1 < parts.length) {
+ result.push(parts[i]);
+ result.push({parts[i + 1]});
+ i += 3;
+ }
+ result.push(parts[parts.length - 1]);
+ return result.filter(Boolean);
+}
+
+export function markupToReact(mdString: string) {
+ const parts = mdString.split(BOLD_REGEXP);
+ if (parts.length === 1) {
+ return linkify(parts[0]);
+ }
+ let result = [];
+ let i = 0;
+ while (i + 1 < parts.length) {
+ result = result.concat(linkify(parts[i]));
+ result.push({parts[i + 2]});
+ i += 3;
+ }
+ result = result.concat(linkify(parts.pop()));
+ return result.filter(Boolean);
+}
diff --git a/jest_config/jest.config.json b/jest_config/jest.config.json
index 7965fbb8..3c8b3e2d 100644
--- a/jest_config/jest.config.json
+++ b/jest_config/jest.config.json
@@ -10,7 +10,6 @@
"^routing": "/common/routing",
"^components$": "/common/components",
"^containers$": "/common/containers",
- "^config$": "/common/config/test.js",
- "^translations$": "/common/translations"
+ "^translations(.*)": "/common/translations$1"
}
}
diff --git a/spec/translations/markup.spec.js b/spec/translations/markup.spec.js
new file mode 100644
index 00000000..9c4427ac
--- /dev/null
+++ b/spec/translations/markup.spec.js
@@ -0,0 +1,69 @@
+import React from 'react';
+import { markupToReact } from 'translations/markup';
+
+describe('markupToReact', () => {
+ it('passes plain string as is', () => {
+ const value = 'string';
+ const expected = 'string';
+ expect(markupToReact(value)).toEqual(expected);
+ });
+
+ it('transforms bold syntax', () => {
+ let value = '**foo**';
+ let expected = [foo];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = '**foo** bar';
+ expected = [foo, ' bar'];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = 'bar **foo**';
+ expected = ['bar ', foo];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = 'bar **foo** baz';
+ expected = ['bar ', foo, ' baz'];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = '**foo****bar**';
+ expected = [foo, bar];
+ expect(markupToReact(value)).toEqual(expected);
+ });
+
+ it('transforms link syntax', () => {
+ let value = '[foo](http://google.com)';
+ let expected = [foo];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = '[foo](http://google.com) bar';
+ expected = [foo, ' bar'];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = 'bar [foo](http://google.com)';
+ expected = ['bar ', foo];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = 'bar [foo](http://google.com) baz';
+ expected = ['bar ', foo, ' baz'];
+ expect(markupToReact(value)).toEqual(expected);
+
+ value = '[foo](http://google.com)[bar](http://google.ca)';
+ expected = [
+ foo,
+ bar
+ ];
+ expect(markupToReact(value)).toEqual(expected);
+ });
+
+ it('converts mixed syntax', () => {
+ let value = 'Bold **foo** link [foo](http://google.com) text';
+ let expected = [
+ 'Bold ',
+ foo,
+ ' link ',
+ foo,
+ ' text'
+ ];
+ expect(markupToReact(value)).toEqual(expected);
+ });
+});