本文中本地化失效可能是一个文件名的BUG问题,仅供参考,还有一种本地化失效问题,可移步至新的文章《Swift本地化应用名称失效问题》
环境配置
1、Mac Sonoma 14.5
2、Xcode Version 15.4 (15F31d)
情景复现
因为我有一款“存钱猪猪”应用,目前还是初版。然后我打算推翻现有的内容,重新梳理这款软件的架构,其中比较重要的操作是删除了之前的文件,包括本地化问题、View等等问题。
删除后,重新实施本地化时,发现失效了。
我在配置Localizable文件时,我原本是默认中文,为了更好的推广应用,改为英文,并配置了简体中文的应用名称以及应用内容,但是应用无论如何都只显示英文的应用名称和内容。
好在,我之前提交到Github上了代码,我把之前的版本拉过来,进行问题的排查。
问题排查
首先是将新版本的代码复制到旧版本上,发现旧版本的本地化是正常的,虽然我在新版本中添加了lottie动画、渐变色等效果,但在旧版本上都能复现。
随后,开始对比参数,发现各项参数都是正常的,我甚至怀疑因为我改新版本时,调整了iOS最低的支持版本导致的问题,修改了支持版本仍然报错。
经过一上午的反复比较,发现旧版本和新版本的Localizable文件的命名不一样的,因为新版本为了做区分,将String Catalog类型的文件命名为LocalizableCatalog,将String File(Legacy)类型的文件命名为LocalizableLegacy。
然后我尝试修改新版本的String File(Legacy)文件的命名,将其改为旧版本的名称,本地化效果重新实现。
(本地化文件改为旧名称,本地化效果实现)
(本地化文件改为非旧名称,本地化效果失效)
经过几次测试,发现问题就是存在于本地化文件命名的问题。
这个文件影响了应用的本地化文件名称。
除此之外,另一个String Catalog文件也存在本地化失效的问题,我以为是String File(Legacy)是这个BUG间接导致的String Catalog文件的失效,然后我将现有的String Catalog文件删除后,重新创建String Catalog,发现还是本地化失效。
然后,我默默的将String Catalog类型文件改为旧版本的命名,应用内容的本地化效果实现。
(本地化文件改为旧名称,本地化效果实现)
(本地化文件改为非旧名称,本地化效果失效)
总结
经过了一个上午的仔细排查,问题出在本地化文件的命名,问题的原因可能为Xcode的BUG,在Xcode项目开始创建Localizable文件后,Xcode会将创建的Localizable文件的命名作为常量进行存储。如果后面修改了这个文件的命名,本地化效果就会失效。
以上是我在排查Xcode本地化失效问题时,自我作出的总结,也可能是其他字段导致的问题。
每遇到一个BUG,就会耽误我很长的一段开发进度,都2024年了,有时还是会出现莫名其妙的闪退,应该好好修一修Xcode,另外对于支持版本的事,我也发现很多特性都是iOS 14 或者iOS 15才能使用,如果不设置最低的支持版本,可能本地化的功能都实现不了,根本不考虑向下兼容的事。
后记
2024年年底(12月30日),又针对这一问题进行详细的排查。
经过长达2天半的时间,得出的结论为: Strings File(Legacy)文件只能命名为:
InfoPlist
其他的任何命名都会导致应用无法实现应用名称的本地化。
因此,当创建String Catalog和String File(Legacy)时,命名要为下图的旧版本的命名,自定义命名会导致本地化失效。
下面是论证的过程,有兴趣的朋友可以浏览并作为参考:
排查过程
当我重新梳理之前的《存钱猪猪》应用时,仍然是存在应用名称本地化失效的问题。
因此,想要尝试寻找这一问题的其他解决方式,例如修改Info.plist文件等等。因此开始了下面的排查之旅。
无论是设置String Catalog文件的CFBundleDisplayName字段,对应的Key为:
CFBundleDisplayName
还是设置Info.plist文件:
Bundle display name
都无法解决本地化应用名称失效的问题。
接着,我开始怀疑是两个Localizable文件冲突导致的。
因为如果两种Localizable文件并存且名称一致的话,还会报错:
/Users/fangjunyu.com/Documents/iOS开发/iOS应用-存钱猪猪/存钱猪猪/piglet/Language/Localizable.xcstrings:1:1 Localizable.xcstrings cannot co-exist with other .strings or .stringsdict tables with the same name.
然后,我尝试保留String Catalog,因此需要删除传统的Strings File文件。
在String Catalog中,设置CFBundleDisplayName字段:
CFBundleDisplayName
在中文语境下,我设置为“存钱猪猪”。
经过测试,发现这一方法也无法实现本地化应用实现的问题。
为什么要把Localizable命名为InfoPlist,这是因为我前面学习InfoPlist和Localizable时搞混了命名,当我再次清理并重建项目时,应用名称失效问题得到解决。
接着就是探讨问题的根源,为什么S文件只能使用首次命名,如果忘记第一次命名是否意味着无法再次失效应用名称的本地化?因此,推倒是Xcode内的某个字段保留了首次Localizable文件的命名,后面即使创建新的Localizable文件,也无法换绑或更改。
目前的推断是Xcode 项目中的本地化机制与文件名的绑定逻辑可能存在某些隐式约束,这与 Xcode 的内部设置以及 iOS 系统如何处理本地化文件有直接关系。
为什么最早的文件名生效?
第一次为项目设置 InfoPlist.strings 并本地化时,Xcode 自动在内部维护了一些关联数据。这些关联数据可能存储在以下位置:
1、Xcode 的项目文件 (.xcodeproj)
.xcodeproj 是一个文件夹结构,里面包含了项目配置。
本地化文件的路径和关联可能存储在 project.pbxproj 文件中。如果某些绑定未被正确更新或删除,Xcode 会继续引用原始路径。
2、Derived Data
Derived Data 文件夹是 Xcode 用于缓存构建信息的地方,可能包含旧的本地化文件路径。
如果 Derived Data 没有清理干净,系统可能继续使用缓存中的原始文件名路径。
3、Info.plist 中的引用
虽然 Info.plist 中未直接存储 InfoPlist.strings 的文件名,但 Xcode 的默认行为是将 CFBundleDisplayName 与 InfoPlist.strings 自动绑定。如果改用其他文件名(如 Localizable.strings),需要手动重新配置绑定逻辑。
因为我在前面测试时,删除过Derived Data文件,同时也检查过Info.plist文件,因此只能尝试检查.xcodeproj文件中是否存在绑定的问题。
检查.xcodeproj文件
String File(Legacy)文件的命名目前只能使用InfoPlist(首次命名的命名)才有效。
否则,应用名称只会显示piglet(项目名称)。
首先,检查.xcodeproj文件的内容,找到项目文件中的. xcodeproj文件,右击点击“显示包内容”。
打开 .xcodeproj 包内容,找到 project.pbxproj 文件。
打开后,搜寻旧文件名称:
InfoPlist.strings
当然,这也是目前的Localizable的文件名称,找到如下字段:
1DD325F92D21671600C7FF2F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1DD325F72D21671600C7FF2F /* InfoPlist.strings */; };
1DD325F82D21671600C7FF2F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
1DDC999A2D2167F400C17F90 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
1D64EFD22D21661F00832FB4 /* Strings */ = {
isa = PBXGroup;
children = (
1DD325F72D21671600C7FF2F /* InfoPlist.strings */,
);
path = Strings;
sourceTree = "<group>";
};
1DF5556F2BF60B1000BF0DE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1DE688052D21629500DB1AFA /* Localizable.xcstrings in Resources */,
1DD325F92D21671600C7FF2F /* InfoPlist.strings in Resources */,
1DF555792BF60B1200BF0DE5 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
1DD325F72D21671600C7FF2F /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
1DD325F82D21671600C7FF2F /* en */,
1DDC999A2D2167F400C17F90 /* zh-Hans */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
接着,测试旧文件名称和新文件名称的关联关系,因此,删除现在使用旧文件命名的Localizable文件。
注意:删除的时候,也把Xcode中的对应Localizable文件也删除掉,避免产生影响。
创建一个新的Localizable文件,最好放在一个文件夹中,这里创建了一个Strings文件夹,否则会在保存位置为每一个语言创建一个文件夹,显示混乱。
创建新的Localizable文件步骤:
这里,我使用了一个新的命名为:
LocalizableStrings
创建完成后,可以在项目中找到新的Localizable文件:
在新的文件中,设置中文语言下的命名:
"CFBundleDisplayName" = "存钱猪猪";
当中文语言下,现在的名称就是存钱猪猪。
然后,清理并重新构建项目:
1、点击Xcode – Product – Clean Build Folder Immediately。
2、在模拟器上删除之前下载的应用:
3、退出Xcode应用。
4、在访达中,按快捷键:
Command + Shift + G
快速找到DerivedData文件夹:
~/Library/Developer/Xcode/DerivedData
删除DerivedData文件中的所有文件:
重新运行Xcode应用:
在英语语言下,可以看到应用名称随着Localizable文件名称的变更,重新变成失效的状态。
接着关闭Xcode应用,进入到piglet.xcodeproj包中,重新打开project.pbxproj文件,可以看到有些字段已经改用了新的Localizable文件名称:
再次检索首次创建的Localizable文件名称:
InfoPlist.strings
并没有再次找到旧的文件名称:
因此,问题可能不在.xcodeproj文件中。
项目内检索旧文件名称
在项目中,尝试使用grep命令检索之前的Localizable文件名称:
InfoPlist
经检查发现两个文件含有InfoPlist的字符,
grep -r "InfoPlist" .
Binary file ./piglet.xcodeproj/project.xcworkspace/xcuserdata/fangjunyu.xcuserdatad/UserInterfaceState.xcuserstate matches
Binary file ./.git/index matches
piglet.xcodeproj/project.xcworkspace/xcuserdata/fangjunyu.xcuserdatad/
首先是判断问题在于UserInterfaceState.xcuserstate文件中,但查询了解到UserInterfaceState.xcuserstate 是一个二进制文件,包含 Xcode 用户界面状态的缓存信息,例如窗口布局、打开的文件、最近的选择等。
这个文件一般不会直接影响项目的构建或运行。即使内容包含旧文件名引用,也通常仅限于用户界面层面(比如上次关闭 Xcode 时打开的文件),不会影响项目逻辑。
为了测试,将这个文件移至桌面。
然后清理并重新构建项目,前面提到过这个清理的步骤。
完成之后,重新运行Xcode项目。
经过测试发现并没有解决问题。
把.git文件夹也删除进行测试,发现问题也未得到解决。
然后尝试在本地电脑查询所有的InfoPlist.strings:
find / -name 'InfoPlist.strings' -not -path "/System/Volumes/Data/*" 2>/dev/null
经过漫长的查询等待,并没有找到涉及项目名称和InfoPlist.strings文件相关的信息,但我发现关键的一点就是很多应用都有使用InfoPlist.strings文件的命名。
例如,微信使用的是InfoPlist.strings:
Hype4也使用的是InfoPlist.strings:
因此,我的推断是在创建Strings File(Legacy)文件时,只能使用
InfoPlist.strings
这个命名,其他的命名都会报错,同时从网上也找到创建并命名为InfoPlist.strings的文章。
注意,创建Strings File(Legacy)文件时,只需要输入InfoPlist,后面的strings是系统生成的文件后缀。
最后,为了验证这个问题,我拿出另一个项目《汇率仓库》进行核验:
然后创建新的Strings File(Legacy)文件后,应用名称成功翻译为中文。
总结
最后的总结就是,Strings File(Legacy)只能命名为:
InfoPlist
之前以为是可以自定义的,现在看来是Xcode指定的Strings File(Legacy)唯一名称,不能自定义修改为其他的名称。
相关文章
Swift本地化应用名称失效问题:https://fangjunyu.com/2024/10/29/swift%e6%9c%ac%e5%9c%b0%e5%8c%96%e5%ba%94%e7%94%a8%e5%90%8d%e7%a7%b0%e5%a4%b1%e6%95%88%e9%97%ae%e9%a2%98/
How to localise a string inside the iOS info.plist file?:https://stackoverflow.com/questions/25736700/how-to-localise-a-string-inside-the-ios-info-plist-file