Skip to content

Commit 18966f6

Browse files
flakoleflukZYSzys
authored andcommitted
Build default language with locale (adds preserveLocale flag) (#1940)
Currently when navigating to a page that does not have a locale, it will default the english one, this breaks the navigation (it doesn't really break it, but everything including links now changes locale to english) ![2018-12-15 01 11 30](https://user-images.githubusercontent.com/11986564/50038916-c2886300-0007-11e9-8755-0ad42a12c67e.gif) This PR adds a preserveLocale flag that will run a second build of the files not included in the locale that exist in the "en" locale but using the current locale site.json. Build time is considerably longer (*en* locale has almost 700 files, compared to others with 20 or less) The result: ![2018-12-15 01 16 14](https://user-images.githubusercontent.com/11986564/50039015-86ee9880-0009-11e9-82ca-39405727747b.gif) Open for discussion.
1 parent 7e8ac9d commit 18966f6

File tree

4 files changed

+70
-50
lines changed

4 files changed

+70
-50
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ If you want to submit a new feature or a bugfix, the best way is to create the c
4141
* The top of each Markdown file is a block of YAML for page specific localization information that is passed to various templates.
4242
* The bulk of the Markdown content for each page is referenced as `{{{content}}}` in the corresponding template.
4343

44+
### Serve/Build Options
45+
46+
* `DEFAULT_LOCALE={{locale}} npm run serve` builds only the files present in the specified locale folder (will display 404 if file is not present)
47+
* `DEFAULT_LOCALE={{locale}} npm run serve -- --preserveLocale` builds the files present in the specified locale folder and adds the pages present in the english locale that are missing.
48+
* `npm run serve` builds all languages and returns 404 when a file is not present in the current locale
49+
* `npm run serve -- --preserveLocale` builds all languages and adds the pages present in the english locale that are missing.
50+
* Multiple locales can be built by using comma separated values in the DEFAULT_LOCALE option. i.e: DEFAULT_LOCALE=en,es,it
51+
52+
4453
### Deployment
4554

4655
Full set up is in https://github.com/nodejs/build/tree/master/setup/www minus secrets and certificates. The webhook is setup on GitHub for this project and talks to a small Node server on the host which does the work. See the [github-webhook](https://github.com/rvagg/github-webhook) package for this.

build.js

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,16 @@ function i18nJSON (lang) {
5656
// This is the function where the actual magic happens. This contains the main
5757
// Metalsmith build cycle used for building a locale subsite, such as the
5858
// english one.
59-
function buildLocale (source, locale) {
59+
function buildLocale (source, locale, opts) {
6060
console.log(`[metalsmith] build/${locale} started`)
6161
console.time(`[metalsmith] build/${locale} finished`)
6262
const metalsmith = Metalsmith(__dirname)
6363
metalsmith
64-
// Sets global metadata imported from the locale's respective site.json.
64+
// Sets global metadata imported from the locale's respective site.json.
6565
.metadata({ site: i18nJSON(locale), project: source.project })
66-
// Sets the build source as the locale folder.
66+
// Sets the build source as the locale folder.
6767
.source(path.join(__dirname, 'locale', locale))
68+
.use(withPreserveLocale(opts && opts.preserveLocale))
6869
// Extracts the main menu and sub-menu links form locale's site.json and
6970
// adds them to the metadata. This data is used in the navigation template
7071
.use(navigation(source.project.latestVersions))
@@ -170,6 +171,31 @@ function buildLocale (source, locale) {
170171
})
171172
}
172173

174+
// This plugin reads the files present in the english locale that are missing
175+
// in the current locale being built (requires preserveLocale flag)
176+
function withPreserveLocale (preserveLocale) {
177+
return (files, m, next) => {
178+
if (preserveLocale) {
179+
var path = m.path('locale/en')
180+
m.read(path, function (err, newfiles) {
181+
if (err) {
182+
console.error(err)
183+
return next(err)
184+
}
185+
186+
Object.keys(newfiles).forEach(function (key) {
187+
if (!files[key]) {
188+
files[key] = newfiles[key]
189+
}
190+
})
191+
next()
192+
})
193+
} else {
194+
next()
195+
}
196+
}
197+
}
198+
173199
// This middleware adds "Edit on GitHub" links to every editable page
174200
function githubLinks (options) {
175201
return (files, m, next) => {
@@ -268,7 +294,8 @@ function getSource (callback) {
268294

269295
// This is where the build is orchestrated from, as indicated by the function
270296
// name. It brings together all build steps and dependencies and executes them.
271-
function fullBuild () {
297+
function fullBuild (opts) {
298+
const { preserveLocale, selectedLocales } = opts
272299
// Build static files.
273300
copyStatic()
274301
// Build layouts
@@ -278,16 +305,19 @@ function fullBuild () {
278305

279306
// Executes the build cycle for every locale.
280307
fs.readdir(path.join(__dirname, 'locale'), (e, locales) => {
281-
locales.filter(junk.not).forEach((locale) => {
282-
buildLocale(source, locale)
283-
})
308+
locales.filter(file => junk.not(file) && (selectedLocales ? selectedLocales.includes(file) : true))
309+
.forEach((locale) => {
310+
buildLocale(source, locale, { preserveLocale })
311+
})
284312
})
285313
})
286314
}
287315

288316
// Starts the build if the file was executed from the command line
289317
if (require.main === module) {
290-
fullBuild()
318+
const preserveLocale = process.argv.includes('--preserveLocale')
319+
const selectedLocales = process.env.DEFAULT_LOCALE ? process.env.DEFAULT_LOCALE.toLowerCase().split(',') : process.env.DEFAULT_LOCALE
320+
fullBuild({ selectedLocales, preserveLocale })
291321
}
292322

293323
exports.getSource = getSource

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
"homepage": "https://nodejs.org",
66
"scripts": {
77
"build": "node build.js",
8+
"build:deploy":"node build.js --preserveLocale",
89
"serve": "node server.js",
910
"external:survey": "rsync -avz --exclude 'node_modules*' --exclude 'package*' external/survey-2018/ build/en/user-survey-report",
1011
"gzip": "find build -type f \\( -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.xml' -o -name '*.json' \\) -exec gzip -kf9 {} \\;",
11-
"deploy": "npm run load-schedule && npm run build && npm run external:survey && npm run gzip",
12+
"deploy": "npm run load-schedule && npm run build:deploy && npm run external:survey && npm run gzip",
1213
"load-versions": "node scripts/load-versions.js",
1314
"load-schedule": "curl -sS https://github.com/raw/nodejs/Release/master/schedule.json -o source/schedule.json",
1415
"start": "npm run serve",

server.js

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ const build = require('./build')
1818

1919
const port = process.env.PORT || 8080
2020

21+
const selectedLocales = process.env.DEFAULT_LOCALE ? process.env.DEFAULT_LOCALE.toLowerCase().split(',') : process.env.DEFAULT_LOCALE
22+
const preserveLocale = process.argv.includes('--preserveLocale')
23+
2124
// Watches for file changes in the locale, layout and static directories, and
2225
// rebuilds the modified one.
2326
const opts = {
@@ -34,38 +37,6 @@ const opts = {
3437
const locales = chokidar.watch(path.join(__dirname, 'locale'), opts)
3538
const layouts = chokidar.watch(path.join(__dirname, 'layouts'), opts)
3639
const statics = chokidar.watch(path.join(__dirname, 'static'), opts)
37-
const fs = require('fs')
38-
// Read all the langs under `locale`
39-
const SUPPORTED_LANGUAGES = new Set(fs.readdirSync(path.join(__dirname, 'locale')))
40-
41-
// Redirect mechanism meant as a fix for languages where some pages
42-
// have not been translated yet, therefore redirect to the english equivalent,
43-
// which isn't the correct language, but better than a 404-page
44-
function redirectToEnglishUrl (req, res) {
45-
return () => {
46-
// Url should be case insensitive.(e.g: zh-CN = zh-cn),
47-
// So we should make a convert to the lower case and check the route values.
48-
let url = req.url.toLowerCase()
49-
const splitedValues = url.split('/')
50-
// For urls like `/blog`, add `en` before that
51-
if (splitedValues.length === 2) {
52-
splitedValues[0] = 'en'
53-
url = splitedValues.join('/').trim()
54-
} else if (splitedValues[1] !== 'en' && SUPPORTED_LANGUAGES.has(splitedValues[1])) {
55-
// For urls like `/lang/docs/`.
56-
// If we found the lang in our set, this means the specific lang
57-
// doesn't have proper translated pages yet, so force the default
58-
// lang to `en`.
59-
splitedValues[1] = 'en'
60-
url = splitedValues.join('/').trim()
61-
}
62-
63-
res.writeHead(302, {
64-
location: url
65-
})
66-
res.end()
67-
}
68-
}
6940

7041
// Gets the locale name by path.
7142
function getLocale (filePath) {
@@ -77,18 +48,24 @@ build.getSource((err, source) => {
7748
if (err) { throw err }
7849

7950
locales.on('change', (filePath) => {
80-
build.buildLocale(source, getLocale(filePath))
51+
const locale = getLocale(filePath)
52+
if (!selectedLocales || selectedLocales.includes(locale)) {
53+
build.buildLocale(source, locale)
54+
}
8155
})
8256
locales.on('add', (filePath) => {
83-
build.buildLocale(source, getLocale(filePath))
84-
locales.add(filePath)
57+
const locale = getLocale(filePath)
58+
if (!selectedLocales || selectedLocales.includes(locale)) {
59+
build.buildLocale(source, locale)
60+
locales.add(filePath)
61+
}
8562
})
8663
})
8764

88-
layouts.on('change', build.fullBuild)
65+
layouts.on('change', () => build.fullBuild({ selectedLocales, preserveLocale }))
8966
layouts.on('add', (filePath) => {
9067
layouts.add(filePath)
91-
build.fullBuild()
68+
build.fullBuild({ selectedLocales, preserveLocale })
9269
})
9370

9471
statics.on('change', build.copyStatic)
@@ -97,15 +74,18 @@ statics.on('add', (filePath) => {
9774
build.copyStatic()
9875
})
9976

77+
const mainLocale = (selectedLocales && selectedLocales[0]) || 'en'
78+
10079
// Initializes the server and mounts it in the generated build directory.
10180
http.createServer((req, res) => {
10281
// If we are accessing the root, it should be redirected to `/en` instead.
10382
// We shouldn't get a 404 page.
83+
10484
if (req.url === '/') {
105-
req.url = '/en'
85+
req.url = `/${mainLocale}`
10686
}
107-
mount(req, res, redirectToEnglishUrl(req, res))
108-
}).listen(port, () => console.log(`\x1B[32mServer running at http://localhost:${port}/en/\x1B[39m`))
87+
mount(req, res)
88+
}).listen(port, () => console.log(`\x1B[32mServer running at http://localhost:${port}/${mainLocale}/\x1B[39m`))
10989

11090
// Start the initial build of static HTML pages
111-
build.fullBuild()
91+
build.fullBuild({ selectedLocales, preserveLocale })

0 commit comments

Comments
 (0)