Translate extension for MediaWiki
 
Loading...
Searching...
No Matches
export-rename-language.php
Go to the documentation of this file.
1<?php
9// Standard boilerplate to define $IP
10if ( getenv( 'MW_INSTALL_PATH' ) !== false ) {
11 $IP = getenv( 'MW_INSTALL_PATH' );
12} else {
13 $dir = __DIR__;
14 $IP = "$dir/../../..";
15}
16require_once "$IP/maintenance/Maintenance.php";
17
18class ExportRenameLanguage extends Maintenance {
19 private const MARKER = '%CODE%';
20
21 public function __construct() {
22 parent::__construct();
23 $this->addDescription( 'Renames language codes in repos.' );
24 $this->addOption(
25 'group',
26 'Comma separated list of group IDs (can use * as wildcard)',
27 true, /*required*/
28 true /*has arg*/
29 );
30 $this->addOption(
31 'source-language',
32 'Language code',
33 true, /*required*/
34 true /*has arg*/
35 );
36
37 $this->addOption(
38 'target-language',
39 'Language code',
40 true, /*required*/
41 true /*has arg*/
42 );
43 $this->addOption(
44 'target',
45 'Target directory for exported files',
46 true, /*required*/
47 true /*has arg*/
48 );
49 $this->requireExtension( 'Translate' );
50 }
51
52 public function execute() {
53 $target = rtrim( $this->getOption( 'target' ), '/' );
54 $sourceLanguage = $this->getOption( 'source-language' );
55 $targetLanguage = $this->getOption( 'target-language' );
56
57 if ( !is_writable( $target ) ) {
58 $this->fatalError( "Target directory is not writable ($target)." );
59 }
60
61 $groupIds = explode( ',', trim( $this->getOption( 'group' ) ) );
62 $groupIds = MessageGroups::expandWildcards( $groupIds );
63 $groups = MessageGroups::getGroupsById( $groupIds );
64 $groups = $this->filterGroups( $groups );
65
66 if ( $groups === [] ) {
67 $this->fatalError( 'EE1: No valid message groups identified.' );
68 }
69
70 foreach ( $groups as $group ) {
71 // Source path can be wrong if source language is the source language of the
72 // message group. This is because getTargetFilename doesn't check definitionFile
73 // property first.
74 $sourcePath = $group->getTargetFilename( $sourceLanguage );
75 $targetPath = $group->getTargetFilename( $targetLanguage );
76
77 if ( !file_exists( "$target/$sourcePath" ) ) {
78 continue;
79 }
80
81 $this->output( "Renaming $sourcePath to $targetPath\n" );
82 $this->renameFile( "$target/$sourcePath", "$target/$targetPath" );
83
84 $pathPattern = "$target/" . $group->getTargetFilename( self::MARKER );
85 $pathToRemove = '';
86 $needsCleanup = $this->needsCleanup( $pathPattern, $sourceLanguage, $pathToRemove );
87 if ( $needsCleanup === 'yes' ) {
88 $this->output( "Removing empty directory $pathToRemove\n" );
89 rmdir( $pathToRemove );
90 } elseif ( $needsCleanup === 'maybe' ) {
91 $this->output( "Not removing (yet?) non-empty directory $pathToRemove\n" );
92 }
93 }
94
95 $this->output( "Done\n" );
96 }
97
102 private function filterGroups( array $groups ) {
103 $return = [];
104 foreach ( $groups as $groupId => $group ) {
105 if ( !$group instanceof FileBasedMessageGroup ) {
106 $this->output( "Skipping non-file based message group $groupId.\n" );
107 continue;
108 }
109 $return[$groupId] = $group;
110 }
111 return $return;
112 }
113
114 private function renameFile( $source, $target ) {
115 // In case %CODE% is in the path
116 if ( !is_dir( dirname( $target ) ) ) {
117 mkdir( dirname( $target ), 0777, true );
118 }
119
120 rename( $source, $target );
121 }
122
123 private function isDirectoryEmpty( $dir ) {
124 return array_diff( scandir( $dir ), [ '..', '.' ] ) === [];
125 }
126
127 private function needsCleanup( $pathPattern, $sourceLanguage, &$pathToRemove ) {
128 do {
129 $currentComponent = basename( $pathPattern );
130 if ( strpos( $currentComponent, self::MARKER ) === false ) {
131 $pathPattern = dirname( $pathPattern );
132 continue;
133 }
134
135 $pathToRemove = str_replace( self::MARKER, $sourceLanguage, $pathPattern );
136 if ( !is_dir( $pathToRemove ) ) {
137 // %CODE% is in the filename
138 return 'no';
139 }
140
141 return $this->isDirectoryEmpty( $pathToRemove ) ? 'yes' : 'maybe';
142 } while ( $currentComponent !== '' );
143
144 // This should never be reached.
145 return 'no';
146 }
147}
148
149$maintClass = ExportRenameLanguage::class;
150require_once RUN_MAINTENANCE_IF_MAIN;
This class implements default behavior for file based message groups.