Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect language loaded for Spanish (Argentina) #5257

Closed
richarson opened this issue May 23, 2023 · 16 comments · Fixed by #5418
Closed

Incorrect language loaded for Spanish (Argentina) #5257

richarson opened this issue May 23, 2023 · 16 comments · Fixed by #5418
Labels
0. to triage Pending approval or rejection bug

Comments

@richarson
Copy link

Steps to reproduce

  1. Set language to "Spanish (Argentina)" in Personal settings
  2. Go to Calendar

Expected behavior

Entries in the Calendar shoud be in Argentinian Spanish (es_AR)

Actual behaviour

Entries appear to be in an Arabic language (ar?) instead

Calendar app version

4.3.4

CalDAV-clients used

No response

Browser

Opera 99, Firefox 113

Client operating system

Ubuntu, Fedora

Server operating system

CentOS 7.9

Web server

Apache

Database engine version

MySQL

PHP engine version

PHP 7.4

Nextcloud version

25.0.6

Updated from an older installed version or fresh install

Updated from an older version

List of activated apps

Enabled:
  - activity: 2.17.0
  - bruteforcesettings: 2.5.0
  - calendar: 4.3.4
  - circles: 25.0.0
  - cloud_federation_api: 1.8.0
  - comments: 1.15.0
  - contactsinteraction: 1.6.0
  - dashboard: 7.5.0
  - dav: 1.24.0
  - deck: 1.8.5
  - federatedfilesharing: 1.15.0
  - federation: 1.15.0
  - files: 1.20.1
  - files_pdfviewer: 2.6.0
  - files_rightclick: 1.4.0
  - files_sharing: 1.17.0
  - files_trashbin: 1.15.0
  - files_versions: 1.18.0
  - firstrunwizard: 2.14.0
  - forms: 3.3.0
  - groupfolders: 13.1.3
  - logreader: 2.10.0
  - lookup_server_connector: 1.13.0
  - nextcloud_announcements: 1.14.0
  - notes: 4.7.2
  - notifications: 2.13.1
  - oauth2: 1.13.0
  - onlyoffice: 7.8.0
  - password_policy: 1.15.0
  - photos: 2.0.1
  - privacy: 1.9.0
  - provisioning_api: 1.15.0
  - recommendations: 1.4.0
  - related_resources: 1.0.4
  - serverinfo: 1.15.0
  - settings: 1.7.0
  - sharebymail: 1.15.0
  - support: 1.8.0
  - survey_client: 1.13.0
  - systemtags: 1.15.0
  - tasks: 0.15.0
  - text: 3.6.0
  - theming: 2.0.1
  - twofactor_backupcodes: 1.14.0
  - twofactor_totp: 7.0.0
  - updatenotification: 1.15.0
  - user_status: 1.5.0
  - viewer: 1.9.0
  - weather_status: 1.5.0
  - workflowengine: 2.7.0
Disabled:
  - admin_audit
  - encryption
  - files_external
  - suspicious_login
  - user_ldap

Nextcloud configuration

{
    "system": {
        "instanceid": "***REMOVED SENSITIVE VALUE***",
        "passwordsalt": "***REMOVED SENSITIVE VALUE***",
        "secret": "***REMOVED SENSITIVE VALUE***",
        "trusted_domains": [
            "localhost",
            "***REMOVED SENSITIVE VALUE***",
            "***REMOVED SENSITIVE VALUE***",
            "***REMOVED SENSITIVE VALUE***"
        ],
        "default_language": "es_AR",
        "default_locale": "es_AR",
        "default_phone_region": "AR",
        "datadirectory": "***REMOVED SENSITIVE VALUE***",
        "memcache.local": "\\OC\\Memcache\\APCu",
        "dbtype": "mysql",
        "version": "25.0.6.1",
        "overwrite.cli.url": "***REMOVED SENSITIVE VALUE***",
        "htaccess.RewriteBase": "\/",
        "dbname": "***REMOVED SENSITIVE VALUE***",
        "dbhost": "***REMOVED SENSITIVE VALUE***",
        "dbport": "",
        "dbtableprefix": "oc_",
        "dbuser": "***REMOVED SENSITIVE VALUE***",
        "dbpassword": "***REMOVED SENSITIVE VALUE***",
        "installed": true,
        "mail_smtpmode": "sendmail",
        "mail_from_address": "***REMOVED SENSITIVE VALUE***",
        "mail_domain": "***REMOVED SENSITIVE VALUE***",
        "maintenance": false,
        "theme": "",
        "loglevel": 2,
        "updater.release.channel": "stable",
        "mysql.utf8mb4": true,
        "mail_sendmailmode": "smtp",
        "app_install_overwrite": [
            "user_external",
            "breezedark"
        ],
        "lost_password_link": "disabled",
    }
}

Web server error log

No response

Log file

No response

Browser log

No response

Additional info

No response

@richarson richarson added 0. to triage Pending approval or rejection bug labels May 23, 2023
@richarson
Copy link
Author

Screenshot of the interface with "Spanish (Argentina)" set:

image

@ChristophWurst
Copy link
Member

is this the only app where this happens?

@ChristophWurst
Copy link
Member

what's your locale set to?

@section1
Copy link

section1 commented May 30, 2023

Hi! have same problem..same calendar version and i see this request with Firefox debug tools when my user have Spanish (Argentina) as Language:

GET https://domain.tld/apps/calendar/js/calendar-node_modules_moment_locale_ar_js.js?v=cf0ab950a5e4e8b2f8d7

is taking Arabic locale ?
for example with Spanish (Chile) or (Mexico) this don't happens.

in case of Chile i get this:

GET https://domain.tld/apps/calendar/js/calendar-node_modules_moment_locale_es_js.js?v=a62256a047e01c0bb879

In case of Mexico this:

GET https://domain.tld/apps/calendar/js/calendar-node_modules_moment_locale_es-mx_js.js?v=592e7b69e9f941e1aee5

Thanks.

@muchachagrande
Copy link

This happened to me with version 4.3.4 and the workaround was setting language to spanish from Spaint es_ES.
Now, updated to 4.4.0 and it is happening with es_ES too.
So I changed forced language on config.php to "es" alone, without specification and now it is fixed again.
It is only happening with Calendar app, the other apps are showing fine.

@section1
Copy link

section1 commented Aug 3, 2023

Hello, any update in this issue ? do you need to test anything else so we can provide more information ? thanks.

@edumerco
Copy link

Same thing here, with 27.0.1 and es_ar locale.
How can we help to fix this?
Thanks a lot... :)

@jmcclelland
Copy link
Contributor

This bug is very easy to reproduce - just change your language to Spanish (Argentina) and visit the calendar page.

I haven't had a chance to properly test, but for anyone who has a dev environment setup - I'm pretty sure the bug is with the getLocaleFor() function.

  1. First, it tries to import the 'es-ar' locale. "es" is for Spanish and "ar" is for Argentina. But that locale does not exist.
  2. Then it splits the string into two parts ('es' and 'ar')
  3. Then it tries to import the second member of the set (ar) and treats it like it's a language, not a country, so it pulls in the arabic locale. Woops.
  4. It should try to pull in the first member (locale[0] instead of locale[1] on line 87 to "es" and pull in the generic spanish locale). Also,the block that tries to include the second member should probably be deleted. I'm not sure why we would ever want that.

@ChristophWurst
Copy link
Member

@TeaDrinkingProgrammer 👀 ^ :)

#5022 (comment)

Do we need better handling for these special cases?

@TeaDrinkingProgrammer
Copy link
Contributor

@TeaDrinkingProgrammer 👀 ^ :)

#5022 (comment)

Do we need better handling for these special cases?

I have done some more digging and found something which seems so obvious now: we can just parse the locale string with Momentjs:

Moment will also try locale specifier substrings from most-specific to least-specific until it finds a locale it knows. This is useful when supplying Moment with a locale string pulled from the user's environment, such as window.navigator.language.

moment.locale('en-nz'); // 'en'

Right now, we are splitting it manually and trying to parse the seperate two-letter codes:

E.G en-nz

Nz -> failsz tries next code
en -> success!

es-ar

ar -> succeeds (chooses arabic)

Should I try seeing if I can refactor the code to use this method? I can't get to it now but I can look into it in a few weeks.

@jmcclelland
Copy link
Contributor

I can try it out this week. One question - do we need the 'await import()' code to actually import the file or is that just there to test whether or not it is available?

@TeaDrinkingProgrammer
Copy link
Contributor

That's a great question. I don't actually know. That was what I wanted to test. If you want some test locales, I would suggest: en-us, en-de, es-ar

@jmcclelland
Copy link
Contributor

My impression based on the docs is that we don't need the import statement - moment should be loading these locales for us.

But... I think there is some kind of timing issue going on.

Here's what I'm testing:


async function getLocaleFor(locale) {
  try {
    const bestAvailableLocale = moment.locale(locale)
    console.debug("Returning", bestAvailableLocale, "for", locale)
    return bestAvailableLocale
  } catch (error) {
    console.debug('Error determining locale for', locale, 'Error:', error, 'Fallback to en')
    return 'en'
  }
}

And here's what I'm seeing in the console:

image

In other words, when the code runs, it always returns "en" no matter what I give it. But after the page has loaded, it works as expected. Any suggestions?

@jmcclelland
Copy link
Contributor

This more lightly modified code works as I would expect it to:

async function getLocaleFor(locale) {                                                                                                                                                                                
  // IMPORTANT: Keep each '/moment/local/...' string as is. Otherwise, webpack might not bundle                                                                                                                      
  //            locale data because the contentRegExp fails to detect any files.                                                                                                                                     
  try {                                                                                                                                                                                                              
    // default load e.g. en-de                                                                                                                                                                                       
    await import(`moment/locale/${locale}.js`)                                                                                                                                                                       
    return locale                                                                                                                                                                                                    
  } catch (error) {                                                                                                                                                                                                  
    const splitLocale = locale.split('-')                                                                                                                                                                            
    try {                                                                                                                                                                                                            
      // failure: fallback to first part of locale, which                                                                                                                                                            
      // should be langugae                                                                                                                                                                                          
      locale = splitLocale[0]                                                                                                                                                                                        
      await import(`moment/locale/${locale}.js`)                                                                                                                                                                     
      return locale                                                                                                                                                                                                  
    } catch (e) {                                                                                                                                                                                                    
      // failure, fallback to english                                                                                                                                                                                
      console.debug('Fallback to locale', 'en')                                                                                                                                                                      
      // English is the default locale and doesn't need to imported.                                                                                                                                                 
      // It is already included in moment.js.                                                                                                                                                                        
    }                                                                                                                                                                                                                
  }                                                                                                                                                                                                                  
                                                                                                                                                                                                                     
  return 'en'                                                                                                                                                                                                        
} 

I see that there is discussion about replacing the moment library altogether so maybe getting an imperfect fix is better than trying to make the moment library behave properly?

Also, it seems like there may be some bigger language/locale issues in Nextcloud core.

For example, while testing I noticed this:

In the United States, the week starts on Sunday (a locale setting right?):

image

But if we change the language to German while keeping the Enlighs (US) locale, the the week start date changes:

image

I think the day should continue starting on Sunday as long as English (US) is selected for locale. At this point, though, I'm not really sure ???

@TeaDrinkingProgrammer
Copy link
Contributor

This more lightly modified code works as I would expect it to:

async function getLocaleFor(locale) {                                                                                                                                                                                
  // IMPORTANT: Keep each '/moment/local/...' string as is. Otherwise, webpack might not bundle                                                                                                                      
  //            locale data because the contentRegExp fails to detect any files.                                                                                                                                     
  try {                                                                                                                                                                                                              
    // default load e.g. en-de                                                                                                                                                                                       
    await import(`moment/locale/${locale}.js`)                                                                                                                                                                       
    return locale                                                                                                                                                                                                    
  } catch (error) {                                                                                                                                                                                                  
    const splitLocale = locale.split('-')                                                                                                                                                                            
    try {                                                                                                                                                                                                            
      // failure: fallback to first part of locale, which                                                                                                                                                            
      // should be langugae                                                                                                                                                                                          
      locale = splitLocale[0]                                                                                                                                                                                        
      await import(`moment/locale/${locale}.js`)                                                                                                                                                                     
      return locale                                                                                                                                                                                                  
    } catch (e) {                                                                                                                                                                                                    
      // failure, fallback to english                                                                                                                                                                                
      console.debug('Fallback to locale', 'en')                                                                                                                                                                      
      // English is the default locale and doesn't need to imported.                                                                                                                                                 
      // It is already included in moment.js.                                                                                                                                                                        
    }                                                                                                                                                                                                                
  }                                                                                                                                                                                                                  
                                                                                                                                                                                                                     
  return 'en'                                                                                                                                                                                                        
} 

I see that there is discussion about replacing the moment library altogether so maybe getting an imperfect fix is better than trying to make the moment library behave properly?

Also, it seems like there may be some bigger language/locale issues in Nextcloud core.

For example, while testing I noticed this:

In the United States, the week starts on Sunday (a locale setting right?):

image

But if we change the language to German while keeping the Enlighs (US) locale, the the week start date changes:

image

I think the day should continue starting on Sunday as long as English (US) is selected for locale. At this point, though, I'm not really sure ???

I agree with the discussion about the fix, let's keep it temporary because Momentjs should be replaced anyway. The week should indeed start on monday with German and en-us locale. Could you show logs for that setting?

jmcclelland added a commit to jmcclelland/calendar that referenced this issue Aug 17, 2023
@jmcclelland
Copy link
Contributor

I agree with the discussion about the fix, let's keep it temporary because Momentjs should be replaced anyway. The week should indeed start on monday with German and en-us locale. Could you show logs for that setting?

I just made a pull request for the simpler change.

Should this new bug be opened against Nextcloud core instead of the calendar app? It seems to happen even with the calendar app disabled.

Also I see three very similar sounding open bugs:

Here is my config:

{
    "system": {
        "instanceid": "***REMOVED SENSITIVE VALUE***",
        "passwordsalt": "***REMOVED SENSITIVE VALUE***",
        "secret": "***REMOVED SENSITIVE VALUE***",
        "trusted_domains": [
            "nextcloud.loc.cx"
        ],
        "datadirectory": "***REMOVED SENSITIVE VALUE***",
        "dbtype": "mysql",
        "version": "28.0.0.2",
        "overwrite.cli.url": "https:\/\/nextcloud.loc.cx",
        "dbname": "***REMOVED SENSITIVE VALUE***",
        "dbhost": "***REMOVED SENSITIVE VALUE***",
        "dbport": "",
        "dbtableprefix": "oc_",
        "mysql.utf8mb4": true,
        "dbuser": "***REMOVED SENSITIVE VALUE***",
        "dbpassword": "***REMOVED SENSITIVE VALUE***",
        "updater.release.channel": "git",
        "installed": true,
        "app_install_overwrite": [
            "user_external"
        ],
        "user_backends": [
            {
                "class": "\\OCA\\UserExternal\\Yes",
                "arguments": []
            }
        ],
        "theme": "",
        "loglevel": 2,
        "maintenance": false
    },
    "apps": {
        "backgroundjob": {
            "lastjob": "4"
        },
        "calendar": {
            "enabled": "no",
            "installed_version": "4.5.0-beta.2",
            "types": ""
        },
        "cloud_federation_api": {
            "enabled": "yes",
            "installed_version": "1.11.0",
            "types": "filesystem"
        },
        "comments": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": "logging"
        },
        "contacts": {
            "enabled": "yes",
            "installed_version": "5.4.0-beta.2",
            "types": "dav"
        },
        "contactsinteraction": {
            "enabled": "yes",
            "installed_version": "1.9.0",
            "types": "dav"
        },
        "core": {
            "installedat": "1691795002.8084",
            "lastcron": "1692283999",
            "lastupdateResult": "[]",
            "lastupdatedat": "1692283819",
            "moveavatarsdone": "yes",
            "oc.integritycheck.checker": "[]",
            "previewsCleanedUp": "1",
            "public_files": "files_sharing\/public.php",
            "public_webdav": "dav\/appinfo\/v1\/publicwebdav.php",
            "vendor": "nextcloud"
        },
        "dashboard": {
            "enabled": "yes",
            "installed_version": "7.8.0",
            "types": ""
        },
        "dav": {
            "enabled": "yes",
            "installed_version": "1.28.0",
            "types": "filesystem"
        },
        "federatedfilesharing": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": ""
        },
        "federation": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": "authentication"
        },
        "files": {
            "enabled": "yes",
            "installed_version": "1.23.0",
            "types": "filesystem"
        },
        "files_reminders": {
            "enabled": "yes",
            "installed_version": "1.0.0",
            "types": ""
        },
        "files_sharing": {
            "enabled": "yes",
            "installed_version": "1.20.0",
            "types": "filesystem"
        },
        "files_trashbin": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": "filesystem,dav"
        },
        "files_versions": {
            "enabled": "yes",
            "installed_version": "1.21.0",
            "types": "filesystem,dav"
        },
        "lookup_server_connector": {
            "enabled": "yes",
            "installed_version": "1.16.0",
            "types": "authentication"
        },
        "mail": {
            "enabled": "yes",
            "installed_version": "3.4.0-beta.2",
            "types": ""
        },
        "notes": {
            "enabled": "yes",
            "installed_version": "4.8.1",
            "types": ""
        },
        "oauth2": {
            "enabled": "yes",
            "installed_version": "1.16.2",
            "types": "authentication"
        },
        "provisioning_api": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": "prevent_group_restriction"
        },
        "settings": {
            "enabled": "yes",
            "installed_version": "1.10.0",
            "types": ""
        },
        "sharebymail": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": "filesystem"
        },
        "systemtags": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": "logging"
        },
        "theming": {
            "enabled": "yes",
            "installed_version": "2.3.0",
            "types": "logging"
        },
        "twofactor_backupcodes": {
            "enabled": "yes",
            "installed_version": "1.17.0",
            "types": ""
        },
        "updatenotification": {
            "enabled": "yes",
            "installed_version": "1.18.0",
            "types": ""
        },
        "user_external": {
            "enabled": "yes",
            "installed_version": "3.2.0",
            "types": "prelogin,authentication"
        },
        "user_status": {
            "enabled": "yes",
            "installed_version": "1.8.0",
            "types": ""
        },
        "viewer": {
            "enabled": "yes",
            "installed_version": "2.2.0",
            "types": ""
        },
        "weather_status": {
            "enabled": "yes",
            "installed_version": "1.8.0",
            "types": ""
        },
        "workflowengine": {
            "enabled": "yes",
            "installed_version": "2.10.0",
            "types": "filesystem"
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0. to triage Pending approval or rejection bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants