19 public const CONTENT_MODEL_ID =
'translate-messagebundle';
23 'allowOnlyPriorityLanguages',
33 public function __construct( $text, $modelId = self::CONTENT_MODEL_ID ) {
34 parent::__construct( $text, $modelId );
37 public function isValid(): bool {
41 return parent::isValid();
42 }
catch ( MalformedBundle $e ) {
53 public function prepareSave( WikiPage $page, $flags, $parentRevId, User $user ) {
60 return Status::newGood();
61 }
catch ( MalformedBundle $e ) {
63 return Status::newFatal(
'translate-messagebundle-validation-error', wfMessage( $e ) );
69 if ( $this->messages ) {
70 return $this->messages;
73 $data = $this->getRawData();
75 unset( $data[
'@metadata'] );
77 foreach ( $data as $key => $value ) {
82 if ( strlen( $key ) > 100 ) {
83 throw new MalformedBundle(
84 'translate-messagebundle-error-key-too-long',
89 if ( !preg_match(
'/^[a-zA-Z0-9-_.]+$/', $key ) ) {
90 throw new MalformedBundle(
91 'translate-messagebundle-error-key-invalid-characters',
96 if ( !is_string( $value ) ) {
97 throw new MalformedBundle(
98 'translate-messagebundle-error-invalid-value',
103 if ( trim( $value ) ===
'' ) {
104 throw new MalformedBundle(
105 'translate-messagebundle-error-empty-value',
111 $this->messages = $data;
112 return $this->messages;
115 public function getMetadata(): MessageBundleMetadata {
116 if ( $this->metadata ) {
117 return $this->metadata;
120 $data = $this->getRawData();
121 $metadata = $data[
'@metadata'] ?? [];
123 if ( !is_array( $metadata ) ) {
124 throw new MalformedBundle(
'translate-messagebundle-error-metadata-type' );
127 foreach ( $metadata as $key => $value ) {
128 if ( !in_array( $key, self::METADATA_KEYS ) ) {
129 throw new MalformedBundle(
130 'translate-messagebundle-error-invalid-metadata',
131 [ $key, Message::listParam( self::METADATA_KEYS ) ]
136 $sourceLanguage = $metadata[
'sourceLanguage'] ??
null;
137 if ( $sourceLanguage && !is_string( $sourceLanguage ) ) {
138 throw new MalformedBundle(
139 'translate-messagebundle-error-invalid-sourcelanguage', [ $sourceLanguage ]
143 $priorityLanguageCodes = $metadata[
'priorityLanguages'] ??
null;
144 if ( $priorityLanguageCodes ) {
145 if ( !is_array( $priorityLanguageCodes ) ) {
146 throw new MalformedBundle(
'translate-messagebundle-error-invalid-prioritylanguage-format' );
149 $priorityLanguageCodes = array_unique( $priorityLanguageCodes );
152 $description = $metadata[
'description'] ??
null;
153 if ( $description !==
null ) {
154 if ( !is_string( $description ) ) {
155 throw new MalformedBundle(
156 'translate-messagebundle-error-invalid-description'
160 $description = trim( $description ) ===
'' ? null : trim( $description );
163 $this->metadata =
new MessageBundleMetadata(
165 $priorityLanguageCodes,
166 (
bool)( $metadata[
'allowOnlyPriorityLanguages'] ??
false ),
169 return $this->metadata;
172 private function getRawData(): array {
173 $status = FormatJson::parse( $this->getText(), FormatJson::FORCE_ASSOC );
174 if ( !$status->isOK() ) {
175 throw new MalformedBundle(
176 'translate-messagebundle-error-parsing',
177 [ $status->getMessage()->text() ]
181 $data = $status->getValue();
183 if ( !is_array( $data ) || ( $data !== [] && array_values( $data ) === $data ) ) {
184 throw new MalformedBundle(
185 'translate-messagebundle-error-invalid-array',