/* * Copyright (C) 2011 The Android Open Source Project * * 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. */ package com.android.tools.lint.checks; import com.android.tools.lint.detector.api.Detector; @SuppressWarnings("javadoc") public class TranslationDetectorTest extends AbstractCheckTest { @Override protected Detector getDetector() { return new TranslationDetector(); } @Override protected boolean includeParentPath() { return true; } public void testTranslation() throws Exception { TranslationDetector.sCompleteRegions = false; assertEquals( // Sample files from the Home app "res/values/strings.xml:20: Error: \"show_all_apps\" is not translated in \"nl-rNL\" (Dutch: Netherlands) [MissingTranslation]\n" + " <string name=\"show_all_apps\">All</string>\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "res/values/strings.xml:23: Error: \"menu_wallpaper\" is not translated in \"nl-rNL\" (Dutch: Netherlands) [MissingTranslation]\n" + " <string name=\"menu_wallpaper\">Wallpaper</string>\n" + " ~~~~~~~~~~~~~~~~~~~~~\n" + "res/values/strings.xml:25: Error: \"menu_settings\" is not translated in \"cs\" (Czech), \"de-rDE\" (German: Germany), \"es\" (Spanish), \"es-rUS\" (Spanish: United States), \"nl-rNL\" (Dutch: Netherlands) [MissingTranslation]\n" + " <string name=\"menu_settings\">Settings</string>\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "res/values-cs/arrays.xml:3: Error: \"security_questions\" is translated here but not found in default locale [ExtraTranslation]\n" + " <string-array name=\"security_questions\">\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " res/values-es/strings.xml:12: Also translated here\n" + "res/values-de-rDE/strings.xml:11: Error: \"continue_skip_label\" is translated here but not found in default locale [ExtraTranslation]\n" + " <string name=\"continue_skip_label\">\"Weiter\"</string>\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "5 errors, 0 warnings\n", lintProject( "res/values/strings.xml", "res/values-cs/strings.xml", "res/values-de-rDE/strings.xml", "res/values-es/strings.xml", "res/values-es-rUS/strings.xml", "res/values-land/strings.xml", "res/values-cs/arrays.xml", "res/values-es/donottranslate.xml", "res/values-nl-rNL/strings.xml")); } public void testTranslationWithCompleteRegions() throws Exception { TranslationDetector.sCompleteRegions = true; assertEquals( // Sample files from the Home app "res/values/strings.xml:19: Error: \"home_title\" is not translated in \"es-rUS\" (Spanish: United States) [MissingTranslation]\n" + " <string name=\"home_title\">Home Sample</string>\n" + " ~~~~~~~~~~~~~~~~~\n" + "res/values/strings.xml:20: Error: \"show_all_apps\" is not translated in \"es-rUS\" (Spanish: United States), \"nl-rNL\" (Dutch: Netherlands) [MissingTranslation]\n" + " <string name=\"show_all_apps\">All</string>\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "res/values/strings.xml:23: Error: \"menu_wallpaper\" is not translated in \"es-rUS\" (Spanish: United States), \"nl-rNL\" (Dutch: Netherlands) [MissingTranslation]\n" + " <string name=\"menu_wallpaper\">Wallpaper</string>\n" + " ~~~~~~~~~~~~~~~~~~~~~\n" + "res/values/strings.xml:25: Error: \"menu_settings\" is not translated in \"cs\" (Czech), \"de-rDE\" (German: Germany), \"es-rUS\" (Spanish: United States), \"nl-rNL\" (Dutch: Netherlands) [MissingTranslation]\n" + " <string name=\"menu_settings\">Settings</string>\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "res/values/strings.xml:29: Error: \"wallpaper_instructions\" is not translated in \"es-rUS\" (Spanish: United States) [MissingTranslation]\n" + " <string name=\"wallpaper_instructions\">Tap picture to set portrait wallpaper</string>\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + " res/values-land/strings.xml:19: <No location-specific message\n" + "res/values-de-rDE/strings.xml:11: Error: \"continue_skip_label\" is translated here but not found in default locale [ExtraTranslation]\n" + " <string name=\"continue_skip_label\">\"Weiter\"</string>\n" + " ~~~~~~~~~~~~~~~~~~~~~~~~~~\n" + "6 errors, 0 warnings\n", lintProject( "res/values/strings.xml", "res/values-cs/strings.xml", "res/values-de-rDE/strings.xml", "res/values-es-rUS/strings.xml", "res/values-land/strings.xml", "res/values-nl-rNL/strings.xml")); } public void testHandleBom() throws Exception { // This isn't really testing translation detection; it's just making sure that the // XML parser doesn't bomb on BOM bytes (byte order marker) at the beginning of // the XML document assertEquals( "No warnings.", lintProject( "res/values-de/strings.xml" )); } public void testTranslatedArrays() throws Exception { TranslationDetector.sCompleteRegions = true; assertEquals( "No warnings.", lintProject( "res/values/translatedarrays.xml", "res/values-cs/translatedarrays.xml")); } public void testTranslationSuppresss() throws Exception { TranslationDetector.sCompleteRegions = false; assertEquals( "No warnings.", lintProject( "res/values/strings_ignore.xml=>res/values/strings.xml", "res/values-es/strings_ignore.xml=>res/values-es/strings.xml", "res/values-nl-rNL/strings.xml=>res/values-nl-rNL/strings.xml")); } public void testMixedTranslationArrays() throws Exception { // See issue http://code.google.com/p/android/issues/detail?id=29263 assertEquals( "No warnings.", lintProject( "res/values/strings3.xml=>res/values/strings.xml", "res/values-fr/strings.xml=>res/values-fr/strings.xml")); } public void testLibraryProjects() throws Exception { // If a library project provides additional locales, that should not force // the main project to include all those translations assertEquals( "No warnings.", lintProject( // Master project "multiproject/main-manifest.xml=>AndroidManifest.xml", "multiproject/main.properties=>project.properties", "res/values/strings2.xml", // Library project "multiproject/library-manifest.xml=>../LibraryProject/AndroidManifest.xml", "multiproject/library.properties=>../LibraryProject/project.properties", "res/values/strings.xml=>../LibraryProject/res/values/strings.xml", "res/values-cs/strings.xml=>../LibraryProject/res/values-cs/strings.xml", "res/values-cs/strings.xml=>../LibraryProject/res/values-de/strings.xml", "res/values-cs/strings.xml=>../LibraryProject/res/values-nl/strings.xml" )); } public void testNonTranslatable1() throws Exception { TranslationDetector.sCompleteRegions = true; assertEquals( "res/values-nb/nontranslatable.xml:3: Error: The resource string \"dummy\" has been marked as translatable=\"false\" [ExtraTranslation]\n" + " <string name=\"dummy\">Ignore Me</string>\n" + " ~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n" + "", lintProject("res/values/nontranslatable.xml", "res/values/nontranslatable2.xml=>res/values-nb/nontranslatable.xml")); } public void testNonTranslatable2() throws Exception { TranslationDetector.sCompleteRegions = true; assertEquals( "res/values-nb/nontranslatable.xml:3: Error: Non-translatable resources should only be defined in the base values/ folder [ExtraTranslation]\n" + " <string name=\"dummy\" translatable=\"false\">Ignore Me</string>\n" + " ~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n" + "", lintProject("res/values/nontranslatable.xml=>res/values-nb/nontranslatable.xml")); } public void testSpecifiedLanguageOk() throws Exception { TranslationDetector.sCompleteRegions = false; assertEquals( "No warnings.", lintProject( "res/values-es/strings.xml=>res/values-es/strings.xml", "res/values-es-rUS/strings.xml")); } public void testSpecifiedLanguage() throws Exception { TranslationDetector.sCompleteRegions = false; assertEquals( "No warnings.", lintProject( "res/values-es/strings_locale.xml=>res/values/strings.xml", "res/values-es-rUS/strings.xml")); } public void testAnalytics() throws Exception { // See http://code.google.com/p/android/issues/detail?id=43070 assertEquals( "No warnings.", lintProject( "res/values/analytics.xml", "res/values-es/donottranslate.xml" // to make app multilingual )); } public void testIssue33845() throws Exception { // See http://code.google.com/p/android/issues/detail?id=33845 assertEquals("" + "res/values/strings.xml:5: Error: \"dateTimeFormat\" is not translated in \"de\" (German) [MissingTranslation]\n" + " <string name=\"dateTimeFormat\">MM/dd/yyyy - HH:mm</string>\n" + " ~~~~~~~~~~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", lintProject( "locale33845/.classpath=>.classpath", "locale33845/AndroidManifest.xml=>AndroidManifest.xml", "locale33845/project.properties=>project.properties", "locale33845/res/values/strings.xml=>res/values/strings.xml", "locale33845/res/values-de/strings.xml=>res/values-de/strings.xml", "locale33845/res/values-en-rGB/strings.xml=>res/values-en-rGB/strings.xml" )); } public void testIssue33845b() throws Exception { // Similar to issue 33845, but with some variations to the test data // See http://code.google.com/p/android/issues/detail?id=33845 assertEquals("No warnings.", lintProject( "locale33845/.classpath=>.classpath", "locale33845/AndroidManifest.xml=>AndroidManifest.xml", "locale33845/project.properties=>project.properties", "locale33845/res/values/styles.xml=>res/values/styles.xml", "locale33845/res/values/strings2.xml=>res/values/strings.xml", "locale33845/res/values-en-rGB/strings2.xml=>res/values-en-rGB/strings.xml" )); } public void testEnglishRegionAndValuesAsEnglish1() throws Exception { // tools:locale=en in base folder // Regression test for https://code.google.com/p/android/issues/detail?id=75879 assertEquals("No warnings.", lintProject( "locale33845/res/values/strings3.xml=>res/values/strings.xml", "locale33845/res/values-en-rGB/strings3.xml=>res/values-en-rGB/strings.xml" )); } public void testEnglishRegionAndValuesAsEnglish2() throws Exception { // No tools:locale specified in the base folder: *assume* English // Regression test for https://code.google.com/p/android/issues/detail?id=75879 assertEquals("" + "res/values/strings.xml:5: Error: \"other\" is not translated in \"de-rDE\" (German: Germany) [MissingTranslation]\n" + " <string name=\"other\">other</string>\n" + " ~~~~~~~~~~~~\n" + "1 errors, 0 warnings\n", lintProject( "locale33845/res/values/strings4.xml=>res/values/strings.xml", // Flagged because it's not the default locale: "locale33845/res/values-en-rGB/strings3.xml=>res/values-de-rDE/strings.xml", // Not flagged because it's the implicit default locale "locale33845/res/values-en-rGB/strings3.xml=>res/values-en-rGB/strings.xml" )); } public void testEnglishRegionAndValuesAsEnglish3() throws Exception { // tools:locale=de in base folder // Regression test for https://code.google.com/p/android/issues/detail?id=75879 assertEquals("No warnings.", lintProject( "locale33845/res/values/strings5.xml=>res/values/strings.xml", "locale33845/res/values-en-rGB/strings3.xml=>res/values-de-rDE/strings.xml" )); } }