Brion VIBBER has uploaded a new change for review. https://gerrit.wikimedia.org/r/145708
Change subject: Update storyboard strings, qqq files when master files change ...................................................................... Update storyboard strings, qqq files when master files change en.lproj/Main_iPhone.strings now updates automatically when new things appear in Main_iPhone.storyboard. qqq.lproj/*.strings files now have stub entries added for any new entries in en.lproj/*.strings files. These should be very visible in code review if they don't get caught before committing. :) Change-Id: Ibd01ba5eb754ec9aaafddf0391496c8c527273cc --- M Wikipedia.xcodeproj/project.pbxproj A scripts/update-qqq.php M wikipedia/qqq.lproj/Localizable.strings M wikipedia/qqq.lproj/Main_iPhone.strings 4 files changed, 281 insertions(+), 66 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/apps/ios/wikipedia refs/changes/08/145708/1 diff --git a/Wikipedia.xcodeproj/project.pbxproj b/Wikipedia.xcodeproj/project.pbxproj index be38747..ad6ceb2 100644 --- a/Wikipedia.xcodeproj/project.pbxproj +++ b/Wikipedia.xcodeproj/project.pbxproj @@ -1573,9 +1573,11 @@ buildPhases = ( D4991431181D51DE00E6073C /* Sources */, D4991432181D51DE00E6073C /* Frameworks */, - D4991433181D51DE00E6073C /* Resources */, 04272E7619404CDF00CC682F /* ShellScript */, 04272E75193FF7F000CC682F /* ShellScript */, + D4C16A621970946900CD91AD /* ShellScript */, + D4C16A631970949A00CD91AD /* ShellScript */, + D4991433181D51DE00E6073C /* Resources */, ); buildRules = ( ); @@ -1753,6 +1755,37 @@ shellPath = /bin/sh; shellScript = "scripts/run-grunt.sh"; }; + D4C16A621970946900CD91AD /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/wikipedia/Base.lproj/Main_iPhone.storyboard", + ); + outputPaths = ( + "$(SRCROOT)/wikipedia/en.lproj/Main_iPhone.strings", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "scripts/update-storyboard-strings.php"; + }; + D4C16A631970949A00CD91AD /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/wikipedia/en.lproj/Main_iPhone.strings", + "$(SRCROOT)/wikipedia/en.lproj/InfoPlist.strings", + "$(SRCROOT)/wikipedia/en.lproj/Localizable.strings", + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "scripts/update-qqq.php"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/scripts/update-qqq.php b/scripts/update-qqq.php new file mode 100755 index 0000000..c192a6d --- /dev/null +++ b/scripts/update-qqq.php @@ -0,0 +1,239 @@ +#!/usr/bin/php -q +<?php + +/** + * AppleFFS class implements support for Apple .strings files. + * This class reads and writes only UTF-8 files. + * + * @author Brion Vibber <bvib...@wikimedia.org> + * + * derived from the AppleFFS in Translate extension, but hacked down + */ +class AppleStringsFile { + // READ + + public function readFromFile( $path ) { + $data = file_get_contents( $path ); + return $this->readFromVariable( $data ); + } + + public function write( $data ) { + return $this->writeReal( $data ); + } + + /** + * @param array $data + * @return array Parsed data. + * @throws Exception + */ + public function readFromVariable( $data ) { + $lines = explode( "\n", $data ); + $authors = $messages = array(); + $linecontinuation = false; + + $value = ''; + foreach ( $lines as $line ) { + if ( $linecontinuation ) { + $linecontinuation = false; + $valuecont = $line; + $value .= $valuecont; + } else { + if ( $line === '' ) { + continue; + } + + if ( substr( $line, 0, 2 ) === '//' ) { + // Single-line comment + $match = array(); + $ok = preg_match( '~//\s*Author:\s*(.*)~', $line, $match ); + if ( $ok ) { + $authors[] = $match[1]; + } + continue; + } + + if ( substr( $line, 0, 2 ) === '/*' ) { + if ( strpos( $line, '*/', 2 ) === false ) { + $linecontinuation = true; + } + continue; + } + + list( $key, $value ) = self::readRow( $line ); + $messages[$key] = $value; + } + } + + return array( + 'AUTHORS' => $authors, + 'MESSAGES' => $messages, + ); + } + + /** + * Parses non-empty strings file row to key and value. + * @param string $line + * @throws Exception + * @return array( string $key, string $val ) + */ + public static function readRow( $line ) { + $match = array(); + if ( preg_match( '/^"((?:\\\"|[^"])*)"\s*=\s*"((?:\\\"|[^"])*)"\s*;\s*$/', $line, $match ) ) { + $key = self::unescapeString( $match[1] ); + $value = self::unescapeString( $match[2] ); + if ( $key === '' ) { + throw new Exception( "Empty key in line $line" ); + } + return array( $key, $value ); + } else { + throw new Exception( "Unrecognized line format: $line" ); + } + } + + // Write + + /** + * @param MessageCollection $collection + * @return string + */ + protected function writeReal( array $collection ) { + $header = $this->doHeader( $collection ); + $header .= $this->doAuthors( $collection ); + $header .= "\n"; + + $output = ''; + + /** + * @var TMessage $m + */ + foreach ( $collection['MESSAGES'] as $key => $m ) { + $value = $m; + + if ( $value === '' ) { + continue; + } + + $output .= self::writeRow( $key, $value ); + } + + if ( $output ) { + $data = $header . $output; + } else { + $data = $header; + } + + return $data; + } + + /** + * Writes well-formed properties file row with key and value. + * @param string $key + * @param string $value + * @return string + */ + public static function writeRow( $key, $value ) { + return self::quoteString( $key ) . ' = ' . self::quoteString( $value ) . ';' . "\n"; + } + + /** + * Quote and escape Obj-C-style strings for .strings format + */ + protected static function quoteString( $str ) { + return '"' . self::escapeString( $str ) . '"'; + } + + /** + * Escape Obj-C-style strings; use backslash-escapes etc. + * + * @param string $str + * @return string + */ + protected static function escapeString( $str ) { + $str = addcslashes( $str, '\\"' ); + $str = str_replace( "\n", '\\n', $str ); + return $str; + } + + /** + * Unescape Obj-C-style strings; can include backslash-escapes + * + * @todo support \UXXXX + * + * @param string $str + * @return string + */ + protected static function unescapeString( $str ) { + return stripcslashes( $str ); + } + + /** + * @param MessageCollection $collection + * @return string + */ + protected function doHeader( array $collection ) { + if ( isset( $this->extra['header'] ) ) { + $output = $this->extra['header']; + } else { + $wgSitename = 'translatewiki.net'; + + $name = 'Message documentation'; + $native = 'Message documentation'; + $output = "// Messages for $name ($native)\n"; + $output .= "// Exported from $wgSitename\n"; + } + + return $output; + } + + /** + * @param MessageCollection $collection + * @return string + */ + protected function doAuthors( array $collection ) { + $output = ''; + $authors = $collection['AUTHORS']; + + foreach ( $authors as $author ) { + $output .= "// Author: $author\n"; + } + + return $output; + } +} + +function fillStubs( &$en, &$qqq ) { + $enKeys = array_keys( $en['MESSAGES'] ); + $qqqKeys = array_keys( $qqq['MESSAGES'] ); + $missing = array_diff( $enKeys, $qqqKeys ); + + if (count( $missing ) > 0) { + foreach( $missing as $key ) { + $qqq['MESSAGES'][$key] = 'MISSING DESCRIPTION; DO NOT COMMIT FILE YET'; + } + return true; + } else { + return false; + } +} + +function processStubs( $filename ) { + $base = realpath( dirname( __DIR__ ) ) . "/wikipedia"; + + $parser = new AppleStringsFile(); + + $file_en = "$base/en.lproj/$filename.strings"; + $file_qqq = "$base/qqq.lproj/$filename.strings"; + + $data_en = $parser->readFromFile( $file_en ); + $data_qqq = $parser->readFromFile( $file_qqq ); + + if (fillStubs( $data_en, $data_qqq )) { + $out = $parser->write( $data_qqq ); + file_put_contents( $file_qqq, $out ); + echo "Updated qqq.lproj/$filename.strings\n"; + } +} + +processStubs('InfoPlist'); +processStubs('Main_iPhone'); +processStubs('Localizable'); diff --git a/wikipedia/qqq.lproj/Localizable.strings b/wikipedia/qqq.lproj/Localizable.strings index aee3ca4..badb85c 100644 --- a/wikipedia/qqq.lproj/Localizable.strings +++ b/wikipedia/qqq.lproj/Localizable.strings @@ -149,3 +149,9 @@ "license-footer-text" = "Brief footer text linking to CC-BY-SA license. '$1' is placeholder for the license-footer-name message"; "license-footer-name" = "License short name; usually leave untranslated as CC-BY-SA 3.0"; "table-of-contents-heading" = "Header text appearing above the first section in the table of contents"; +"wikitext-upload-save-terms-name" = "Formal name of Wikipedia 'Terms of Use' in local language, used as a link"; +"page_protected_autoconfirmed" = "Brief description of Wikipedia 'autoconfirmed' protection level, shown when editing a page that is protected."; +"page_protected_sysop" = "Brief description of Wikipedia 'sysop' protection level, shown when editing a page that is protected."; +"page_protected_other" = "Brief description of Wikipedia unknown protection level, shown when editing a page that is protected."; +"page_protected_can_not_edit" = "Text of alert dialog shown when trying to edit a page that is protected beyond what the user can edit."; +"page_protected_can_not_edit_title" = "Title of alert dialog shown when trying to edit a page that is protected beyond what the user can edit."; diff --git a/wikipedia/qqq.lproj/Main_iPhone.strings b/wikipedia/qqq.lproj/Main_iPhone.strings index 342b360..1ef24b8 100644 --- a/wikipedia/qqq.lproj/Main_iPhone.strings +++ b/wikipedia/qqq.lproj/Main_iPhone.strings @@ -1,99 +1,36 @@ +// Messages for Message documentation (Message documentation) +// Exported from translatewiki.net -/* Class = "IBUIButton"; normalTitle = "Show another captcha"; ObjectID = "21c-U6-yfo"; */ "21c-U6-yfo.normalTitle" = "Label for button on captcha screen to fetch and show another captcha image"; - -/* Class = "IBUILabel"; text = "github repo"; ObjectID = "3gs-D6-glW"; */ "3gs-D6-glW.text" = "label for link to project source on github"; - -/* Class = "IBUILabel"; text = "wikimedia"; ObjectID = "5KU-bp-5Fs"; */ "5KU-bp-5Fs.text" = "label for links to project source"; - -/* Class = "IBUITextField"; placeholder = "User name"; ObjectID = "5cT-2Y-0Ie"; */ "5cT-2Y-0Ie.placeholder" = "Label on login screen "; - -/* Class = "IBUILabel"; text = "NSDate-Extensions"; ObjectID = "6O2-5x-h41"; */ "6O2-5x-h41.text" = "Name of an open-source library used in the project; usually do not translate."; - -/* Class = "IBUILabel"; text = "Saved pages are pretty awesome. Think of them as bookmarks that you can access when you are offline."; ObjectID = "GiD-Rj-wb7"; */ "GiD-Rj-wb7.text" = "Explanatory text shown on saved pages list when no saved pages are present."; - -/* Class = "IBUILabel"; text = "Preview"; ObjectID = "LfM-01-aCF"; */ "LfM-01-aCF.text" = "Button text for 'Preview' button on edit screen"; - -/* Class = "IBUILabel"; text = "Skip"; ObjectID = "P6J-IE-CiO"; */ "P6J-IE-CiO.text" = "Button text for 'Skip' button on onboarding screen that offers to log in or sign up"; - -/* Class = "IBUITextField"; placeholder = "Password"; ObjectID = "PCr-0J-fBj"; */ "PCr-0J-fBj.placeholder" = "Placeholder label text for password field on create-account screen"; - -/* Class = "IBUILabel"; text = "Canonical Language"; ObjectID = "SER-n4-DZC"; */ "SER-n4-DZC.text" = "Unused; do not translate"; - -/* Class = "IBUITextField"; placeholder = "Re-type password"; ObjectID = "UgH-77-lyp"; */ "UgH-77-lyp.placeholder" = "Placeholder label text for second password field on create-account screen"; - -/* Class = "IBUILabel"; text = "No saved pages yet."; ObjectID = "W1c-wQ-1pa"; */ "W1c-wQ-1pa.text" = "Label text shown on saved pages list when there are no saved pages."; - -/* Class = "IBUILabel"; text = "Log in"; ObjectID = "Wff-o9-AdH"; */ "Wff-o9-AdH.text" = "Button text for 'Log in' button"; - -/* Class = "IBUILabel"; text = "Label"; ObjectID = "XkB-Xo-Xq0"; */ "XkB-Xo-Xq0.text" = "Unused; do not translate"; - -/* Class = "IBUILabel"; text = "Test Zero Label Text"; ObjectID = "aCV-ih-PXn"; */ "aCV-ih-PXn.text" = "Unused; do not translate"; - -/* Class = "IBUILabel"; text = "No recent pages yet."; ObjectID = "aUp-0e-F6i"; */ "aUp-0e-F6i.text" = "Label text shown on 'recent pages' list when there are no recent pages."; - -/* Class = "IBUILabel"; text = "Create Account"; ObjectID = "c3c-PU-Exz"; */ "c3c-PU-Exz.text" = "Button to Create Account on the onboarding screen"; - -/* Class = "IBUILabel"; text = "Label"; ObjectID = "cbH-8H-z54"; */ "cbH-8H-z54.text" = "Unused; do not translate"; - -/* Class = "IBUILabel"; text = "Hpple"; ObjectID = "eSk-uQ-Ran"; */ "eSk-uQ-Ran.text" = "Name of an open-source library used in the project; usually do not translate."; - -/* Class = "IBUITextField"; placeholder = "Enter CAPTCHA text from image above"; ObjectID = "gPg-cg-Yjy"; */ "gPg-cg-Yjy.placeholder" = "Placeholder for input text on captcha input screen"; - -/* Class = "IBUILabel"; text = "main repo"; ObjectID = "gzT-kN-7kp"; */ "gzT-kN-7kp.text" = "label for link to project source on Wikimedia Gerrit"; - -/* Class = "IBUILabel"; text = "Already have an account? Log in"; ObjectID = "heA-3K-nhS"; */ "heA-3K-nhS.text" = "Button label on onboarding screen offering to log in instead of creating account"; - -/* Class = "IBUILabel"; text = "Recent pages are not as awesome as Saved pages. They are not available for Offline Reading."; ObjectID = "huU-kO-aYI"; */ "huU-kO-aYI.text" = "Explanatory text shown on recent pages list when there are no recent pages"; - -/* Class = "IBUILabel"; text = "credits"; ObjectID = "ieH-d1-Ds7"; */ "ieH-d1-Ds7.text" = "placeholder text; do not translate"; - -/* Class = "IBUILabel"; text = "Create Account"; ObjectID = "jiW-Cg-oL3"; */ "jiW-Cg-oL3.text" = "Button label to create account"; - -/* Class = "IBUILabel"; text = "Language"; ObjectID = "jxY-ej-I9e"; */ "jxY-ej-I9e.text" = "placeholder text; do not translate"; - -/* Class = "IBUITextField"; placeholder = "Password"; ObjectID = "kVb-lx-d6C"; */ "kVb-lx-d6C.placeholder" = "Placeholder label for login password field"; - -/* Class = "IBUITextField"; placeholder = "User name"; ObjectID = "mAk-1N-jPC"; */ "mAk-1N-jPC.placeholder" = "Placeholder label for login username field"; - -/* Class = "IBUILabel"; text = "Label"; ObjectID = "nI1-bn-0Ii"; */ "nI1-bn-0Ii.text" = "placeholder text; do not translate"; - -/* Class = "IBUILabel"; text = "WikiFont"; ObjectID = "qQl-8k-ux4"; */ "qQl-8k-ux4.text" = "Name of open-source font project on about screen. Usually do not translate."; - -/* Class = "IBUITextField"; placeholder = "Email address (optional)"; ObjectID = "rKI-nq-3p7"; */ "rKI-nq-3p7.placeholder" = "Placeholder text for email field on create account form"; - -/* Class = "IBUILabel"; text = "external"; ObjectID = "ven-ec-xzg"; */ "ven-ec-xzg.text" = "placeholder text; do not translate"; - -/* Class = "IBUILabel"; text = "Create account"; ObjectID = "wkl-j8-wLX"; */ "wkl-j8-wLX.text" = "Button label to go to Create Account form from Login form"; -- To view, visit https://gerrit.wikimedia.org/r/145708 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ibd01ba5eb754ec9aaafddf0391496c8c527273cc Gerrit-PatchSet: 1 Gerrit-Project: apps/ios/wikipedia Gerrit-Branch: master Gerrit-Owner: Brion VIBBER <br...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits