66use yii \db \BaseActiveRecord ;
77use yii \behaviors \AttributeBehavior ;
88use lajax \translatemanager \helpers \Language ;
9+ use lajax \translatemanager \models \LanguageSource ;
10+ use lajax \translatemanager \models \LanguageTranslate ;
911
1012/**
11- * TranslateManager Database translate behavior.
13+ * Behavior that translates the model attributes, and saves the changes into database.
14+ *
15+ * This behavior does the following:
16+ * - Replaces the specified attributes with translations after the model is loaded.
17+ * - Saves the attribute values as:
18+ * 1. Source messages, if the current language is the source language.
19+ * 2. Translations, if the current language is different from the source language.
20+ * This way the value stored in database is not overwritten with the translation.
21+ *
22+ * **Note**: If the model should be saved as translation, but the source message does not exist yet in the database
23+ * then the message is saved as the source message whether the current language is the source language or not.
24+ * To avoid this scan the database for existing messages when using the behavior first, and only save new records
25+ * when the current language is the source language.
1226 *
1327 * Installation:
1428 *
@@ -45,6 +59,11 @@ class TranslateBehavior extends AttributeBehavior
4559 */
4660 public $ category = 'database ' ;
4761
62+ /**
63+ * @var BaseActiveRecord the owner model of this behavior
64+ */
65+ public $ owner ;
66+
4867 /**
4968 * @inheritdoc
5069 */
@@ -68,31 +87,88 @@ public function events()
6887 }
6988
7089 /**
71- * Translates a message to the specified language.
90+ * Translates the attributes to the current language.
7291 *
7392 * @param \yii\base\Event $event
7493 */
7594 public function translateAttributes ($ event )
7695 {
77- /* @var $owner BaseActiveRecord */
78- $ owner = $ this ->owner ;
7996 foreach ($ this ->translateAttributes as $ attribute ) {
80- $ owner ->{$ attribute } = Yii::t ($ this ->category , $ owner ->attributes [$ attribute ]);
97+ $ this -> owner ->{$ attribute } = Yii::t ($ this ->category , $ this -> owner ->attributes [$ attribute ]);
8198 }
8299 }
83100
84101 /**
85- * Saveing new language element by category.
102+ * Saves new language element by category.
86103 *
87104 * @param \yii\base\Event $event
88105 */
89106 public function saveAttributes ($ event )
90107 {
91- /* @var $owner BaseActiveRecord */
92- $ owner = $ this -> owner ;
108+ $ isAppInSourceLanguage = Yii:: $ app -> sourceLanguage === Yii:: $ app -> language ;
109+
93110 foreach ($ this ->translateAttributes as $ attribute ) {
94- if ($ owner ->isAttributeChanged ($ attribute )) {
95- Language::saveMessage ($ owner ->attributes [$ attribute ], $ this ->category );
111+ if (!$ this ->owner ->isAttributeChanged ($ attribute )) {
112+ continue ;
113+ }
114+
115+ if ($ isAppInSourceLanguage || !$ this ->saveAttributeValueAsTranslation ($ attribute )) {
116+ Language::saveMessage ($ this ->owner ->attributes [$ attribute ], $ this ->category );
117+ }
118+ }
119+ }
120+
121+ /**
122+ * @param string $attribute The name of the attribute.
123+ *
124+ * @return bool Whether the translation is saved.
125+ */
126+ private function saveAttributeValueAsTranslation ($ attribute )
127+ {
128+ $ sourceMessage = $ this ->owner ->getOldAttribute ($ attribute );
129+ $ translatedMessage = $ this ->owner ->attributes [$ attribute ];
130+
131+ // Restore the original value, so it won't be replaced with the translation in the database.
132+ $ this ->owner ->{$ attribute } = $ sourceMessage ;
133+
134+ $ translateSource = $ this ->findSourceMessage ($ sourceMessage );
135+ if (!$ translateSource ) {
136+ return false ; // The source does not exist, the message cannot be saved as translation.
137+ }
138+
139+ $ translation = new LanguageTranslate ();
140+ foreach ($ translateSource ->languageTranslates as $ tmpTranslate ) {
141+ if ($ tmpTranslate ->language === Yii::$ app ->language ) {
142+ $ translation = $ tmpTranslate ;
143+ break ;
144+ }
145+ }
146+
147+ if ($ translation ->isNewRecord ) {
148+ $ translation ->id = $ translateSource ->id ;
149+ $ translation ->language = Yii::$ app ->language ;
150+ }
151+
152+ $ translation ->translation = $ translatedMessage ;
153+ $ translation ->save ();
154+
155+ return true ;
156+ }
157+
158+ /**
159+ * Finds the source record with case sensitive match.
160+ *
161+ * @param string $message
162+ *
163+ * @return LanguageSource|null Null if the source is not found.
164+ */
165+ private function findSourceMessage ($ message )
166+ {
167+ $ sourceMessages = LanguageSource::findAll (['message ' => $ message , 'category ' => $ this ->category ]);
168+
169+ foreach ($ sourceMessages as $ source ) {
170+ if ($ source ->message === $ message ) {
171+ return $ source ;
96172 }
97173 }
98174 }
0 commit comments