Skip to content

Copy untranslated english pages to other languages #1961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Aug 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,14 @@ cypress/videos
# Dynamically parsed data

source/_data/banners.yml

# Translations
# By default we ignore each translation folder like "source/ja",
# During the build, We copy English file for each untranslated page to
# the language folder - if there is no fully translated file there.
# Thus when you add a new translation, add it to the source control
# with "git add --force" command to override the folder.
#
source/ja
source/zh-cn

3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"eslint.enable": true,
"editor.formatOnSave": false
"editor.formatOnSave": false,
"workbench.colorCustomizations": {}
}
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ Our currently supported languages can be found at [`/source/_data/languages.yml`

Translate existing documentation then submit a [pull request](#Pull-Requests) for your change.

If a page does not have a translation, then a pre-start step copies the English file to the language folder. These copies should NOT be committed into the source code. Only when the file has been translated you can add it to the source code with `git add --force source/<language>/.../file.md` and this file will not be overwritten by the English file.

## Committing Code

### Linting
Expand Down
122 changes: 122 additions & 0 deletions copy-english-docs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// @ts-check

const debug = require('debug')('copy-english-docs')
const execa = require('execa')
const R = require('ramda')
const pluralize = require('pluralize')
const fs = require('fs-extra')
const Promise = require('bluebird')
const path = require('path')

// work in progress
/* eslint-disable no-console */

const getLanguageName = (short) => {
const names = {
ja: 'Japanese',
'zh-cn': 'Chinese',
}

if (!names[short]) {
throw new Error(`Unknown language short name ${short}`)
}

return names[short]
}

const findFilesTrackedByGit = (folder) => {
return execa('git', ['ls-files', folder]).then(R.prop('stdout')).then(R.split('\n'))
}

const removePrefix = (prefix) => {
const n = prefix.length + 1 // prefix + "/"

const remove = (relativeFilename) => {
return R.startsWith(prefix, relativeFilename) ? relativeFilename.substr(n) : relativeFilename
}

return R.map(remove)
}

const findAllDocs = () => {
debug('finding all docs')

const sourcesFolderName = 'source'

return findFilesTrackedByGit(sourcesFolderName)
}

const isJapaneseDoc = R.test(/\/ja\//)
const isChineseDoc = R.test(/\/zh-cn\//)
const isImage = R.test(/\/img\//)
const isTranslation = R.anyPass([isJapaneseDoc, isChineseDoc, isImage])

const translationsFilter = R.reject(isTranslation)

const findAllEnglishDocs = () => {
debug('finding tracked English docs')

return findAllDocs().then(translationsFilter).then(removePrefix('source'))
}

/**
* @param {("ja" | "zh-cn")} shortName The short language name
*/
const findAllDocsFor = (shortName) => {
const relativeSourceFolder = `source/${shortName}`

return findFilesTrackedByGit(relativeSourceFolder).then(removePrefix(relativeSourceFolder))
}

/**
* @param {("ja" | "zh-cn")} targetLanguage
*/
const copyAllEnglishDocsNotTranslatedTo = (targetLanguage) => {
return Promise.all([
findAllEnglishDocs(),
findAllDocsFor(targetLanguage),
]).then(([englishFiles, translatedFiles]) => {
return R.difference(englishFiles, translatedFiles)
})
.then((untransledEnglishFiles) => {
if (!untransledEnglishFiles.length) {
console.log('No untranslated English docs compared to %s', getLanguageName(targetLanguage))

return
}

console.log('Copying %s from English to %s',
pluralize('file', untransledEnglishFiles.length, true), getLanguageName(targetLanguage))
console.table(untransledEnglishFiles)

return Promise.mapSeries(untransledEnglishFiles, (relativePathToEnglishFile) => {
const sourcePath = path.join('source', relativePathToEnglishFile)
const destinationPath = path.join('source', targetLanguage, relativePathToEnglishFile)
const destinationFolder = path.dirname(destinationPath)

return fs.ensureDir(destinationFolder)
.then(() => {
return fs.copyFile(sourcePath, destinationPath)
})

})
})
}

const copyUntranslatedDocs = () => {
return copyAllEnglishDocsNotTranslatedTo('ja')
.then(() => {
return copyAllEnglishDocsNotTranslatedTo('zh-cn')
})

}

// allow using module.parent
// @ts-ignore
if (!module.parent) {
copyUntranslatedDocs()
} else {
module.exports = {
copyUntranslatedDocs,
}
}
47 changes: 34 additions & 13 deletions cypress/integration/page_header_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ describe('Page Header', () => {
})

it('displays correct page title', function () {
cy.wrap(this.langValues).each(function (lang) {
// disabling this test because we are copying untranslated English document pages
// into other language folders. A single translated page title is not enough to count
// thus the sidebar has translated title, but the page itself shows English translation
// limit to English instead of "this.langValues"
const languages = ['en']

cy.wrap(languages).each(function (lang) {
let sidebarYaml = 'source/_data/sidebar.yml'
let visitUrlPrefix = ''

Expand Down Expand Up @@ -55,21 +61,36 @@ describe('Page Header', () => {
})
})

it('should have link to edit doc', function () {
cy.wrap(this.MAIN_NAV).each((nav) => {
let path = `${nav.path}.html`
let mdPath = `${nav.path}.md`
it('should have link to edit doc in each language', function () {
cy.wrap(this.langValues).each(function (lang) {
// In English it probably is "Improve this doc",
// and in other languages it is a translation
const improvePageText = this[lang].page.improve

if (nav.path === '/plugins/') {
path = `${nav.path}index.html`
mdPath = `${nav.path}index.md`
cy.log(`Language **${lang}**`)
let visitUrlPrefix = ''

if (lang !== 'en') {
visitUrlPrefix = lang
}

cy.visit(path)
cy.contains('a', 'Improve this doc').as('editLink')
.should('have.attr', 'href')
.and('include', mdPath)
.and('include', this.improveUrl)
cy.wrap(this.MAIN_NAV).each((nav) => {
let path = `${nav.path}.html`
let mdPath = `${nav.path}.md`

if (nav.path === '/plugins/') {
path = `${nav.path}index.html`
mdPath = `${nav.path}index.md`
}

cy.visit(`${visitUrlPrefix}${path}`)


cy.contains('a', improvePageText).as('editLink')
.should('have.attr', 'href')
.and('include', mdPath)
.and('include', this.improveUrl)
})
})
})
})
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ process.on('unhandledRejection', function (reason, p) {
process.exit(-1)
})

const { copyUntranslatedDocs } = require('./copy-english-docs')
const Hexo = require('hexo')
const chalk = require('chalk')
const minimist = require('minimist')
Expand Down Expand Up @@ -149,4 +150,5 @@ function initHexo () {
})
}

initHexo()
copyUntranslatedDocs()
.then(initHexo)
Loading