19 public const CONTENT_MODEL_ID =
'translate-messagebundle';
23 'allowOnlyPriorityLanguages',
29 private ?array $messages =
null;
32 public function __construct( $text, $modelId = self::CONTENT_MODEL_ID ) {
33 parent::__construct( $text, $modelId );
36 public function isValid(): bool {
40 return parent::isValid();
41 }
catch ( MalformedBundle $e ) {
52 public function prepareSave( WikiPage $page, $flags, $parentRevId, User $user ) {
59 return Status::newGood();
60 }
catch ( MalformedBundle $e ) {
62 return Status::newFatal(
'translate-messagebundle-validation-error', wfMessage( $e ) );
68 if ( isset( $this->messages ) ) {
69 return $this->messages;
72 $data = $this->getRawData();
74 unset( $data[
'@metadata'] );
76 foreach ( $data as $key => $value ) {
81 if ( strlen( $key ) > 100 ) {
82 throw new MalformedBundle(
83 'translate-messagebundle-error-key-too-long',
88 if ( !preg_match(
'/^[a-zA-Z0-9-_.]+$/', $key ) ) {
89 throw new MalformedBundle(
90 'translate-messagebundle-error-key-invalid-characters',
95 if ( !is_string( $value ) ) {
96 throw new MalformedBundle(
97 'translate-messagebundle-error-invalid-value',
102 if ( trim( $value ) ===
'' ) {
103 throw new MalformedBundle(
104 'translate-messagebundle-error-empty-value',
110 $this->messages = $data;
111 return $this->messages;
114 public function getMetadata(): MessageBundleMetadata {
115 if ( isset( $this->metadata ) ) {
116 return $this->metadata;
119 $data = $this->getRawData();
120 $metadata = $data[
'@metadata'] ?? [];
122 if ( !is_array( $metadata ) ) {
123 throw new MalformedBundle(
'translate-messagebundle-error-metadata-type' );
126 foreach ( $metadata as $key => $value ) {
127 if ( !in_array( $key, self::METADATA_KEYS ) ) {
128 throw new MalformedBundle(
129 'translate-messagebundle-error-invalid-metadata',
130 [ $key, Message::listParam( self::METADATA_KEYS ) ]
135 $sourceLanguage = $metadata[
'sourceLanguage'] ??
null;
136 if ( $sourceLanguage && !is_string( $sourceLanguage ) ) {
137 throw new MalformedBundle(
138 'translate-messagebundle-error-invalid-sourcelanguage', [ $sourceLanguage ]
142 $priorityLanguageCodes = $metadata[
'priorityLanguages'] ??
null;
143 if ( $priorityLanguageCodes ) {
144 if ( !is_array( $priorityLanguageCodes ) ) {
145 throw new MalformedBundle(
'translate-messagebundle-error-invalid-prioritylanguage-format' );
148 $priorityLanguageCodes = array_unique( $priorityLanguageCodes );
151 $description = $metadata[
'description'] ??
null;
152 if ( $description !==
null ) {
153 if ( !is_string( $description ) ) {
154 throw new MalformedBundle(
155 'translate-messagebundle-error-invalid-description'
159 $description = trim( $description ) ===
'' ? null : trim( $description );
162 $label = $metadata[
'label'] ??
null;
163 if ( $label !==
null ) {
164 if ( !is_string( $label ) ) {
165 throw new MalformedBundle(
166 'translate-messagebundle-error-invalid-label'
170 $label = trim( $label ) ===
'' ? null : trim( $label );
173 $this->metadata =
new MessageBundleMetadata(
175 $priorityLanguageCodes,
176 (
bool)( $metadata[
'allowOnlyPriorityLanguages'] ??
false ),
180 return $this->metadata;
183 private function getRawData(): array {
184 $status = FormatJson::parse( $this->getText(), FormatJson::FORCE_ASSOC );
185 if ( !$status->isOK() ) {
186 throw new MalformedBundle(
187 'translate-messagebundle-error-parsing',
188 [ $status->getMessage()->text() ]
192 $data = $status->getValue();
194 if ( !is_array( $data ) || ( $data !== [] && array_values( $data ) === $data ) ) {
195 throw new MalformedBundle(
196 'translate-messagebundle-error-invalid-array',