diff --git a/screenshots/html/screenshots.css b/screenshots/html/screenshots.css
index 71806dbe6a..5b9fb085f7 100644
--- a/screenshots/html/screenshots.css
+++ b/screenshots/html/screenshots.css
@@ -50,10 +50,19 @@ img {
display: block;
}
+.missing {
+ text-align: center;
+}
+
th {
background: #0DBD8B;
}
+br {
+ display: block;
+ margin: 4px 0;
+}
+
#form_container {
margin: 0px auto;
}
diff --git a/screenshots/html/script.js b/screenshots/html/script.js
index f2dacaca0c..63656dfcb9 100644
--- a/screenshots/html/script.js
+++ b/screenshots/html/script.js
@@ -15,10 +15,19 @@
*/
import { screenshots } from './data.js';
-const header = screenshots[0];
+const dataLanguages = screenshots[0];
+const dataPaths = screenshots[1];
+
+// Read default visible languages from the fragment
+const fragment = new URLSearchParams(window.location.hash.substring(1));
+// Get the wanted languages from the fragment, or default to "de" and "fr", and ensure "en" is always there
+const wantedLanguages = (fragment.get('languages') ? fragment.get('languages').split(',') : ['de', 'fr']) + ["en"];
+
+// Map dataLanguages to visibleLanguages, set to 1 if the language is in wantedLanguages, 0 otherwise
+let visibleLanguages = dataLanguages.map((language) => wantedLanguages.includes(language) ? 1 : 0);
-let visibleLanguages = header.map((x) => 1);
let imageWidth = 300;
+let showAllScreenshots = false;
function addForm() {
// Insert the form into the div with id form_container
@@ -26,14 +35,14 @@ function addForm() {
const languageLabel = document.createElement('label');
languageLabel.textContent = 'Languages:';
form.appendChild(languageLabel);
- // Add a check box per entry in the header
- for (let i = 0; i < header.length; i++){
+ // Add a check box per entry in the dataLanguages
+ for (let i = 0; i < dataLanguages.length; i++){
const label = document.createElement('label');
- const text = document.createTextNode(header[i]);
+ const text = document.createTextNode(dataLanguages[i]);
const input = document.createElement('input');
input.type = 'checkbox';
input.disabled = i == 0;
- input.name = header[i];
+ input.name = dataLanguages[i];
input.checked = visibleLanguages[i] == 1;
input.onchange = (e) => {
if (e.target.checked) {
@@ -47,6 +56,8 @@ function addForm() {
label.appendChild(text);
form.appendChild(label);
}
+ // Add a break line
+ form.appendChild(document.createElement('br'));
// Add a label with the text "Width"
const label = document.createElement('label');
label.textContent = 'Screenshots width:';
@@ -64,6 +75,20 @@ function addForm() {
addTable();
};
form.appendChild(widthInput);
+ // Add a label with the text "Show all screenshots"
+ const label2 = document.createElement('label');
+ label2.textContent = 'Show all screenshots:';
+ label2.title = 'Show all screenshots, including those with no translated versions.';
+ const input2 = document.createElement('input');
+ input2.type = 'checkbox';
+ input2.name = "test";
+ input2.checked = showAllScreenshots;
+ input2.onchange = (e) => {
+ showAllScreenshots = e.target.checked;
+ addTable();
+ };
+ label2.appendChild(input2);
+ form.appendChild(label2);
document.getElementById('form_container').appendChild(form);
}
@@ -86,55 +111,76 @@ function addTable() {
// First item of screenshots contains the languages
// Build the languages row
const languagesHeaderRow = document.createElement('tr');
- for (let i = 0; i < header.length; i++) {
+ for (let languageIndex = 0; languageIndex < dataLanguages.length; languageIndex++) {
// Do not add the language if it is hidden
- if (visibleLanguages[i] == 0) {
+ if (visibleLanguages[languageIndex] == 0) {
continue;
}
const th = document.createElement('th');
- th.textContent = header[i];
+ th.textContent = dataLanguages[languageIndex];
languagesHeaderRow.appendChild(th);
}
const numVisibleLanguages = languagesHeaderRow.childElementCount
+ // Second item contains the paths
// Next items are the data
var currentHeaderValue = "";
- for (let i = 1; i < screenshots.length; i++) {
- // Add a header for row, if different from previous
- let name = getNiceName(screenshots[i][0]);
- if(name != currentHeaderValue) {
- currentHeaderValue = name;
- const trHead = document.createElement('tr');
- const tdHead = document.createElement('td');
- tdHead.colSpan = numVisibleLanguages;
- tdHead.className = "view-header";
- tdHead.textContent = name;
- trHead.appendChild(tdHead);
- tbody.appendChild(trHead);
- tbody.appendChild(languagesHeaderRow.cloneNode(true));
- }
+ for (let screenshotIndex = 2; screenshotIndex < screenshots.length; screenshotIndex++) {
+ let englishFile = screenshots[screenshotIndex][0];
const tr = document.createElement('tr');
- for (let j = 0; j < screenshots[i].length; j++) {
- if (visibleLanguages[j] == 0) {
+ let hasTranslatedFiles = false;
+ for (let languageIndex = 0; languageIndex < dataLanguages.length; languageIndex++) {
+ if (visibleLanguages[languageIndex] == 0) {
continue;
}
const td = document.createElement('td');
- let imageFile = screenshots[i][j];
- if (imageFile === '') {
- const text = document.createElement('p');
- text.textContent = 'No image';
- td.appendChild(text);
- } else {
+ if (languageIndex == 0) {
+ const fullFile = `${dataPaths[0]}/${englishFile}.png`;
const img = document.createElement('img');
img.className = "screenshot";
- img.src = `../${imageFile}`;
- img.title = imageFile;
+ img.src = `../${fullFile}`;
+ img.title = fullFile;
img.alt = "Missing image";
img.width = imageWidth;
td.appendChild(img);
+ } else {
+ let hasFile = screenshots[screenshotIndex][languageIndex];
+ if (hasFile === 0) {
+ const text = document.createElement('p');
+ text.className = "missing";
+ text.textContent = 'No image';
+ td.appendChild(text);
+ } else {
+ hasTranslatedFiles = true;
+ // Foreign file is the same as the english file, replacing the language
+ const foreignFile = englishFile.replace("en]", `${dataLanguages[languageIndex]}]`).replace("_S_", "_T_")
+ const fullForeignFile = `${dataPaths[languageIndex]}/${foreignFile}.png`;
+ const img = document.createElement('img');
+ img.className = "screenshot";
+ img.src = `../${fullForeignFile}`;
+ img.title = fullForeignFile;
+ img.alt = "Missing image";
+ img.width = imageWidth;
+ td.appendChild(img);
+ }
}
tr.appendChild(td);
}
- tbody.appendChild(tr);
+ if (showAllScreenshots || hasTranslatedFiles) {
+ // Add a header for row, if different from previous
+ let name = getNiceName(englishFile);
+ if (name != currentHeaderValue) {
+ currentHeaderValue = name;
+ const trHead = document.createElement('tr');
+ const tdHead = document.createElement('td');
+ tdHead.colSpan = numVisibleLanguages;
+ tdHead.className = "view-header";
+ tdHead.textContent = name;
+ trHead.appendChild(tdHead);
+ tbody.appendChild(trHead);
+ tbody.appendChild(languagesHeaderRow.cloneNode(true));
+ }
+ tbody.appendChild(tr);
+ }
}
table.appendChild(thead);
table.appendChild(tbody);
diff --git a/tools/test/generateAllScreenshots.py b/tools/test/generateAllScreenshots.py
index 6ba1ab2b67..cd9d3ec6ab 100755
--- a/tools/test/generateAllScreenshots.py
+++ b/tools/test/generateAllScreenshots.py
@@ -1,35 +1,53 @@
#!/usr/bin/env python3
+#
+# Copyright 2024 New Vector Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
import os
import re
import sys
from util import compare
+
# Read all arguments and return a list of them, this are the languages list.
def readArguments():
# Return sys.argv without the first argument
return sys.argv[1:]
+
def generateAllScreenshots(languages):
# If languages is empty, generate all screenshots
if len(languages) == 0:
- print("Generating all screenshots...")
- os.system("./gradlew recordPaparazziDebug -PallLanguages")
+ print("Generating all screenshots...")
+ os.system("./gradlew --stop")
+ os.system("./gradlew recordPaparazziDebug -PallLanguages")
else:
- tFile = "tests/uitests/src/test/kotlin/ui/T.kt"
- print("Generating screenshots for languages: %s" % languages)
- # Patch file T.kt, replace `@TestParameter(value = ["de"]) localeStr: String,` with `@TestParameter(value = ["de", "fr"]) localeStr: String,`
- with open(tFile, "r") as file:
- data = file.read()
- languagesList = ", ".join([f"\"{lang}\"" for lang in languages])
- data = data.replace("@TestParameter(value = [\"de\"]) localeStr: String,", "@TestParameter(value = [%s]) localeStr: String," % languagesList)
- with open(tFile, "w") as file:
- file.write(data)
- os.system("./gradlew recordPaparazziDebug -PallLanguagesNoEnglish")
- # Git reset the change on file T.kt
- os.system("git checkout HEAD -- %s" % tFile)
-
-
+ tFile = "tests/uitests/src/test/kotlin/ui/T.kt"
+ print("Generating screenshots for languages: %s" % languages)
+ # Record the languages one by one, else it's getting too slow
+ for lang in languages:
+ print("Generating screenshots for language: %s" % lang)
+ # Patch file T.kt, replace `@TestParameter(value = ["de"]) localeStr: String,` with `@TestParameter(value = []) localeStr: String,`
+ with open(tFile, "r") as file:
+ data = file.read()
+ data = data.replace("@TestParameter(value = [\"de\"]) localeStr: String,", "@TestParameter(value = [\"%s\"]) localeStr: String," % lang)
+ with open(tFile, "w") as file:
+ file.write(data)
+ os.system("./gradlew recordPaparazziDebug -PallLanguagesNoEnglish")
+ # Git reset the change on file T.kt
+ os.system("git checkout HEAD -- %s" % tFile)
def detectLanguages():
@@ -82,38 +100,44 @@ def detectRecordedLanguages():
# List all the subfolders of the screenshots folder which contains 2 letters, sorted alphabetically
return sorted([f for f in os.listdir("screenshots") if len(f) == 2])
+
def generateJavascriptFile():
__doc__ = "Generate a javascript file to load the screenshots"
print("Generating javascript file...")
languages = detectRecordedLanguages()
# First item is the list of languages, adding "en" at the beginning
data = [["en"] + languages]
- # If any translated screenshot exists, keep the file
+ # Second item is the path of the containing file
+ data.append(["./tests/uitests/src/test/snapshots/images"] + ["./screenshots/" + l for l in languages])
files = sorted(
os.listdir("tests/uitests/src/test/snapshots/images/"),
key=lambda file: file[file.find("_", 6):],
)
for file in files:
- fullFile = "./tests/uitests/src/test/snapshots/images/" + file
- dataForFile = [fullFile]
- hasAnyTranslatedFile = False
+ # Continue if file contains "-Night", keep only light screenshots (maybe the night screenshots could be on the second column?)
+ if "-Night" in file:
+ continue
+ dataForFile = [file[:-4]]
for l in languages:
- translatedFile = "./screenshots/" + l + "/" + file[:3] + "T" + file[4:-7] + l + file[-5:]
+ simpleFile = file[:3] + "T" + file[4:-7] + l + file[-5:-4]
+ translatedFile = "./screenshots/" + l + "/" + simpleFile + ".png"
if os.path.exists(translatedFile):
- hasAnyTranslatedFile = True
- dataForFile.append(translatedFile)
+ dataForFile.append(1)
else:
- dataForFile.append("")
- if hasAnyTranslatedFile:
- data.append(dataForFile)
+ dataForFile.append(0)
+ data.append(dataForFile)
with open("screenshots/html/data.js", "w") as f:
f.write("// Generated file, do not edit\n")
f.write("export const screenshots = [\n")
for line in data:
- f.write("[\n")
+ f.write("[")
for item in line:
- f.write("\"" + item + "\",\n")
+ # If item is a string, add quotes
+ if isinstance(item, str):
+ f.write("\"" + item + "\",")
+ else:
+ f.write(str(item) + ",")
f.write("],\n")
f.write("];\n")
diff --git a/tools/test/generateWorldScreenshots.py b/tools/test/generateWorldScreenshots.py
new file mode 100755
index 0000000000..8c68ed8266
--- /dev/null
+++ b/tools/test/generateWorldScreenshots.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+#
+# Copyright 2024 New Vector Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import os
+
+def detectAllExistingTranslations():
+ # Read all the folder in "libraries/ui-strings/src/main/res"
+ folders = os.listdir("libraries/ui-strings/src/main/res")
+ # Remove the "values" folder
+ folders.remove("values")
+ # Map to keep only the language code
+ folders = list(map(lambda folder: folder[7:], folders))
+ # Map to keep only the string before the "-"
+ folders = list(map(lambda folder: folder.split("-")[0], folders))
+ # Remove duplicates
+ folders = list(set(folders))
+ return folders
+
+
+def main():
+ languages = detectAllExistingTranslations()
+ print ("Will record the screenshots for those languages: %s" % languages)
+ # Run the python script "generateAllScreenshots.py" with the detected languages
+ os.system("./tools/test/generateAllScreenshots.py %s" % " ".join(languages))
+
+main()