Skip to content

Commit

Permalink
Merge pull request #4491 from wordpress-mobile/release/1.70.0
Browse files Browse the repository at this point in the history
Release 1.70.0
  • Loading branch information
fluiddot authored Jan 20, 2022
2 parents 703b310 + 936093f commit d4cfb5b
Show file tree
Hide file tree
Showing 150 changed files with 2,446 additions and 9,114 deletions.
3 changes: 3 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ steps:
image: "public.ecr.aws/automattic/gb-mobile-image:latest"
environment:
- "CI=true"
# Allow WP-CLI to be run as root, otherwise it throws an exception.
# Reference: https://git.io/J9q2S
- "WP_CLI_ALLOW_ROOT=true"
command: |
source /root/.bashrc
Expand Down
9 changes: 6 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ commands:
key: npm-i18n-v5-cache-v{{ .Environment.CACHE_TRIGGER_VERSION }}-job-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package-lock.json" }}
paths:
- ~/.npm
- i18n-cache/data
- src/i18n-cache
npm-install-full:
steps:
- restore_cache:
Expand All @@ -39,7 +39,7 @@ commands:
key: npm-i18n-v5-cache-v{{ .Environment.CACHE_TRIGGER_VERSION }}-job-{{ .Environment.CIRCLE_JOB }}-{{ checksum "gutenberg/package-lock.json" }}
paths:
- ~/.npm
- i18n-cache/data
- src/i18n-cache
checkout-shallow:
steps:
- run:
Expand Down Expand Up @@ -248,8 +248,11 @@ jobs:
- install-node-version
- npm-install
- run:
name: Run Android native unit tests
name: Run Android native-editor unit tests
command: cd gutenberg/packages/react-native-editor/android && ./gradlew testDebug
- run:
name: Run Android native-bridge unit tests
command: cd gutenberg/packages/react-native-bridge/android && ./gradlew test
ios-device-checks:
parameters:
post-to-slack:
Expand Down
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ bundle/ios/assets/gutenberg/packages/block-library/src/*

# Local configuration file (sdk path, etc)
local.properties
.tool-versions

# XCode
build/
Expand Down Expand Up @@ -117,6 +118,11 @@ bin/wp-cli.phar
/junit.xml

# Cocoapods

ios/Pods
ios/vendor

# i18n update
i18n-test/

# i18n cache
src/i18n-cache/
2 changes: 1 addition & 1 deletion Gutenberg.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Pod::Spec.new do |s|
s.requires_arc = true
s.preserve_paths = 'bundle/ios/*'
s.swift_version = '5.0'
s.resources = ['gutenberg/packages/react-native-bridge/common/**/*.{js,css,json}', 'src/block-support/supported-blocks.json', 'resources/**/*.js']
s.resources = ['gutenberg/packages/react-native-bridge/common/**/*.{js,css,json}', 'src/block-support/supported-blocks.json', 'resources/**/*.{js,css}']

s.dependency 'React', react_native_version
s.dependency 'React-CoreModules', react_native_version
Expand Down
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,83 @@ To have the linter also _fix_ the violations run: `npm run lint:fix`.

You might want to use Visual Studio Code as an editor. The project includes the configuration needed to use the above codestyle and linting tools automatically.

## Internationalization (i18n)

The support for i18n in the project is provided by three main areas for the different plugins included in Gutenberg Mobile:
1. Translations files download
2. Locale setup
3. Localization strings file generation

### Main areas

#### Translation files download
A translation file is basically a JSON object that contains key-value items with the translation for each individual string. This content is fetched from [translate.wordpress.org](https://translate.wordpress.org/) that holds translations for WordPress and a list of different plugins like Gutenberg.

These files are cached under the folder located at `src/i18n-cache/<PLUGIN_NAME>`, and can be optimized depending on the command used for fetching them. Additionally, an index file (`index.js`) is generated that acts as the entry point to import and get translations for each plugin.

Fetched translations contain all the strings of the plugin, including strings that are not used in the native version of the editor, however, and in order to reduce their file size, they can be optimized by filtering out the unused strings.

By default, when installing dependencies, un-optimized translations will be downloaded for the plugins specified in the `i18n:check-cache` NPM command within the `package.json` file. The reason for getting the un-optimized version is purely for speed reasons, as the optimization process takes up several minutes.

For the optimized versions, similarly, we have the `i18n:update` NPM command that can be used for this purpose. This command is also automatically run when generating the bundle via `npm run bundle`, this way we guarantee that a new version of the bundle contains up-to-date translations. On the other hand, it's important to mention that this command also generates the localization strings files described in a later section.

#### Locale setup
This is done upon the [editor initialization](https://github.com/wordpress-mobile/gutenberg-mobile/blob/develop/src/index.js), an array containing the following items related to each plugin is passed:
```
[
{
domain: <DOMAIN / PLUGIN NAME>, (i.e. `jetpack`)
getTranslation: <CALLBACK_FOR_GETTING_TRANSLATION> (i.e. `getTranslation` function imported from `src/i18n-cache/jetpack/index.js`)
},
...
]
```

#### Localization strings file generation
Some of the strings referenced in the editor are only used in the native version, these strings are not included in the translations fetched from [translate.wordpress.org](https://translate.wordpress.org/), however, they are part of the WordPress app translations. For this reason, we generate the following localization strings files, which contain these types of string, for each platform, and that are bundled and incorporated in the translation pipeline of the app.
- [`bundle/android/strings.xml`](https://github.com/wordpress-mobile/gutenberg-mobile/blob/develop/bundle/android/strings.xml)
- [`bundle/ios/GutenbergNativeTranslations.swift`](https://github.com/wordpress-mobile/gutenberg-mobile/blob/develop/bundle/ios/GutenbergNativeTranslations.swift)

These files are generated via the `i18n:update` NPM command, and like translations, they are also produced when generating the bundle.

### NPM commands
- `npm run i18n:update`: Downloads optimized translations and generate localization strings files for all plugins. **NOTE:** This command is attached to `bundle` NPM command via `prebundle:js`, so it will be automatically executed when generating a bundle.
- `npm run i18n:check-cache`: Downloads un-optimized translations for plugins that don't have a cache folder. **NOTE:** This command is attached to dependency installation via `postinstall`, so it will be automatically executed when installing dependencies.

### How to add a new plugin
1. Identify the i18n domain, which usually matches the plugin's name (i.e. `jetpack`).
2. Identify the path to the plugin source code (i.e. `./jetpack/projects/plugins/jetpack/extensions`).
3. Append the plugin's name to the arguments of `i18n:check-cache` NPM command.
4. Append the plugin's name and source code path to the arguments of `i18n:update` NPM command.
5. Add the i18n domain of the plugin and the callback for getting translation to the [editor initialization](https://github.com/wordpress-mobile/gutenberg-mobile/blob/develop/src/index.js).
*Example:*
```
import { getTranslation as getJetpackTranslation } from './i18n-translations/jetpack';
...
const pluginTranslations = [
{
domain: 'jetpack',
getTranslation: getJetpackTranslation,
},
...
];
```

## Caveats
- Strings that are only used in the native version, and reference a [context](https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#disambiguation-by-context), won't be included in the localization strings files hence, they won't be translated. This is a limitation in the format of the localization strings files.
- Localization strings files don’t support domains, so the strings extracted from plugins that are only used in the native version, will be unified in the same file, which might involve string conflicts.

## Troubleshooting

### A string is missing the translation
This can be produced by several causes, check the following steps in order to identify the source:
- Verify that the string uses the `__` i18n function or similar ([reference](https://github.com/WordPress/gutenberg/blob/trunk/packages/i18n/README.md)).
- Check for warnings in the output when running `i18n:update` NPM command, especially the following ones:
- Parsing files issues (i.e. `Debug (make-pot): Could not parse file <FILE>`)
- Missing strings in translation files (i.e. `WARNING: The following strings are missing from translations:`)
- If the string is only used in the native version, the translation won't be available until the a new version of the app is cut and its translations are requested. Check if the string is included in the localization strings files, if not, verify the output of `i18n:update` NPM command and look for warnings that reference the string.

## License

Gutenberg Mobile is an Open Source project covered by the [GNU General Public License version 2](LICENSE).
Expand Down
11 changes: 11 additions & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
Unreleased
---

1.70.0
---
* [**] Fix content justification attribute in Buttons block [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4451]
* [*] Hide help button from Unsupported Block Editor. [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4352/]
* [*] Add contrast checker to text-based blocks [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4357]
* [*] Fix missing Featured Image translations [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4464]
* [*] Fix missing translations of color settings [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4479]
* [*] Fix cut-off setting labels by properly wrapping the text [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4475]
* [*] Highlight text: fix applying formatting for non-selected text [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4471]
* [**] Fix Android handling of Hebrew and Indonesian translations [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4397]

1.69.1
---
* [*] Fix app freeze when closing link picker while virtual keyboard is hidden [https://github.com/wordpress-mobile/gutenberg-mobile/pull/4443]
Expand Down
68 changes: 68 additions & 0 deletions bin/i18n-check-cache.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash
#
# Checks i18n cache folders in order to guarantee that translations are present for provided plugins.
# A cache folder will be created, in case a plugin doesn't have it, with its translations that
# will be fetched before creation.
#
# NOTE: The translations fetched are NOT OPTIMIZED, the reason for this is purely for making
# the script fast as it will be mainly used upon dependency installation.

# Exit if any command fails
set -euo pipefail

function error() {
echo -e "\033[0;31m$1\033[0m"
exit 1
}

function arrayLength() { echo "$#"; }

function check_plugin_cache() {
local plugin_name=$1
local i18n_cache_folder="$TRANSLATIONS_OUTPUT_PATH/$plugin_name"

if [[ ! -d $i18n_cache_folder ]]; then
NOT_FOUND_PLUGIN_I18N_CACHE+=( $i18n_cache_folder )
echo -e "Couldn't find i18n cache folder (\"$i18n_cache_folder\") for plugin \"$plugin_name\", downloading un-optimized translations for creating the cache."
fetch_translations "$plugin_name" "$TRANSLATIONS_OUTPUT_PATH"
fi
}

function update_gutenberg_i18n_cache() {
local output_path=$1

echo "Update \"react-native-editor\" package i18n cache"
cp -r "$output_path/gutenberg/data" gutenberg/packages/react-native-editor/i18n-cache
cp "$output_path/gutenberg/index.js" gutenberg/packages/react-native-editor/i18n-cache/index.native.js
}

function fetch_translations() {
local plugin_name=$1
local output_path=$2

echo -e "\n\033[1mDownload I18n translations for \"$plugin_name\" plugin\033[0m"
node gutenberg/packages/react-native-editor/bin/i18n-translations-download "$plugin_name" "$output_path"
}

# Get parameters
PLUGINS=( "$@" )

# Define constants
TRANSLATIONS_OUTPUT_PATH="src/i18n-cache"

echo -e "\n\033[1m== Checking i18n cache ==\033[0m"

# Check plugins cache
for PLUGIN in "${PLUGINS[@]+"${PLUGINS[@]}"}"; do
check_plugin_cache "$PLUGIN"
done

# Check Gutenberg cache
check_plugin_cache "gutenberg"

if [[ $(arrayLength "${NOT_FOUND_PLUGIN_I18N_CACHE[@]+"${NOT_FOUND_PLUGIN_I18N_CACHE[@]}"}") -eq 0 ]]; then
echo -e "i18n cache for provided plugins is present ✅"
fi

# We need to guarantee that i18n cache within react-native-editor package is updated
update_gutenberg_i18n_cache "$TRANSLATIONS_OUTPUT_PATH"
11 changes: 0 additions & 11 deletions bin/i18n-download.sh

This file was deleted.

45 changes: 30 additions & 15 deletions bin/i18n-update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,15 @@ while test $# -gt 0; do
case "$1" in
-h|--help)
echo "options:"
echo "-h, --help show brief help"
echo "-p, --path local path for generating files (by default a temp folder will be used)"
echo "-d, --debug print extra info for debugging"
echo "-h, --help show brief help"
echo "-p, --path local path for generating files (by default a temp folder will be used)"
exit 0
;;
-p|--path*)
shift
LOCAL_PATH=$1
shift
;;
-d|--debug*)
shift
DEBUG='true'
;;
*)
break
;;
Expand All @@ -54,6 +49,23 @@ function error() {

function arrayLength() { echo "$#"; }

function check_plugin() {
local plugin_folder=$1

if [[ ! -d $plugin_folder ]]; then
NOT_FOUND_PLUGIN_FOLDERS+=( $plugin_folder )
echo -e "\033[0;31mPlugin folder \"$plugin_folder\" doesn't exist.\033[0m"
fi
}

function update_gutenberg_i18n_cache() {
local output_path=$1

echo "Update \"react-native-editor\" package i18n cache"
cp -r "$output_path/gutenberg/data" gutenberg/packages/react-native-editor/i18n-cache
cp "$output_path/gutenberg/index.js" gutenberg/packages/react-native-editor/i18n-cache/index.native.js
}

function fetch_translations() {
local plugin_name=$1
local output_path=$2
Expand All @@ -63,9 +75,7 @@ function fetch_translations() {
node gutenberg/packages/react-native-editor/bin/i18n-translations-download "$plugin_name" "$output_path" "$used_strings_file"

if [[ "$plugin_name" == "gutenberg" ]]; then
echo "Update \"react-native-editor\" package i18n cache"
cp -r "$output_path/gutenberg/data" gutenberg/packages/react-native-editor/i18n-cache
cp "$output_path/gutenberg/index.js" gutenberg/packages/react-native-editor/i18n-cache/index.native.js
update_gutenberg_i18n_cache "$output_path"
fi
}

Expand All @@ -80,21 +90,27 @@ fi
# Get parameters
PLUGINS=( "$@" )

# Define constants
TRANSLATIONS_OUTPUT_PATH="src/i18n-cache"

echo -e "\n\033[1m== Updating i18n localizations ==\033[0m"

# Validate parameters
if [[ $((${#PLUGINS[@]}%2)) -ne 0 ]]; then
error "Plugin arguments must be supplied as tuples (i.e. domain path/to/plugin)."
fi

# Check plugins parameters
for (( index=0; index<${#PLUGINS[@]}; index+=2 )); do
PLUGIN_FOLDER=${PLUGINS[index+1]}

if [[ ! -d $PLUGIN_FOLDER ]]; then
NOT_FOUND_PLUGIN_FOLDERS+=( $PLUGIN_FOLDER )
echo -e "\033[0;31mPlugin folder \"$PLUGIN_FOLDER\" doesn't exist.\033[0m"
fi
check_plugin "$PLUGIN_FOLDER"
done

# Check Gutenberg plugin
check_plugin "./gutenberg"

# Stop if can't find any plugin folder
if [[ $(arrayLength "${NOT_FOUND_PLUGIN_FOLDERS[@]+"${NOT_FOUND_PLUGIN_FOLDERS[@]}"}") -gt 0 ]]; then
exit 1
fi
Expand All @@ -110,7 +126,6 @@ npm run build:gutenberg
METRO_CONFIG="metro.config.js" node gutenberg/packages/react-native-editor/bin/extract-used-strings "$USED_STRINGS_PATH" "${PLUGINS[@]}"

# Download translations of plugins (i.e. Jetpack)
TRANSLATIONS_OUTPUT_PATH="src/i18n-cache"
for (( index=0; index<${#PLUGINS[@]}; index+=2 )); do
PLUGIN_NAME=${PLUGINS[index]}

Expand Down
Loading

0 comments on commit d4cfb5b

Please sign in to comment.