jeessy2/ddns-go · warning
i18n: No such language "${lang}" in langDict ${langDict}
Error message
i18n: No such language "${lang}" in langDict ${langDict} What it means
After resolving a langDict, i18n picks the user's language via getLocalLang(Object.keys(langDict)) and returns langDict[lang] only if that key exists. When the resolved language is absent from the dictionary, it logs this warn and returns the raw key. Unlike error 83, the key exists but lacks a translation for the detected language.
Source
Thrown at static/i18n.js:299
}
const i18n = (keyOrLangDict) => {
let key = keyOrLangDict;
let langDict = keyOrLangDict;
if (typeof keyOrLangDict === 'string') {
langDict = I18N_MAP[keyOrLangDict];
} else {
key = null;
}
if (!langDict) {
console.warn(`i18n: No translation for key "${key}"`);
return key;
}
const lang = getLocalLang(Object.keys(langDict));
if (lang in langDict) {
return langDict[lang];
}
console.warn(`i18n: No such language "${lang}" in langDict ${langDict}`);
return key;
}
const convertDom = (dom = document) => {
dom.querySelectorAll('[data-i18n]').forEach(el => {
const key = el.dataset.i18n;
el.textContent = i18n(key);
});
dom.querySelectorAll('[data-i18n-html]').forEach(el => {
const key = el.dataset.i18nHtml;
el.innerHTML = i18n(key);
});
dom.querySelectorAll('[data-i18n-attr]').forEach(el => {
el.dataset.i18nAttr.split(',').forEach(item => {
let [attr, key] = item.split(':');
attr = attr.trim();
key = key || el.getAttribute(attr);
el.setAttribute(attr, i18n(key));View on GitHub (pinned to 5874c2e666)
Solutions
- Add the missing language entry to the key's langDict so every supported language is covered.
- Ensure getLocalLang maps locale variants to a language actually present in the dictionaries (e.g. normalize zh-TW -> zh).
- Provide an English fallback: if lang not in langDict, return langDict.en before falling back to the key.
- Audit all I18N_MAP entries to include the same language set.
Example fix
// before
if (lang in langDict) {
return langDict[lang];
}
console.warn(`i18n: No such language "${lang}" in langDict ${langDict}`);
return key;
// after
if (lang in langDict) return langDict[lang];
if ('en' in langDict) return langDict.en;
return key; Defensive patterns
Strategy: fallback
Validate before calling
function hasLang(langDict) {
const lang = getLocalLang(Object.keys(langDict));
return lang != null && Object.prototype.hasOwnProperty.call(langDict, lang);
}
if (!hasLang(I18N_MAP[key])) { /* use fallback lang or default */ } Type guard
function langDictSupports(langDict, lang) {
return langDict != null && Object.prototype.hasOwnProperty.call(langDict, lang);
} Prevention
- Give every key the same set of languages; enforce via a schema or test.
- Normalize locales in getLocalLang (zh-TW -> zh, en-US -> en).
- Always define an 'en' fallback entry per key.
- Track untranslated keys with the console.warn output during QA.
When it happens
Trigger: i18n('existingKey') or convertDom on data-i18n="existingKey" where I18N_MAP.existingKey exists but does not include the language returned by getLocalLang (e.g. dict has only en/zh, user locale is ja).
Common situations: New language added to the UI but existing keys not yet translated; a language dict written with only one locale; getLocalLang returning a code variant (e.g. 'zh-TW') not present in the dict.
Related errors
AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03).
Data as JSON: /api/errors/2a0402c944bcf192.
Report an issue: GitHub.