diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6264e92aa8..78182e2b73 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1935,7 +1935,7 @@
Introducing PINs
PINs add another level of security to your account. Create one now.
Learn More
- https://support.signal.org/hc/en-us/articles/360007059792-Registration-Lock
+ https://support.signal.org/hc/articles/360007059792
Registration Lock = PIN
Your Registration Lock is now called a PIN, and it does more. Update it now.
Read more about PINs.
@@ -1955,7 +1955,7 @@
Your account has been locked to protect your privacy and security. After %1$d days of inactivity in your account you\'ll be able to re-register this phone number without needing your PIN. All content will be deleted.
Next
Learn More
- https://support.signal.org/hc/en-us/articles/360007059792-Registration-Lock
+ https://support.signal.org/hc/articles/360007059792
Enter your PIN
diff --git a/app/src/test/java/org/thoughtcrime/securesms/l10n/SupportArticleTest.java b/app/src/test/java/org/thoughtcrime/securesms/l10n/SupportArticleTest.java
new file mode 100644
index 0000000000..214b31cc5d
--- /dev/null
+++ b/app/src/test/java/org/thoughtcrime/securesms/l10n/SupportArticleTest.java
@@ -0,0 +1,84 @@
+package org.thoughtcrime.securesms.l10n;
+
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public final class SupportArticleTest {
+
+ private static final File MAIN_STRINGS = new File("src/main/res/values/strings.xml");
+ private static final Pattern SUPPORT_ARTICLE = Pattern.compile(".*:\\/\\/support.signal.org\\/.*articles\\/.*" );
+ private static final Pattern CORRECT_SUPPORT_ARTICLE = Pattern.compile("https:\\/\\/support.signal.org\\/hc\\/articles\\/\\d+");
+
+ /**
+ * Tests that support articles found in strings.xml:
+ *
+ * - Do not have a locale mentioned in the url.
+ * - Only have an article number, i.e. no trailing text.
+ * - Are https.
+ * - Are marked as translatable="false".
+ */
+ @Test
+ public void ensure_format_and_translatable_state_of_all_support_article_urls() throws Exception {
+ assertTrue(MAIN_STRINGS.exists());
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ List errors = new LinkedList<>();
+ int seen = 0;
+
+ try (InputStream fileStream = new FileInputStream(MAIN_STRINGS)) {
+ Document doc = builder.parse(fileStream);
+ NodeList strings = doc.getElementsByTagName("string");
+
+ for (int i = 0; i < strings.getLength(); i++) {
+ Node stringNode = strings.item(i);
+ String string = stringNode.getTextContent();
+ String stringName = stringName(stringNode);
+
+ if (SUPPORT_ARTICLE.matcher(string).matches()) {
+ seen++;
+
+ if (!CORRECT_SUPPORT_ARTICLE.matcher(string).matches()) {
+ errors.add(String.format("Article url format is not correct [%s] url: %s", stringName, string));
+ }
+ if (isTranslatable(stringNode)) {
+ errors.add(String.format("Article string is translatable [%s], add translatable=\"false\"", stringName));
+ }
+ }
+ }
+ }
+
+ assertThat(seen, greaterThan(0));
+ assertThat(errors, is(Collections.emptyList()));
+ }
+
+ private static boolean isTranslatable(Node item) {
+ if (item.hasAttributes()) {
+ Node translatableAttribute = item.getAttributes().getNamedItem("translatable");
+ return translatableAttribute == null || !"false".equals(translatableAttribute.getTextContent());
+ }
+ return true;
+ }
+
+ private static String stringName(Node item) {
+ return item.getAttributes().getNamedItem("name").getTextContent();
+ }
+}