+
+
+
+
+
+
+
+
diff --git a/contentcuration/contentcuration/frontend/channelEdit/composables/useFetch.js b/contentcuration/contentcuration/frontend/channelEdit/composables/useFetch.js
new file mode 100644
index 0000000000..eadf93ed35
--- /dev/null
+++ b/contentcuration/contentcuration/frontend/channelEdit/composables/useFetch.js
@@ -0,0 +1,28 @@
+import { ref } from 'vue';
+
+export function useFetch({ asyncFetchFunc }) {
+ const isLoading = ref(true);
+ const isFinished = ref(false);
+ const data = ref(null);
+ const error = ref(null);
+
+ async function fetchData() {
+ isLoading.value = true;
+ isFinished.value = false;
+ data.value = null;
+ error.value = null;
+ try {
+ data.value = await asyncFetchFunc();
+ isLoading.value = false;
+ isFinished.value = true;
+ } catch (error) {
+ error.value = error;
+ throw error;
+ } finally {
+ isLoading.value = false;
+ }
+ }
+ fetchData();
+
+ return { isLoading, isFinished, data, error };
+}
diff --git a/contentcuration/contentcuration/frontend/channelEdit/utils.js b/contentcuration/contentcuration/frontend/channelEdit/utils.js
index 54e2530f0f..0d734e558f 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/utils.js
+++ b/contentcuration/contentcuration/frontend/channelEdit/utils.js
@@ -2,7 +2,8 @@ import translator from './translator';
import { RouteNames } from './constants';
import { ContentKindsNames } from 'shared/leUtils/ContentKinds';
import { MasteryModelsNames } from 'shared/leUtils/MasteryModels';
-import { metadataStrings, constantStrings } from 'shared/mixins';
+import { metadataStrings } from 'shared/strings/metadataStrings';
+import { constantStrings } from 'shared/mixins';
import {
ContentModalities,
AssessmentItemTypes,
diff --git a/contentcuration/contentcuration/frontend/channelEdit/views/TreeView/TreeViewBase.vue b/contentcuration/contentcuration/frontend/channelEdit/views/TreeView/TreeViewBase.vue
index 95bb47fa68..6ca82f5d2d 100644
--- a/contentcuration/contentcuration/frontend/channelEdit/views/TreeView/TreeViewBase.vue
+++ b/contentcuration/contentcuration/frontend/channelEdit/views/TreeView/TreeViewBase.vue
@@ -84,6 +84,31 @@
>
{{ $tr('apiGenerated') }}
+
+
+
+ {{ $tr('shareMenuButton') }}
+
+
+
+
+ {{ $tr('submitToCommunityLibrary') }}
+
+
+ {{ $tr('inviteCollaborators') }}
+
+
+ {{ $tr('shareToken') }}
+
+
+
+ response.data.languages);
return uniq(compact(localLanguages.concat(remoteLanguages)));
},
+ async getPublishedData(id) {
+ const response = await client.get(window.Urls.channel_published_data(id));
+ return response.data;
+ },
});
function getChannelFromChannelScope() {
@@ -2393,3 +2397,17 @@ export const Recommendation = new APIResource({
});
},
});
+
+export const CommunityLibrarySubmission = new APIResource({
+ urlName: 'community_library_submission',
+ fetchCollection(params) {
+ return client.get(this.collectionUrl(), { params }).then(response => {
+ return response.data || [];
+ });
+ },
+ create(params) {
+ return client.post(this.collectionUrl(), params).then(response => {
+ return response.data;
+ });
+ },
+});
diff --git a/contentcuration/contentcuration/frontend/shared/mixins.js b/contentcuration/contentcuration/frontend/shared/mixins.js
index fa7625859c..c99f8e033c 100644
--- a/contentcuration/contentcuration/frontend/shared/mixins.js
+++ b/contentcuration/contentcuration/frontend/shared/mixins.js
@@ -1,4 +1,3 @@
-import camelCase from 'lodash/camelCase';
import isEqual from 'lodash/isEqual';
import transform from 'lodash/transform';
import uniq from 'lodash/uniq';
@@ -13,6 +12,7 @@ import {
ONE_TB,
filterTypes,
} from './constants';
+import { translateMetadataString } from './utils/metadataStringsTranslation';
import { createTranslator, updateTabTitle } from 'shared/i18n';
import Languages from 'shared/leUtils/Languages';
import Licenses from 'shared/leUtils/Licenses';
@@ -200,560 +200,16 @@ export const constantsTranslationMixin = {
},
};
-// METADATA STRINGS AND RELATED MIXIN
-
-export const metadataStrings = createTranslator('CommonMetadataStrings', {
- // Titles/Headers
-
- learningActivity: {
- message: 'Learning Activity',
- context: 'A title for the category of education material interaction, i.e. watch, read, listen',
- },
- completion: {
- message: 'Completion',
- context: 'A title for the metadata that explains when an activity is finished',
- },
- duration: {
- message: 'Duration',
- context: 'A title for the metadata that explains how long an activity will take',
- },
- category: {
- message: 'Category',
- context: 'A title for the metadata that explains the subject matter of an activity',
- },
- // Completion criteria types
- reference: {
- message: 'Reference material',
- context:
- 'One of the completion criteria types. Progress made on a resource with this criteria is not tracked.',
- },
- completeDuration: {
- message: 'When time spent is equal to duration',
- context:
- 'One of the completion criteria types. A resource with this criteria is considered complete when learners spent given time studying it.',
- },
- exactTime: {
- message: 'Time to complete',
- context:
- 'One of the completion criteria types. A subset of "When time spent is equal to duration". For example, for an audio resource with this criteria, learnes need to hear the whole length of audio for the resource to be considered complete.',
- },
- allContent: {
- message: 'Viewed in its entirety',
- context:
- 'One of the completion criteria types. A resource with this criteria is considered complete when learners studied it all, for example they saw all pages of a document.',
- },
- determinedByResource: {
- message: 'Determined by the resource',
- context:
- 'One of the completion criteria types. Typically used for embedded html5/h5p resources that contain their own completion criteria, for example reaching a score in an educational game.',
- },
- masteryMofN: {
- message: 'Goal: {m} out of {n}',
- context:
- 'One of the completion criteria types specific to exercises. An exercise with this criteria is considered complete when learners answered m questions out of n correctly.',
- },
- goal: {
- message: 'When goal is met',
- context:
- 'One of the completion criteria types specific to exercises. An exercise with this criteria is considered complete when learners reached a given goal, for example 100% correct.',
- },
- practiceQuiz: {
- message: 'Practice quiz',
- context:
- 'One of the completion criteria types specific to exercises. An exercise with this criteria represents a quiz.',
- },
- survey: {
- message: 'Survey',
- context:
- 'One of the completion criteria types specific to exercises. An exercise with this criteria represents a survey.',
- },
-
- // Learning Activities
- all: {
- message: 'All',
- context: 'A label for everything in the group of activities.',
- },
- watch: {
- message: 'Watch',
- context:
- 'Resource and filter label for the type of learning activity with video. Translate as a VERB',
- },
- create: {
- message: 'Create',
- context: 'Resource and filter label for the type of learning activity. Translate as a VERB',
- },
- read: {
- message: 'Read',
- context:
- 'Resource and filter label for the type of learning activity with documents. Translate as a VERB',
- },
- practice: {
- message: 'Practice',
- context:
- 'Resource and filter label for the type of learning activity with questions and answers. Translate as a VERB',
- },
- reflect: {
- message: 'Reflect',
- context: 'Resource and filter label for the type of learning activity. Translate as a VERB',
- },
- listen: {
- message: 'Listen',
- context:
- 'Resource and filter label for the type of learning activity with audio. Translate as a VERB',
- },
- explore: {
- message: 'Explore',
- context: 'Resource and filter label for the type of learning activity. Translate as a VERB',
- },
-
- // Library Categories
- school: {
- message: 'School',
- context: 'Category type.',
- },
- basicSkills: {
- message: 'Basic skills',
- context:
- 'Category type. Basic skills refer to learning resources focused on aspects like literacy, numeracy and digital literacy.',
- },
- work: {
- message: 'Work',
- context:
- 'Top level category group that contains resources for acquisition of professional skills.',
- },
- dailyLife: {
- message: 'Daily life',
- context: 'Category type. See https://en.wikipedia.org/wiki/Everyday_life',
- },
- forTeachers: {
- message: 'For teachers',
- context: 'Category type',
- },
-
- // School Categories
- mathematics: {
- message: 'Mathematics',
- context: 'Category type. See https://en.wikipedia.org/wiki/Mathematics',
- },
- sciences: {
- message: 'Sciences',
- context: 'Category type. See https://en.wikipedia.org/wiki/Science',
- },
- socialSciences: {
- message: 'Social sciences',
- context: 'Category type. See https://en.wikipedia.org/wiki/Social_science',
- },
- arts: {
- message: 'Arts',
- context: 'Refers to a category group type. See https://en.wikipedia.org/wiki/The_arts',
- },
- computerScience: {
- message: 'Computer science',
- context: 'Category type. See https://en.wikipedia.org/wiki/Computer_science',
- },
- languageLearning: {
- message: 'Language learning',
- context: 'Category type.',
- },
- history: {
- message: 'History',
- context: 'Category type.',
- },
- readingAndWriting: {
- message: 'Reading and writing',
- context: 'School subject category',
- },
-
- // Mathematics Subcategories
- arithmetic: {
- message: 'Arithmetic',
- context: 'Math category type. See https://en.wikipedia.org/wiki/Arithmetic',
- },
- algebra: {
- message: 'Algebra',
- context: 'A type of math category. See https://en.wikipedia.org/wiki/Algebra',
- },
- geometry: {
- message: 'Geometry',
- context: 'Category type.',
- },
- calculus: {
- message: 'Calculus',
- context: 'Math category type. https://en.wikipedia.org/wiki/Calculus',
- },
- statistics: {
- message: 'Statistics',
- context: 'A math category. See https://en.wikipedia.org/wiki/Statistics',
- },
-
- // Sciences Subcategories
- biology: {
- message: 'Biology',
- context: 'Science category type. See https://en.wikipedia.org/wiki/Biology',
- },
- chemistry: {
- message: 'Chemistry',
- context: 'Science category type. See https://en.wikipedia.org/wiki/Chemistry',
- },
- physics: {
- message: 'Physics',
- context: 'Category type. See https://en.wikipedia.org/wiki/Physics.',
- },
- earthScience: {
- message: 'Earth science',
- context: 'Category type. See https://en.wikipedia.org/wiki/Earth_science',
- },
- astronomy: {
- message: 'Astronomy',
- context: 'Science category type. See https://en.wikipedia.org/wiki/Astronomy',
- },
-
- // Literature Subcategories
- literature: {
- message: 'Literature',
- context: 'Category type. See https://en.wikipedia.org/wiki/Literature',
- },
- readingComprehension: {
- message: 'Reading comprehension',
- context: 'Category type.',
- },
- writing: {
- message: 'Writing',
- context: 'Category type. See https://en.wikipedia.org/wiki/Writing',
- },
- logicAndCriticalThinking: {
- message: 'Logic and critical thinking',
- context: 'Category type. See https://en.wikipedia.org/wiki/Critical_thinking',
- },
-
- // Social Sciences Subcategories
- politicalScience: {
- message: 'Political science',
- context: 'Category type. See https://en.wikipedia.org/wiki/Political_science.',
- },
- sociology: {
- message: 'Sociology',
- context: 'Category type. See https://en.wikipedia.org/wiki/Sociology',
- },
- anthropology: {
- message: 'Anthropology',
- context: 'Category type. See https://en.wikipedia.org/wiki/Anthropology',
- },
- civicEducation: {
- message: 'Civic education',
- context:
- 'Category type. Civic education is the study of the rights and obligations of citizens in society. See https://en.wikipedia.org/wiki/Civics',
- },
-
- // Arts Subcategories = {
- visualArt: {
- message: 'Visual art',
- context: 'Category type. See https://en.wikipedia.org/wiki/Visual_arts',
- },
- music: {
- message: 'Music',
- context: 'Category type. See https://en.wikipedia.org/wiki/Music',
- },
- dance: {
- message: 'Dance',
- context: 'Category type. See https://en.wikipedia.org/wiki/Dance',
- },
- drama: {
- message: 'Drama',
- context: 'Category type. See https://en.wikipedia.org/wiki/Drama',
- },
-
- // Computer Science Subcategories
- programming: {
- message: 'Programming',
- context: 'Category type. See https://en.wikipedia.org/wiki/Computer_programming',
- },
- mechanicalEngineering: {
- message: 'Mechanical engineering',
- context: 'Category type. See https://en.wikipedia.org/wiki/Mechanical_engineering.',
- },
- webDesign: {
- message: 'Web design',
- context: 'Category type. See https://en.wikipedia.org/wiki/Web_design',
- },
-
- // Basic Skills
- literacy: {
- message: 'Literacy',
- context: 'Category type. See https://en.wikipedia.org/wiki/Literacy',
- },
- numeracy: {
- message: 'Numeracy',
- context: 'Category type. See https://en.wikipedia.org/wiki/Numeracy',
- },
- digitalLiteracy: {
- message: 'Digital literacy',
- context: 'Category type. See https://en.wikipedia.org/wiki/Digital_literacy',
- },
- learningSkills: {
- message: 'Learning skills',
- context:
- 'A category label and type of basic skill.\nhttps://en.wikipedia.org/wiki/Study_skills',
- },
-
- // Work Categories
- professionalSkills: {
- message: 'Professional skills',
- context: 'Category type. Refers to skills that are related to a profession or a job.',
- },
- technicalAndVocationalTraining: {
- message: 'Technical and vocational training',
- context:
- 'A level of education. See https://en.wikipedia.org/wiki/TVET_(Technical_and_Vocational_Education_and_Training)',
- },
-
- // VocationalSubcategories
- softwareToolsAndTraining: {
- message: 'Software tools and training',
- context: 'Subcategory type for technical and vocational training.',
- },
- skillsTraining: {
- message: 'Skills training',
- context: 'Subcategory type for technical and vocational training.',
- },
- industryAndSectorSpecific: {
- message: 'Industry and sector specific',
- context: 'Subcategory type for technical and vocational training.',
- },
-
- // Daily Life Categories
- publicHealth: {
- message: 'Public health',
- context: 'Category type. See https://en.wikipedia.org/wiki/Public_health.',
- },
- entrepreneurship: {
- message: 'Entrepreneurship',
- context: 'Category type. See https://en.wikipedia.org/wiki/Entrepreneurship',
- },
- financialLiteracy: {
- message: 'Financial literacy',
- context: 'Category type. See https://en.wikipedia.org/wiki/Financial_literacy',
- },
- currentEvents: {
- message: 'Current events',
- context:
- "Category type. Could also be translated as 'News'. See https://en.wikipedia.org/wiki/News",
- },
- environment: {
- message: 'Environment',
- context: 'Category type. See https://en.wikipedia.org/wiki/Environmental_studies',
- },
- mediaLiteracy: {
- message: 'Media literacy',
- context: 'Category type. See https://en.wikipedia.org/wiki/Media_literacy',
- },
- diversity: {
- message: 'Diversity',
- context: 'Category type. See https://en.wikipedia.org/wiki/Diversity_(politics)',
- },
- mentalHealth: {
- message: 'Mental health',
- context: 'Category type. See https://en.wikipedia.org/wiki/Mental_health',
- },
-
- // Teacher-Specific Categories
- guides: {
- message: 'Guides',
- context:
- 'Category label in the Kolibri resources library; refers to any guide-type material for teacher professional development.',
- },
- lessonPlans: {
- message: 'Lesson plans',
- context:
- 'Category label in the Kolibri resources library; refers to lesson planning materials for teachers.',
- },
-
- // Resources Needed Categories = {
- forBeginners: {
- message: 'For beginners',
- context: 'Filter option and a label for the resources in the Kolibri Library.',
- },
- toUseWithPaperAndPencil: {
- message: 'Paper and pencil',
- context: 'Refers to a filter for resources.\n',
- },
- needsInternet: {
- message: 'Internet connection',
- context: 'Refers to a filter for resources.',
- },
- needsMaterials: {
- message: 'Other supplies',
- context: 'Refers to a filter for resources.\n',
- },
- softwareTools: {
- message: 'Other software tools',
- context: 'Refers to a filter for resources that need additional software to be used.',
- },
- peers: {
- message: 'Working with peers',
- context:
- 'Refers to a filter for resources that require a learner to work with other learners to be used.',
- },
- teacher: {
- message: 'Working with a teacher',
- context:
- 'Refers to a filter for resources that require a learner to work with a teacher to be used.',
- },
-
- // Accessibility category name
- accessibility: {
- message: 'Accessibility',
- context:
- 'Allows the user to filter for all the resources with accessibility features for learners with disabilities.',
- },
- // Accessibility Categories
- signLanguage: {
- message: 'Includes sign language captions',
- context:
- 'https://en.wikipedia.org/wiki/Sign_language\nhttps://en.wikipedia.org/wiki/List_of_sign_languages\nWherever communities of deaf people exist, sign languages have developed as useful means of communication, and they form the core of local Deaf cultures. Although signing is used primarily by the deaf and hard of hearing, it is also used by hearing individuals, such as those unable to physically speak, those who have trouble with spoken language due to a disability or condition (augmentative and alternative communication), or those with deaf family members, such as children of deaf adults. ',
- },
- audioDescription: {
- message: 'Includes audio descriptions',
- context:
- 'Content has narration used to provide information surrounding key visual elements for the benefit of blind and visually impaired users.\nhttps://en.wikipedia.org/wiki/Audio_description',
- },
- taggedPdf: {
- message: 'Tagged PDF',
- context:
- 'A tagged PDF includes hidden accessibility markups (tags) that make the document accessible to those who use screen readers and other assistive technology (AT).\n\nhttps://taggedpdf.com/what-is-a-tagged-pdf/',
- },
- altText: {
- message: 'Includes alternative text descriptions for images',
- context:
- 'Alternative text, or alt text, is a written substitute for an image. It is used to describe information being provided by an image, graph, or any other visual element on a web page. It provides information about the context and function of an image for people with varying degrees of visual and cognitive impairments. When a screen reader encounters an image, it will read aloud the alternative text.\nhttps://www.med.unc.edu/webguide/accessibility/alt-text/',
- },
- highContrast: {
- message: 'Includes high contrast text for learners with low vision',
- context:
- "Accessibility filter used to search for resources that have high contrast color themes for users with low vision ('display' refers to digital content, not the hardware like screens or monitors).\nhttps://veroniiiica.com/2019/10/25/high-contrast-color-schemes-low-vision/",
- },
- captionsSubtitles: {
- message: 'Includes captions or subtitles',
- context:
- 'Accessibility filter to search for video and audio resources that have text captions for users who are deaf or hard of hearing.\nhttps://www.w3.org/WAI/media/av/captions/',
- },
-
- // Used to categorize the level or audience of content
- // ContentLevels
- level: {
- message: 'Level',
- context: 'Refers to the educational learning level, such a preschool, primary, secondary, etc.',
- },
- preschool: {
- message: 'Preschool',
- context:
- 'Refers to a level of education offered to children before they begin compulsory education at primary school.\n\nSee https://en.wikipedia.org/wiki/Preschool',
- },
- lowerPrimary: {
- message: 'Lower primary',
- context:
- 'Refers to a level of learning. Approximately corresponds to the first half of primary school.',
- },
- upperPrimary: {
- message: 'Upper primary',
- context:
- 'Refers to a level of education. Approximately corresponds to the second half of primary school.\n',
- },
- lowerSecondary: {
- message: 'Lower secondary',
- context:
- 'Refers to a level of learning. Approximately corresponds to the first half of secondary school (high school).',
- },
- upperSecondary: {
- message: 'Upper secondary',
- context:
- 'Refers to a level of education. Approximately corresponds to the second half of secondary school.',
- },
- tertiary: {
- message: 'Tertiary',
- context: 'A level of education. See https://en.wikipedia.org/wiki/Tertiary_education',
- },
- specializedProfessionalTraining: {
- message: 'Specialized professional training',
- context: 'Level of education that refers to training for a profession (job).',
- },
- allLevelsBasicSkills: {
- message: 'All levels -- basic skills',
- context: 'Refers to a type of educational level.',
- },
- allLevelsWorkSkills: {
- message: 'All levels -- work skills',
- context: 'Refers to a type of educational level.',
- },
-
- browseChannel: {
- message: 'Browse channel',
- context: 'Heading on page where a user can browse the content within a channel',
- },
- topicLabel: {
- message: 'Folder',
- context:
- 'A collection of resources and other subfolders within a channel. Nested folders allow a channel to be organized as a tree or hierarchy.',
- },
- readReference: {
- message: 'Reference',
- context:
- "Label displayed for the 'Read' learning activity, used instead of the time duration information, to indicate a resource that may not need sequential reading from the beginning to the end. Similar concept as the 'reference' books in the traditional library, that the user just 'consults', and does not read from cover to cover.",
- },
- shortActivity: {
- message: 'Short activity',
- context: 'Label with time estimation for learning activities that take less than 30 minutes.',
- },
- longActivity: {
- message: 'Long activity',
- context: 'Label with time estimation for learning activities that take more than 30 minutes.',
- },
-});
+// METADATA MIXIN
export const metadataTranslationMixin = {
methods: {
translateMetadataString(key) {
- const camelKey = camelCase(key);
- if (nonconformingKeys[key]) {
- key = nonconformingKeys[key];
- } else if (nonconformingKeys[camelKey]) {
- key = nonconformingKeys[camelKey];
- } else if (
- !metadataStrings._defaultMessages[key] &&
- metadataStrings._defaultMessages[camelKey]
- ) {
- key = camelKey;
- }
- return metadataStrings.$tr(key);
+ return translateMetadataString(key);
},
},
};
-/**
- * An object mapping ad hoc keys (like those to be passed to CommonMetadataStrings()) which do not
- * conform to the expectations. Examples:
- *
- * - Misspelling of the key in CommonMetadataStrings but a kolibri-constant used to access it is
- * spelled correctly and will not map.
- * - Keys were defined and string-froze which are not camelCase.
- * - Keys which, when _.camelCase()'ed will not result in a valid key, requiring manual mapping
- */
-const nonconformingKeys = {
- PAPER_PENCIL: 'toUseWithPaperAndPencil',
- PEERS: 'peers',
- TEACHER: 'teacher',
- INTERNET: 'needsInternet',
- BASIC_SKILLS: 'allLevelsBasicSkills',
- FOUNDATIONS: 'basicSkills',
- foundationsLogicAndCriticalThinking: 'logicAndCriticalThinking',
- toolsAndSoftwareTraining: 'softwareToolsAndTraining',
- foundations: 'basicSkills',
- OTHER_SUPPLIES: 'needsMaterials',
- SPECIAL_SOFTWARE: 'softwareTools',
- PROFESSIONAL: 'specializedProfessionalTraining',
- WORK_SKILLS: 'allLevelsWorkSkills',
-};
-
/**
* jayoshih: using a mixin to handle this to handle the translations
* and handle cases where user opens page at a component
diff --git a/contentcuration/contentcuration/frontend/shared/strings/communityChannelsStrings.js b/contentcuration/contentcuration/frontend/shared/strings/communityChannelsStrings.js
index e9488d7099..43762612be 100644
--- a/contentcuration/contentcuration/frontend/shared/strings/communityChannelsStrings.js
+++ b/contentcuration/contentcuration/frontend/shared/strings/communityChannelsStrings.js
@@ -69,4 +69,124 @@ export const communityChannelsStrings = createTranslator('CommunityChannelsStrin
message: 'Language is required',
context: 'Error message when language selection is required',
},
+ pendingStatus: {
+ message: 'Pending',
+ context: 'Status indicating that an Community Library submission is pending',
+ },
+ approvedStatus: {
+ message: 'Approved',
+ context: 'Status indicating that an Community Library submission is approved',
+ },
+ flaggedStatus: {
+ message: 'Flagged',
+ context: 'Status indicating that an Community Library submission is rejected',
+ },
+ // Submit to Community Library panel strings
+ submitToCommunityLibrary: {
+ message: 'Submit to Community Library',
+ context: 'The title of the "Submit to Community Library" panel',
+ },
+ submittedPrimaryInfo: {
+ message: 'A previous version is still pending review.',
+ context:
+ 'Information shown in the "Submit to Community Library" panel when a previous version is pending review',
+ },
+ reviewersWillSeeLatestFirst: {
+ message: 'Reviewers will see the latest submission first.',
+ context:
+ 'Information shown in the "Submit to Community Library" panel about how reviewers see submissions',
+ },
+ approvedPrimaryInfo: {
+ message: 'A previous version is live in the Community Library.',
+ context:
+ 'Information shown in the "Submit to Community Library" panel when a previous version is approved and live',
+ },
+ flaggedPrimaryInfo: {
+ message:
+ 'A previous version was flagged for review. Ensure you have fixed all highlighted issues before submitting.',
+ context:
+ 'Information shown in the "Submit to Community Library" panel when a previous version was flagged',
+ },
+ nonePrimaryInfo: {
+ message: 'Your published channel will be added to the Community Library review queue.',
+ context:
+ 'Information shown in the "Submit to Community Library" panel when there are no previous submissions',
+ },
+ moreDetailsButton: {
+ message: 'More details about the Community Library',
+ context:
+ 'Button in the "Submit to Community Library" panel to show more details about the Community Library',
+ },
+ lessDetailsButton: {
+ message: 'Show less',
+ context:
+ 'Button in the "Submit to Community Library" panel to hide details about the Community Library',
+ },
+ moreDetails: {
+ message:
+ "The Kolibri Community Library features channels created by the community. Share your openly licensed work for review, and once it's approved, it will be available to users in your selected region or language.",
+ context:
+ 'Detailed description of the Community Library shown in the "Submit to Community Library" panel',
+ },
+ notPublishedWarning: {
+ message:
+ "This channel isn't published to Kolibri Studio yet. Publish first, then submit to the Community Library.",
+ context:
+ 'Warning shown in the "Submit to Community Library" panel when the channel is not published',
+ },
+ publicWarning: {
+ message:
+ 'This channel is currently public in the Content Library. It is not possible to submit public channels to the Community Library.',
+ context: 'Warning shown in the "Submit to Community Library" panel when the channel is public',
+ },
+ alreadySubmittedWarning: {
+ message:
+ 'This version of the channel has already been submitted to the Community Library. Please wait for review or make changes and publish a new version before submitting again.',
+ context:
+ 'Warning shown in the "Submit to Community Library" panel when the current version of the channel is already submitted',
+ },
+ descriptionLabel: {
+ message: "Describe what's new in this submission",
+ context:
+ 'Label for the submission description field in the "Submit to Community Library" panel',
+ },
+ descriptionRequired: {
+ message: 'Description is required',
+ context:
+ 'Error message shown in the "Submit to Community Library" panel when description is required but empty',
+ },
+ submitButton: {
+ message: 'Submit for review',
+ context: 'Button in the "Submit to Community Library" panel to submit channel for review',
+ },
+ submittingSnackbar: {
+ message: 'Submitting channel to Community Library...',
+ context: 'Snackbar message shown while submitting from the "Submit to Community Library" panel',
+ },
+ submittedSnackbar: {
+ message: 'Channel submitted to Community Library',
+ context:
+ 'Snackbar message shown after successful submission from the "Submit to Community Library" panel',
+ },
+ errorSnackbar: {
+ message: 'There was an error submitting the channel',
+ context:
+ 'Snackbar message shown when submission fails from the "Submit to Community Library" panel',
+ },
+ countryLabel: {
+ message: 'Country',
+ context: 'Label for the country selection field in the "Submit to Community Library" panel',
+ },
+ languagesDetected: {
+ message: 'Language(s) detected',
+ context: 'Label for detected languages in the "Submit to Community Library" panel',
+ },
+ licensesDetected: {
+ message: 'License(s) detected',
+ context: 'Label for detected licenses in the "Submit to Community Library" panel',
+ },
+ categoriesDetected: {
+ message: 'Categories',
+ context: 'Label for detected categories in the "Submit to Community Library" panel',
+ },
});
diff --git a/contentcuration/contentcuration/frontend/shared/strings/metadataStrings.js b/contentcuration/contentcuration/frontend/shared/strings/metadataStrings.js
new file mode 100644
index 0000000000..8b1ee9ae58
--- /dev/null
+++ b/contentcuration/contentcuration/frontend/shared/strings/metadataStrings.js
@@ -0,0 +1,509 @@
+import { createTranslator } from 'shared/i18n';
+
+export const metadataStrings = createTranslator('CommonMetadataStrings', {
+ // Titles/Headers
+
+ learningActivity: {
+ message: 'Learning Activity',
+ context: 'A title for the category of education material interaction, i.e. watch, read, listen',
+ },
+ completion: {
+ message: 'Completion',
+ context: 'A title for the metadata that explains when an activity is finished',
+ },
+ duration: {
+ message: 'Duration',
+ context: 'A title for the metadata that explains how long an activity will take',
+ },
+ category: {
+ message: 'Category',
+ context: 'A title for the metadata that explains the subject matter of an activity',
+ },
+ // Completion criteria types
+ reference: {
+ message: 'Reference material',
+ context:
+ 'One of the completion criteria types. Progress made on a resource with this criteria is not tracked.',
+ },
+ completeDuration: {
+ message: 'When time spent is equal to duration',
+ context:
+ 'One of the completion criteria types. A resource with this criteria is considered complete when learners spent given time studying it.',
+ },
+ exactTime: {
+ message: 'Time to complete',
+ context:
+ 'One of the completion criteria types. A subset of "When time spent is equal to duration". For example, for an audio resource with this criteria, learnes need to hear the whole length of audio for the resource to be considered complete.',
+ },
+ allContent: {
+ message: 'Viewed in its entirety',
+ context:
+ 'One of the completion criteria types. A resource with this criteria is considered complete when learners studied it all, for example they saw all pages of a document.',
+ },
+ determinedByResource: {
+ message: 'Determined by the resource',
+ context:
+ 'One of the completion criteria types. Typically used for embedded html5/h5p resources that contain their own completion criteria, for example reaching a score in an educational game.',
+ },
+ masteryMofN: {
+ message: 'Goal: {m} out of {n}',
+ context:
+ 'One of the completion criteria types specific to exercises. An exercise with this criteria is considered complete when learners answered m questions out of n correctly.',
+ },
+ goal: {
+ message: 'When goal is met',
+ context:
+ 'One of the completion criteria types specific to exercises. An exercise with this criteria is considered complete when learners reached a given goal, for example 100% correct.',
+ },
+ practiceQuiz: {
+ message: 'Practice quiz',
+ context:
+ 'One of the completion criteria types specific to exercises. An exercise with this criteria represents a quiz.',
+ },
+ survey: {
+ message: 'Survey',
+ context:
+ 'One of the completion criteria types specific to exercises. An exercise with this criteria represents a survey.',
+ },
+
+ // Learning Activities
+ all: {
+ message: 'All',
+ context: 'A label for everything in the group of activities.',
+ },
+ watch: {
+ message: 'Watch',
+ context:
+ 'Resource and filter label for the type of learning activity with video. Translate as a VERB',
+ },
+ create: {
+ message: 'Create',
+ context: 'Resource and filter label for the type of learning activity. Translate as a VERB',
+ },
+ read: {
+ message: 'Read',
+ context:
+ 'Resource and filter label for the type of learning activity with documents. Translate as a VERB',
+ },
+ practice: {
+ message: 'Practice',
+ context:
+ 'Resource and filter label for the type of learning activity with questions and answers. Translate as a VERB',
+ },
+ reflect: {
+ message: 'Reflect',
+ context: 'Resource and filter label for the type of learning activity. Translate as a VERB',
+ },
+ listen: {
+ message: 'Listen',
+ context:
+ 'Resource and filter label for the type of learning activity with audio. Translate as a VERB',
+ },
+ explore: {
+ message: 'Explore',
+ context: 'Resource and filter label for the type of learning activity. Translate as a VERB',
+ },
+
+ // Library Categories
+ school: {
+ message: 'School',
+ context: 'Category type.',
+ },
+ basicSkills: {
+ message: 'Basic skills',
+ context:
+ 'Category type. Basic skills refer to learning resources focused on aspects like literacy, numeracy and digital literacy.',
+ },
+ work: {
+ message: 'Work',
+ context:
+ 'Top level category group that contains resources for acquisition of professional skills.',
+ },
+ dailyLife: {
+ message: 'Daily life',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Everyday_life',
+ },
+ forTeachers: {
+ message: 'For teachers',
+ context: 'Category type',
+ },
+
+ // School Categories
+ mathematics: {
+ message: 'Mathematics',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Mathematics',
+ },
+ sciences: {
+ message: 'Sciences',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Science',
+ },
+ socialSciences: {
+ message: 'Social sciences',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Social_science',
+ },
+ arts: {
+ message: 'Arts',
+ context: 'Refers to a category group type. See https://en.wikipedia.org/wiki/The_arts',
+ },
+ computerScience: {
+ message: 'Computer science',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Computer_science',
+ },
+ languageLearning: {
+ message: 'Language learning',
+ context: 'Category type.',
+ },
+ history: {
+ message: 'History',
+ context: 'Category type.',
+ },
+ readingAndWriting: {
+ message: 'Reading and writing',
+ context: 'School subject category',
+ },
+
+ // Mathematics Subcategories
+ arithmetic: {
+ message: 'Arithmetic',
+ context: 'Math category type. See https://en.wikipedia.org/wiki/Arithmetic',
+ },
+ algebra: {
+ message: 'Algebra',
+ context: 'A type of math category. See https://en.wikipedia.org/wiki/Algebra',
+ },
+ geometry: {
+ message: 'Geometry',
+ context: 'Category type.',
+ },
+ calculus: {
+ message: 'Calculus',
+ context: 'Math category type. https://en.wikipedia.org/wiki/Calculus',
+ },
+ statistics: {
+ message: 'Statistics',
+ context: 'A math category. See https://en.wikipedia.org/wiki/Statistics',
+ },
+
+ // Sciences Subcategories
+ biology: {
+ message: 'Biology',
+ context: 'Science category type. See https://en.wikipedia.org/wiki/Biology',
+ },
+ chemistry: {
+ message: 'Chemistry',
+ context: 'Science category type. See https://en.wikipedia.org/wiki/Chemistry',
+ },
+ physics: {
+ message: 'Physics',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Physics.',
+ },
+ earthScience: {
+ message: 'Earth science',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Earth_science',
+ },
+ astronomy: {
+ message: 'Astronomy',
+ context: 'Science category type. See https://en.wikipedia.org/wiki/Astronomy',
+ },
+
+ // Literature Subcategories
+ literature: {
+ message: 'Literature',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Literature',
+ },
+ readingComprehension: {
+ message: 'Reading comprehension',
+ context: 'Category type.',
+ },
+ writing: {
+ message: 'Writing',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Writing',
+ },
+ logicAndCriticalThinking: {
+ message: 'Logic and critical thinking',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Critical_thinking',
+ },
+
+ // Social Sciences Subcategories
+ politicalScience: {
+ message: 'Political science',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Political_science.',
+ },
+ sociology: {
+ message: 'Sociology',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Sociology',
+ },
+ anthropology: {
+ message: 'Anthropology',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Anthropology',
+ },
+ civicEducation: {
+ message: 'Civic education',
+ context:
+ 'Category type. Civic education is the study of the rights and obligations of citizens in society. See https://en.wikipedia.org/wiki/Civics',
+ },
+
+ // Arts Subcategories = {
+ visualArt: {
+ message: 'Visual art',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Visual_arts',
+ },
+ music: {
+ message: 'Music',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Music',
+ },
+ dance: {
+ message: 'Dance',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Dance',
+ },
+ drama: {
+ message: 'Drama',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Drama',
+ },
+
+ // Computer Science Subcategories
+ programming: {
+ message: 'Programming',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Computer_programming',
+ },
+ mechanicalEngineering: {
+ message: 'Mechanical engineering',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Mechanical_engineering.',
+ },
+ webDesign: {
+ message: 'Web design',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Web_design',
+ },
+
+ // Basic Skills
+ literacy: {
+ message: 'Literacy',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Literacy',
+ },
+ numeracy: {
+ message: 'Numeracy',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Numeracy',
+ },
+ digitalLiteracy: {
+ message: 'Digital literacy',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Digital_literacy',
+ },
+ learningSkills: {
+ message: 'Learning skills',
+ context:
+ 'A category label and type of basic skill.\nhttps://en.wikipedia.org/wiki/Study_skills',
+ },
+
+ // Work Categories
+ professionalSkills: {
+ message: 'Professional skills',
+ context: 'Category type. Refers to skills that are related to a profession or a job.',
+ },
+ technicalAndVocationalTraining: {
+ message: 'Technical and vocational training',
+ context:
+ 'A level of education. See https://en.wikipedia.org/wiki/TVET_(Technical_and_Vocational_Education_and_Training)',
+ },
+
+ // VocationalSubcategories
+ softwareToolsAndTraining: {
+ message: 'Software tools and training',
+ context: 'Subcategory type for technical and vocational training.',
+ },
+ skillsTraining: {
+ message: 'Skills training',
+ context: 'Subcategory type for technical and vocational training.',
+ },
+ industryAndSectorSpecific: {
+ message: 'Industry and sector specific',
+ context: 'Subcategory type for technical and vocational training.',
+ },
+
+ // Daily Life Categories
+ publicHealth: {
+ message: 'Public health',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Public_health.',
+ },
+ entrepreneurship: {
+ message: 'Entrepreneurship',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Entrepreneurship',
+ },
+ financialLiteracy: {
+ message: 'Financial literacy',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Financial_literacy',
+ },
+ currentEvents: {
+ message: 'Current events',
+ context:
+ "Category type. Could also be translated as 'News'. See https://en.wikipedia.org/wiki/News",
+ },
+ environment: {
+ message: 'Environment',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Environmental_studies',
+ },
+ mediaLiteracy: {
+ message: 'Media literacy',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Media_literacy',
+ },
+ diversity: {
+ message: 'Diversity',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Diversity_(politics)',
+ },
+ mentalHealth: {
+ message: 'Mental health',
+ context: 'Category type. See https://en.wikipedia.org/wiki/Mental_health',
+ },
+
+ // Teacher-Specific Categories
+ guides: {
+ message: 'Guides',
+ context:
+ 'Category label in the Kolibri resources library; refers to any guide-type material for teacher professional development.',
+ },
+ lessonPlans: {
+ message: 'Lesson plans',
+ context:
+ 'Category label in the Kolibri resources library; refers to lesson planning materials for teachers.',
+ },
+
+ // Resources Needed Categories = {
+ forBeginners: {
+ message: 'For beginners',
+ context: 'Filter option and a label for the resources in the Kolibri Library.',
+ },
+ toUseWithPaperAndPencil: {
+ message: 'Paper and pencil',
+ context: 'Refers to a filter for resources.\n',
+ },
+ needsInternet: {
+ message: 'Internet connection',
+ context: 'Refers to a filter for resources.',
+ },
+ needsMaterials: {
+ message: 'Other supplies',
+ context: 'Refers to a filter for resources.\n',
+ },
+ softwareTools: {
+ message: 'Other software tools',
+ context: 'Refers to a filter for resources that need additional software to be used.',
+ },
+ peers: {
+ message: 'Working with peers',
+ context:
+ 'Refers to a filter for resources that require a learner to work with other learners to be used.',
+ },
+ teacher: {
+ message: 'Working with a teacher',
+ context:
+ 'Refers to a filter for resources that require a learner to work with a teacher to be used.',
+ },
+
+ // Accessibility category name
+ accessibility: {
+ message: 'Accessibility',
+ context:
+ 'Allows the user to filter for all the resources with accessibility features for learners with disabilities.',
+ },
+ // Accessibility Categories
+ signLanguage: {
+ message: 'Includes sign language captions',
+ context:
+ 'https://en.wikipedia.org/wiki/Sign_language\nhttps://en.wikipedia.org/wiki/List_of_sign_languages\nWherever communities of deaf people exist, sign languages have developed as useful means of communication, and they form the core of local Deaf cultures. Although signing is used primarily by the deaf and hard of hearing, it is also used by hearing individuals, such as those unable to physically speak, those who have trouble with spoken language due to a disability or condition (augmentative and alternative communication), or those with deaf family members, such as children of deaf adults. ',
+ },
+ audioDescription: {
+ message: 'Includes audio descriptions',
+ context:
+ 'Content has narration used to provide information surrounding key visual elements for the benefit of blind and visually impaired users.\nhttps://en.wikipedia.org/wiki/Audio_description',
+ },
+ taggedPdf: {
+ message: 'Tagged PDF',
+ context:
+ 'A tagged PDF includes hidden accessibility markups (tags) that make the document accessible to those who use screen readers and other assistive technology (AT).\n\nhttps://taggedpdf.com/what-is-a-tagged-pdf/',
+ },
+ altText: {
+ message: 'Includes alternative text descriptions for images',
+ context:
+ 'Alternative text, or alt text, is a written substitute for an image. It is used to describe information being provided by an image, graph, or any other visual element on a web page. It provides information about the context and function of an image for people with varying degrees of visual and cognitive impairments. When a screen reader encounters an image, it will read aloud the alternative text.\nhttps://www.med.unc.edu/webguide/accessibility/alt-text/',
+ },
+ highContrast: {
+ message: 'Includes high contrast text for learners with low vision',
+ context:
+ "Accessibility filter used to search for resources that have high contrast color themes for users with low vision ('display' refers to digital content, not the hardware like screens or monitors).\nhttps://veroniiiica.com/2019/10/25/high-contrast-color-schemes-low-vision/",
+ },
+ captionsSubtitles: {
+ message: 'Includes captions or subtitles',
+ context:
+ 'Accessibility filter to search for video and audio resources that have text captions for users who are deaf or hard of hearing.\nhttps://www.w3.org/WAI/media/av/captions/',
+ },
+
+ // Used to categorize the level or audience of content
+ // ContentLevels
+ level: {
+ message: 'Level',
+ context: 'Refers to the educational learning level, such a preschool, primary, secondary, etc.',
+ },
+ preschool: {
+ message: 'Preschool',
+ context:
+ 'Refers to a level of education offered to children before they begin compulsory education at primary school.\n\nSee https://en.wikipedia.org/wiki/Preschool',
+ },
+ lowerPrimary: {
+ message: 'Lower primary',
+ context:
+ 'Refers to a level of learning. Approximately corresponds to the first half of primary school.',
+ },
+ upperPrimary: {
+ message: 'Upper primary',
+ context:
+ 'Refers to a level of education. Approximately corresponds to the second half of primary school.\n',
+ },
+ lowerSecondary: {
+ message: 'Lower secondary',
+ context:
+ 'Refers to a level of learning. Approximately corresponds to the first half of secondary school (high school).',
+ },
+ upperSecondary: {
+ message: 'Upper secondary',
+ context:
+ 'Refers to a level of education. Approximately corresponds to the second half of secondary school.',
+ },
+ tertiary: {
+ message: 'Tertiary',
+ context: 'A level of education. See https://en.wikipedia.org/wiki/Tertiary_education',
+ },
+ specializedProfessionalTraining: {
+ message: 'Specialized professional training',
+ context: 'Level of education that refers to training for a profession (job).',
+ },
+ allLevelsBasicSkills: {
+ message: 'All levels -- basic skills',
+ context: 'Refers to a type of educational level.',
+ },
+ allLevelsWorkSkills: {
+ message: 'All levels -- work skills',
+ context: 'Refers to a type of educational level.',
+ },
+
+ browseChannel: {
+ message: 'Browse channel',
+ context: 'Heading on page where a user can browse the content within a channel',
+ },
+ topicLabel: {
+ message: 'Folder',
+ context:
+ 'A collection of resources and other subfolders within a channel. Nested folders allow a channel to be organized as a tree or hierarchy.',
+ },
+ readReference: {
+ message: 'Reference',
+ context:
+ "Label displayed for the 'Read' learning activity, used instead of the time duration information, to indicate a resource that may not need sequential reading from the beginning to the end. Similar concept as the 'reference' books in the traditional library, that the user just 'consults', and does not read from cover to cover.",
+ },
+ shortActivity: {
+ message: 'Short activity',
+ context: 'Label with time estimation for learning activities that take less than 30 minutes.',
+ },
+ longActivity: {
+ message: 'Long activity',
+ context: 'Label with time estimation for learning activities that take more than 30 minutes.',
+ },
+});
diff --git a/contentcuration/contentcuration/frontend/shared/utils/countries.js b/contentcuration/contentcuration/frontend/shared/utils/countries.js
new file mode 100644
index 0000000000..34ee48dc51
--- /dev/null
+++ b/contentcuration/contentcuration/frontend/shared/utils/countries.js
@@ -0,0 +1,11 @@
+// NOTE that this list MUST stay in sync with the list of countries
+// generated on the backend in contentcuration/management/commands/loadconstants.py,
+// and special care should be taken when updating the i18n-iso-countries library.
+const countries = require('i18n-iso-countries');
+countries.registerLocale(require('i18n-iso-countries/langs/en.json'));
+countries.registerLocale(require('i18n-iso-countries/langs/es.json'));
+countries.registerLocale(require('i18n-iso-countries/langs/ar.json'));
+countries.registerLocale(require('i18n-iso-countries/langs/fr.json'));
+countries.registerLocale(require('i18n-iso-countries/langs/pt.json'));
+
+export default countries;
diff --git a/contentcuration/contentcuration/frontend/shared/utils/metadataStringsTranslation.js b/contentcuration/contentcuration/frontend/shared/utils/metadataStringsTranslation.js
new file mode 100644
index 0000000000..d755334623
--- /dev/null
+++ b/contentcuration/contentcuration/frontend/shared/utils/metadataStringsTranslation.js
@@ -0,0 +1,40 @@
+import camelCase from 'lodash/camelCase';
+
+import { metadataStrings } from 'shared/strings/metadataStrings';
+
+/**
+ * An object mapping ad hoc keys (like those to be passed to CommonMetadataStrings()) which do not
+ * conform to the expectations. Examples:
+ *
+ * - Misspelling of the key in CommonMetadataStrings but a kolibri-constant used to access it is
+ * spelled correctly and will not map.
+ * - Keys were defined and string-froze which are not camelCase.
+ * - Keys which, when _.camelCase()'ed will not result in a valid key, requiring manual mapping
+ */
+const nonconformingKeys = {
+ PAPER_PENCIL: 'toUseWithPaperAndPencil',
+ PEERS: 'peers',
+ TEACHER: 'teacher',
+ INTERNET: 'needsInternet',
+ BASIC_SKILLS: 'allLevelsBasicSkills',
+ FOUNDATIONS: 'basicSkills',
+ foundationsLogicAndCriticalThinking: 'logicAndCriticalThinking',
+ toolsAndSoftwareTraining: 'softwareToolsAndTraining',
+ foundations: 'basicSkills',
+ OTHER_SUPPLIES: 'needsMaterials',
+ SPECIAL_SOFTWARE: 'softwareTools',
+ PROFESSIONAL: 'specializedProfessionalTraining',
+ WORK_SKILLS: 'allLevelsWorkSkills',
+};
+
+export function translateMetadataString(key) {
+ const camelKey = camelCase(key);
+ if (nonconformingKeys[key]) {
+ key = nonconformingKeys[key];
+ } else if (nonconformingKeys[camelKey]) {
+ key = nonconformingKeys[camelKey];
+ } else if (!metadataStrings._defaultMessages[key] && metadataStrings._defaultMessages[camelKey]) {
+ key = camelKey;
+ }
+ return metadataStrings.$tr(key);
+}
diff --git a/contentcuration/contentcuration/frontend/shared/views/contentNodeFields/CompletionOptions/index.vue b/contentcuration/contentcuration/frontend/shared/views/contentNodeFields/CompletionOptions/index.vue
index c4ba819651..b3260130ec 100644
--- a/contentcuration/contentcuration/frontend/shared/views/contentNodeFields/CompletionOptions/index.vue
+++ b/contentcuration/contentcuration/frontend/shared/views/contentNodeFields/CompletionOptions/index.vue
@@ -131,7 +131,8 @@
getDurationValidators,
translateValidator,
} from 'shared/utils/validation';
- import { metadataStrings, metadataTranslationMixin } from 'shared/mixins';
+ import { metadataTranslationMixin } from 'shared/mixins';
+ import { metadataStrings } from 'shared/strings/metadataStrings';
import ExpandableSelect from 'shared/views/form/ExpandableSelect';
const DEFAULT_SHORT_ACTIVITY = 600;
diff --git a/contentcuration/contentcuration/frontend/shared/views/form/CountryField.vue b/contentcuration/contentcuration/frontend/shared/views/form/CountryField.vue
index 8254a4f8bb..13d8f1f0d5 100644
--- a/contentcuration/contentcuration/frontend/shared/views/form/CountryField.vue
+++ b/contentcuration/contentcuration/frontend/shared/views/form/CountryField.vue
@@ -28,17 +28,9 @@