diff --git a/lib/core/Doc.js b/lib/core/Doc.js index 9c15e9542b6c2..a3e960c7352c1 100644 --- a/lib/core/Doc.js +++ b/lib/core/Doc.js @@ -10,18 +10,18 @@ const MarkdownBlock = require('./MarkdownBlock.js'); const translate = require('../server/translate.js').translate; -const editThisDoc = translate( - 'Edit this Doc|recruitment message asking to edit the doc source' -); -const translateThisDoc = translate( - 'Translate this Doc|recruitment message asking to translate the docs' -); - // inner doc component for article itself class Doc extends React.Component { render() { let docSource = this.props.source; + const editThisDoc = translate( + 'Edit this Doc|recruitment message asking to edit the doc source' + ); + const translateThisDoc = translate( + 'Translate this Doc|recruitment message asking to translate the docs' + ); + if (this.props.version && this.props.version !== 'next') { // If versioning is enabled and the current version is not next, we need to trim out "version-*" from the source if we want a valid edit link. docSource = docSource.match(new RegExp(/version-.*\/(.*\.md)/, 'i'))[1]; diff --git a/lib/core/DocsLayout.js b/lib/core/DocsLayout.js index 7078eef068d36..8591aeed2124b 100644 --- a/lib/core/DocsLayout.js +++ b/lib/core/DocsLayout.js @@ -17,7 +17,7 @@ const OnPageNav = require('./nav/OnPageNav.js'); const Site = require('./Site.js'); const translation = require('../server/translation.js'); const docs = require('../server/docs.js'); -const {idx, getGitLastUpdated} = require('./utils.js'); +const {getGitLastUpdated} = require('./utils.js'); // component used to generate whole webpage for docs, including sidebar/header/footer class DocsLayout extends React.Component { @@ -37,10 +37,10 @@ class DocsLayout extends React.Component { render() { const metadata = this.props.metadata; const content = this.props.children; - const i18n = translation[metadata.language]; const id = metadata.localized_id; const defaultTitle = metadata.title; let DocComponent = Doc; + if (this.props.Doc) { DocComponent = this.props.Doc; } @@ -50,19 +50,18 @@ class DocsLayout extends React.Component { updateTime = getGitLastUpdated(filepath); } - const title = - idx(i18n, ['localized-strings', 'docs', id, 'title']) || defaultTitle; + const title = translation.t(['docs', id, 'title']) || defaultTitle; const hasOnPageNav = this.props.config.onPageNav === 'separate'; const previousTitle = - idx(i18n, ['localized-strings', metadata.previous_id]) || - idx(i18n, ['localized-strings', 'previous']) || + translation.t(metadata.previous_id) || metadata.previous_title || + translation.t('previous') || 'Previous'; const nextTitle = - idx(i18n, ['localized-strings', metadata.next_id]) || - idx(i18n, ['localized-strings', 'next']) || + translation.t(metadata.next_id) || metadata.next_title || + translation.t('next') || 'Next'; return ( diff --git a/lib/core/Redirect.js b/lib/core/Redirect.js index 2a8af6f73074e..3c20cd3014fc3 100644 --- a/lib/core/Redirect.js +++ b/lib/core/Redirect.js @@ -8,14 +8,11 @@ const React = require('react'); const Head = require('./Head.js'); const translation = require('../server/translation.js'); -const {idx} = require('./utils.js'); // Component used to provide same head, header, footer, other scripts to all pages class Redirect extends React.Component { render() { - const tagline = - idx(translation, [this.props.language, 'localized-strings', 'tagline']) || - this.props.config.tagline; + const tagline = translation.t('tagline') || this.props.config.tagline; const title = this.props.title ? `${this.props.title} · ${this.props.config.title}` : (!this.props.config.disableTitleTagline && diff --git a/lib/core/Site.js b/lib/core/Site.js index ad45ac4647a43..df4c4bb99fb91 100644 --- a/lib/core/Site.js +++ b/lib/core/Site.js @@ -8,22 +8,19 @@ const React = require('react'); const fs = require('fs'); +const CWD = process.cwd(); + const HeaderNav = require('./nav/HeaderNav.js'); const Head = require('./Head.js'); -const Footer = require(`${process.cwd()}/core/Footer.js`); +const Footer = require(`${CWD}/core/Footer.js`); const translation = require('../server/translation.js'); const constants = require('./constants'); -const {idx} = require('./utils.js'); - -const CWD = process.cwd(); // Component used to provide same head, header, footer, other scripts to all pages class Site extends React.Component { render() { - const tagline = - idx(translation, [this.props.language, 'localized-strings', 'tagline']) || - this.props.config.tagline; + const tagline = translation.t('tagline') || this.props.config.tagline; const title = this.props.title ? `${this.props.title} · ${this.props.config.title}` : (!this.props.config.disableTitleTagline && diff --git a/lib/core/nav/HeaderNav.js b/lib/core/nav/HeaderNav.js index 893a67205fcd0..97c7821ac2816 100644 --- a/lib/core/nav/HeaderNav.js +++ b/lib/core/nav/HeaderNav.js @@ -12,29 +12,25 @@ const fs = require('fs'); const classNames = require('classnames'); const siteConfig = require(`${CWD}/siteConfig.js`); +const {versioning} = require('../../server/env.js'); const translation = require('../../server/translation.js'); -const env = require('../../server/env.js'); - -const translate = require('../../server/translate.js').translate; -const setLanguage = require('../../server/translate.js').setLanguage; - +const {translate} = require('../../server/translate.js'); const readMetadata = require('../../server/readMetadata.js'); readMetadata.generateMetadataDocs(); const Metadata = require('../metadata.js'); -const {idx, getPath} = require('../utils.js'); +const {getPath} = require('../utils.js'); const extension = siteConfig.cleanUrl ? '' : '.html'; // language dropdown nav item for when translations are enabled class LanguageDropDown extends React.Component { render() { - setLanguage(this.props.language || 'en'); const helpTranslateString = translate( 'Help Translate|recruit community translators for your project' ); // add all enabled languages to dropdown - const enabledLanguages = env.translation + const enabledLanguages = translation .enabledLanguages() .filter(lang => lang.tag !== this.props.language) .map(lang => { @@ -66,7 +62,7 @@ class LanguageDropDown extends React.Component { } // Get the current language full name for display in the header nav - const currentLanguage = env.translation + const currentLanguage = translation .enabledLanguages() .filter(lang => lang.tag === this.props.language) .map(lang => lang.name); @@ -143,10 +139,7 @@ class HeaderNav extends React.Component { ); } if (link.languages) { - if ( - env.translation.enabled && - env.translation.enabledLanguages().length > 1 - ) { + if (translation.enabled && translation.enabledLanguages().length > 1) { return ( - {idx(i18n, ['localized-strings', 'links', link.label]) || link.label} + {translation.t(['links', link.label]) || link.label} ); @@ -292,7 +285,7 @@ class HeaderNav extends React.Component { : 'headerTitle'; const versionsLink = this.props.baseUrl + - (env.translation.enabled + (translation.enabled ? `${this.props.language}/versions${extension}` : `versions${extension}`); return ( @@ -302,7 +295,7 @@ class HeaderNav extends React.Component { {siteConfig.headerIcon && ( {this.props.title} )} - {env.versioning.enabled && ( + {versioning.enabled && ( -

{this.props.version || env.versioning.defaultVersion}

+

{this.props.version || versioning.defaultVersion}

)} {this.renderResponsiveNav()} diff --git a/lib/core/nav/SideNav.js b/lib/core/nav/SideNav.js index 8cc150a64ea5b..252d31e06efff 100644 --- a/lib/core/nav/SideNav.js +++ b/lib/core/nav/SideNav.js @@ -10,36 +10,28 @@ const classNames = require('classnames'); const siteConfig = require(`${process.cwd()}/siteConfig.js`); const translation = require('../../server/translation.js'); -const {getPath, idx} = require('../utils.js'); +const {getPath} = require('../utils.js'); class SideNav extends React.Component { // return appropriately translated category string getLocalizedCategoryString(category) { - const categoryString = - idx(translation, [ - this.props.language, - 'localized-strings', - 'categories', - category, - ]) || category; + const categoryString = translation.t(['categories', category]) || category; + return categoryString; } // return appropriately translated label to use for doc/blog in sidebar getLocalizedString(metadata) { let localizedString; - const i18n = translation[this.props.language]; const id = metadata.localized_id; const sbTitle = metadata.sidebar_label; if (sbTitle) { - localizedString = - idx(i18n, ['localized-strings', 'docs', id, 'sidebar_label']) || - sbTitle; + localizedString = translation.t(['docs', id, 'sidebar_label']) || sbTitle; } else { - localizedString = - idx(i18n, ['localized-strings', 'docs', id, 'title']) || metadata.title; + localizedString = translation.t(['docs', id, 'title']) || metadata.title; } + return localizedString; } diff --git a/lib/server/blog.js b/lib/server/blog.js index 0c218efc8034a..475531de10d65 100644 --- a/lib/server/blog.js +++ b/lib/server/blog.js @@ -34,8 +34,12 @@ function fileToUrl(file) { function getPagesMarkup(numOfBlog, config) { const BlogPageLayout = require('../core/BlogPageLayout.js'); + const env = require('./env'); const blogPages = {}; const perPage = 10; + + env.translation.setLanguage('en'); + for (let page = 0; page < Math.ceil(numOfBlog / perPage); page++) { const metadata = {page, perPage}; const blogPageComp = ( @@ -65,10 +69,16 @@ function getMetadata(file) { function getPostMarkup(file, config) { const metadata = getMetadata(file); + if (!metadata) { return null; } + + const env = require('./env'); const BlogPostLayout = require('../core/BlogPostLayout.js'); + + env.translation.setLanguage('en'); + const blogPostComp = ( {metadata.content} diff --git a/lib/server/docs.js b/lib/server/docs.js index 387985198a05b..7354890b7a6ed 100644 --- a/lib/server/docs.js +++ b/lib/server/docs.js @@ -101,6 +101,8 @@ function getMarkup(rawContent, mdToHtml, metadata) { // replace any relative links to static assets (not in fenced code blocks) to absolute links content = replaceAssetsLink(content); + env.translation.setLanguage(metadata.language); + const DocsLayout = require('../core/DocsLayout.js'); return renderToStaticMarkupWithDoctype( } key + * @param {'default' | 'pages'} [category='default'] + * @param {Object} options + * @param {string} options.language + * + * @return {string} - translation or key + */ + t(key, category = 'default', options = {}) { + const language = options.language || this.getLanguage(); + + const categoryMap = { + default: 'localized-strings', + pages: 'pages-strings', + }; + + if (!categoryMap[category]) { + throw new Error(`Unknown category name: ${category}`); + } + + const message = idx( + this.translations, + [language, categoryMap[category]].concat(key) + ); + + if (message) { + if (category === 'pages' && options.fallbackFrom) { + console.error( + `Could not find a string translation in '${ + options.fallbackFrom + }' for string '${key}'. Using English version instead.` + ); + } + + return this.parseEscapeSequences(message); + } + + if (options.fallbackFrom) { + if (category === 'pages') { + // for pages we have more strict rules + throw new Error( + `Text that you've identified for translation ('${key}') hasn't been added to the global list in 'en.json'. To solve this problem run 'yarn write-translations'.` + ); + } + } else { + return this.t(key, category, { + language: DEFAULT_LANG, + fallbackFrom: language, + }); + } + + return null; } enabledLanguages = () => this.languages.filter(lang => lang.enabled); - getLanguage(file, refDir) { + /** + * Parse locale from doc file path + * + * @param {string} file + * @param {string} refDir + * + * @return {?string} + */ + getFileLanguage(file, refDir) { const separator = escapeStringRegexp(path.sep); const baseDir = escapeStringRegexp(path.basename(refDir)); const regexSubFolder = new RegExp( @@ -38,6 +114,7 @@ class Translation { const enabledLanguages = this.enabledLanguages().map( language => language.tag ); + if (enabledLanguages.indexOf(match[1]) !== -1) { return match[1]; } @@ -51,6 +128,59 @@ class Translation { this.enabled = true; this.languages = require(languagesFile); } + + this.loadTranslations(); + } + + loadTranslations() { + const translations = {languages: this.enabledLanguages()}; + + const files = glob.sync(`${CWD}/i18n/**`); + const langRegex = /\/i18n\/(.*)\.json$/; + let wasWarned = false; + + files.forEach(file => { + const extension = path.extname(file); + + if (extension === '.json') { + const match = langRegex.exec(file); + const language = match[1]; + + translations[language] = require(file); + + Object.defineProperty(this, language, { + get() { + if (!wasWarned) { + wasWarned = true; + + console.error( + "translation[language][category][key] api is deprecated. Please use translation.t(key, category = 'default')" + ); + } + + return translations[language]; + }, + set() { + // noop + }, + }); + } + }); + + this.translations = translations; + } + + /* handle escaped characters that get converted into json strings */ + parseEscapeSequences(str) { + return str + .replace(new RegExp('\\\\n', 'g'), '\n') + .replace(new RegExp('\\\\b', 'g'), '\b') + .replace(new RegExp('\\\\f', 'g'), '\f') + .replace(new RegExp('\\\\r', 'g'), '\r') + .replace(new RegExp('\\\\t', 'g'), '\t') + .replace(new RegExp("\\\\'", 'g'), "'") + .replace(new RegExp('\\\\"', 'g'), '"') + .replace(new RegExp('\\\\', 'g'), '\\'); } } diff --git a/lib/server/env/__tests__/Translation.test.js b/lib/server/env/__tests__/Translation.test.js index 0584244c8d2ff..49b49c724ae25 100644 --- a/lib/server/env/__tests__/Translation.test.js +++ b/lib/server/env/__tests__/Translation.test.js @@ -27,7 +27,11 @@ beforeEach(() => { ]; }); -test('getLanguage', () => { +afterEach(() => { + jest.restoreAllMocks(); +}); + +test('#getFileLanguage()', () => { const testDocEnglish = path.join('translated_docs', 'en', 'test.md'); const testDocJapanese = path.join('translated_docs', 'ja', 'test.md'); const testDocJapaneseInSubfolder = path.join( @@ -39,13 +43,114 @@ test('getLanguage', () => { const testDocInSubfolder = path.join('docs', 'ro', 'test.md'); const testDocNoLanguage = path.join('docs', 'test.md'); - expect(translation.getLanguage(testDocEnglish, 'translated_docs')).toBe('en'); - expect(translation.getLanguage(testDocJapanese, 'translated_docs')).toBe( + expect(translation.getFileLanguage(testDocEnglish, 'translated_docs')).toBe( + 'en' + ); + expect(translation.getFileLanguage(testDocJapanese, 'translated_docs')).toBe( 'ja' ); expect( - translation.getLanguage(testDocJapaneseInSubfolder, 'translated_docs') + translation.getFileLanguage(testDocJapaneseInSubfolder, 'translated_docs') ).toBe('ja'); - expect(translation.getLanguage(testDocInSubfolder, 'docs')).toBeNull(); - expect(translation.getLanguage(testDocNoLanguage, 'docs')).toBeNull(); + expect(translation.getFileLanguage(testDocInSubfolder, 'docs')).toBeNull(); + expect(translation.getFileLanguage(testDocNoLanguage, 'docs')).toBeNull(); +}); + +describe('#t()', () => { + beforeEach(() => { + translation.translations = {}; + }); + + test('translate default category', () => { + translation.translations = { + en: { + 'localized-strings': { + foo: 'foo-en', + }, + }, + }; + + expect(translation.t('foo')).toBe('foo-en'); + }); + + test('key specified by an array', () => { + translation.translations = { + en: { + 'localized-strings': { + foo: { + bar: { + baz: 'baz-en', + }, + }, + }, + }, + }; + + expect(translation.t(['foo', 'bar', 'baz'])).toBe('baz-en'); + }); + + test('translate default category in other lang', () => { + translation.translations = { + fr: { + 'localized-strings': { + foo: 'foo-fr', + }, + }, + }; + + translation.setLanguage('fr'); + + expect(translation.t('foo')).toBe('foo-fr'); + }); + + test('fallback to en lang', () => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + translation.translations = { + en: { + 'localized-strings': { + foo: 'foo-en', + }, + }, + }; + + translation.setLanguage('fr'); + + expect(translation.t('foo')).toBe('foo-en'); + expect(console.error).not.toHaveBeenCalled(); + }); + + test('returns null when no translation', () => { + expect(translation.t('foo')).toBe(null); + }); + + test('throws error when no translation for pages category', () => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + translation.setLanguage('fr'); + + expect(() => + translation.t('foo', 'pages') + ).toThrowErrorMatchingInlineSnapshot( + `"Text that you've identified for translation ('foo') hasn't been added to the global list in 'en.json'. To solve this problem run 'yarn write-translations'."` + ); + expect(console.error).not.toHaveBeenCalled(); + }); + + test('warns when fallbacks to default lang for pages category', () => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + + translation.translations = { + en: { + 'pages-strings': { + foo: 'foo-en', + }, + }, + }; + + translation.setLanguage('fr'); + + expect(translation.t('foo', 'pages')).toBe('foo-en'); + expect(console.error).toHaveBeenCalledWith( + "Could not find a string translation in 'fr' for string 'foo'. Using English version instead." + ); + }); }); diff --git a/lib/server/generate.js b/lib/server/generate.js index fd0710db0c4f8..93ecb1e1ce9c3 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -20,9 +20,8 @@ async function execute() { const glob = require('glob'); const chalk = require('chalk'); const Site = require('../core/Site.js'); - const env = require('./env.js'); const siteConfig = require(`${CWD}/siteConfig.js`); - const translate = require('./translate.js'); + const translation = require('./translation.js'); const feed = require('./feed.js'); const sitemap = require('./sitemap.js'); const join = path.join; @@ -281,9 +280,7 @@ async function execute() { fs.writeFileSync(mainCss, css); // compile/copy pages from user - const enabledLanguages = env.translation - .enabledLanguages() - .map(lang => lang.tag); + const enabledLanguages = translation.enabledLanguages().map(lang => lang.tag); files = glob.sync(join(CWD, 'pages', '**')); files.forEach(file => { // Why normalize? In case we are on Windows. @@ -326,7 +323,8 @@ async function execute() { normalizedFile.replace(`${sep}en${sep}`, sep + language + sep) ) ) { - translate.setLanguage(language); + translation.setLanguage(language); + const str = renderToStaticMarkupWithDoctype(
{ - if (!translation.getLanguage(file, translatedDir)) { + if (!translation.getFileLanguage(file, translatedDir)) { return; } @@ -182,7 +182,7 @@ class DocsMetadata { const sidebarIndex = this.sidebarIndex; const result = metadataUtils.extractMetadata(fs.readFileSync(file, 'utf8')); - const language = translation.getLanguage(file, refDir) || 'en'; + const language = translation.getFileLanguage(file, refDir) || 'en'; const metadata = {}; Object.keys(result.metadata).forEach(fieldName => { diff --git a/lib/server/metadata/__tests__/DocsMetadata.test.js b/lib/server/metadata/__tests__/DocsMetadata.test.js index b96437ea31102..84f6aa3d921c0 100644 --- a/lib/server/metadata/__tests__/DocsMetadata.test.js +++ b/lib/server/metadata/__tests__/DocsMetadata.test.js @@ -30,7 +30,7 @@ test('metadata for simple docs', () => { }, translation: { enabled: false, - getLanguage() { + getFileLanguage() { return null; }, enabledLanguages() { @@ -70,7 +70,7 @@ test('wrong id format', () => { sidebars: {}, translation: { enabled: false, - getLanguage() { + getFileLanguage() { return null; }, enabledLanguages() { @@ -116,7 +116,7 @@ it('metadata for siteConfig.useEnglishUrl', () => { }, translation: { enabled: false, - getLanguage() { + getFileLanguage() { return null; }, enabledLanguages() { @@ -199,7 +199,7 @@ test('metadata with versioning', () => { }, translation: { enabled: false, - getLanguage() { + getFileLanguage() { return null; }, enabledLanguages() { @@ -244,7 +244,7 @@ test('metadata with translations', () => { }, translation: { enabled: true, - getLanguage(file) { + getFileLanguage(file) { return file.includes('/de/') ? 'de' : 'en'; }, enabledLanguages() { @@ -293,7 +293,7 @@ test('metadata with translations and versioning', () => { }, translation: { enabled: true, - getLanguage(file) { + getFileLanguage(file) { return file.includes('/de/') ? 'de' : 'en'; }, enabledLanguages() { diff --git a/lib/server/readCategories.js b/lib/server/readCategories.js index 21c22427c5bb9..7a6e4956cd2fd 100644 --- a/lib/server/readCategories.js +++ b/lib/server/readCategories.js @@ -5,28 +5,13 @@ * LICENSE file in the root directory of this source tree. */ -const fs = require('fs'); - +const env = require('./env'); const Metadata = require('../core/metadata.js'); -const CWD = process.cwd(); -let languages; -if (fs.existsSync(`${CWD}/languages.js`)) { - languages = require(`${CWD}/languages.js`); -} else { - languages = [ - { - enabled: true, - name: 'English', - tag: 'en', - }, - ]; -} - // returns data broken up into categories for a sidebar function readCategories(sidebar) { - const enabledLanguages = languages - .filter(lang => lang.enabled) + const enabledLanguages = env.translation + .enabledLanguages() .map(lang => lang.tag); const allCategories = {}; diff --git a/lib/server/server.js b/lib/server/server.js index 87a59d9dc2c52..a6014aa601648 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -12,7 +12,6 @@ function execute(port, options) { const metadataUtils = require('./metadataUtils'); const blog = require('./blog'); const docs = require('./docs'); - const env = require('./env.js'); const express = require('express'); const React = require('react'); const request = require('request'); @@ -25,7 +24,7 @@ function execute(port, options) { const gaze = require('gaze'); const tinylr = require('tiny-lr'); const constants = require('../core/constants'); - const translate = require('./translate'); + const translation = require('./translation'); const {renderToStaticMarkupWithDoctype} = require('./renderUtils'); const feed = require('./feed'); const sitemap = require('./sitemap'); @@ -216,6 +215,9 @@ function execute(port, options) { if (siteConfig.wrapPagesHTML) { removeModuleAndChildrenFromCache(join('..', 'core', 'Site.js')); const Site = require(join('..', 'core', 'Site.js')); + + translation.setLanguage('en'); + const str = renderToStaticMarkupWithDoctype( lang.tag); @@ -287,7 +289,9 @@ function execute(port, options) { const ReactComp = require(tempFile); removeModuleAndChildrenFromCache(join('..', 'core', 'Site.js')); const Site = require(join('..', 'core', 'Site.js')); - translate.setLanguage(language); + + translation.setLanguage(language); + const str = renderToStaticMarkupWithDoctype( lang.enabled); - } + const enabledLanguages = env.translation.enabledLanguages(); // Create a url mapping to all the enabled languages files const urls = files.map(file => { diff --git a/lib/server/translate.js b/lib/server/translate.js index 68d929e8dc233..7ccce7d79bd1b 100644 --- a/lib/server/translate.js +++ b/lib/server/translate.js @@ -5,61 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -const translation = require('./translation.js'); - -let language = 'en'; - -/* handle escaped characters that get converted into json strings */ -function parseEscapeSequences(str) { - return str - .replace(new RegExp('\\\\n', 'g'), '\n') - .replace(new RegExp('\\\\b', 'g'), '\b') - .replace(new RegExp('\\\\f', 'g'), '\f') - .replace(new RegExp('\\\\r', 'g'), '\r') - .replace(new RegExp('\\\\t', 'g'), '\t') - .replace(new RegExp("\\\\'", 'g'), "'") - .replace(new RegExp('\\\\"', 'g'), '"') - .replace(new RegExp('\\\\', 'g'), '\\'); -} - -function setLanguage(lang) { - language = lang; -} - -function doesTranslationExist(str, lang) { - return ( - translation[lang] && - translation[lang]['pages-strings'] && - translation[lang]['pages-strings'][str] - ); -} +const {translation} = require('./env.js'); function translate(str) { - if (!language || language === '') { - // Check English, just in case; otherwise, just return the raw string back - if (doesTranslationExist(str, 'en')) { - return parseEscapeSequences(translation.en['pages-strings'][str]); - } - return str; - } - - if (!doesTranslationExist(str, language)) { - // if a translated string doesn't exist, but english does then fallback - if (doesTranslationExist(str, 'en')) { - console.error( - `Could not find a string translation in '${language}' for string '${str}'. Using English version instead.` - ); - - return parseEscapeSequences(translation.en['pages-strings'][str]); - } - throw new Error( - `Text that you've identified for translation ('${str}') hasn't been added to the global list in 'en.json'. To solve this problem run 'yarn write-translations'.` - ); - } - return parseEscapeSequences(translation[language]['pages-strings'][str]); + return translation.t(str, 'pages'); } module.exports = { - setLanguage, translate, }; diff --git a/lib/server/translation.js b/lib/server/translation.js index 885df363ae5f2..ad05e9443d0c0 100644 --- a/lib/server/translation.js +++ b/lib/server/translation.js @@ -5,40 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -// translation object contains all translations for each string in i18n/en.json +const env = require('./env'); -const CWD = process.cwd(); -const fs = require('fs'); -const glob = require('glob'); -const path = require('path'); - -let languages; -if (fs.existsSync(`${CWD}/languages.js`)) { - languages = require(`${CWD}/languages.js`); -} else { - languages = [ - { - enabled: true, - name: 'English', - tag: 'en', - }, - ]; -} - -const enabledLanguages = languages.filter(lang => lang.enabled); - -const translation = {languages: enabledLanguages}; - -const files = glob.sync(`${CWD}/i18n/**`); -const langRegex = /\/i18n\/(.*)\.json$/; - -files.forEach(file => { - const extension = path.extname(file); - if (extension === '.json') { - const match = langRegex.exec(file); - const language = match[1]; - translation[language] = require(file); - } -}); - -module.exports = translation; +module.exports = env.translation; diff --git a/lib/server/utils.js b/lib/server/utils.js index 16a24432b7f9f..4306d3c372854 100644 --- a/lib/server/utils.js +++ b/lib/server/utils.js @@ -15,12 +15,6 @@ function getSubDir(file, refDir) { return subDir !== '.' && !subDir.includes('..') ? subDir : null; } -function getLanguage(file, refDir) { - const env = require('./env.js'); - - return env.translation.getLanguage(file, refDir); -} - function isSeparateCss(file, separateDirs) { if (!separateDirs) { return false; @@ -52,7 +46,6 @@ function autoPrefixCss(cssContent) { module.exports = { getSubDir, - getLanguage, isSeparateCss, minifyCss, autoPrefixCss,