last_modified( $translation_set ) . "+0000 */\n"; $result .= "/* Plural-Forms: nplurals={$locale->nplurals}; plural={$locale->plural_expression}; */\n"; $result .= '/* Generator: GlotPress/' . GP_VERSION . " */\n"; $language_code = $this->get_language_code( $locale ); if ( false !== $language_code ) { $result .= '/* Language: ' . $language_code . " */\n"; } $result .= "\n"; $sorted_entries = $entries; usort( $sorted_entries, array( 'GP_Format_Strings', 'sort_entries' ) ); foreach ( $sorted_entries as $entry ) { $translation = $this->escape( empty( $entry->translations ) ? $entry->singular : $entry->translations[0] ); $context = str_replace( "\n", "\\n", $this->escape( $entry->context ) ); $translation = str_replace( "\n", "\\n", $translation ); $comment = preg_replace( '/(^\s+)|(\s+$)/us', '', $entry->extracted_comments ); if ( '' == $comment ) { $comment = 'No comment provided by engineer.'; } $result .= "/* $comment */\n\"$context\" = \"$translation\";\n\n"; } return $result; } /** * Reads a set of original strings from a strings file. * * @since 1.0.0 * * @param string $file_name The name of the uploaded strings file. * @return Translations|bool The extracted originals on success, false on failure. */ public function read_originals_from_file( $file_name ) { $entries = new Translations(); $file = file_get_contents( $file_name ); if ( false === $file ) { return false; } /** * Check to see if the input file is UTF-16/32 encoded, if so convert it to UTF-8. * * Note, Apple recommends UTF-8 but some of their tools (like genstrings) export * UTF-16LE or UTF-16BE. To remain backwards compatible we support both for importing, * but we only export UTF-8. */ foreach ( array( // See https://www.php.net/manual/en/function.mb-detect-encoding.php#91051. 'UTF-8' => chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ), 'UTF-32BE' => chr( 0x00 ) . chr( 0x00 ) . chr( 0xFE ) . chr( 0xFF ), 'UTF-32LE' => chr( 0xFF ) . chr( 0xFE ) . chr( 0x00 ) . chr( 0x00 ), 'UTF-16LE' => chr( 0xFF ) . chr( 0xFE ), 'UTF-16BE' => chr( 0xFE ) . chr( 0xFF ), ) as $encoding => $bom ) { if ( 0 === strpos( $file, $bom ) ) { if ( 'UTF-8' !== $encoding ) { $file = mb_convert_encoding( $file, 'UTF-8', $encoding ); } break; } } // Convert multi-line comments into a single line. $file = preg_replace_callback( '/\/\*\s*(.*?)\s*\*\//s', function( $m ) { return str_replace( PHP_EOL, '\n', $m[0] ); }, $file ); $context = $comment = null; $lines = explode( "\n", $file ); foreach ( $lines as $line ) { if ( is_null( $context ) ) { if ( preg_match( '/^\/\*\s*(.*)\s*\*\/$/', $line, $matches ) ) { $matches[1] = trim( str_replace( '\n', PHP_EOL, $matches[1] ) ); if ( 'No comment provided by engineer.' !== $matches[1] ) { $comment = $matches[1]; } else { $comment = null; } } elseif ( preg_match( '/^"(.*)" = "(.*)";$/', $line, $matches ) ) { $entry = new Translation_Entry(); $entry->context = $this->unescape( $matches[1] ); $entry->singular = $this->unescape( $matches[2] ); if ( ! is_null( $comment ) ) { $entry->extracted_comments = $comment; $comment = null; } $entry->translations = array(); $entries->add_entry( $entry ); } } } return $entries; } /** * Sorts the translation entries based on the context attribute. * * @since 1.0.0 * * @param string $a First string to compare. * @param string $b Second string to compare. * @return int +1 or -1 based on the order to sort. */ private function sort_entries( $a, $b ) { if ( $a->context == $b->context ) { return 0; } return ( $a->context > $b->context ) ? +1 : -1; } /** * Strips any escaping from a string. * * @since 1.0.0 * * @param string $string The string to strip escapes from. * @return string The unescaped string. */ private function unescape( $string ) { return stripcslashes( $string ); } /** * Adds escaping to a string. * * @since 1.0.0 * * @param string $string The string to add escapes to. * @return string The escaped string. */ private function escape( $string ) { return addcslashes( $string, '"\\/' ); } } GP::$formats['strings'] = new GP_Format_Strings();