From 1602e192145a6fff3f360750042e6f9492f3377a Mon Sep 17 00:00:00 2001 From: crptm Date: Fri, 26 May 2017 02:05:11 +0400 Subject: [PATCH] support translations markup --- common/translations/index.js | 6 ++- common/translations/markup.js | 37 +++++++++++++++++ jest_config/jest.config.json | 3 +- spec/translations/markup.spec.js | 69 ++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 common/translations/markup.js create mode 100644 spec/translations/markup.spec.js 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); + }); +});