def _add_announcement_and_translation(self, locale, is_draft=False): announcement = announcements.AnnouncementEntity() announcement.title = 'Test Announcement' announcement.html = 'Announcement Content' announcement.is_draft = is_draft announcement.put() key = i18n_dashboard.ResourceBundleKey( announcements.ResourceHandlerAnnouncement.TYPE, announcement.key().id(), locale) dto = i18n_dashboard.ResourceBundleDTO( str(key), { 'title': { 'type': 'string', 'source_value': '', 'data': [{ 'source_value': 'Test Announcement', 'target_value': 'TEST ANNOUNCEMENT' }] }, 'html': { 'type': 'string', 'source_value': '', 'data': [{ 'source_value': 'Announcement Content', 'target_value': 'ANNOUNCEMENT CONTENT' }] }, }) i18n_dashboard.ResourceBundleDAO.save(dto) return announcement
def test_hook_i18n(self): actions.update_course_config( COURSE_NAME, { 'html_hooks': {'base': {'after_body_tag_begins': 'foozle'}}, 'extra_locales': [ {'locale': 'de', 'availability': 'available'}, ] }) hook_bundle = { 'content': { 'type': 'html', 'source_value': '', 'data': [{ 'source_value': 'foozle', 'target_value': 'FUZEL', }], } } hook_key = i18n_dashboard.ResourceBundleKey( utils.ResourceHtmlHook.TYPE, 'base.after_body_tag_begins', 'de') with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.save( i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) # Verify non-translated version. response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('foozle', html_hook.text) # Set preference to translated language, and check that that's there. with common_utils.Namespace(NAMESPACE): prefs = models.StudentPreferencesDAO.load_or_default() prefs.locale = 'de' models.StudentPreferencesDAO.save(prefs) response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('FUZEL', html_hook.text) # With no translation present, but preference set to foreign language, # verify that we fall back to the original language. # Remove translation bundle, and clear cache. with common_utils.Namespace(NAMESPACE): i18n_dashboard.ResourceBundleDAO.delete( i18n_dashboard.ResourceBundleDTO(str(hook_key), hook_bundle)) model_caching.CacheFactory.get_cache_instance( i18n_dashboard.RESOURCE_BUNDLE_CACHE_NAME).clear() response = self.get(BASE_URL) dom = self.parse_html_string(response.body) html_hook = dom.find('.//div[@id="base-after-body-tag-begins"]') self.assertEquals('foozle', html_hook.text)
def add_location(self, resource_bundle_key, loc_name, loc_type): resource_key = resource_bundle_key.resource_key fixed_location_bundle_key = i18n_dashboard.ResourceBundleKey( resource_key.type, resource_key.key, self._locale_to_use) super(OverriddenLocaleTranslationMessage, self).add_location(fixed_location_bundle_key, loc_name, loc_type)
def get_message(self, resource_bundle_key, message_key): resource_key = resource_bundle_key.resource_key resource_bundle_key = i18n_dashboard.ResourceBundleKey( resource_key.type, resource_key.key, self._locale_to_use) return super(OverriddenLocaleTranslationContents, self).get_message(resource_bundle_key, message_key)
def test_locale_agnostic_lifecycle(self): app_context = self._import_course() course = courses.Course(None, app_context=app_context) unit = course.add_unit() unit.title = 'Title in base language' course.save() extra_env = { 'extra_locales': [ { 'locale': 'de', 'availability': 'available' }, { 'locale': 'fr', 'availability': 'available' }, ] } bundle_key_de = str( i18n_dashboard.ResourceBundleKey('unit', str(unit.unit_id), 'de')) bundle_key_fr = str( i18n_dashboard.ResourceBundleKey('unit', str(unit.unit_id), 'fr')) # Do language-agnostic export; should get locale 'gv'. with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locale_agnostic ' '--export=all' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') index = lines.index('msgid "Title in base language"') self.assertGreater(index, -1) # Provide 'translation' for unit title to 'German'. lines[index + 1] = 'msgstr "Title in German"' data = '\n'.join(lines) with zipfile.ZipFile(self.zipfile_name, 'w') as zf: zf.writestr( 'locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE, data) zf.close() # Run upload, forcing locale to German. self.run_upload_job('--job_args=%s --force_locale=de' % self.zipfile_name) # Verify that we now have DE translation bundle. with common_utils.Namespace(self.NAMESPACE): bundle = i18n_dashboard.ResourceBundleDAO.load(bundle_key_de) self.assertEquals('Title in German', bundle.dict['title']['data'][0]['target_value']) # Also upload to 'fr', which will give us the wrong content, but # the user said "--force", so we force it. self.run_upload_job('--job_args=%s --force_locale=fr' % self.zipfile_name) # Verify that we now have FR translation bundle. with common_utils.Namespace(self.NAMESPACE): bundle = i18n_dashboard.ResourceBundleDAO.load(bundle_key_fr) self.assertEquals('Title in German', bundle.dict['title']['data'][0]['target_value']) # Do a locale-agnostic download, specifying all content. # Since it's --export=all, we should get the unit title, but # since it's locale agnostic, we should get no translated text. os.unlink(self.zipfile_name) with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locale_agnostic ' '--export=all' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') index = lines.index('msgid "Title in base language"') self.assertGreater(index, -1) self.assertEquals('msgstr ""', lines[index + 1]) # Do locale-agnostic download, specifying only new content. # We don't specificy locale, which means we should consider # 'de' and 'fr'. But since both of those are up-to-date, # we shouldn't see the translation for the unit title even # appear in the output file. os.unlink(self.zipfile_name) with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locale_agnostic ' '--export=new' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') self.assertEquals(0, lines.count('msgid "Title in base language"')) # Modify unit title. unit = course.find_unit_by_id(unit.unit_id) unit.title = 'New and improved title in the base language' course.save() # Submit a new translation of the changed title, but only for DE. os.unlink(self.zipfile_name) with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locale_agnostic ' '--locales=de ' '--export=new' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') index = lines.index( 'msgid "New and improved title in the base language"') self.assertGreater(index, -1) lines[index + 1] = 'msgstr = "New and improved German title"' data = '\n'.join(lines) with zipfile.ZipFile(self.zipfile_name, 'w') as zf: zf.writestr( 'locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE, data) zf.close() # Run upload, forcing locale to German. self.run_upload_job('--job_args=%s --force_locale=de' % self.zipfile_name) # Locale-agnostic download, for DE only, and only for 'new' # items. Since we've updated the translation bundle since # the time we updated the course, we don't expect to see the # unit title exported to the .po file. os.unlink(self.zipfile_name) with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locales=de ' '--locale_agnostic ' '--export=new' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') self.assertEquals( 0, lines.count('msgid "New and improved title in the base language"')) # Exact same download, but change 'de' to 'fr'. Since the FR # translation was not updated, we should see that item in the # export. os.unlink(self.zipfile_name) with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locales=fr ' '--locale_agnostic ' '--export=new' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') self.assertEquals( 1, lines.count('msgid "New and improved title in the base language"')) # Download again, leaving off the locales argument. This should # find both locales, and in this case, since at least one of the # locales has not been updated, we should, again, see that item. os.unlink(self.zipfile_name) with actions.OverriddenEnvironment(extra_env): self.run_download_job('--job_args=%s ' '--locale_agnostic ' '--export=new' % self.zipfile_name) with zipfile.ZipFile(self.zipfile_name) as zf: data = zf.read('locale/%s/LC_MESSAGES/messages.po' % jobs.AGNOSTIC_EXPORT_LOCALE) lines = data.split('\n') self.assertEquals( 1, lines.count('msgid "New and improved title in the base language"'))
def test_localized_search(self): def _text(elt): return ''.join(elt.itertext()) dogs_page = """ <html> <body> A page about dogs. </body> </html>""" dogs_link = 'http://dogs.null/' self.pages[dogs_link + '$'] = (dogs_page, 'text/html') dogs_page_fr = """ <html> <body> A page about French dogs. </body> </html>""" dogs_link_fr = 'http://dogs_fr.null/' self.pages[dogs_link_fr + '$'] = (dogs_page_fr, 'text/html') self.base = '/test' context = actions.simple_add_course('test', '*****@*****.**', 'Test Course') course = courses.Course(None, context) actions.login('*****@*****.**') actions.register(self, 'Some Admin') unit = course.add_unit() unit.availability = courses.AVAILABILITY_AVAILABLE lesson = course.add_lesson(unit) lesson.objectives = 'A lesson about <a href="%s">dogs</a>' % dogs_link lesson.availability = courses.AVAILABILITY_AVAILABLE course.save() lesson_bundle = { 'objectives': { 'type': 'html', 'source_value': ('A lesson about <a href="%s">dogs</a>' % dogs_link), 'data': [{ 'source_value': ('A lesson about <a#1 href="%s">dogs</a#1>' % dogs_link), 'target_value': ('A lesson about French <a#1 href="%s">' 'dogs</a#1>' % dogs_link_fr) }] } } lesson_key_fr = i18n_dashboard.ResourceBundleKey( resources_display.ResourceLesson.TYPE, lesson.lesson_id, 'fr') with common_utils.Namespace('ns_test'): i18n_dashboard.ResourceBundleDAO.save( i18n_dashboard.ResourceBundleDTO(str(lesson_key_fr), lesson_bundle)) extra_locales = [{'locale': 'fr', 'availability': 'available'}] with actions.OverriddenEnvironment({'extra_locales': extra_locales}): self.index_test_course() dom = self.parse_html_string(self.get('search?query=dogs').body) snippets = dom.findall( './/div[@class="gcb-search-result-snippet"]') self.assertEquals(2, len(snippets)) # Expect no French hits self.assertIn('page about dogs', _text(snippets[0])) self.assertIn('lesson about dogs', _text(snippets[1])) # Switch locale to 'fr' with common_utils.Namespace('ns_test'): prefs = models.StudentPreferencesDAO.load_or_default() prefs.locale = 'fr' models.StudentPreferencesDAO.save(prefs) dom = self.parse_html_string(self.get('search?query=dogs').body) snippets = dom.findall( './/div[@class="gcb-search-result-snippet"]') self.assertEquals(2, len(snippets)) # Expect no Engish hits self.assertIn('page about French dogs', _text(snippets[0])) self.assertIn('lesson about French dogs', _text(snippets[1]))
def _put_translation(self, data, locale, title, html): resource_key = str( i18n_dashboard.ResourceBundleKey( announcements.ResourceHandlerAnnouncement.TYPE, db.Key(encoded=data['key']).id(), locale)) xsrf_token = crypto.XsrfTokenManager.create_xsrf_token( i18n_dashboard.TranslationConsoleRestHandler.XSRF_TOKEN_NAME) request = { 'key': resource_key, 'xsrf_token': xsrf_token, 'validate': False, 'payload': transforms.dumps({ 'title': 'Announcements', 'key': resource_key, 'source_locale': 'en_US', 'target_locale': locale, 'sections': [ { 'name': 'title', 'label': 'Title', 'type': 'string', 'source_value': '', 'data': [{ 'source_value': data['title'], 'target_value': title, 'verb': 1, # verb NEW 'old_source_value': '', 'changed': True }] }, { 'name': 'html', 'label': 'Body', 'type': 'html', 'source_value': '', 'data': [{ 'source_value': data['html'], 'target_value': html, 'verb': 1, # verb NEW 'old_source_value': '', 'changed': True }] } ] }) } response = self.put( self.base + i18n_dashboard.TranslationConsoleRestHandler.URL.lstrip(), {'request': transforms.dumps(request)}) self.assertEquals(200, response.status_int) response = transforms.loads(response.body) self.assertEquals(200, response['status'])