-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[build] [translation] Fix translation build error.
1. Update all gulp dependencies. 2. Use the new transifex API to push and pull files.
- Loading branch information
Showing
22 changed files
with
18,321 additions
and
9,480 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Generate from here: https://app.transifex.com/user/settings/api/ | ||
TRANSIFEX_API="..." | ||
TRANSIFEX_ORGANIZATION=freemius | ||
TRANSIFEX_PROJECT=sdk-testing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Contributing to Freemius SDK for WordPress | ||
|
||
We love to receive contributions from our community — you! There are many ways to contribute, from writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests or writing code which can be incorporated into Freemius SDK for WordPress itself. | ||
Please be sure to read our [contributing guide](https://freemius.com/help/documentation/wordpress-sdk/freemius-sdk-contribute/) before making a pull request. | ||
|
||
## Setup Node.js | ||
|
||
We make use of several Node.js packages to build and test the SDK. To install them, you need to have Node.js installed on your machine. We recommend using | ||
[nvm](https://github.com/nvm-sh/nvm). Once you have it installed, run the following commands to install the correct version of Node.js and the dependencies: | ||
|
||
```bash | ||
# Make sure to use the latest LTS version of Node.js. | ||
nvm install --lts | ||
nvm use --lts | ||
|
||
# Install with a frozen lockfile. | ||
npm ci | ||
```` | ||
|
||
Now you may check the available commands by running: | ||
|
||
```bash | ||
npm run | ||
``` | ||
|
||
## Translations | ||
|
||
We use a custom build to extract translations and generate the POT file. The prerequisites are: | ||
|
||
- You must be a team member of Freemius. | ||
- You must have access to our [Transifex](https://app.transifex.com/freemius/wordpress-sdk/dashboard/) project. | ||
- You have set the `.env` file in the project with the needed variables. Check the `.env.example` file for reference. | ||
|
||
Now, you can run the following commands: | ||
|
||
|
||
```bash | ||
# Run the script to extract translations and generate the POT file. | ||
npm run translate | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,4 @@ | ||
var gulp = require('gulp'); | ||
var path = require('path'); | ||
var filesystem = require('fs'); | ||
var wpPot = require('gulp-wp-pot'); | ||
var gettext = require('gulp-gettext'); | ||
var sort = require('gulp-sort'); | ||
var pofill = require('gulp-pofill'); | ||
var rename = require('gulp-rename'); | ||
var clean = require('gulp-clean'); | ||
require('dotenv').config(); | ||
const {createTranslation} = require('./gulptasks/translate'); | ||
|
||
var languagesFolder = './languages/'; | ||
|
||
var options = require('./transifex-config.json'); | ||
|
||
function getFolders(dir) { | ||
return filesystem.readdirSync(dir) | ||
.filter(function (file) { | ||
return filesystem.statSync(path.join(dir, file)).isDirectory(); | ||
}); | ||
} | ||
|
||
var transifex = require('gulp-transifex').createClient(options); | ||
|
||
// Create POT out of PHP files | ||
gulp.task('prepare-source', function () { | ||
gulp.src('**/*.php') | ||
.pipe(sort()) | ||
.pipe(wpPot({ | ||
destFile : 'freemius.pot', | ||
package : 'freemius', | ||
bugReport : 'https://github.com/Freemius/wordpress-sdk/issues', | ||
lastTranslator : 'Vova Feldman <[email protected]>', | ||
team : 'Freemius Team <[email protected]>', | ||
|
||
gettextFunctions: [ | ||
{name: 'get_text_inline'}, | ||
|
||
{name: 'fs_text_inline'}, | ||
{name: 'fs_echo_inline'}, | ||
{name: 'fs_esc_js_inline'}, | ||
{name: 'fs_esc_attr_inline'}, | ||
{name: 'fs_esc_attr_echo_inline'}, | ||
{name: 'fs_esc_html_inline'}, | ||
{name: 'fs_esc_html_echo_inline'}, | ||
|
||
{name: 'get_text_x_inline', context: 2}, | ||
{name: 'fs_text_x_inline', context: 2}, | ||
{name: 'fs_echo_x_inline', context: 2}, | ||
{name: 'fs_esc_attr_x_inline', context: 2}, | ||
{name: 'fs_esc_js_x_inline', context: 2}, | ||
{name: 'fs_esc_js_echo_x_inline', context: 2}, | ||
{name: 'fs_esc_html_x_inline', context: 2}, | ||
{name: 'fs_esc_html_echo_x_inline', context: 2} | ||
] | ||
})) | ||
.pipe(gulp.dest(languagesFolder + 'freemius.pot')); | ||
|
||
// Create English PO out of the POT. | ||
return gulp.src(languagesFolder + 'freemius.pot') | ||
.pipe(pofill({ | ||
items: function (item) { | ||
// If msgstr is empty, use identity translation | ||
if (!item.msgstr.length) { | ||
item.msgstr = ['']; | ||
} | ||
if (!item.msgstr[0]) { | ||
item.msgstr[0] = item.msgid; | ||
} | ||
return item; | ||
} | ||
})) | ||
.pipe(rename('freemius-en.po')) | ||
.pipe(gulp.dest(languagesFolder)); | ||
}); | ||
|
||
// Push updated po resource to transifex. | ||
gulp.task('update-transifex', ['prepare-source'], function () { | ||
return gulp.src(languagesFolder + 'freemius-en.po') | ||
.pipe(transifex.pushResource()); | ||
}); | ||
|
||
// Download latest *.po translations. | ||
gulp.task('download-translations', ['update-transifex'], function () { | ||
return gulp.src(languagesFolder + 'freemius-en.po') | ||
.pipe(transifex.pullResource()); | ||
}); | ||
|
||
// Move translations to languages root. | ||
gulp.task('prepare-translations', ['download-translations'], function () { | ||
var folders = getFolders(languagesFolder); | ||
|
||
return folders.map(function (folder) { | ||
return gulp.src(path.join(languagesFolder, folder, 'freemius-en.po')) | ||
.pipe(rename('freemius-' + folder + '.po')) | ||
.pipe(gulp.dest(languagesFolder)); | ||
}); | ||
}); | ||
|
||
// Feel up empty translations with English. | ||
gulp.task('translations-feelup', ['prepare-translations'], function () { | ||
return gulp.src(languagesFolder + '*.po') | ||
.pipe(pofill({ | ||
items: function (item) { | ||
// If msgstr is empty, use identity translation | ||
if (0 == item.msgstr.length) { | ||
item.msgstr = ['']; | ||
} | ||
if (0 == item.msgstr[0].length) { | ||
// item.msgid[0] = item.msgid; | ||
item.msgstr[0] = item.msgid; | ||
} | ||
return item; | ||
} | ||
})) | ||
.pipe(gulp.dest(languagesFolder)); | ||
}); | ||
|
||
// Cleanup temporary translation folders. | ||
gulp.task('cleanup', ['prepare-translations'], function () { | ||
var folders = getFolders(languagesFolder); | ||
|
||
return folders.map(function (folder) { | ||
return gulp.src(path.join(languagesFolder, folder), {read: false}) | ||
.pipe(clean()); | ||
}); | ||
}); | ||
|
||
// Compile *.po to *.mo binaries for usage. | ||
gulp.task('compile-translations', ['translations-feelup'], function () { | ||
// Compile POs to MOs. | ||
return gulp.src(languagesFolder + '*.po') | ||
.pipe(gettext()) | ||
.pipe(gulp.dest(languagesFolder)) | ||
}); | ||
|
||
gulp.task('default', [], function () { | ||
gulp.run('prepare-source'); | ||
gulp.run('update-transifex'); | ||
gulp.run('download-translations'); | ||
gulp.run('prepare-translations'); | ||
gulp.run('translations-feelup'); | ||
gulp.run('cleanup'); | ||
gulp.run('compile-translations'); | ||
}); | ||
exports.translate = createTranslation; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/** | ||
* All Transifex related APIs and code. | ||
* | ||
* @link https://developers.transifex.com/recipes/create-update-and-delete-a-resource-in-nodejs | ||
* @todo Refactor into a class/proper library if we end up using this at more places. | ||
*/ | ||
const {transifexApi} = require('@transifex/api'); | ||
const fs = require('node:fs'); | ||
const log = require('fancy-log'); | ||
|
||
transifexApi.setup({ | ||
auth: process.env.TRANSIFEX_API | ||
}); | ||
|
||
const SOURCE_SLUG = 'freemius-enpo'; | ||
const SOURCE_NAME = 'freemius-en.po'; | ||
|
||
async function getOrganization() { | ||
// Safety check, unless we feel 100% confident, this wouldn't break the existing resources. | ||
if ('wordpress-sdk' === process.env.TRANSIFEX_ORGANIZATION) { | ||
throw new Error('Can not use the production organization yet!'); | ||
} | ||
|
||
const organization = await transifexApi.Organization.get({slug: process.env.TRANSIFEX_ORGANIZATION}); | ||
|
||
if (!organization) { | ||
throw new Error(`Organization "${process.env.TRANSIFEX_ORGANIZATION}" not found!`); | ||
} | ||
|
||
log(`Using organization "${organization.attributes.name}"`); | ||
|
||
return organization; | ||
} | ||
|
||
/** | ||
* @param {import('@transifex/api').JsonApiResource} organization | ||
* @return {Promise<import('@transifex/api').JsonApiResource>} | ||
*/ | ||
async function getProject(organization) { | ||
const projects = await organization.fetch('projects', false); | ||
const project = await projects.get({slug: process.env.TRANSIFEX_PROJECT}); | ||
|
||
if (!project) { | ||
throw new Error(`Project "${process.env.TRANSIFEX_PROJECT}" not found!`); | ||
} | ||
|
||
log(`Using project "${project.attributes.name}"`); | ||
|
||
return project; | ||
} | ||
|
||
async function getOrgAndProject() { | ||
const organization = await getOrganization(); | ||
const project = await getProject(organization); | ||
|
||
return {organization, project}; | ||
} | ||
|
||
/** | ||
* @param {import('@transifex/api').JsonApiResource} project | ||
* @param {string} name | ||
* @param {string} slug | ||
* @param {import('@transifex/api').JsonApiResource} i18nFormat | ||
* @return {Promise<import('@transifex/api').JsonApiResource>} | ||
*/ | ||
async function getResourceStringForUpload(project, name, slug, i18nFormat) { | ||
const resources = await project.fetch('resources', false); | ||
/** | ||
* IMPORTANT: DO NOT DELETE THE RESOURCE from the API. | ||
* It will delete all the translations too. | ||
* So first try to see if the resource is present and use it. If not, then only create it. | ||
*/ | ||
|
||
/** | ||
* @type {import('@transifex/api').JsonApiResource} | ||
*/ | ||
let resource; | ||
|
||
try { | ||
resource = await resources.get({slug}); | ||
log(`Resource "${name}" already exists, updating...`) | ||
} catch (e) { | ||
// No resources yet | ||
log(`Creating resource "${name}"`); | ||
resource = await transifexApi.Resource.create({ | ||
name, | ||
slug, | ||
project, | ||
i18n_format: i18nFormat, | ||
}); | ||
} | ||
|
||
return resource; | ||
} | ||
|
||
async function uploadEnglishPoToTransifex(poPath) { | ||
const {organization, project} = await getOrgAndProject(); | ||
const content = fs.readFileSync(poPath, {encoding: 'utf-8'}); | ||
|
||
const i18nFormat = await transifexApi.i18n_formats.get({ | ||
organization, | ||
name: 'PO' | ||
}); | ||
|
||
const resource = await getResourceStringForUpload(project, SOURCE_NAME, SOURCE_SLUG, i18nFormat); | ||
|
||
await transifexApi.ResourceStringsAsyncUpload.upload({ | ||
resource, | ||
content, | ||
}); | ||
|
||
return resource; | ||
} | ||
|
||
/** | ||
* @param {string} languageCode | ||
* @param {import('@transifex/api').JsonApiResource} resource | ||
* @return {Promise<string>} | ||
*/ | ||
async function getTranslation(languageCode, resource) { | ||
const language = await transifexApi.Language.get({code: languageCode}); | ||
const url = await transifexApi.ResourceTranslationsAsyncDownload.download({ | ||
resource, | ||
language, | ||
}); | ||
|
||
const response = await fetch(url); | ||
return await response.text(); | ||
} | ||
|
||
exports.uploadEnglishPoToTransifex = uploadEnglishPoToTransifex; | ||
exports.getTranslation = getTranslation; |
Oops, something went wrong.