Learning universal syntax
Typically, this goes over the generic logic blocks: such as if, else, else if, for, while, and switch-case statements, also creating function definitions and lambda functions. As well as determining the available primitive types, like int, float, char, string or arrays. And, whether the language is statically typed or dynamically typed and strongly typed or weakly typed.
Learning language-specific syntax
Languages may be object oriented or not, so classes, interfaces, and traits may or may not exists in some other languages. Functional languages may like to use functors more often than typical syntaxes, so retaining commonly used functors may be essential. Some modern language may introduce new logic blocks, like Rust's if-let or loop statements. Compile-time and run-time syntaxes may behaved differently requiring deeper understanding of languages with a build step. Generally, involves gaining a deeper understanding of the language's compiler or interpreter.
Learning the standard library, packages, or modules of a given language
Each languages may implement common data structures differently, such a map may be refered to as a Hash Map or as an Object prototype in other languages, and maps may be ordered and/or unordered depending on the language. Same goes for every possible implementation of a linked list, such as doubly-linked, single-ended, or double-ended, wherein other languages just opt to only implement a doubly-linked list. As an extension, remembering commonly used dependecies found and installed through a languages' package manager may be helpful. Extensive knowledge of libraries and module provides a keen insight for instances such as: a project requiring a package that can quickly implement JSON Serialization/Deserialization; or finding a well-maintained and adaptable image processing libraries; or debating between using a quick and accessible network communication interface or for a more flexible one.
Advanced System Programming & Concurrency
This involves utilising advanced features of the machines such as multithreading, asynchronous tasks, coroutines, and performing networking IO. Applications of aforementioned concepts can be applied in creating ACID functionalities, scheduling job queues, or communicating with several peripherals effectively
Memory Management or employing Type Safety
For lower level languages, it is essential to deallocate every dynamically allocated memory to prevent undefined behaviour and segmentation faults within a program. But for higher level languages, it is also essential to explicitly identify the type being used in a certain context especially for weakly & dynamically typed languages like JS. This also include, defining operator overloads to make custom types integrate naturally with the language's syntax/functors.
Utilising programming language in a project
Nothing proves someone's proficiency more than actually using the language to create something. It enlightens programmers on how to actually use the language in the context of applying it to an actual problem. And, it naturally reveals the limits and strengths of a language as the project scales in scope and size. Some of the aforementioned proficiencies are naturally developed as you go through a project. And, applying programming knowledge to coding projects will intuitively help retain problem solving skills from problems that pop up naturally in the course of a coding project.