add support for catalan (CA) locale

fixes FOO-519
flag  = none

   \__/
   (xx)
  //||\\
   test
    plan

- rebuild assets & run rails and webpack with RAILS_LOAD_ALL_LOCALES=1
- switch your language to Catalan / CA
- verify it looks OK generally
- go to new assignment and verify the date picker works OK: try
  selecting specific days, hours/minutes, and typing[1]
- again in new assignment, verify we're formatting the numbers as
  expected (XXX.YYY,ZZ) by punching a large number into "Points"
- go to calendar and verify the month names look OK
- go to the RCE somewhere and verify everything is localized
- find places where it appears to be broken...

Change-Id: Iad5e9a40a8b099b0cb5ae687e96b0cf0ddc2a1b7
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/243131
Reviewed-by: August Thornton <august@instructure.com>
Reviewed-by: Simon Williams <simon@instructure.com>
QA-Review: August Thornton <august@instructure.com>
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Product-Review: Ahmad Amireh <ahmad@instructure.com>
This commit is contained in:
Jacob Burroughs 2020-07-21 16:12:18 -05:00 committed by Ahmad Amireh
parent 4ef0746ece
commit eabb8c5ada
11 changed files with 293 additions and 5 deletions

View File

@ -43,7 +43,7 @@ import htmlEscape from 'str/htmlEscape'
import calendarEventFilter from './CalendarEventFilter'
import schedulerActions from 'jsx/calendar/scheduler/actions'
import 'fullcalendar'
import 'fullcalendar/dist/lang-all'
import 'fullcalendar_locales'
import 'jsx/calendar/patches-to-fullcalendar'
import 'jquery.instructure_misc_helpers'
import 'jquery.instructure_misc_plugins'

View File

@ -41,6 +41,27 @@ ar:
formats:
tiny: "%k:%M"
tiny_on_the_hour: "%k:%M"
ca:
bigeasy_locale: ca_ES
dow_offset: 1
locales:
ca: Català
date:
formats:
default: '%d/%m/%Y'
number:
currency:
format:
delimiter: "."
separator: ","
format:
delimiter: "."
separator: ","
helpers:
accessible_date_only_format: "DD/MM/YYYY"
accessible_date_format: "DD/MM/YYYY hh:mm"
# this is for accessibleDateFormat.js
yyyy_mm_dd_hh_mm_a01b6081: "DD/MM/YYYY hh:mm"
cy:
locales:
cy: Cymraeg

View File

@ -20,7 +20,7 @@ const glob = require('glob')
const path = require('path')
// Put any custom moment locales here:
const customMomentLocales = ['de', 'fa', 'fr', 'fr-ca', 'he', 'ht-ht', 'hy-am', 'mi-nz', 'pl', 'sl']
const customMomentLocales = ['ca', 'de', 'fa', 'fr', 'fr-ca', 'he', 'ht-ht', 'hy-am', 'mi-nz', 'pl', 'sl']
const momentLocaleBundles = glob
.sync('moment/locale/**/*.js', {cwd: 'node_modules'})

View File

@ -44,6 +44,7 @@ gulp.task('rev', () => {
'rfc822.js',
'synopsis.js',
'zones.js',
'ca_ES.js',
'de_DE.js',
'fr_FR.js',
'fr_CA.js',

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2018 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import formatMessage from '../format-message'
import locale from '@instructure/translations/lib/canvas-rce/ca.json'
import '../rce/languages/ca'
formatMessage.addLocale({ca: locale})

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2020 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import I18n from 'i18nObj'
import moment from 'moment';
const lookupInCA = phrase => I18n.lookup(phrase, { locale: 'ca' })
// some lists in ca.yml start with a blank item, we don't want it here:
const withoutLeadingBlank = (x,i) => i === 0 ? (x && x.length) : true;
const apply = () => {
// keep track of it to restore it later because defineLocale() appears to also
// activate it...
const origLocale = moment.locale()
// uses 'node_modules/moment/locale/ca.js' as a reference
moment.defineLocale('ca', {
months: {
standalone: lookupInCA('date.month_names').filter(withoutLeadingBlank),
format: [
'de Gener',
'de Febrer',
'de Març',
'd\'Abril',
'de Maig',
'de Juny',
'de Juliol',
'd\'Agost',
'de Setembre',
'd\'Octubre',
'de Novembre',
'de Desembre',
],
isFormat: /D[oD]?(\s)+MMMM/
},
monthsShort: lookupInCA('date.abbr_month_names').filter(withoutLeadingBlank),
monthsParseExact: true,
weekdays: lookupInCA('date.day_names'),
weekdaysShort: lookupInCA('date.abbr_day_names'),
weekdaysMin: lookupInCA('date.datepicker.column_headings'),
weekdaysParseExact: true,
longDateFormat: {
LT: 'H:mm',
LTS: 'H:mm:ss',
L: 'DD/MM/YYYY',
LL: 'D MMMM [de] YYYY',
ll: 'D MMM YYYY',
LLL: 'D MMMM [de] YYYY [a les] H:mm',
lll: 'D MMM YYYY, H:mm',
LLLL: 'dddd D MMMM [de] YYYY [a les] H:mm',
llll: 'ddd D MMM YYYY, H:mm'
},
calendar: {
sameDay: function () {
return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
},
nextDay: function () {
return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
},
nextWeek: function () {
return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
},
lastDay: function () {
return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
},
lastWeek: function () {
return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';
},
sameElse: 'L'
},
relativeTime: {
future: 'd\'aquí %s',
past: 'fa %s',
s: 'uns segons',
ss: '%d segons',
m: 'un minut',
mm: '%d minuts',
h: 'una hora',
hh: '%d hores',
d: 'un dia',
dd: '%d dies',
M: 'un mes',
MM: '%d mesos',
y: 'un any',
yy: '%d anys'
},
dayOfMonthOrdinalParse: /\d{1,2}(r|n|t|è|a)/,
ordinal: function (number, period) {
var output = (number === 1) ? 'r' :
(number === 2) ? 'n' :
(number === 3) ? 'r' :
(number === 4) ? 't' : 'è'
;
if (period === 'w' || period === 'W') {
output = 'a';
}
return number + output;
},
week: {
dow: 1, // Monday is the first day of the week.
doy: 4 // The week that contains Jan 4th is the first week of the year.
}
});
moment.locale(origLocale)
}
apply();
export default apply;

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2019 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module.exports = {
"name": "ca_ES",
"day": {
"abbrev": [
"Dg.",
"Dl.",
"Dt.",
"Dc.",
"Dj.",
"Dv.",
"Ds.",
],
"full": [
"Diumenge",
"Dilluns",
"Dimarts",
"Dimecres",
"Dijous",
"Divendres",
"Dissabte",
],
},
"month": {
"abbrev": [
"Gen.",
"Febr.",
"Març",
"Abr.",
"Maig",
"Juny",
"Jul.",
"Ag.",
"Set.",
"Oct.",
"Nov.",
"Des.",
],
"full": [
"Gener",
"Febrer",
"Març",
"Abril",
"Maig",
"Juny",
"Juliol",
"Agost",
"Setembre",
"Octubre",
"Novembre",
"Desembre",
],
},
"meridiem": [
"",
""
],
"date": "%d/%m/%Y", // date.formats.default
"time24": "%T",
"dateTime": "%-d de %b a les %l:%M%P", // date.formats.date_at_time
"time12": "",
"full": "%-d de %b, %Y %-l:%M%P", // date.formats.full
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2020 - present Instructure, Inc.
*
* This file is part of Canvas.
*
* Canvas is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3 of the License.
*
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'fullcalendar'
import 'fullcalendar/dist/lang-all'
// fullcalendar's locale bundle configures moment's locales too and overrides
// ours..
//
// Since such a workaround did not exist prior to introducing the Catalan
// language support, I'm assuming it's not affecting other languages. If that
// turns out not to be the case, though, either extend this or revisit the
// whole approach (e.g. import fullcalendar's locales earlier in the build)
import reconfigureMomentCALocale from 'custom_moment_locales/ca'
reconfigureMomentCALocale()

View File

@ -51,7 +51,7 @@ I18n.locale = document.documentElement.getAttribute('lang')
I18n.lookup = function(scope, options = {}) {
const translations = I18n.translations
const locales = I18n.getLocaleAndFallbacks(I18n.currentLocale())
const locales = I18n.getLocaleAndFallbacks(options.locale || I18n.currentLocale())
if (typeof scope === 'object') {
scope = scope.join(this.defaultSeparator)
}

View File

@ -98,8 +98,11 @@ $.timeString = function(date, options) {
// match ruby-side short format on the hour, e.g. `1pm`
// can't just check getMinutes, cuz not all timezone offsets are on the hour
const format =
tz.format(date, '%M') === '00' ? 'time.formats.tiny_on_the_hour' : 'time.formats.tiny'
const format = tz.hasMeridian() && tz.format(date, '%M') === '00' ? (
'time.formats.tiny_on_the_hour'
) : (
'time.formats.tiny'
)
if (typeof timezone === 'string' || timezone instanceof String) {
return tz.format(date, format, timezone) || ''

View File

@ -26,6 +26,7 @@ import 'translations/_core'
import 'translations/_core_en'
import bigeasyLocales from 'timezone/locales'
import bigeasyLocale_ca_ES from 'custom_timezone_locales/ca_ES'
import bigeasyLocale_cy_GB from 'custom_timezone_locales/cy_GB'
import bigeasyLocale_de_DE from 'custom_timezone_locales/de_DE'
import bigeasyLocale_fr_FR from 'custom_timezone_locales/fr_FR'
@ -44,6 +45,7 @@ import bigeasyLocale_tr_TR from 'custom_timezone_locales/tr_TR'
import bigeasyLocale_uk_UA from 'custom_timezone_locales/uk_UA'
import bigeasyLocale_el_GR from 'custom_timezone_locales/el_GR'
import 'custom_moment_locales/ca'
import 'custom_moment_locales/de'
import 'custom_moment_locales/he'
import 'custom_moment_locales/pl'
@ -60,6 +62,7 @@ let originalFallbacksMap
const bigeasyLocalesWithCustom = [
...bigeasyLocales,
bigeasyLocale_ca_ES,
bigeasyLocale_cy_GB,
bigeasyLocale_de_DE,
bigeasyLocale_fr_FR,