Localazy: improve search, parallelize checks (#7261)

* Remove no longer temporary string

These are now in localazy and the sync strings CI flow was failing because we have 2 conflicting values in `temporary.xml` and `localazy.xml`

* Use the right placeholder value in `screen_local_network_opt_in_subtitle`

* Localazy: improve search, parallelize checks

The search for XML files has been narrowed down and it's several times faster now, and processing the files is now done in parallel

* Improve script to also find and delete previous files

Also add the option of having a `-v|--verbose` flag to print which files we're modifying

* Use `LocalBuildMeta` to get the app name inside `LocalNetworkPermissionDialogView`

* Allow finding all the forbidden terms in the strings and translations and then return an error exit code instead of a success one

---------

Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Jorge Martin Espinosa
2026-07-27 15:12:53 +02:00
committed by GitHub
parent 0e3d479490
commit bbb83c2ff0
13 changed files with 110 additions and 30 deletions
@@ -85,7 +85,6 @@ fun LoggedInView(
}
LocalNetworkPermissionDialogView(
appName = state.appName,
dialog = state.localNetworkPermissionDialog,
onSubmit = { state.eventSink(LoggedInEvents.RequestLocationNetworkPermission) },
onDismiss = { state.eventSink(LoggedInEvents.DismissLocalNetworkPermissionPrompt) },
@@ -123,7 +123,6 @@ fun ChangeServerView(
AsyncData.Uninitialized -> Unit
}
LocalNetworkPermissionDialogView(
appName = LocalBuildMeta.current.applicationName,
dialog = state.localNetworkPermissionDialog,
onSubmit = {
eventSink.invoke(ChangeServerEvents.RequestLocalNetworkPermission)
@@ -41,7 +41,6 @@ import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.TopAppBar
@@ -139,7 +138,6 @@ fun ChooseAccountProviderView(
}
}
LocalNetworkPermissionDialogView(
appName = LocalBuildMeta.current.applicationName,
dialog = state.loginModeState.localNetworkPermissionDialog,
onSubmit = {
state.loginModeState.eventSink(LoginModeEvent.RequestLocalNetworkPermission)
@@ -47,7 +47,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.avatar.BitmapAvatar
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.Text
@@ -208,7 +207,6 @@ fun LoginWithClassicView(
onCreateAccountContinue = onCreateAccountContinue,
)
LocalNetworkPermissionDialogView(
appName = LocalBuildMeta.current.applicationName,
dialog = state.loginModeState.localNetworkPermissionDialog,
onSubmit = {
state.loginModeState.eventSink(LoginModeEvent.RequestLocalNetworkPermission)
@@ -29,7 +29,6 @@ import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.TextButton
import io.element.android.libraries.matrix.api.auth.OAuthDetails
@@ -113,7 +112,6 @@ fun ConfirmAccountProviderView(
}
LocalNetworkPermissionDialogView(
appName = LocalBuildMeta.current.applicationName,
dialog = state.loginModeState.localNetworkPermissionDialog,
onSubmit = {
state.loginModeState.eventSink(LoginModeEvent.RequestLocalNetworkPermission)
@@ -87,7 +87,6 @@ fun OnBoardingView(
onCreateAccountContinue = onCreateAccountContinue,
)
LocalNetworkPermissionDialogView(
appName = state.productionApplicationName,
dialog = state.loginModeState.localNetworkPermissionDialog,
onSubmit = {
state.loginModeState.eventSink(LoginModeEvent.RequestLocalNetworkPermission)
@@ -11,11 +11,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun LocalNetworkPermissionDialogView(
appName: String,
dialog: LocalNetworkPermissionDialog,
onSubmit: () -> Unit,
onDismiss: () -> Unit,
@@ -28,7 +28,7 @@ fun LocalNetworkPermissionDialogView(
}
ConfirmationDialog(
title = stringResource(CommonStrings.screen_local_network_opt_in_title),
content = stringResource(CommonStrings.screen_local_network_opt_in_subtitle, appName),
content = stringResource(CommonStrings.screen_local_network_opt_in_subtitle, LocalBuildMeta.current.applicationName),
submitText = stringResource(submitTextRes),
cancelText = stringResource(CommonStrings.action_not_now),
onSubmitClick = onSubmit,
+5
View File
@@ -34,6 +34,11 @@ forbiddenTerms = {
# Contains "Element Classic"
"screen_missing_key_backup_open_element_classic",
"screen_missing_key_backup_step_1",
# These are notification sound names
"screen_notification_settings_sound_element_default",
"screen_notification_settings_sound_element_fade",
# This contains the word 'element' in some languages
"screen_media_upload_preview_item_count",
]
}
+95 -11
View File
@@ -8,23 +8,51 @@
set -e
if [[ $1 == "--all" ]]; then
allFiles=0
while [[ $# -gt 0 ]]; do
case $1 in
-a|--all)
allFiles=1
shift
;;
-v|--verbose)
verbose=1
shift
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ $allFiles == 1 ]]; then
echo "Note: I will update all the files."
allFiles=1
else
echo "Note: I will update only the English files."
allFiles=0
fi
echo "Generating the configuration file for localazy..."
python3 ./tools/localazy/generateLocalazyConfig.py $allFiles
# Search for existing string files first so we can remove them
localazyXmlFiles=$(find . \
-type d \( -name build -o -name .git \) -prune -o \
-type f -path '*/src/*/res/values/localazy.xml' -print | sort)
if [[ $allFiles == 1 ]]; then
translationXmlFiles=$(find . \
-type d \( -name build -o -name .git \) -prune -o \
-type f -path '*/src/*/res/values-*/translations.xml' -print | sort)
fi
echo "Deleting all existing localazy.xml files..."
find . -name 'localazy.xml' -delete
echo "$localazyXmlFiles" | xargs -L1 -P0 rm
if [[ $allFiles == 1 ]]; then
echo "Deleting all existing translations.xml files..."
find . -name 'translations.xml' -delete
echo "$translationXmlFiles" | xargs -L1 -P0 rm
fi
echo "Importing the strings..."
@@ -33,16 +61,72 @@ localazy download --config ./tools/localazy/localazy.json
echo "Removing the generated config"
rm ./tools/localazy/localazy.json
echo "Formatting the resources files..."
find . -name 'localazy.xml' -exec ./tools/localazy/formatXmlResourcesFile.py {} \;
# Now list the newly generated files so we can format them and check for forbidden terms
localazyXmlFiles=$(find . \
-type d \( -name build -o -name .git \) -prune -o \
-type f -path '*/src/*/res/values/localazy.xml' -print | sort)
if [[ $allFiles == 1 ]]; then
find . -name 'translations.xml' -exec ./tools/localazy/formatXmlResourcesFile.py {} \;
translationXmlFiles=$(find . \
-type d \( -name build -o -name .git \) -prune -o \
-type f -path '*/src/*/res/values-*/translations.xml' -print | sort)
fi
echo "Checking forbidden terms..."
find . -name 'localazy.xml' -exec ./tools/localazy/checkForbiddenTerms.py {} \;
formatXmlFiles() {
local xml="$1"
if [[ $verbose == 1 ]]; then
echo "Formatting $xml"
fi
./tools/localazy/formatXmlResourcesFile.py "$xml"
}
checkForbiddenTerms() {
set +e
local xml="$1"
if [[ $verbose == 1 ]]; then
echo "Checking forbidden terms in $xml"
fi
./tools/localazy/checkForbiddenTerms.py "$xml"
# If the script finds a forbidden term, it will exit with a non-zero status code and interrupt the execution, but we don't want that.
# Instead we want to capture that exit code and write it to a global variable so we can check later if any forbidden terms were found.
status=$?
if [[ $status != 0 ]]; then
forbiddenTermsResult=$((forbiddenTermsResult || status))
fi
}
export -f formatXmlFiles
export -f checkForbiddenTerms
echo "Formatting the resources files..."
echo "Formatting original localazy.xml files..."
# Format the original localazy.xml files in parallel
echo "$localazyXmlFiles" | xargs -L1 -P0 bash -c 'formatXmlFiles "$@"' _
if [[ $allFiles == 1 ]]; then
find . -name 'translations.xml' -exec ./tools/localazy/checkForbiddenTerms.py {} \;
if [[ $verbose == 1 ]]; then
echo "Formatting translation files..."
fi
echo "$translationXmlFiles" | xargs -L1 -P0 bash -c 'formatXmlFiles "$@"' _
fi
# This stores whether any forbidden terms were found in any of the files. If any forbidden terms are found, this will be set to a non-zero value.
export forbiddenTermsResult=0
echo "Checking forbidden terms..."
echo "$localazyXmlFiles" | xargs -L1 -P0 bash -c 'checkForbiddenTerms "$@"' _
if [[ $allFiles == 1 ]]; then
echo "Checking forbidden terms in translation files..."
echo "$translationXmlFiles" | xargs -L1 -P0 bash -c 'checkForbiddenTerms "$@"' _
fi
if [[ $forbiddenTermsResult != 0 ]]; then
echo "Error: Forbidden terms found in the resources files. Please check the output above."
exit 1
fi
echo "Success!"